📄 tar.c
字号:
/* Tar -- a tape archiver.
Copyright (C) 1988 Free Software Foundation
GNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY. No author or distributor accepts responsibility to anyone
for the consequences of using it or for whether it serves any
particular 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 Public
License. A copy of this license is supposed to have been given to you
along with GNU tar so you can know your rights and responsibilities. It
should be in a file named COPYING. Among other things, the copyright
notice and this notice must be preserved on all copies.
In other words, go ahead and share GNU tar, but don't try to stop
anyone 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"
#include "regex.h"
#ifdef USG
#define rindex strrchr
#endif
#ifdef BSD42
#include <sys/dir.h>
#else
#ifdef __MSDOS__
#include "msd_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
#endif
extern 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 atoi
extern 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 get_date();
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", 0, 0, 'x'},
{"list", 0, 0, 't'},
{"update", 0, 0, 'u'},
{"catenate", 0, 0, 'A'},
{"concatenate", 0, 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'},
{"label", 1, 0, 'V'},
{"exclude-from", 1, 0, 'X'},
{"exclude", 1, 0, 15},
{"file", 1, 0, 'f'},
{"block-size", 1, 0, 'b'},
{"version", 0, 0, 11},
{"verbose", 0, 0, 'v'},
{"totals", 0, &f_totals, 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", 1, 0, 'N'},
{"after-date", 1, 0, 'N'},
{"newer-mtime", 1, 0, 13},
{"incremental", 0, 0, 'G'},
{"listed-incremental", 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},
{"confirmation", 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},
{"tape-length", 1, 0, 'L'},
{0, 0, 0, 0}
};
/*
* Main routine for tar.
*/
main(argc, argv)
int argc;
char **argv;
{
extern char version_string[];
tar = argv[0]; /* JF: was "tar" Set program name */
errors = 0;
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();
if (f_totals)
fprintf (stderr, "Total bytes written: %d\n", tot_written);
break;
case CMD_EXTRACT:
if (f_volhdr) {
char *err;
label_pattern = (struct re_pattern_buffer *)
ck_malloc (sizeof *label_pattern);
err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
label_pattern);
if (err) {
fprintf (stderr,"Bad regular expression: %s\n",
err);
errors++;
break;
}
}
extr_init();
read_and(extract_archive);
break;
case CMD_LIST:
if (f_volhdr) {
char *err;
label_pattern = (struct re_pattern_buffer *)
ck_malloc (sizeof *label_pattern);
err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
label_pattern);
if (err) {
fprintf (stderr,"Bad regular expression: %s\n",
err);
errors++;
break;
}
}
read_and(list_archive);
#if 0
if (!errors)
errors = different;
#endif
break;
case CMD_DIFF:
diff_init();
read_and(diff_archive);
break;
case CMD_VERSION:
fprintf(stderr,"%s\n",version_string);
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(errors);
/* NOTREACHED */
}
/*
* Parse the options for tar.
*/
void
options(argc, argv)
int argc;
char **argv;
{
register int c; /* Option letter */
int ind = -1;
/* 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:lL:mMN: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:
if(cmd_mode!=CMD_NONE)
goto badopt;
cmd_mode=CMD_VERSION;
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 15:
f_exclude++;
add_exclude(optarg);
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -