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