📄 tar.c
字号:
/* Tar -- a tape archiver. Copyright (C) 1988 Free Software FoundationGNU tar is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY. No author or distributor accepts responsibility to anyonefor the consequences of using it or for whether it serves anyparticular purpose or works at all, unless he says so in writing.Refer to the GNU tar General Public License for full details.Everyone is granted permission to copy, modify and redistribute GNU tar,but only under the conditions described in the GNU tar General PublicLicense. A copy of this license is supposed to have been given to youalong with GNU tar so you can know your rights and responsibilities. Itshould be in a file named COPYING. Among other things, the copyrightnotice and this notice must be preserved on all copies.In other words, go ahead and share GNU tar, but don't try to stopanyone else from sharing it farther. Help stamp out software hoarding!*//* * A tar (tape archiver) program. * * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85. * * @(#)tar.c 1.34 11/6/87 - gnu */#include <stdio.h>#include <sys/types.h> /* Needed for typedefs in tar.h */#include <sys/stat.h> /* JF */#include "getopt.h"#ifdef USG#define rindex strrchr#endif#ifdef BSD42#include <sys/dir.h>#else#ifdef MSDOS#include <sys/dir.h>#else#ifdef USG#ifdef NDIR#include <ndir.h>#else#include <dirent.h>#endif#ifndef DIRECT#define direct dirent#endif#define DP_NAMELEN(x) strlen((x)->d_name)#else/* * FIXME: On other systems there is no standard place for the header file * for the portable directory access routines. Change the #include line * below to bring it in from wherever it is. */#include "ndir.h"#endif#endif#endif#ifndef DP_NAMELEN#define DP_NAMELEN(x) (x)->d_namlen#endifextern char *malloc();extern char *getenv();extern char *strncpy();extern char *index();extern char *strcpy(); /* JF */extern char *strcat(); /* JF */extern char *optarg; /* Pointer to argument */extern int optind; /* Global argv index from getopt */extern char *ck_malloc();extern char *ck_realloc();/* * The following causes "tar.h" to produce definitions of all the * global variables, rather than just "extern" declarations of them. */#define TAR_EXTERN /**/#include "tar.h"/* * We should use a conversion routine that does reasonable error * checking -- atoi doesn't. For now, punt. FIXME. */#define intconv atoiextern int getoldopt();extern void read_and();extern void list_archive();extern void extract_archive();extern void diff_archive();extern void create_archive();extern void update_archive();extern void junk_archive();/* JF */extern time_t getdate();time_t new_time;static FILE *namef; /* File to read names from */static char **n_argv; /* Argv used by name routines */static int n_argc; /* Argc used by name routines */static char **n_ind; /* Store an array of names */static int n_indalloc; /* How big is the array? */static int n_indused; /* How many entries does it have? */static int n_indscan; /* How many of the entries have we scanned? */extern FILE *msg_file;void describe();void options();#ifndef S_IFLNK#define lstat stat#endif#ifndef DEFBLOCKING#define DEFBLOCKING 20#endif#ifndef DEF_AR_FILE#define DEF_AR_FILE "tar.out"#endif/* For long options that unconditionally set a single flag, we have getopt do it. For the others, we share the code for the equivalent short named option, the name of which is stored in the otherwise-unused `val' field of the `struct option'; for long options that have no equivalent short option, we use nongraphic characters as pseudo short option characters, starting (for no particular reason) with character 10. */struct option long_options[] ={ {"create", 0, 0, 'c'}, {"append", 0, 0, 'r'}, {"extract", 0, 0, 'x'}, {"get", 1, 0, 'x'}, {"list", 0, 0, 't'}, {"update", 0, 0, 'u'}, {"catenate", 0, 0, 'A'}, {"concatenate", 1, 0, 'A'}, {"compare", 0, 0, 'd'}, {"diff", 0, 0, 'd'}, {"delete", 0, 0, 14}, {"help", 0, 0, 12}, {"directory", 1, 0, 'C'}, {"record-number", 0, &f_sayblock, 1}, {"files-from", 1, 0, 'T'}, {"volume", 1, 0, 'V'}, {"exclude", 1, 0, 'X'}, {"file", 1, 0, 'f'}, {"block-size", 1, 0, 'b'}, {"version", 0, 0, 11}, {"verbose", 0, &f_verbose, 1}, {"read-full-blocks", 0, &f_reblock, 1}, {"starting-file", 1, 0, 'K'}, {"to-stdout", 0, &f_exstdout, 1}, {"ignore-zeros", 0, &f_ignorez, 1}, {"keep-old-files", 0, 0, 'k'}, {"uncompress", 0, &f_compress, 1}, {"same-permissions", 0, &f_use_protection, 1}, {"preserve-permissions",0, &f_use_protection, 1}, {"modification-time", 0, &f_modified, 1}, {"preserve", 0, 0, 10}, {"same-order", 0, &f_sorted_names, 1}, {"same-owner", 0, &f_do_chown, 1}, {"preserve-order", 0, &f_sorted_names, 1}, {"newer", 0, 0, 'N'}, {"after-date", 1, 0, 'N'}, {"newer-mtime", 1, 0, 13}, {"incremental", 0, 0, 'G'}, {"listed-imcremental", 1, 0, 'g'}, {"multi-volume", 0, &f_multivol, 1}, {"info-script", 1, &f_run_script_at_end, 1}, {"absolute-paths", 0, &f_absolute_paths, 1}, {"interactive", 0, &f_confirm, 1}, {"verify", 0, &f_verify, 1}, {"dereference", 0, &f_follow_links, 1}, {"one-file-system", 0, &f_local_filesys, 1}, {"old-archive", 0, 0, 'o'}, {"portability", 0, 0, 'o'}, {"compress", 0, &f_compress, 1}, {"compress-block", 0, &f_compress, 2}, {"sparse", 0, &f_sparse_files, 1}, {0, 0, 0, 0}};/* * Main routine for tar. */main(argc, argv) int argc; char **argv;{ tar = argv[0]; /* JF: was "tar" Set program name */ options(argc, argv); if(!n_argv) name_init(argc, argv); switch(cmd_mode) { case CMD_CAT: case CMD_UPDATE: case CMD_APPEND: update_archive(); break; case CMD_DELETE: junk_archive(); break; case CMD_CREATE: create_archive(); break; case CMD_EXTRACT: extr_init(); read_and(extract_archive); break; case CMD_LIST: read_and(list_archive); break; case CMD_DIFF: diff_init(); read_and(diff_archive); break; case CMD_NONE: msg("you must specify exactly one of the r, c, t, x, or d options\n"); fprintf(stderr,"For more information, type ``%s +help''.\n",tar); exit(EX_ARGSBAD); } exit(0); /* NOTREACHED */}/* * Parse the options for tar. */voidoptions(argc, argv) int argc; char **argv;{ register int c; /* Option letter */ int ind = -1; extern char version_string[]; /* Set default option values */ blocking = DEFBLOCKING; /* From Makefile */ ar_file = getenv("TAPE"); /* From environment, or */ if (ar_file == 0) ar_file = DEF_AR_FILE; /* From Makefile */ /* Parse options */ while ((c = getoldopt(argc, argv, "-01234567Ab:BcC:df:F:g:GhikK:lmMN:oOpPrRsStT:uvV:wWxX:zZ", long_options, &ind)) != EOF) { switch (c) { case 0: /* long options that set a single flag */ break; case 1: /* File name or non-parsed option */ name_add(optarg); break; case 'C': name_add("-C"); name_add(optarg); break; case 10: /* preserve */ f_use_protection = f_sorted_names = 1; break; case 11: /* version */ fprintf(stderr,"%s\n",version_string); break; case 12: /* help */ fprintf(stderr,"This is GNU tar, the tape archiving program.\n"); describe(); exit(1); case 13: f_new_files++; goto get_newer; case 14: /* Delete in the archive */ if(cmd_mode!=CMD_NONE) goto badopt; cmd_mode=CMD_DELETE; break; 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=optarg; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { /* JF this'll have to be modified for other systems, of course! */ int d,add; static char buf[50]; d=getoldopt(argc,argv,"lmh");#ifdef MAYBEDEF sprintf(buf,"/dev/rmt/%d%c",c,d);#else#ifndef LOW_NUM#define LOW_NUM 0#define MID_NUM 8#define HGH_NUM 16#endif if(d=='l') add=LOW_NUM; else if(d=='m') add=MID_NUM; else if(d=='h') add=HGH_NUM; else goto badopt; sprintf(buf,"/dev/rmt%d",add+c-'0');#endif ar_file=buf; } break; case 'A': /* Arguments are tar files, just cat them onto the end of the archive. */ if(cmd_mode!=CMD_NONE) goto badopt; cmd_mode=CMD_CAT; break; case 'b': /* Set blocking factor */ blocking = intconv(optarg); break; case 'B': /* Try to reblock input */ f_reblock++; /* For reading 4.2BSD pipes */ break; case 'c': /* Create an archive */ if(cmd_mode!=CMD_NONE) goto badopt; cmd_mode=CMD_CREATE; break;/* case 'C': if(chdir(optarg)<0) msg_perror("Can't change directory to %d",optarg); break; */ case 'd': /* Find difference tape/disk */ if(cmd_mode!=CMD_NONE) goto badopt; cmd_mode=CMD_DIFF; break; case 'f': /* Use ar_file for the archive */ ar_file = optarg; break; case 'F': /* Since -F is only useful with -M , make it implied */ f_run_script_at_end++; /* run this script at the end */ info_script = optarg; /* of each tape */ f_multivol++; break; 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 '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=getdate(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(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. */voiddescribe(){ msg("choose one of the following:"); fputs("\-A, +catenate append tar files to an archive\n\-c, +create create a new archive\n\-d, +diff 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 extract files from an archive\n",stderr); fputs("\Other options:\n\-b, +block-size N block size of Nx512 bytes\n\-B, +read-full-blocks reblock as we read (for reading 4.2BSD pipes)\n\-C, +directory dir change to directory DIR\n\", stderr); /* KLUDGE */ fputs("\-f, +file F use archive file or device F (or hostname:/dev/file)\n\-G, +incremental F create/list/extract 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\-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\", stderr); /* KLUDGE */ fputs("\-m, +modification-time don't extract file modified time\n\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -