]> Dogcows Code - chaz/tar/blob - src/tar.c
*** empty log message ***
[chaz/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 }
This page took 0.09726 seconds and 5 git commands to generate.