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