]> 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, 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 #else
980 char *getwd();
981
982 if(!getwd(path)) {
983 msg("Couldn't get current directory: %s",path);
984 exit(EX_SYSTEM);
985 }
986 #endif
987 chdir_name=new_name(path,chdir_name);
988 free(path);
989 }
990 }
991
992 if (name)
993 {
994 i = strlen(name);
995 /*NOSTRICT*/
996 p = (struct name *)malloc((unsigned)(sizeof(struct name) + i));
997 }
998 else
999 p = (struct name *)malloc ((unsigned)(sizeof (struct name)));
1000 if (!p) {
1001 if (name)
1002 msg("cannot allocate mem for name '%s'.",name);
1003 else
1004 msg("cannot allocate mem for chdir record.");
1005 exit(EX_SYSTEM);
1006 }
1007 p->next = (struct name *)NULL;
1008 if (name)
1009 {
1010 p->fake = 0;
1011 p->length = i;
1012 strncpy(p->name, name, i);
1013 p->name[i] = '\0'; /* Null term */
1014 }
1015 else
1016 p->fake = 1;
1017 p->found = 0;
1018 p->regexp = 0; /* Assume not a regular expression */
1019 p->firstch = 1; /* Assume first char is literal */
1020 p->change_dir=chdir_name;
1021 p->dir_contents = 0; /* JF */
1022 if (name)
1023 {
1024 if (index(name, '*') || index(name, '[') || index(name, '?')) {
1025 p->regexp = 1; /* No, it's a regexp */
1026 if (name[0] == '*' || name[0] == '[' || name[0] == '?')
1027 p->firstch = 0; /* Not even 1st char literal */
1028 }
1029 }
1030
1031 if (namelast) namelast->next = p;
1032 namelast = p;
1033 if (!namelist) namelist = p;
1034 }
1035
1036 /*
1037 * Return nonzero if name P (from an archive) matches any name from
1038 * the namelist, zero if not.
1039 */
1040 int
1041 name_match(p)
1042 register char *p;
1043 {
1044 register struct name *nlp;
1045 register int len;
1046
1047 again:
1048 if (0 == (nlp = namelist)) /* Empty namelist is easy */
1049 return 1;
1050 if (nlp->fake)
1051 {
1052 if (nlp->change_dir && chdir (nlp->change_dir))
1053 msg_perror ("Can't change to directory %d", nlp->change_dir);
1054 namelist = 0;
1055 return 1;
1056 }
1057 len = strlen(p);
1058 for (; nlp != 0; nlp = nlp->next) {
1059 /* If first chars don't match, quick skip */
1060 if (nlp->firstch && nlp->name[0] != p[0])
1061 continue;
1062
1063 /* Regular expressions (shell globbing, actually). */
1064 if (nlp->regexp) {
1065 if (fnmatch(nlp->name, p, FNM_TARPATH) == 0) {
1066 nlp->found = 1; /* Remember it matched */
1067 if(f_startfile) {
1068 free((void *)namelist);
1069 namelist=0;
1070 }
1071 if(nlp->change_dir && chdir(nlp->change_dir))
1072 msg_perror("Can't change to directory %s",nlp->change_dir);
1073 return 1; /* We got a match */
1074 }
1075 continue;
1076 }
1077
1078 /* Plain Old Strings */
1079 if (nlp->length <= len /* Archive len >= specified */
1080 && (p[nlp->length] == '\0' || p[nlp->length] == '/')
1081 /* Full match on file/dirname */
1082 && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
1083 {
1084 nlp->found = 1; /* Remember it matched */
1085 if(f_startfile) {
1086 free((void *)namelist);
1087 namelist = 0;
1088 }
1089 if(nlp->change_dir && chdir(nlp->change_dir))
1090 msg_perror("Can't change to directory %s",nlp->change_dir);
1091 return 1; /* We got a match */
1092 }
1093 }
1094
1095 /*
1096 * Filename from archive not found in namelist.
1097 * If we have the whole namelist here, just return 0.
1098 * Otherwise, read the next name in and compare it.
1099 * If this was the last name, namelist->found will remain on.
1100 * If not, we loop to compare the newly read name.
1101 */
1102 if (f_sorted_names && namelist->found) {
1103 name_gather(); /* Read one more */
1104 if (!namelist->found) goto again;
1105 }
1106 return 0;
1107 }
1108
1109
1110 /*
1111 * Print the names of things in the namelist that were not matched.
1112 */
1113 void
1114 names_notfound()
1115 {
1116 register struct name *nlp,*next;
1117 register char *p;
1118
1119 for (nlp = namelist; nlp != 0; nlp = next) {
1120 next=nlp->next;
1121 if (!nlp->found)
1122 msg("%s not found in archive",nlp->name);
1123
1124 /*
1125 * We could free() the list, but the process is about
1126 * to die anyway, so save some CPU time. Amigas and
1127 * other similarly broken software will need to waste
1128 * the time, though.
1129 */
1130 #ifdef amiga
1131 if (!f_sorted_names)
1132 free(nlp);
1133 #endif
1134 }
1135 namelist = (struct name *)NULL;
1136 namelast = (struct name *)NULL;
1137
1138 if (f_sorted_names) {
1139 while (0 != (p = name_next(1)))
1140 msg("%s not found in archive", p);
1141 }
1142 }
1143
1144 /* These next routines were created by JF */
1145
1146 void
1147 name_expand()
1148 {
1149 ;
1150 }
1151
1152 /* This is like name_match(), except that it returns a pointer to the name
1153 it matched, and doesn't set ->found The caller will have to do that
1154 if it wants to. Oh, and if the namelist is empty, it returns 0, unlike
1155 name_match(), which returns TRUE */
1156
1157 struct name *
1158 name_scan(p)
1159 register char *p;
1160 {
1161 register struct name *nlp;
1162 register int len;
1163
1164 again:
1165 if (0 == (nlp = namelist)) /* Empty namelist is easy */
1166 return 0;
1167 len = strlen(p);
1168 for (; nlp != 0; nlp = nlp->next) {
1169 /* If first chars don't match, quick skip */
1170 if (nlp->firstch && nlp->name[0] != p[0])
1171 continue;
1172
1173 /* Regular expressions */
1174 if (nlp->regexp) {
1175 if (fnmatch(nlp->name, p, FNM_TARPATH) == 0)
1176 return nlp; /* We got a match */
1177 continue;
1178 }
1179
1180 /* Plain Old Strings */
1181 if (nlp->length <= len /* Archive len >= specified */
1182 && (p[nlp->length] == '\0' || p[nlp->length] == '/')
1183 /* Full match on file/dirname */
1184 && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
1185 return nlp; /* We got a match */
1186 }
1187
1188 /*
1189 * Filename from archive not found in namelist.
1190 * If we have the whole namelist here, just return 0.
1191 * Otherwise, read the next name in and compare it.
1192 * If this was the last name, namelist->found will remain on.
1193 * If not, we loop to compare the newly read name.
1194 */
1195 if (f_sorted_names && namelist->found) {
1196 name_gather(); /* Read one more */
1197 if (!namelist->found) goto again;
1198 }
1199 return (struct name *) 0;
1200 }
1201
1202 /* This returns a name from the namelist which doesn't have ->found set.
1203 It sets ->found before returning, so successive calls will find and return
1204 all the non-found names in the namelist */
1205
1206 struct name *gnu_list_name;
1207
1208 char *
1209 name_from_list()
1210 {
1211 if(!gnu_list_name)
1212 gnu_list_name = namelist;
1213 while(gnu_list_name && gnu_list_name->found)
1214 gnu_list_name=gnu_list_name->next;
1215 if(gnu_list_name) {
1216 gnu_list_name->found++;
1217 if(gnu_list_name->change_dir)
1218 if(chdir(gnu_list_name->change_dir)<0)
1219 msg_perror("can't chdir to %s",gnu_list_name->change_dir);
1220 return gnu_list_name->name;
1221 }
1222 return (char *)0;
1223 }
1224
1225 void
1226 blank_name_list()
1227 {
1228 struct name *n;
1229
1230 gnu_list_name = 0;
1231 for(n=namelist;n;n=n->next)
1232 n->found = 0;
1233 }
1234
1235 char *
1236 new_name(path,name)
1237 char *path,*name;
1238 {
1239 char *path_buf;
1240
1241 path_buf=(char *)malloc(strlen(path)+strlen(name)+2);
1242 if(path_buf==0) {
1243 msg("Can't allocate memory for name '%s/%s",path,name);
1244 exit(EX_SYSTEM);
1245 }
1246 (void) sprintf(path_buf,"%s/%s",path,name);
1247 return path_buf;
1248 }
1249
1250 /* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */
1251
1252 int
1253 confirm(action,file)
1254 char *action, *file;
1255 {
1256 int c,nl;
1257 static FILE *confirm_file = 0;
1258 extern FILE *msg_file;
1259 extern char TTY_NAME[];
1260
1261 fprintf(msg_file,"%s %s?", action, file);
1262 fflush(msg_file);
1263 if(!confirm_file) {
1264 confirm_file = (archive == 0) ? fopen(TTY_NAME, "r") : stdin;
1265 if(!confirm_file) {
1266 msg("Can't read confirmation from user");
1267 exit(EX_SYSTEM);
1268 }
1269 }
1270 c=getc(confirm_file);
1271 for(nl = c; nl != '\n' && nl != EOF; nl = getc(confirm_file))
1272 ;
1273 return (c=='y' || c=='Y');
1274 }
1275
1276 char *x_buffer = 0;
1277 int size_x_buffer;
1278 int free_x_buffer;
1279
1280 char **exclude = 0;
1281 int size_exclude = 0;
1282 int free_exclude = 0;
1283
1284 char **re_exclude = 0;
1285 int size_re_exclude = 0;
1286 int free_re_exclude = 0;
1287
1288 void
1289 add_exclude(name)
1290 char *name;
1291 {
1292 /* char *rname;*/
1293 /* char **tmp_ptr;*/
1294 int size_buf;
1295
1296 un_quote_string(name);
1297 size_buf = strlen(name);
1298
1299 if(x_buffer==0) {
1300 x_buffer = (char *)ck_malloc(size_buf+1024);
1301 free_x_buffer=1024;
1302 } else if(free_x_buffer<=size_buf) {
1303 char *old_x_buffer;
1304 char **tmp_ptr;
1305
1306 old_x_buffer = x_buffer;
1307 x_buffer = (char *)ck_realloc(x_buffer,size_x_buffer+1024);
1308 free_x_buffer = 1024;
1309 for(tmp_ptr=exclude;tmp_ptr<exclude+size_exclude;tmp_ptr++)
1310 *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer);
1311 for(tmp_ptr=re_exclude;tmp_ptr<re_exclude+size_re_exclude;tmp_ptr++)
1312 *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer);
1313 }
1314
1315 if(is_regex(name)) {
1316 if(free_re_exclude==0) {
1317 re_exclude= (char **)(re_exclude ? ck_realloc(re_exclude,(size_re_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
1318 free_re_exclude+=32;
1319 }
1320 re_exclude[size_re_exclude]=x_buffer+size_x_buffer;
1321 size_re_exclude++;
1322 free_re_exclude--;
1323 } else {
1324 if(free_exclude==0) {
1325 exclude=(char **)(exclude ? ck_realloc(exclude,(size_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
1326 free_exclude+=32;
1327 }
1328 exclude[size_exclude]=x_buffer+size_x_buffer;
1329 size_exclude++;
1330 free_exclude--;
1331 }
1332 strcpy(x_buffer+size_x_buffer,name);
1333 size_x_buffer+=size_buf+1;
1334 free_x_buffer-=size_buf+1;
1335 }
1336
1337 void
1338 add_exclude_file(file)
1339 char *file;
1340 {
1341 FILE *fp;
1342 char buf[1024];
1343
1344 if(strcmp(file, "-"))
1345 fp=fopen(file,"r");
1346 else
1347 /* Let's hope the person knows what they're doing. */
1348 /* Using -X - -T - -f - will get you *REALLY* strange
1349 results. . . */
1350 fp=stdin;
1351
1352 if(!fp) {
1353 msg_perror("can't open %s",file);
1354 exit(2);
1355 }
1356 while(fgets(buf,1024,fp)) {
1357 /* int size_buf;*/
1358 char *end_str;
1359
1360 end_str=rindex(buf,'\n');
1361 if(end_str)
1362 *end_str='\0';
1363 add_exclude(buf);
1364
1365 }
1366 fclose(fp);
1367 }
1368
1369 int
1370 is_regex(str)
1371 char *str;
1372 {
1373 return index(str,'*') || index(str,'[') || index(str,'?');
1374 }
1375
1376 /* Returns non-zero if the file 'name' should not be added/extracted */
1377 int
1378 check_exclude(name)
1379 char *name;
1380 {
1381 int n;
1382 char *str;
1383 extern char *strstr();
1384
1385 for(n=0;n<size_re_exclude;n++) {
1386 if(fnmatch(re_exclude[n], name, FNM_TARPATH) == 0)
1387 return 1;
1388 }
1389 for(n=0;n<size_exclude;n++) {
1390 /* Accept the output from strstr only if it is the last
1391 part of the string. There is certainly a faster way to
1392 do this. . . */
1393 if( (str=strstr(name,exclude[n]))
1394 && (str==name || str[-1]=='/')
1395 && str[strlen(exclude[n])]=='\0')
1396 return 1;
1397 }
1398 return 0;
1399 }
This page took 0.100012 seconds and 5 git commands to generate.