📄 tar.c
字号:
case 'G': /* We are making a GNU dump; save
directories at the beginning of
the archive, and include in each
directory its contents */
if(f_oldarch)
goto badopt;
f_gnudump++;
gnu_dumpfile=0;
break;
case 'h':
f_follow_links++; /* follow symbolic links */
break;
case 'i':
f_ignorez++; /* Ignore zero records (eofs) */
/*
* This can't be the default, because Unix tar
* writes two records of zeros, then pads out the
* block with garbage.
*/
break;
case 'k': /* Don't overwrite files */
#ifdef NO_OPEN3
msg("can't do -k option on this system");
exit(EX_ARGSBAD);
#else
f_keep++;
#endif
break;
case 'K':
f_startfile++;
addname(optarg);
break;
case 'l': /* When dumping directories, don't
dump files/subdirectories that are
on other filesystems. */
f_local_filesys++;
break;
case 'L':
tape_length = intconv (optarg);
f_multivol++;
break;
case 'm':
f_modified++;
break;
case 'M': /* Make Multivolume archive:
When we can't write any more
into the archive, re-open it,
and continue writing */
f_multivol++;
break;
case 'N': /* Only write files newer than X */
get_newer:
f_new_files++;
new_time=get_date(optarg,(struct timeb *)0);
break;
case 'o': /* Generate old archive */
if(f_gnudump /* || f_dironly */)
goto badopt;
f_oldarch++;
break;
case 'O':
f_exstdout++;
break;
case 'p':
f_use_protection++;
break;
case 'P':
f_absolute_paths++;
break;
case 'r': /* Append files to the archive */
if(cmd_mode!=CMD_NONE)
goto badopt;
cmd_mode=CMD_APPEND;
break;
case 'R':
f_sayblock++; /* Print block #s for debug */
break; /* of bad tar archives */
case 's':
f_sorted_names++; /* Names to extr are sorted */
break;
case 'S': /* deal with sparse files */
f_sparse_files++;
break;
case 't':
if(cmd_mode!=CMD_NONE)
goto badopt;
cmd_mode=CMD_LIST;
f_verbose++; /* "t" output == "cv" or "xv" */
break;
case 'T':
name_file = optarg;
f_namefile++;
break;
case 'u': /* Append files to the archive that
aren't there, or are newer than the
copy in the archive */
if(cmd_mode!=CMD_NONE)
goto badopt;
cmd_mode=CMD_UPDATE;
break;
case 'v':
f_verbose++;
break;
case 'V':
f_volhdr=optarg;
break;
case 'w':
f_confirm++;
break;
case 'W':
f_verify++;
break;
case 'x': /* Extract files from the archive */
if(cmd_mode!=CMD_NONE)
goto badopt;
cmd_mode=CMD_EXTRACT;
break;
case 'X':
f_exclude++;
add_exclude_file(optarg);
break;
case 'z': /* Easy to type */
case 'Z': /* Like the filename extension .Z */
f_compress++;
break;
case '?':
badopt:
msg("Unknown option. Use '%s +help' for a complete list of options.", tar);
exit(EX_ARGSBAD);
}
}
blocksize = blocking * RECORDSIZE;
}
/*
* Print as much help as the user's gonna get.
*
* We have to sprinkle in the KLUDGE lines because too many compilers
* cannot handle character strings longer than about 512 bytes. Yuk!
* In particular, MSDOS and Xenix MSC and PDP-11 V7 Unix have this
* problem.
*/
void
describe()
{
msg("choose one of the following:");
fputs("\
-A, +catenate,\n\
+concatenate append tar files to an archive\n\
-c, +create create a new archive\n\
-d, +diff,\n\
+compare find differences between archive and file system\n\
+delete delete from the archive (not for use on mag tapes!)\n\
-r, +append append files to the end of an archive\n\
-t, +list list the contents of an archive\n\
-u, +update only append files that are newer than copy in archive\n\
-x, +extract,\n\
+get extract files from an archive\n",stderr);
fprintf(stderr, "\
Other options:\n\
-b, +block-size N block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING);
fputs ("\
-B, +read-full-blocks reblock as we read (for reading 4.2BSD pipes)\n\
-C, +directory DIR change to directory DIR\n\
", stderr); /* KLUDGE */ fprintf(stderr, "\
-f, +file [HOSTNAME:]F use archive file or device F (default %s)\n",
DEF_AR_FILE); fputs("\
-F, +info-script F run script at end of each tape (implies -M)\n\
-G, +incremental create/list/extract old GNU-format incremental backup\n\
-g, +listed-incremental F create/list/extract new GNU-format incremental backup\n\
-h, +dereference don't dump symlinks; dump the files they point to\n\
-i, +ignore-zeros ignore blocks of zeros in archive (normally mean EOF)\n\
", stderr); /* CHRIS */ fputs("\
-k, +keep-old-files keep existing files; don't overwrite them from archive\n\
-K, +starting-file FILE begin at FILE in the archive\n\
-l, +one-file-system stay in local file system when creating an archive\n\
-L, +tape-length LENGTH change tapes after writing LENGTH\n\
", stderr); /* KLUDGE */ fputs("\
-m, +modification-time don't extract file modified time\n\
-M, +multi-volume create/list/extract multi-volume archive\n\
-N, +after-date DATE,\n\
+newer DATE only store files newer than DATE\n\
", stderr); /* CHRIS */ fputs("\
-o, +old-archive,\n\
+portability write a V7 format archive, rather than ANSI format\n\
-O, +to-stdout extract files to standard output\n\
-p, +same-permissions,\n\
+preserve-permissions extract all protection information\n\
-P, +absolute-paths don't strip leading `/'s from file names\n\
+preserve like -p -s\n\
", stderr); /* KLUDGE */ fputs("\
-R, +record-number show record number within archive with each message\n\
-s, +same-order,\n\
+preserve-order list of names to extract is sorted to match archive\n\
+same-order create extracted files with the same ownership \n\
-S, +sparse handle sparse files efficiently\n\
-T, +files-from F get names to extract or create from file F\n\
+totals print total bytes written with +create\n\
", stderr); /* CHRIS */ fputs("\
-v, +verbose verbosely list files processed\n\
-V, +label NAME create archive with volume name NAME\n\
+version print tar program version number\n\
-w, +interactive,\n\
+confirmation ask for confirmation for every action\n\
", stderr); /* KLUDGE */ fputs("\
-W, +verify attempt to verify the archive after writing it\n\
-X, +exclude FILE exclude file FILE\n\
+exclude-from FILE exclude files listed in FILE\n\
-z, -Z, +compress,\n\
+uncompress filter the archive through compress\n\
-[0-7][lmh] specify drive and density\n\
", stderr);
}
name_add(name)
char *name;
{
if(n_indalloc==n_indused) {
n_indalloc+=10;
n_ind=(char **)(n_indused ? ck_realloc(n_ind,n_indalloc*sizeof(char *)) : ck_malloc(n_indalloc*sizeof(char *)));
}
n_ind[n_indused++]=name;
}
/*
* Set up to gather file names for tar.
*
* They can either come from stdin or from argv.
*/
name_init(argc, argv)
int argc;
char **argv;
{
if (f_namefile) {
if (optind < argc) {
msg("too many args with -T option");
exit(EX_ARGSBAD);
}
if (!strcmp(name_file, "-")) {
namef = stdin;
} else {
namef = fopen(name_file, "r");
if (namef == NULL) {
msg_perror("can't open file %s",name_file);
exit(EX_BADFILE);
}
}
} else {
/* Get file names from argv, after options. */
n_argc = argc;
n_argv = argv;
}
}
/*
* Get the next name from argv or the name file.
*
* Result is in static storage and can't be relied upon across two calls.
*/
/* C is non-zero if we should deal with -C */
char *
name_next(c)
{
static char *buffer; /* Holding pattern */
static buffer_siz;
register char *p;
register char *q = 0;
register char *q2 = 0;
extern char *un_quote_string();
if(buffer_siz==0) {
buffer=ck_malloc(NAMSIZ+2);
buffer_siz=NAMSIZ;
}
tryagain:
if (namef == NULL) {
if(n_indscan<n_indused)
p=n_ind[n_indscan++];
else if (optind < n_argc)
/* Names come from argv, after options */
p=n_argv[optind++];
else {
if(q)
msg("Missing filename after -C");
return NULL;
}
/* JF trivial support for -C option. I don't know if
chdir'ing at this point is dangerous or not.
It seems to work, which is all I ask. */
if(c && !q && p[0]=='-' && p[1]=='C' && p[2]=='\0') {
q=p;
goto tryagain;
}
if(q) {
if(chdir(p)<0)
msg_perror("Can't chdir to %s",p);
q=0;
goto tryagain;
}
/* End of JF quick -C hack */
if(f_exclude && check_exclude(p))
goto tryagain;
return un_quote_string(p);
}
while(p = fgets(buffer, buffer_siz+1 /*nl*/, namef)) {
q = p+strlen(p)-1; /* Find the newline */
if (q <= p) /* Ignore empty lines */
continue;
while(q==p+buffer_siz && *q!='\n') {
buffer=ck_realloc(buffer,buffer_siz+NAMSIZ+2);
p=buffer;
q=buffer+buffer_siz;
buffer_siz+=NAMSIZ;
fgets(q+1,NAMSIZ,namef);
q=p+strlen(p)-1;
}
*q-- = '\0'; /* Zap the newline */
while (q > p && *q == '/') /* Zap trailing /s */
*q-- = '\0';
if (c && !q2 && p[0] == '-' && p[1] == 'C' && p[2] == '\0') {
q2 = p;
goto tryagain;
}
if (q2) {
if (chdir (p) < 0)
msg_perror ("Can't chdir to %s", p);
q2 = 0;
goto tryagain;
}
if(f_exclude && check_exclude(p))
goto tryagain;
return un_quote_string(p);
}
return NULL;
}
/*
* Close the name file, if any.
*/
name_close()
{
if (namef != NULL && namef != stdin) fclose(namef);
}
/*
* Gather names in a list for scanning.
* Could hash them later if we really care.
*
* If the names are already sorted to match the archive, we just
* read them one by one. name_gather reads the first one, and it
* is called by name_match as appropriate to read the next ones.
* At EOF, the last name read is just left in the buffer.
* This option lets users of small machines extract an arbitrary
* number of files by doing "tar t" and editing down the list of files.
*/
name_gather()
{
register char *p;
static struct name *namebuf; /* One-name buffer */
static namelen;
static char *chdir_name;
if (f_sorted_names) {
if(!namelen) {
namelen=NAMSIZ;
namebuf=(struct name *)ck_malloc(sizeof(struct name)+NAMSIZ);
}
p = name_next(0);
if (p) {
if(*p=='-' && p[1]=='C' && p[2]=='\0') {
chdir_name=name_next(0);
p=name_next(0);
if(!p) {
msg("Missing file name after -C");
exit(EX_ARGSBAD);
}
namebuf->change_dir=chdir_name;
}
namebuf->length = strlen(p);
if (namebuf->length >= namelen) {
namebuf=(struct name *)ck_realloc(namebuf,sizeof(struct name)+namebuf->length);
namelen=namebuf->length;
}
strncpy(namebuf->name, p, namebuf->length);
namebuf->name[ namebuf->length ] = 0;
namebuf->next = (struct name *)NULL;
namebuf->found = 0;
namelist = namebuf;
namelast = namelist;
}
return;
}
/* Non sorted names -- read them all in */
while (p = name_next(0))
addname(p);
}
/*
* Add a name to the namelist.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -