📄 tar.c
字号:
-M, +multi-volume create/list/extract multi-volume archive\n\-N, +after-date date only store files newer than DATE\n\-o, +old-archive write a V7 format archive, rather than ANSI format\n\-O, +to-stdout extract files to standard output\n\-p, +same-permissions extract all protection information\n\-P, +absolute-paths don't strip leading `/'s from file names\n\+preserve like -p -s\n\-R, +record-number show record number within archive with each message\n\-s, +same-order list of names to extract is sorted to match archive\n\-S, +sparse handle sparse files efficiently\n\", stderr); /* KLUDGE */ fputs("\-T, +files-from F get names to extract or create from file F\n\-v, +verbose verbosely list files processed\n\-V, +volume VNAM create archive with volume name VNAM\n\+version print tar program version number\n\-w, +interactive ask for confirmation for every action\n\-W, +verify attempt to verify the archive after writing it\n\-X, +exclude FILE exclude files listed in FILE\n\-z, -Z, +compress 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(int)) : ck_malloc(n_indalloc*sizeof(int))); } 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[NAMSIZ+2]; /* Holding pattern */ register char *p; register char *q = 0; extern char *un_quote_string(); 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, NAMSIZ+1 /*nl*/, namef)) { q = p+strlen(p)-1; /* Find the newline */ if (q <= p) /* Ignore empty lines */ continue; *q-- = '\0'; /* Zap the newline */ while (q > p && *q == '/') /* Zap trailing /s */ *q-- = '\0'; 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[1]; /* One-name buffer */ static char *chdir_name; if (f_sorted_names) { 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[0].change_dir=chdir_name; } namebuf[0].length = strlen(p); if (namebuf[0].length >= sizeof namebuf[0].name) { msg("Argument name '%s' too long.",p); namebuf[0].length = (sizeof namebuf[0].name) - 1; } strncpy(namebuf[0].name, p, namebuf[0].length); namebuf[0].name[ namebuf[0].length ] = 0; namebuf[0].next = (struct name *)NULL; namebuf[0].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. */addname(name) char *name; /* pointer to name */{ register int i; /* Length of string */ register struct name *p; /* Current struct pointer */ static char *chdir_name; char *new_name();#define MAXPATHLEN 1024 if(name[0]=='-' && name[1]=='C' && name[2]=='\0') { chdir_name=name_next(0); name=name_next(0); if(!name) { msg("Missing file name after -C"); exit(EX_ARGSBAD); } if(chdir_name[0]!='/') { char path[MAXPATHLEN];#if defined(MSDOS) || defined(USG) int getcwd(); if(!getcwd(path,MAXPATHLEN)) msg("Couldn't get current directory."); exit(EX_SYSTEM);#else char *getwd(); if(!getwd(path)) { msg("Couldn't get current directory: %s",path); exit(EX_SYSTEM); }#endif chdir_name=new_name(path,chdir_name); } } i = strlen(name); /*NOSTRICT*/ p = (struct name *) malloc((unsigned)(i + sizeof(struct name) - NAMSIZ)); if (!p) { msg("cannot allocate mem for name '%s'.",name); exit(EX_SYSTEM); } p->next = (struct name *)NULL; p->length = i; strncpy(p->name, name, i); p->name[i] = '\0'; /* Null term */ p->found = 0; p->regexp = 0; /* Assume not a regular expression */ p->firstch = 1; /* Assume first char is literal */ p->change_dir=chdir_name; p->dir_contents = 0; /* JF */ if (index(name, '*') || index(name, '[') || index(name, '?')) { p->regexp = 1; /* No, it's a regexp */ if (name[0] == '*' || name[0] == '[' || name[0] == '?') p->firstch = 0; /* Not even 1st char literal */ } if (namelast) namelast->next = p; namelast = p; if (!namelist) namelist = p;}/* * Match a name from an archive, p, with a name from the namelist. */name_match(p) register char *p;{ register struct name *nlp; register int len;again: if (0 == (nlp = namelist)) /* Empty namelist is easy */ return 1; len = strlen(p); for (; nlp != 0; nlp = nlp->next) { /* If first chars don't match, quick skip */ if (nlp->firstch && nlp->name[0] != p[0]) continue; /* Regular expressions */ if (nlp->regexp) { if (wildmat(p, nlp->name)) { nlp->found = 1; /* Remember it matched */ if(f_startfile) { free((void *)namelist); namelist=0; } if(nlp->change_dir && chdir(nlp->change_dir)) msg_perror("Can't change to directory %s",nlp->change_dir); return 1; /* We got a match */ } continue; } /* Plain Old Strings */ if (nlp->length <= len /* Archive len >= specified */ && (p[nlp->length] == '\0' || p[nlp->length] == '/') /* Full match on file/dirname */ && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */ { nlp->found = 1; /* Remember it matched */ if(f_startfile) { free((void *)namelist); namelist = 0; } if(nlp->change_dir && chdir(nlp->change_dir)) msg_perror("Can't change to directory %s",nlp->change_dir); return 1; /* We got a match */ } } /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ if (f_sorted_names && namelist->found) { name_gather(); /* Read one more */ if (!namelist->found) goto again; } return 0;}/* * Print the names of things in the namelist that were not matched. */names_notfound(){ register struct name *nlp; register char *p; for (nlp = namelist; nlp != 0; nlp = nlp->next) { if (!nlp->found) msg("%s not found in archive",nlp->name); /* * We could free() the list, but the process is about * to die anyway, so save some CPU time. Amigas and * other similarly broken software will need to waste * the time, though. */#ifndef unix if (!f_sorted_names) free(nlp);#endif } namelist = (struct name *)NULL; namelast = (struct name *)NULL; if (f_sorted_names) { while (0 != (p = name_next(1))) msg("%s not found in archive", p); }}/* These next routines were created by JF */name_expand(){;}/* This is like name_match(), except that it returns a pointer to the name it matched, and doesn't set ->found The caller will have to do that if it wants to. Oh, and if the namelist is empty, it returns 0, unlike name_match(), which returns TRUE */struct name *name_scan(p)register char *p;{ register struct name *nlp; register int len;again: if (0 == (nlp = namelist)) /* Empty namelist is easy */ return 0; len = strlen(p); for (; nlp != 0; nlp = nlp->next) { /* If first chars don't match, quick skip */ if (nlp->firstch && nlp->name[0] != p[0]) continue; /* Regular expressions */ if (nlp->regexp) { if (wildmat(p, nlp->name)) return nlp; /* We got a match */ continue; } /* Plain Old Strings */ if (nlp->length <= len /* Archive len >= specified */ && (p[nlp->length] == '\0' || p[nlp->length] == '/') /* Full match on file/dirname */ && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */ return nlp; /* We got a match */ } /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ if (f_sorted_names && namelist->found) { name_gather(); /* Read one more */ if (!namelist->found) goto again; } return (struct name *) 0;}/* This returns a name from the namelist which doesn't have ->found set. It sets ->found before returning, so successive calls will find and return all the non-found names in the namelist */struct name *gnu_list_name;char *name_from_list(){ if(!gnu_list_name) gnu_list_name = namelist; while(gnu_list_name && gnu_list_name->found) gnu_list_name=gnu_list_name->next; if(gnu_list_name) { gnu_list_name->found++; if(gnu_list_name->change_dir) if(chdir(gnu_list_name->change_dir)<0) msg_perror("can't chdir to %s",gnu_list_name->change_dir); return gnu_list_name->name; } return (char *)0;}blank_name_list(){ struct name *n; gnu_list_name = 0; for(n=namelist;n;n=n->next) n->found = 0;}char *new_name(path,name)char *path,*name;{ char *path_buf; path_buf=(char *)malloc(strlen(path)+strlen(name)+2); if(path_buf==0) { msg("Can't allocate memory for name '%s/%s",path,name); exit(EX_SYSTEM); } (void) sprintf(path_buf,"%s/%s",path,name); return path_buf;}/* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */intconfirm(action,file)char *action, *file;{ int c,nl; static FILE *confirm_file = 0; extern FILE *msg_file; extern char TTY_NAME[]; fprintf(msg_file,"%s %s?", action, file); fflush(msg_file); if(!confirm_file) { confirm_file = (archive == 0) ? fopen(TTY_NAME, "r") : stdin; if(!confirm_file) { msg("Can't read confirmation from user"); exit(EX_SYSTEM); } } c=getc(confirm_file); for(nl = c; nl != '\n' && nl != EOF; nl = getc(confirm_file)) ; return (c=='y' || c=='Y');}char *x_buffer = 0;int size_x_buffer;int free_x_buffer;char **exclude = 0;int size_exclude = 0;int free_exclude = 0;char **re_exclude = 0;int size_re_exclude = 0;int free_re_exclude = 0;add_exclude(file)char *file;{ FILE *fp; char buf[1024]; extern char *rindex(); if(strcmp(file, "-")) fp=fopen(file,"r"); else /* Let's hope the person knows what they're doing. */ /* Using -X - -T - -f - will get you *REALLY* strange results. . . */ fp=stdin; if(!fp) { msg_perror("can't open %s",file); exit(2); } while(fgets(buf,1024,fp)) { int size_buf; char *end_str; end_str=rindex(buf,'\n'); if(end_str) *end_str='\0'; un_quote_string(buf); size_buf = strlen(buf); if(x_buffer==0) { x_buffer = (char *)ck_malloc(size_buf+1024); free_x_buffer=1024; } else if(free_x_buffer<=size_buf) { char *old_x_buffer; char **tmp_ptr; old_x_buffer = x_buffer; x_buffer = (char *)ck_realloc(x_buffer,size_x_buffer+1024); free_x_buffer = 1024; for(tmp_ptr=exclude;tmp_ptr<exclude+size_exclude;tmp_ptr++) *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer); for(tmp_ptr=re_exclude;tmp_ptr<re_exclude+size_re_exclude;tmp_ptr++) *tmp_ptr= x_buffer + ((*tmp_ptr) - old_x_buffer); } if(is_regex(buf)) { if(free_re_exclude==0) { re_exclude= (char **)(re_exclude ? ck_realloc(re_exclude,(size_re_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32)); free_re_exclude+=32; } re_exclude[size_re_exclude]=x_buffer+size_x_buffer; size_re_exclude++; free_re_exclude--; } else { if(free_exclude==0) { exclude=(char **)(exclude ? ck_realloc(exclude,(size_exclude+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32)); free_exclude+=32; } exclude[size_exclude]=x_buffer+size_x_buffer; size_exclude++; free_exclude--; } strcpy(x_buffer+size_x_buffer,buf); size_x_buffer+=size_buf+1; free_x_buffer-=size_buf+1; } fclose(fp);}intis_regex(str)char *str;{ return index(str,'*') || index(str,'[') || index(str,'?');}/* Returns non-zero if the file 'name' should not be added/extracted */intcheck_exclude(name)char *name;{ int n; for(n=0;n<size_re_exclude;n++) { if(wildmat(name,re_exclude[n])) return 1; } for(n=0;n<size_exclude;n++) { if(strstr(name,exclude[n])) return 1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -