*** empty log message ***
[debian/tar] / src / tar.c
1 /* Tar -- a tape archiver.
2    Copyright (C) 1988 Free Software Foundation
3
4 This file is part of GNU Tar.
5
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /*
21  * A tar (tape archiver) program.
22  *
23  * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
24  */
25
26 #include <stdio.h>
27 #include <sys/types.h>          /* Needed for typedefs in tar.h */
28 #include "getopt.h"
29 #include "regex.h"
30
31 /*
32  * The following causes "tar.h" to produce definitions of all the
33  * global variables, rather than just "extern" declarations of them.
34  */
35 #define TAR_EXTERN /**/
36 #include "tar.h"
37
38 #include "port.h"
39
40 #if defined(_POSIX_VERSION) || defined(DIRENT)
41 #include <dirent.h>
42 #ifdef direct
43 #undef direct
44 #endif /* direct */
45 #define direct dirent
46 #define DP_NAMELEN(x) strlen((x)->d_name)
47 #endif /* _POSIX_VERSION or DIRENT */
48 #if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42)
49 #include <sys/dir.h>
50 #define DP_NAMELEN(x)   (x)->d_namlen
51 #endif /* not _POSIX_VERSION and BSD42 */
52 #ifdef __MSDOS__
53 #include "msd_dir.h"
54 #define DP_NAMELEN(x)   (x)->d_namlen
55 #define direct dirent
56 #endif
57 #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT)
58 #include <ndir.h>
59 #define DP_NAMELEN(x) strlen((x)->d_name)
60 #endif /* USG and not _POSIX_VERSION and not DIRENT */
61
62 /*
63  * We should use a conversion routine that does reasonable error
64  * checking -- atoi doesn't.  For now, punt.  FIXME.
65  */
66 #define intconv atoi
67 PTR ck_malloc();
68 PTR ck_realloc();
69 extern int      getoldopt();
70 extern void     read_and();
71 extern void     list_archive();
72 extern void     extract_archive();
73 extern void     diff_archive();
74 extern void     create_archive();
75 extern void     update_archive();
76 extern void     junk_archive();
77
78 /* JF */
79 extern time_t   get_date();
80
81 time_t new_time;
82
83 static FILE     *namef;         /* File to read names from */
84 static char     **n_argv;       /* Argv used by name routines */
85 static int      n_argc;         /* Argc used by name routines */
86 static char     **n_ind;        /* Store an array of names */
87 static int      n_indalloc;     /* How big is the array? */
88 static int      n_indused;      /* How many entries does it have? */
89 static int      n_indscan;      /* How many of the entries have we scanned? */
90
91
92 extern FILE *msg_file;
93
94 int     check_exclude();
95 void    add_exclude();
96 void    add_exclude_file();
97 void    addname();
98 void    describe();
99 void    diff_init();
100 void    extr_init();
101 int     is_regex();
102 void    name_add();
103 void    name_init();
104 void    options();
105 char    *un_quote_string();
106 int     wildmat();
107
108 #ifndef S_ISLNK
109 #define lstat stat
110 #endif
111
112 #ifndef DEFBLOCKING
113 #define DEFBLOCKING 20
114 #endif
115
116 #ifndef DEF_AR_FILE
117 #define DEF_AR_FILE "tar.out"
118 #endif
119
120 /* For long options that unconditionally set a single flag, we have getopt
121    do it.  For the others, we share the code for the equivalent short
122    named option, the name of which is stored in the otherwise-unused `val'
123    field of the `struct option'; for long options that have no equivalent
124    short option, we use nongraphic characters as pseudo short option
125    characters, starting (for no particular reason) with character 10. */
126
127 struct option long_options[] =
128 {
129         {"create",              0,      0,                      'c'},
130         {"append",              0,      0,                      'r'},
131         {"extract",             0,      0,                      'x'},
132         {"get",                 0,      0,                      'x'},
133         {"list",                0,      0,                      't'},
134         {"update",              0,      0,                      'u'},
135         {"catenate",            0,      0,                      'A'},
136         {"concatenate",         0,      0,                      'A'},
137         {"compare",             0,      0,                      'd'},
138         {"diff",                0,      0,                      'd'},
139         {"delete",              0,      0,                      14},
140         {"help",                0,      0,                      12},
141
142         {"null",                0,      0,                      16},
143         {"directory",           1,      0,                      'C'},
144         {"record-number",       0,      &f_sayblock,            1},
145         {"files-from",          1,      0,                      'T'},
146         {"label",               1,      0,                      'V'},
147         {"exclude-from",        1,      0,                      'X'},
148         {"exclude",             1,      0,                      15},
149         {"file",                1,      0,                      'f'},
150         {"block-size",          1,      0,                      'b'},
151         {"version",             0,      0,                      11},
152         {"verbose",             0,      0,                      'v'},
153         {"totals",              0,      &f_totals,              1},
154           
155         {"read-full-blocks",    0,      &f_reblock,             1},
156         {"starting-file",       1,      0,                      'K'},
157         {"to-stdout",           0,      &f_exstdout,            1},
158         {"ignore-zeros",        0,      &f_ignorez,             1},
159         {"keep-old-files",      0,      0,                      'k'},
160         {"uncompress",          0,      &f_compress,            1},
161         {"same-permissions",    0,      &f_use_protection,      1},
162         {"preserve-permissions",0,      &f_use_protection,      1},
163         {"modification-time",   0,      &f_modified,            1},
164         {"preserve",            0,      0,                      10},
165         {"same-order",          0,      &f_sorted_names,        1},
166         {"same-owner",          0,      &f_do_chown,            1},
167         {"preserve-order",      0,      &f_sorted_names,        1},
168
169         {"newer",               1,      0,                      'N'},
170         {"after-date",          1,      0,                      'N'},
171         {"newer-mtime",         1,      0,                      13},
172         {"incremental",         0,      0,                      'G'},
173         {"listed-incremental",  1,      0,                      'g'},
174         {"multi-volume",        0,      &f_multivol,            1},
175         {"info-script",         1,      0,                      'F'},
176         {"absolute-paths",      0,      &f_absolute_paths,      1},
177         {"interactive",         0,      &f_confirm,             1},
178         {"confirmation",        0,      &f_confirm,             1},
179
180         {"verify",              0,      &f_verify,              1},
181         {"dereference",         0,      &f_follow_links,        1},
182         {"one-file-system",     0,      &f_local_filesys,       1},
183         {"old-archive",         0,      0,                      'o'},
184         {"portability",         0,      0,                      'o'},
185         {"compress",            0,      &f_compress,            1},
186         {"compress-block",      0,      &f_compress,            2},
187         {"sparse",              0,      &f_sparse_files,        1},
188         {"tape-length",         1,      0,                      'L'},
189
190         {0, 0, 0, 0}
191 };
192
193 /*
194  * Main routine for tar.
195  */
196 void
197 main(argc, argv)
198         int     argc;
199         char    **argv;
200 {
201         extern char version_string[];
202
203         tar = argv[0];          /* JF: was "tar" Set program name */
204         filename_terminator = '\n';
205         errors = 0;
206
207         options(argc, argv);
208
209         if(!n_argv)
210                 name_init(argc, argv);
211
212         switch(cmd_mode) {
213         case CMD_CAT:
214         case CMD_UPDATE:
215         case CMD_APPEND:
216                 update_archive();
217                 break;
218         case CMD_DELETE:
219                 junk_archive();
220                 break;
221         case CMD_CREATE:
222                 create_archive();
223                 if (f_totals)
224                         fprintf (stderr, "Total bytes written: %d\n", tot_written);
225                 break;
226         case CMD_EXTRACT:
227                 if (f_volhdr) {
228                         char *err;
229                         label_pattern = (struct re_pattern_buffer *)
230                           ck_malloc (sizeof *label_pattern);
231                         err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
232                                                   label_pattern);
233                         if (err) {
234                                 fprintf (stderr,"Bad regular expression: %s\n",
235                                          err);
236                                 errors++;
237                                 break;
238                         }
239                    
240                 }                 
241                 extr_init();
242                 read_and(extract_archive);
243                 break;
244         case CMD_LIST:
245                 if (f_volhdr) {
246                         char *err;
247                         label_pattern = (struct re_pattern_buffer *)
248                           ck_malloc (sizeof *label_pattern);
249                         err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
250                                                   label_pattern);
251                         if (err) {
252                                 fprintf (stderr,"Bad regular expression: %s\n",
253                                          err);
254                                 errors++;
255                                 break;
256                         }
257                 }                 
258                 read_and(list_archive);
259 #if 0
260                 if (!errors)
261                         errors = different;
262 #endif
263                 break;
264         case CMD_DIFF:
265                 diff_init();
266                 read_and(diff_archive);
267                 break;
268         case CMD_VERSION:
269                 fprintf(stderr,"%s\n",version_string);
270                 break;
271         case CMD_NONE:
272                 msg("you must specify exactly one of the r, c, t, x, or d options\n");
273                 fprintf(stderr,"For more information, type ``%s +help''.\n",tar);
274                 exit(EX_ARGSBAD);
275         }
276         exit(errors);
277         /* NOTREACHED */
278 }
279
280
281 /*
282  * Parse the options for tar.
283  */
284 void
285 options(argc, argv)
286         int     argc;
287         char    **argv;
288 {
289         register int    c;              /* Option letter */
290         int             ind = -1;
291
292         /* Set default option values */
293         blocking = DEFBLOCKING;         /* From Makefile */
294         ar_file = getenv("TAPE");       /* From environment, or */
295         if (ar_file == 0)
296                 ar_file = DEF_AR_FILE;  /* From Makefile */
297
298         /* Parse options */
299         while ((c = getoldopt(argc, argv,
300                               "-01234567Ab:BcC:df:F:g:GhikK:lL:mMN:oOpPrRsStT:uvV:wWxX:zZ",
301                               long_options, &ind)) != EOF) {
302                 switch (c) {
303                 case 0:         /* long options that set a single flag */
304                         break;
305                 case 1:
306                         /* File name or non-parsed option */
307                         name_add(optarg);
308                         break;
309                 case 'C':
310                         name_add("-C");
311                         name_add(optarg);
312                         break;
313                 case 10:        /* preserve */
314                         f_use_protection = f_sorted_names = 1;
315                         break;
316                 case 11:
317                         if(cmd_mode!=CMD_NONE)
318                                 goto badopt;
319                         cmd_mode=CMD_VERSION;
320                         break;
321                 case 12:        /* help */
322                         printf("This is GNU tar, the tape archiving program.\n");
323                         describe();
324                         exit(1);
325                 case 13:
326                         f_new_files++;
327                         goto get_newer;
328
329                 case 14:        /* Delete in the archive */
330                         if(cmd_mode!=CMD_NONE)
331                                 goto badopt;
332                         cmd_mode=CMD_DELETE;
333                         break;
334
335                 case 15:
336                         f_exclude++;
337                         add_exclude(optarg);
338                         break;
339
340                 case 16:        /* -T reads null terminated filenames. */
341                         filename_terminator = '\0';
342                         break;
343
344                 case 'g':       /* We are making a GNU dump; save
345                                    directories at the beginning of
346                                    the archive, and include in each
347                                    directory its contents */
348                         if(f_oldarch)
349                                 goto badopt;
350                         f_gnudump++;
351                         gnu_dumpfile=optarg;
352                         break;
353
354
355                 case '0':
356                 case '1':
357                 case '2':
358                 case '3':
359                 case '4':
360                 case '5':
361                 case '6':
362                 case '7':
363                         {
364                                 /* JF this'll have to be modified for other
365                                    systems, of course! */
366                                 int d,add;
367                                 static char buf[50];
368
369                                 d=getoldopt(argc,argv,"lmh");
370 #ifdef MAYBEDEF
371                                 sprintf(buf,"/dev/rmt/%d%c",c,d);
372 #else
373 #ifndef LOW_NUM
374 #define LOW_NUM 0
375 #define MID_NUM 8
376 #define HGH_NUM 16
377 #endif
378                                 if(d=='l') add=LOW_NUM;
379                                 else if(d=='m') add=MID_NUM;
380                                 else if(d=='h') add=HGH_NUM;
381                                 else goto badopt;
382
383                                 sprintf(buf,"/dev/rmt%d",add+c-'0');
384 #endif
385                                 ar_file=buf;
386                         }
387                         break;
388
389                 case 'A':       /* Arguments are tar files,
390                                    just cat them onto the end
391                                    of the archive.  */
392                         if(cmd_mode!=CMD_NONE)
393                                 goto badopt;
394                         cmd_mode=CMD_CAT;
395                         break;
396
397                 case 'b':       /* Set blocking factor */
398                         blocking = intconv(optarg);
399                         break;
400
401                 case 'B':       /* Try to reblock input */
402                         f_reblock++;            /* For reading 4.2BSD pipes */
403                         break;
404
405                 case 'c':                       /* Create an archive */
406                         if(cmd_mode!=CMD_NONE)
407                                 goto badopt;
408                         cmd_mode=CMD_CREATE;
409                         break;
410
411 #if 0
412                 case 'C':
413                         if(chdir(optarg)<0)
414                                 msg_perror("Can't change directory to %d",optarg);
415                         break;
416 #endif
417
418                 case 'd':       /* Find difference tape/disk */
419                         if(cmd_mode!=CMD_NONE)
420                                 goto badopt;
421                         cmd_mode=CMD_DIFF;
422                         break;
423
424                 case 'f':       /* Use ar_file for the archive */
425                         ar_file = optarg;
426                         break;
427
428                 case 'F':
429                         /* Since -F is only useful with -M , make it implied */
430                         f_run_script_at_end++;  /* run this script at the end */
431                         info_script = optarg;   /* of each tape */
432                         f_multivol++;
433                         break;
434
435                 case 'G':       /* We are making a GNU dump; save
436                                    directories at the beginning of
437                                    the archive, and include in each
438                                    directory its contents */
439                         if(f_oldarch)
440                                 goto badopt;
441                         f_gnudump++;
442                         gnu_dumpfile=0;
443                         break;
444
445                 case 'h':
446                         f_follow_links++;       /* follow symbolic links */
447                         break;
448
449                 case 'i':
450                         f_ignorez++;            /* Ignore zero records (eofs) */
451                         /*
452                          * This can't be the default, because Unix tar
453                          * writes two records of zeros, then pads out the
454                          * block with garbage.
455                          */
456                         break;
457
458                 case 'k':       /* Don't overwrite files */
459 #ifdef NO_OPEN3
460                         msg("can't keep old files on this system");
461                         exit(EX_ARGSBAD);
462 #else
463                         f_keep++;
464 #endif
465                         break;
466
467                 case 'K':
468                         f_startfile++;
469                         addname(optarg);
470                         break;
471
472                 case 'l':       /* When dumping directories, don't
473                                    dump files/subdirectories that are
474                                    on other filesystems. */
475                         f_local_filesys++;
476                         break;
477
478                 case 'L':
479                         tape_length = intconv (optarg);
480                         f_multivol++;
481                         break;
482                 case 'm':
483                         f_modified++;
484                         break;
485
486                 case 'M':       /* Make Multivolume archive:
487                                    When we can't write any more
488                                    into the archive, re-open it,
489                                    and continue writing */
490                         f_multivol++;
491                         break;
492
493                 case 'N':       /* Only write files newer than X */
494                 get_newer:
495                         f_new_files++;
496                         new_time=get_date(optarg, (PTR) 0);
497                         if (new_time == (time_t) -1) {
498                           msg("invalid date format `%s'", optarg);
499                           exit(EX_ARGSBAD);
500                         }
501                         break;
502
503                 case 'o':       /* Generate old archive */
504                         if(f_gnudump /* || f_dironly */)
505                                 goto badopt;
506                         f_oldarch++;
507                         break;
508
509                 case 'O':
510                         f_exstdout++;
511                         break;
512
513                 case 'p':
514                         f_use_protection++;
515                         break;
516
517                 case 'P':
518                         f_absolute_paths++;
519                         break;
520
521                 case 'r':       /* Append files to the archive */
522                         if(cmd_mode!=CMD_NONE)
523                                 goto badopt;
524                         cmd_mode=CMD_APPEND;
525                         break;
526
527                 case 'R':
528                         f_sayblock++;           /* Print block #s for debug */
529                         break;                  /* of bad tar archives */
530
531                 case 's':
532                         f_sorted_names++;       /* Names to extr are sorted */
533                         break;
534
535                 case 'S':                       /* deal with sparse files */
536                         f_sparse_files++;
537                         break;
538                 case 't':
539                         if(cmd_mode!=CMD_NONE)
540                                 goto badopt;
541                         cmd_mode=CMD_LIST;
542                         f_verbose++;            /* "t" output == "cv" or "xv" */
543                         break;
544
545                 case 'T':
546                         name_file = optarg;
547                         f_namefile++;
548                         break;
549
550                 case 'u':       /* Append files to the archive that
551                                    aren't there, or are newer than the
552                                    copy in the archive */
553                         if(cmd_mode!=CMD_NONE)
554                                 goto badopt;
555                         cmd_mode=CMD_UPDATE;
556                         break;
557
558                 case 'v':
559                         f_verbose++;
560                         break;
561
562                 case 'V':
563                         f_volhdr=optarg;
564                         break;
565
566                 case 'w':
567                         f_confirm++;
568                         break;
569
570                 case 'W':
571                         f_verify++;
572                         break;
573
574                 case 'x':       /* Extract files from the archive */
575                         if(cmd_mode!=CMD_NONE)
576                                 goto badopt;
577                         cmd_mode=CMD_EXTRACT;
578                         break;
579
580                 case 'X':
581                         f_exclude++;
582                         add_exclude_file(optarg);
583                         break;
584
585                 case 'z':               /* Easy to type */
586                 case 'Z':               /* Like the filename extension .Z */
587                         f_compress++;
588                         break;
589
590                 case '?':
591                 badopt:
592                         msg("Unknown option.  Use '%s +help' for a complete list of options.", tar);
593                         exit(EX_ARGSBAD);
594
595                 }
596         }
597
598         blocksize = blocking * RECORDSIZE;
599 }
600
601
602 /*
603  * Print as much help as the user's gonna get.
604  *
605  * We have to sprinkle in the KLUDGE lines because too many compilers
606  * cannot handle character strings longer than about 512 bytes.  Yuk!
607  * In particular, MS-DOS and Xenix MSC and PDP-11 V7 Unix have this
608  * problem.
609  */
610 void
611 describe()
612 {
613         puts("choose one of the following:");
614         fputs("\
615 -A, --catenate,\n\
616     --concatenate       append tar files to an archive\n\
617 -c, --create            create a new archive\n\
618 -d, --diff,\n\
619     --compare           find differences between archive and file system\n\
620 --delete                        delete from the archive (not for use on mag tapes!)\n\
621 -r, --append            append files to the end of an archive\n\
622 -t, --list              list the contents of an archive\n\
623 -u, --update            only append files that are newer than copy in archive\n\
624 -x, --extract,\n\
625     --get               extract files from an archive\n",stdout);
626
627         fprintf(stdout, "\
628 Other options:\n\
629 -b, --block-size N      block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING);
630         fputs ("\
631 -B, --read-full-blocks  reblock as we read (for reading 4.2BSD pipes)\n\
632 -C, --directory DIR     change to directory DIR\n\
633 ", stdout); /* KLUDGE */ fprintf(stdout, "\
634 -f, --file [HOSTNAME:]F use archive file or device F (default %s)\n",
635                                  DEF_AR_FILE); fputs("\
636 -F, --info-script F     run script at end of each tape (implies -M)\n\
637 -G, --incremental       create/list/extract old GNU-format incremental backup\n\
638 -g, --listed-incremental F create/list/extract new GNU-format incremental backup\n\
639 -h, --dereference       don't dump symlinks; dump the files they point to\n\
640 -i, --ignore-zeros      ignore blocks of zeros in archive (normally mean EOF)\n\
641 -k, --keep-old-files    keep existing files; don't overwrite them from archive\n\
642 -K, --starting-file FILE        begin at FILE in the archive\n\
643 -l, --one-file-system   stay in local file system when creating an archive\n\
644 -L, --tape-length LENGTH change tapes after writing LENGTH\n\
645 ", stdout); /* KLUDGE */ fputs("\
646 -m, --modification-time don't extract file modified time\n\
647 -M, --multi-volume      create/list/extract multi-volume archive\n\
648 -N, --after-date DATE,\n\
649     --newer DATE                only store files newer than DATE\n\
650 -o, --old-archive,\n\
651     --portability       write a V7 format archive, rather than ANSI format\n\
652 -O, --to-stdout         extract files to standard output\n\
653 -p, --same-permissions,\n\
654     --preserve-permissions extract all protection information\n\
655 -P, --absolute-paths    don't strip leading `/'s from file names\n\
656 --preserve              like -p -s\n\
657 ", stdout); /* KLUDGE */ fputs("\
658 -R, --record-number     show record number within archive with each message\n\
659 -s, --same-order,\n\
660     --preserve-order    list of names to extract is sorted to match archive\n\
661 --same-order            create extracted files with the same ownership \n\
662 -S, --sparse            handle sparse files efficiently\n\
663 -T, --files-from F      get names to extract or create from file F\n\
664 --null                  -T reads null-terminated names, disable -C\n\
665 --totals                        print total bytes written with --create\n\
666 -v, --verbose           verbosely list files processed\n\
667 -V, --label NAME                create archive with volume name NAME\n\
668 --version               print tar program version number\n\
669 -w, --interactive,\n\
670     --confirmation      ask for confirmation for every action\n\
671 ", stdout); /* KLUDGE */ fputs("\
672 -W, --verify            attempt to verify the archive after writing it\n\
673 --exclude FILE          exclude file FILE\n\
674 -X, --exclude-from FILE exclude files listed in FILE\n\
675 -z, -Z, --compress,\n\
676     --uncompress        filter the archive through compress\n\
677 -[0-7][lmh]             specify drive and density\n\
678 ", stdout);
679 }
680
681 void
682 name_add(name)
683 char *name;
684 {
685         if(n_indalloc==n_indused) {
686                 n_indalloc+=10;
687                 n_ind=(char **)(n_indused ? ck_realloc(n_ind,n_indalloc*sizeof(char *)) : ck_malloc(n_indalloc*sizeof(char *)));
688         }
689         n_ind[n_indused++]=name;
690 }
691                 
692 /*
693  * Set up to gather file names for tar.
694  *
695  * They can either come from stdin or from argv.
696  */
697 void
698 name_init(argc, argv)
699         int     argc;
700         char    **argv;
701 {
702
703         if (f_namefile) {
704                 if (optind < argc) {
705                         msg("too many args with -T option");
706                         exit(EX_ARGSBAD);
707                 }
708                 if (!strcmp(name_file, "-")) {
709                         namef = stdin;
710                 } else {
711                         namef = fopen(name_file, "r");
712                         if (namef == NULL) {
713                                 msg_perror("can't open file %s",name_file);
714                                 exit(EX_BADFILE);
715                         }
716                 }
717         } else {
718                 /* Get file names from argv, after options. */
719                 n_argc = argc;
720                 n_argv = argv;
721         }
722 }
723
724 /* Read the next filename read from STREAM and null-terminate it.
725    Put it into BUFFER, reallocating and adjusting *PBUFFER_SIZE if necessary.
726    Return the new value for BUFFER, or NULL at end of file. */
727
728 char *
729 read_name_from_file (buffer, pbuffer_size, stream)
730      char *buffer;
731      size_t *pbuffer_size;
732      FILE *stream;
733 {
734   register int c;
735   register int indx = 0;
736   register size_t buffer_size = *pbuffer_size;
737
738   while ((c = getc (stream)) != EOF && c != filename_terminator)
739     {
740       if (indx == buffer_size)
741         {
742           buffer_size += NAMSIZ;
743           buffer = ck_realloc (buffer, buffer_size + 2);
744         }
745       buffer[indx++] = c;
746     }
747   if (indx == 0 && c == EOF)
748     return NULL;
749   if (indx == buffer_size)
750     {
751       buffer_size += NAMSIZ;
752       buffer = ck_realloc (buffer, buffer_size + 2);
753     }
754   buffer[indx] = '\0';
755   *pbuffer_size = buffer_size;
756   return buffer;
757 }
758
759 /*
760  * Get the next name from argv or the name file.
761  *
762  * Result is in static storage and can't be relied upon across two calls.
763  *
764  * If CHANGE_DIRS is non-zero, treat a filename of the form "-C" as
765  * meaning that the next filename is the name of a directory to change to.
766  * If `filename_terminator' is '\0', CHANGE_DIRS is effectively always 0.
767  */
768
769 char *
770 name_next(change_dirs)
771      int change_dirs;
772 {
773         static char     *buffer;        /* Holding pattern */
774         static int buffer_siz;
775         register char   *p;
776         register char   *q = 0;
777         register int    next_name_is_dir = 0;
778         extern char *un_quote_string();
779
780         if(buffer_siz==0) {
781                 buffer=ck_malloc(NAMSIZ+2);
782                 buffer_siz=NAMSIZ;
783         }
784         if (filename_terminator == '\0')
785                 change_dirs = 0;
786  tryagain:
787         if (namef == NULL) {
788                 if(n_indscan<n_indused)
789                         p=n_ind[n_indscan++];
790                 else if (optind < n_argc)               
791                         /* Names come from argv, after options */
792                         p=n_argv[optind++];
793                 else {
794                         if(q)
795                                 msg("Missing filename after -C");
796                         return NULL;
797                 }
798
799                 /* JF trivial support for -C option.  I don't know if
800                    chdir'ing at this point is dangerous or not.
801                    It seems to work, which is all I ask. */
802                 if(change_dirs && !q && p[0]=='-' && p[1]=='C' && p[2]=='\0') {
803                         q=p;
804                         goto tryagain;
805                 }
806                 if(q) {
807                         if(chdir(p)<0)
808                                 msg_perror("Can't chdir to %s",p);
809                         q=0;
810                         goto tryagain;
811                 }
812                 /* End of JF quick -C hack */
813
814                 if(f_exclude && check_exclude(p))
815                         goto tryagain;
816                 return un_quote_string(p);
817         }
818         while (p = read_name_from_file (buffer, &buffer_siz, namef)) {
819                 buffer = p;
820                 if (*p == '\0')
821                         continue; /* Ignore empty lines. */
822                 q = p + strlen (p) - 1;
823                 while (q > p && *q == '/')      /* Zap trailing "/"s. */
824                         *q-- = '\0';
825                 if (change_dirs && next_name_is_dir == 0
826                     && p[0] == '-' && p[1] == 'C' && p[2] == '\0') {
827                         next_name_is_dir = 1;
828                         goto tryagain;
829                 }
830                 if (next_name_is_dir) {
831                         if (chdir (p) < 0)
832                                 msg_perror ("Can't change to directory %s", p);
833                         next_name_is_dir = 0;
834                         goto tryagain;
835                 }
836                 if(f_exclude && check_exclude(p))
837                         goto tryagain;
838                 return un_quote_string(p);
839         }
840         return NULL;
841 }
842
843
844 /*
845  * Close the name file, if any.
846  */
847 void
848 name_close()
849 {
850
851         if (namef != NULL && namef != stdin) fclose(namef);
852 }
853
854
855 /*
856  * Gather names in a list for scanning.
857  * Could hash them later if we really care.
858  *
859  * If the names are already sorted to match the archive, we just
860  * read them one by one.  name_gather reads the first one, and it
861  * is called by name_match as appropriate to read the next ones.
862  * At EOF, the last name read is just left in the buffer.
863  * This option lets users of small machines extract an arbitrary
864  * number of files by doing "tar t" and editing down the list of files.
865  */
866 void
867 name_gather()
868 {
869         register char *p;
870         static struct name *namebuf;    /* One-name buffer */
871         static namelen;
872         static char *chdir_name;
873
874         if (f_sorted_names) {
875                 if(!namelen) {
876                         namelen=NAMSIZ;
877                         namebuf=(struct name *)ck_malloc(sizeof(struct name)+NAMSIZ);
878                 }
879                 p = name_next(0);
880                 if (p) {
881                         if(*p=='-' && p[1]=='C' && p[2]=='\0') {
882                                 chdir_name=name_next(0);
883                                 p=name_next(0);
884                                 if(!p) {
885                                         msg("Missing file name after -C");
886                                         exit(EX_ARGSBAD);
887                                 }
888                                 namebuf->change_dir=chdir_name;
889                         }
890                         namebuf->length = strlen(p);
891                         if (namebuf->length >= namelen) {
892                                 namebuf=(struct name *)ck_realloc(namebuf,sizeof(struct name)+namebuf->length);
893                                 namelen=namebuf->length;
894                         }
895                         strncpy(namebuf->name, p, namebuf->length);
896                         namebuf->name[ namebuf->length ] = 0;
897                         namebuf->next = (struct name *)NULL;
898                         namebuf->found = 0;
899                         namelist = namebuf;
900                         namelast = namelist;
901                 }
902                 return;
903         }
904
905         /* Non sorted names -- read them all in */
906         while (p = name_next(0))
907                 addname(p);
908 }
909
910 /*
911  * Add a name to the namelist.
912  */
913 void
914 addname(name)
915         char    *name;                  /* pointer to name */
916 {
917         register int    i;              /* Length of string */
918         register struct name    *p;     /* Current struct pointer */
919         static char *chdir_name;
920         char *new_name();
921
922         if(name[0]=='-' && name[1]=='C' && name[2]=='\0') {
923                 chdir_name=name_next(0);
924                 name=name_next(0);
925                 if(!chdir_name) {
926                         msg("Missing file name after -C");
927                         exit(EX_ARGSBAD);
928                 }
929                 if(chdir_name[0]!='/') {
930                         char *path = ck_malloc(PATH_MAX);
931 #if defined(__MSDOS__) || defined(USG) || defined(_POSIX_VERSION)
932                         if(!getcwd(path,PATH_MAX))
933                                 msg("Couldn't get current directory.");
934                                 exit(EX_SYSTEM);
935 #else
936                         char *getwd();
937
938                         if(!getwd(path)) {
939                                 msg("Couldn't get current directory: %s",path);
940                                 exit(EX_SYSTEM);
941                         }
942 #endif
943                         chdir_name=new_name(path,chdir_name);
944                         free(path);
945                 }
946         }
947
948         if (name)
949           {
950             i = strlen(name);
951             /*NOSTRICT*/
952             p = (struct name *)malloc((unsigned)(sizeof(struct name) + i));
953           }
954         else
955           p = (struct name *)malloc ((unsigned)(sizeof (struct name)));
956         if (!p) {
957           if (name)
958             msg("cannot allocate mem for name '%s'.",name);
959           else
960             msg("cannot allocate mem for chdir record.");
961           exit(EX_SYSTEM);
962         }
963         p->next = (struct name *)NULL;
964         if (name)
965           {
966             p->fake = 0;
967             p->length = i;
968             strncpy(p->name, name, i);
969             p->name[i] = '\0';  /* Null term */
970           }
971         else
972           p->fake = 1;
973         p->found = 0;
974         p->regexp = 0;          /* Assume not a regular expression */
975         p->firstch = 1;         /* Assume first char is literal */
976         p->change_dir=chdir_name;
977         p->dir_contents = 0;    /* JF */
978         if (name)
979           {
980             if (index(name, '*') || index(name, '[') || index(name, '?')) {
981               p->regexp = 1;    /* No, it's a regexp */
982               if (name[0] == '*' || name[0] == '[' || name[0] == '?')
983                 p->firstch = 0;         /* Not even 1st char literal */
984             }
985           }
986
987         if (namelast) namelast->next = p;
988         namelast = p;
989         if (!namelist) namelist = p;
990 }
991
992 /*
993  * Return nonzero if name P (from an archive) matches any name from
994  * the namelist, zero if not.
995  */
996 int
997 name_match(p)
998         register char *p;
999 {
1000         register struct name    *nlp;
1001         register int            len;
1002
1003 again:
1004         if (0 == (nlp = namelist))      /* Empty namelist is easy */
1005                 return 1;
1006         if (nlp->fake)
1007           {
1008             if (nlp->change_dir && chdir (nlp->change_dir))
1009               msg_perror ("Can't change to directory %d", nlp->change_dir);
1010             namelist = 0;
1011             return 1;
1012           }
1013         len = strlen(p);
1014         for (; nlp != 0; nlp = nlp->next) {
1015                 /* If first chars don't match, quick skip */
1016                 if (nlp->firstch && nlp->name[0] != p[0])
1017                         continue;
1018
1019                 /* Regular expressions (shell globbing, actually). */
1020                 if (nlp->regexp) {
1021                         if (wildmat(p, nlp->name)) {
1022                                 nlp->found = 1; /* Remember it matched */
1023                                 if(f_startfile) {
1024                                         free((void *)namelist);
1025                                         namelist=0;
1026                                 }
1027                                 if(nlp->change_dir && chdir(nlp->change_dir))
1028                                         msg_perror("Can't change to directory %s",nlp->change_dir);
1029                                 return 1;       /* We got a match */
1030                         }
1031                         continue;
1032                 }
1033
1034                 /* Plain Old Strings */
1035                 if (nlp->length <= len          /* Archive len >= specified */
1036                  && (p[nlp->length] == '\0' || p[nlp->length] == '/')
1037                                                 /* Full match on file/dirname */
1038                  && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
1039                 {
1040                         nlp->found = 1;         /* Remember it matched */
1041                         if(f_startfile) {
1042                                 free((void *)namelist);
1043                                 namelist = 0;
1044                         }
1045                         if(nlp->change_dir && chdir(nlp->change_dir))
1046                                 msg_perror("Can't change to directory %s",nlp->change_dir);
1047                         return 1;               /* We got a match */
1048                 }
1049         }
1050
1051         /*
1052          * Filename from archive not found in namelist.
1053          * If we have the whole namelist here, just return 0.
1054          * Otherwise, read the next name in and compare it.
1055          * If this was the last name, namelist->found will remain on.
1056          * If not, we loop to compare the newly read name.
1057          */
1058         if (f_sorted_names && namelist->found) {
1059                 name_gather();          /* Read one more */
1060                 if (!namelist->found) goto again;
1061         }
1062         return 0;
1063 }
1064
1065
1066 /*
1067  * Print the names of things in the namelist that were not matched.
1068  */
1069 void
1070 names_notfound()
1071 {
1072         register struct name    *nlp,*next;
1073         register char           *p;
1074
1075         for (nlp = namelist; nlp != 0; nlp = next) {
1076                 next=nlp->next;
1077                 if (!nlp->found)
1078                         msg("%s not found in archive",nlp->name);
1079
1080                 /*
1081                  * We could free() the list, but the process is about
1082                  * to die anyway, so save some CPU time.  Amigas and
1083                  * other similarly broken software will need to waste
1084                  * the time, though.
1085                  */
1086 #ifdef amiga
1087                 if (!f_sorted_names)
1088                         free(nlp);
1089 #endif
1090         }
1091         namelist = (struct name *)NULL;
1092         namelast = (struct name *)NULL;
1093
1094         if (f_sorted_names) {
1095                 while (0 != (p = name_next(1)))
1096                         msg("%s not found in archive", p);
1097         }
1098 }
1099
1100 /* These next routines were created by JF */
1101
1102 void
1103 name_expand()
1104 {
1105 ;
1106 }
1107
1108 /* This is like name_match(), except that it returns a pointer to the name
1109    it matched, and doesn't set ->found  The caller will have to do that
1110    if it wants to.  Oh, and if the namelist is empty, it returns 0, unlike
1111    name_match(), which returns TRUE */
1112
1113 struct name *
1114 name_scan(p)
1115 register char *p;
1116 {
1117         register struct name    *nlp;
1118         register int            len;
1119
1120 again:
1121         if (0 == (nlp = namelist))      /* Empty namelist is easy */
1122                 return 0;
1123         len = strlen(p);
1124         for (; nlp != 0; nlp = nlp->next) {
1125                 /* If first chars don't match, quick skip */
1126                 if (nlp->firstch && nlp->name[0] != p[0])
1127                         continue;
1128
1129                 /* Regular expressions */
1130                 if (nlp->regexp) {
1131                         if (wildmat(p, nlp->name))
1132                                 return nlp;     /* We got a match */
1133                         continue;
1134                 }
1135
1136                 /* Plain Old Strings */
1137                 if (nlp->length <= len          /* Archive len >= specified */
1138                  && (p[nlp->length] == '\0' || p[nlp->length] == '/')
1139                                                 /* Full match on file/dirname */
1140                  && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
1141                         return nlp;             /* We got a match */
1142         }
1143
1144         /*
1145          * Filename from archive not found in namelist.
1146          * If we have the whole namelist here, just return 0.
1147          * Otherwise, read the next name in and compare it.
1148          * If this was the last name, namelist->found will remain on.
1149          * If not, we loop to compare the newly read name.
1150          */
1151         if (f_sorted_names && namelist->found) {
1152                 name_gather();          /* Read one more */
1153                 if (!namelist->found) goto again;
1154         }
1155         return (struct name *) 0;
1156 }
1157
1158 /* This returns a name from the namelist which doesn't have ->found set.
1159    It sets ->found before returning, so successive calls will find and return
1160    all the non-found names in the namelist */
1161
1162 struct name *gnu_list_name;
1163
1164 char *
1165 name_from_list()
1166 {
1167         if(!gnu_list_name)
1168                 gnu_list_name = namelist;
1169         while(gnu_list_name && gnu_list_name->found)
1170                 gnu_list_name=gnu_list_name->next;
1171         if(gnu_list_name) {
1172                 gnu_list_name->found++;
1173                 if(gnu_list_name->change_dir)
1174                         if(chdir(gnu_list_name->change_dir)<0)
1175                                 msg_perror("can't chdir to %s",gnu_list_name->change_dir);
1176                 return gnu_list_name->name;
1177         }
1178         return (char *)0;
1179 }
1180
1181 void
1182 blank_name_list()
1183 {
1184         struct name *n;
1185
1186         gnu_list_name = 0;
1187         for(n=namelist;n;n=n->next)
1188                 n->found = 0;
1189 }
1190
1191 char *
1192 new_name(path,name)
1193 char *path,*name;
1194 {
1195         char *path_buf;
1196
1197         path_buf=(char *)malloc(strlen(path)+strlen(name)+2);
1198         if(path_buf==0) {
1199                 msg("Can't allocate memory for name '%s/%s",path,name);
1200                 exit(EX_SYSTEM);
1201         }
1202         (void) sprintf(path_buf,"%s/%s",path,name);
1203         return path_buf;
1204 }
1205
1206 /* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */
1207
1208 int
1209 confirm(action,file)
1210 char *action, *file;
1211 {
1212         int     c,nl;
1213         static FILE *confirm_file = 0;
1214         extern FILE *msg_file;
1215         extern char TTY_NAME[];
1216
1217         fprintf(msg_file,"%s %s?", action, file);
1218         fflush(msg_file);
1219         if(!confirm_file) {
1220                 confirm_file = (archive == 0) ? fopen(TTY_NAME, "r") : stdin;
1221                 if(!confirm_file) {
1222                         msg("Can't read confirmation from user");
1223                         exit(EX_SYSTEM);
1224                 }
1225         }
1226         c=getc(confirm_file);
1227         for(nl = c; nl != '\n' && nl != EOF; nl = getc(confirm_file))
1228                 ;
1229         return (c=='y' || c=='Y');
1230 }
1231
1232 char *x_buffer = 0;
1233 int size_x_buffer;
1234 int free_x_buffer;
1235
1236 char **exclude = 0;
1237 int size_exclude = 0;
1238 int free_exclude = 0;
1239
1240 char **re_exclude = 0;
1241 int size_re_exclude = 0;
1242 int free_re_exclude = 0;
1243
1244 void
1245 add_exclude(name)
1246 char *name;
1247 {
1248 /*      char *rname;*/
1249 /*      char **tmp_ptr;*/
1250         int size_buf;
1251
1252         un_quote_string(name);
1253         size_buf = strlen(name);
1254
1255         if(x_buffer==0) {
1256                 x_buffer = (char *)ck_malloc(size_buf+1024);
1257                 free_x_buffer=1024;
1258         } else if(free_x_buffer<=size_buf) {
1259                 char *old_x_buffer;
1260                 char **tmp_ptr;
1261
1262                 old_x_buffer = x_buffer;
1263                 x_buffer = (char *)ck_realloc(x_buffer,size_x_buffer+1024);
1264                 free_x_buffer = 1024;
1265                 for(tmp_ptr=exclude;tmp_ptr<exclude+size_exclude;tmp_ptr++)
1266                         *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer);
1267                 for(tmp_ptr=re_exclude;tmp_ptr<re_exclude+size_re_exclude;tmp_ptr++)
1268                         *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer);
1269         }
1270
1271         if(is_regex(name)) {
1272                 if(free_re_exclude==0) {
1273                         re_exclude= (char **)(re_exclude ? ck_realloc(re_exclude,(size_re_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
1274                         free_re_exclude+=32;
1275                 }
1276                 re_exclude[size_re_exclude]=x_buffer+size_x_buffer;
1277                 size_re_exclude++;
1278                 free_re_exclude--;
1279         } else {
1280                 if(free_exclude==0) {
1281                         exclude=(char **)(exclude ? ck_realloc(exclude,(size_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
1282                         free_exclude+=32;
1283                 }
1284                 exclude[size_exclude]=x_buffer+size_x_buffer;
1285                 size_exclude++;
1286                 free_exclude--;
1287         }
1288         strcpy(x_buffer+size_x_buffer,name);
1289         size_x_buffer+=size_buf+1;
1290         free_x_buffer-=size_buf+1;
1291 }
1292
1293 void
1294 add_exclude_file(file)
1295 char *file;
1296 {
1297         FILE *fp;
1298         char buf[1024];
1299         extern char *rindex();
1300
1301         if(strcmp(file, "-"))
1302                 fp=fopen(file,"r");
1303         else
1304                 /* Let's hope the person knows what they're doing. */
1305                 /* Using -X - -T - -f - will get you *REALLY* strange
1306                    results. . . */
1307                 fp=stdin;
1308
1309         if(!fp) {
1310                 msg_perror("can't open %s",file);
1311                 exit(2);
1312         }
1313         while(fgets(buf,1024,fp)) {
1314 /*              int size_buf;*/
1315                 char *end_str;
1316
1317                 end_str=rindex(buf,'\n');
1318                 if(end_str)
1319                         *end_str='\0';
1320                 add_exclude(buf);
1321
1322         }
1323         fclose(fp);
1324 }
1325
1326 int
1327 is_regex(str)
1328 char *str;
1329 {
1330         return index(str,'*') || index(str,'[') || index(str,'?');
1331 }
1332
1333 /* Returns non-zero if the file 'name' should not be added/extracted */
1334 int
1335 check_exclude(name)
1336 char *name;
1337 {
1338         int n;
1339         char *str;
1340         extern char *strstr();
1341
1342         for(n=0;n<size_re_exclude;n++) {
1343                 if(wildmat(name,re_exclude[n]))
1344                         return 1;
1345         }
1346         for(n=0;n<size_exclude;n++) {
1347                 /* Accept the output from strstr only if it is the last
1348                    part of the string.  There is certainly a faster way to
1349                    do this. . . */
1350                 if(   (str=strstr(name,exclude[n]))
1351                    && (str==name || str[-1]=='/')
1352                    && str[strlen(exclude[n])]=='\0')
1353                         return 1;
1354         }
1355         return 0;
1356 }