X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=e0e731b1ec4d334f19af05d51062b25a209e0013;hb=eada0a9b35a9324daaf0efa8443646e28d5f9bb5;hp=213b277921f1f17fdaf2188de16ec7040df3be32;hpb=d2f18d9ecb2a03e086f93b33fbdb814cfb775f0b;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 213b277..e0e731b 100644 --- a/src/tar.c +++ b/src/tar.c @@ -1,5 +1,8 @@ /* A tar (tape archiver) program. - Copyright 1988, 92,93,94,95,96,97,99, 2000 Free Software Foundation, Inc. + + Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, + 2001, 2003 Free Software Foundation, Inc. + Written by John Gilmore, starting 1985-08-25. This program is free software; you can redistribute it and/or modify it @@ -18,6 +21,7 @@ #include "system.h" +#include #include #include @@ -25,11 +29,6 @@ # define SIGCHLD SIGCLD #endif -#include -#ifndef time -time_t time (); -#endif - /* The following causes "common.h" to produce definitions of all the global variables, rather than just "extern" declarations of them. GNU tar does depend on the system loader to preset all GLOBAL variables to neutral (or @@ -37,15 +36,18 @@ time_t time (); #define GLOBAL #include "common.h" +#include #include #include #include #include -time_t get_date (); - /* Local declarations. */ +#ifndef DEFAULT_ARCHIVE_FORMAT +# define DEFAULT_ARCHIVE_FORMAT GNU_FORMAT +#endif + #ifndef DEFAULT_ARCHIVE # define DEFAULT_ARCHIVE "tar.out" #endif @@ -54,7 +56,7 @@ time_t get_date (); # define DEFAULT_BLOCKING 20 #endif -static void usage PARAMS ((int)) __attribute__ ((noreturn)); +static void usage (int) __attribute__ ((noreturn)); /* Miscellaneous. */ @@ -114,6 +116,48 @@ confirm (const char *message_action, const char *message_name) return reply == 'y' || reply == 'Y'; } } + +static struct fmttab { + char const *name; + enum archive_format fmt; +} const fmttab[] = { + { "v7", V7_FORMAT }, + { "oldgnu", OLDGNU_FORMAT }, + { "posix", POSIX_FORMAT }, +#if 0 /* not fully supported yet */ + { "star", STAR_FORMAT }, +#endif + { "gnu", GNU_FORMAT }, + { NULL, 0 } +}; + +static void +set_archive_format (char const *name) +{ + struct fmttab const *p; + + for (p = fmttab; strcmp (p->name, name) != 0; ) + if (! (++p)->name) + USAGE_ERROR ((0, 0, _("%s: Invalid archive format"), + quotearg_colon (name))); + + if (archive_format != DEFAULT_FORMAT && archive_format != p->fmt) + USAGE_ERROR ((0, 0, _("Conflicting archive format options"))); + + archive_format = p->fmt; +} + +static const char * +archive_format_string (enum archive_format fmt) +{ + struct fmttab const *p; + + for (p = fmttab; p->name; p++) + if (p->fmt == fmt) + return p->name; + return "unknown?"; +} + /* Options. */ @@ -126,35 +170,43 @@ confirm (const char *message_action, const char *message_name) enum { - BACKUP_OPTION = CHAR_MAX + 1, + ANCHORED_OPTION = CHAR_MAX + 1, + ATIME_PRESERVE_OPTION, + BACKUP_OPTION, + CHECKPOINT_OPTION, DELETE_OPTION, EXCLUDE_OPTION, + FORCE_LOCAL_OPTION, + FORMAT_OPTION, GROUP_OPTION, + IGNORE_CASE_OPTION, + IGNORE_FAILED_READ_OPTION, + INDEX_FILE_OPTION, MODE_OPTION, NEWER_MTIME_OPTION, - NO_RECURSE_OPTION, + NO_ANCHORED_OPTION, + NO_IGNORE_CASE_OPTION, + NO_OVERWRITE_DIR_OPTION, + NO_WILDCARDS_OPTION, + NO_WILDCARDS_MATCH_SLASH_OPTION, NULL_OPTION, + NUMERIC_OWNER_OPTION, OVERWRITE_OPTION, OWNER_OPTION, POSIX_OPTION, PRESERVE_OPTION, RECORD_SIZE_OPTION, + RECURSIVE_UNLINK_OPTION, + REMOVE_FILES_OPTION, RSH_COMMAND_OPTION, + SHOW_OMITTED_DIRS_OPTION, + STRIP_PATH_OPTION, SUFFIX_OPTION, + TOTALS_OPTION, USE_COMPRESS_PROGRAM_OPTION, VOLNO_FILE_OPTION, - - /* Some cleanup is being made in GNU tar long options. Using old names is - allowed for a while, but will also send a warning to stderr. Take old - names out in 1.14, or in summer 1997, whichever happens last. */ - - OBSOLETE_ABSOLUTE_NAMES, - OBSOLETE_BLOCK_COMPRESS, - OBSOLETE_BLOCKING_FACTOR, - OBSOLETE_BLOCK_NUMBER, - OBSOLETE_READ_FULL_RECORDS, - OBSOLETE_TOUCH, - OBSOLETE_VERSION_CONTROL + WILDCARDS_OPTION, + WILDCARDS_MATCH_SLASH_OPTION, }; /* If nonzero, display usage information and exit. */ @@ -166,18 +218,17 @@ static int show_version; static struct option long_options[] = { {"absolute-names", no_argument, 0, 'P'}, - {"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES}, {"after-date", required_argument, 0, 'N'}, + {"anchored", no_argument, 0, ANCHORED_OPTION}, {"append", no_argument, 0, 'r'}, - {"atime-preserve", no_argument, &atime_preserve_option, 1}, + {"atime-preserve", no_argument, 0, ATIME_PRESERVE_OPTION}, {"backup", optional_argument, 0, BACKUP_OPTION}, - {"block-compress", no_argument, 0, OBSOLETE_BLOCK_COMPRESS}, {"block-number", no_argument, 0, 'R'}, - {"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR}, {"blocking-factor", required_argument, 0, 'b'}, {"bzip2", no_argument, 0, 'j'}, {"catenate", no_argument, 0, 'A'}, - {"checkpoint", no_argument, &checkpoint_option, 1}, + {"checkpoint", no_argument, 0, CHECKPOINT_OPTION}, + {"check-links", no_argument, &check_links_option, 1}, {"compare", no_argument, 0, 'd'}, {"compress", no_argument, 0, 'Z'}, {"concatenate", no_argument, 0, 'A'}, @@ -193,16 +244,19 @@ static struct option long_options[] = {"extract", no_argument, 0, 'x'}, {"file", required_argument, 0, 'f'}, {"files-from", required_argument, 0, 'T'}, - {"force-local", no_argument, &force_local_option, 1}, + {"force-local", no_argument, 0, FORCE_LOCAL_OPTION}, + {"format", required_argument, 0, FORMAT_OPTION}, {"get", no_argument, 0, 'x'}, {"group", required_argument, 0, GROUP_OPTION}, {"gunzip", no_argument, 0, 'z'}, {"gzip", no_argument, 0, 'z'}, {"help", no_argument, &show_help, 1}, - {"ignore-failed-read", no_argument, &ignore_failed_read_option, 1}, + {"ignore-case", no_argument, 0, IGNORE_CASE_OPTION}, + {"ignore-failed-read", no_argument, 0, IGNORE_FAILED_READ_OPTION}, {"ignore-zeros", no_argument, 0, 'i'}, /* FIXME: --ignore-end as a new name for --ignore-zeros? */ {"incremental", no_argument, 0, 'G'}, + {"index-file", required_argument, 0, INDEX_FILE_OPTION}, {"info-script", required_argument, 0, 'F'}, {"interactive", no_argument, 0, 'w'}, {"keep-old-files", no_argument, 0, 'k'}, @@ -210,16 +264,20 @@ static struct option long_options[] = {"list", no_argument, 0, 't'}, {"listed-incremental", required_argument, 0, 'g'}, {"mode", required_argument, 0, MODE_OPTION}, - {"modification-time", no_argument, 0, OBSOLETE_TOUCH}, {"multi-volume", no_argument, 0, 'M'}, {"new-volume-script", required_argument, 0, 'F'}, {"newer", required_argument, 0, 'N'}, {"newer-mtime", required_argument, 0, NEWER_MTIME_OPTION}, {"null", no_argument, 0, NULL_OPTION}, - {"no-recursion", no_argument, 0, NO_RECURSE_OPTION}, + {"no-anchored", no_argument, 0, NO_ANCHORED_OPTION}, + {"no-ignore-case", no_argument, 0, NO_IGNORE_CASE_OPTION}, + {"no-overwrite-dir", no_argument, 0, NO_OVERWRITE_DIR_OPTION}, + {"no-wildcards", no_argument, 0, NO_WILDCARDS_OPTION}, + {"no-wildcards-match-slash", no_argument, 0, NO_WILDCARDS_MATCH_SLASH_OPTION}, + {"no-recursion", no_argument, &recursion_option, 0}, {"no-same-owner", no_argument, &same_owner_option, -1}, {"no-same-permissions", no_argument, &same_permissions_option, -1}, - {"numeric-owner", no_argument, &numeric_owner_option, 1}, + {"numeric-owner", no_argument, 0, NUMERIC_OWNER_OPTION}, {"old-archive", no_argument, 0, 'o'}, {"one-file-system", no_argument, 0, 'l'}, {"overwrite", no_argument, 0, OVERWRITE_OPTION}, @@ -229,24 +287,24 @@ static struct option long_options[] = {"preserve", no_argument, 0, PRESERVE_OPTION}, {"preserve-order", no_argument, 0, 's'}, {"preserve-permissions", no_argument, 0, 'p'}, - {"recursive-unlink", no_argument, &recursive_unlink_option, 1}, - {"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS}, + {"recursion", no_argument, &recursion_option, FNM_LEADING_DIR}, + {"recursive-unlink", no_argument, 0, RECURSIVE_UNLINK_OPTION}, {"read-full-records", no_argument, 0, 'B'}, /* FIXME: --partial-blocks might be a synonym for --read-full-records? */ - {"record-number", no_argument, 0, OBSOLETE_BLOCK_NUMBER}, {"record-size", required_argument, 0, RECORD_SIZE_OPTION}, - {"remove-files", no_argument, &remove_files_option, 1}, + {"remove-files", no_argument, 0, REMOVE_FILES_OPTION}, {"rsh-command", required_argument, 0, RSH_COMMAND_OPTION}, {"same-order", no_argument, 0, 's'}, {"same-owner", no_argument, &same_owner_option, 1}, {"same-permissions", no_argument, 0, 'p'}, - {"show-omitted-dirs", no_argument, &show_omitted_dirs_option, 1}, + {"show-omitted-dirs", no_argument, 0, SHOW_OMITTED_DIRS_OPTION}, {"sparse", no_argument, 0, 'S'}, {"starting-file", required_argument, 0, 'K'}, + {"strip-path", required_argument, 0, STRIP_PATH_OPTION }, {"suffix", required_argument, 0, SUFFIX_OPTION}, {"tape-length", required_argument, 0, 'L'}, {"to-stdout", no_argument, 0, 'O'}, - {"totals", no_argument, &totals_option, 1}, + {"totals", no_argument, 0, TOTALS_OPTION}, {"touch", no_argument, 0, 'm'}, {"uncompress", no_argument, 0, 'Z'}, {"ungzip", no_argument, 0, 'z'}, @@ -256,9 +314,10 @@ static struct option long_options[] = {"verbose", no_argument, 0, 'v'}, {"verify", no_argument, 0, 'W'}, {"version", no_argument, &show_version, 1}, - {"version-control", required_argument, 0, OBSOLETE_VERSION_CONTROL}, {"volno-file", required_argument, 0, VOLNO_FILE_OPTION}, - + {"wildcards", no_argument, 0, WILDCARDS_OPTION}, + {"wildcards-match-slash", no_argument, 0, WILDCARDS_MATCH_SLASH_OPTION}, + {0, 0, 0, 0} }; @@ -307,6 +366,7 @@ Operation modifiers:\n\ --remove-files remove files after adding them to the archive\n\ -k, --keep-old-files don't replace existing files when extracting\n\ --overwrite overwrite existing files when extracting\n\ + --no-overwrite-dir preserve metadata of existing directories\n\ -U, --unlink-first remove each file prior to extracting over it\n\ --recursive-unlink empty hierarchies prior to extracting directory\n\ -S, --sparse handle sparse files efficiently\n\ @@ -358,10 +418,16 @@ Device blocking:\n\ fputs (_("\ \n\ Archive format selection:\n\ + --format=FMTNAME create archive of the given format.\n\ + FMTNAME is one of the following:\n\ + v7 old V7 tar format\n\ + oldgnu GNU format as per tar <= 1.12\n\ + posix POSIX 1003.1-2001 tar format\n\ + gnu GNU format\n\ + --old-archive, --portability same as --format=v7\n\ + --posix same as --format=posix\n\ -V, --label=NAME create archive with volume name NAME\n\ PATTERN at list/extract time, a globbing PATTERN\n\ - -o, --old-archive, --portability write a V7 format archive\n\ - --posix write a POSIX format archive\n\ -j, --bzip2 filter the archive through bzip2\n\ -z, --gzip, --ungzip filter the archive through gzip\n\ -Z, --compress, --uncompress filter the archive through compress\n\ @@ -371,20 +437,30 @@ Archive format selection:\n\ \n\ Local file selection:\n\ -C, --directory=DIR change to directory DIR\n\ - -T, -I, --files-from=NAME get names to extract or create from file NAME\n\ + -T, --files-from=NAME get names to extract or create from file NAME\n\ --null -T reads null-terminated names, disable -C\n\ - --exclude=PATTERN exclude files, given as a globbing PATTERN\n\ - -X, --exclude-from=FILE exclude globbing patterns listed in FILE\n\ + --exclude=PATTERN exclude files, given as a PATTERN\n\ + -X, --exclude-from=FILE exclude patterns listed in FILE\n\ + --anchored exclude patterns match file name start (default)\n\ + --no-anchored exclude patterns match after any /\n\ + --ignore-case exclusion ignores case\n\ + --no-ignore-case exclusion is case sensitive (default)\n\ + --wildcards exclude patterns use wildcards (default)\n\ + --no-wildcards exclude patterns are plain strings\n\ + --wildcards-match-slash exclude pattern wildcards match '/' (default)\n\ + --no-wildcards-match-slash exclude pattern wildcards do not match '/'\n\ -P, --absolute-names don't strip leading `/'s from file names\n\ -h, --dereference dump instead the files symlinks point to\n\ --no-recursion avoid descending automatically in directories\n\ -l, --one-file-system stay in local file system when creating archive\n\ - -K, --starting-file=NAME begin at file NAME in the archive\n"), + -K, --starting-file=NAME begin at file NAME in the archive\n\ + --strip-path=NUM strip NUM leading components from file names\n\ + before extraction\n"), stdout); #if !MSDOS fputs (_("\ -N, --newer=DATE only store files newer than DATE\n\ - --newer-mtime compare date and time when data changed only\n\ + --newer-mtime=DATE compare date and time when data changed only\n\ --after-date=DATE same as -N\n"), stdout); #endif @@ -399,13 +475,22 @@ Informative output:\n\ --version print tar program version number, then exit\n\ -v, --verbose verbosely list files processed\n\ --checkpoint print directory names while reading the archive\n\ + --check-links print a message if not all links are dumped\n\ --totals print total bytes written while creating archive\n\ + --index-file=FILE send verbose output to FILE\n\ -R, --block-number show block number within archive with each message\n\ -w, --interactive ask for confirmation for every action\n\ --confirmation same as -w\n"), stdout); fputs (_("\ \n\ +Compatibility options:\n\ + -o when creating, same as --old-archive\n\ + when extracting, same as --no-same-owner\n"), + stdout); + + fputs (_("\ +\n\ The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ The version control may be set with --backup or VERSION_CONTROL, values are:\n\ \n\ @@ -415,30 +500,30 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\ stdout); printf (_("\ \n\ -GNU tar cannot read nor produce `--posix' archives. If POSIXLY_CORRECT\n\ -is set in the environment, GNU extensions are disallowed with `--posix'.\n\ -Support for POSIX is only partially implemented, don't count on it yet.\n\ -ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; and FILE may be a file\n\ -or a device. *This* `tar' defaults to `-f%s -b%d'.\n"), +ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; DATE may be a textual date\n\ +or a file name starting with `/' or `.', in which case the file's date is used.\n\ +*This* `tar' defaults to `--format=%s -f%s -b%d'.\n"), + archive_format_string (DEFAULT_ARCHIVE_FORMAT), DEFAULT_ARCHIVE, DEFAULT_BLOCKING); - fputs (_("\nReport bugs to .\n"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); } exit (status); } /* Parse the options for tar. */ -/* Available option letters are DEHJQY and aenqy. Some are reserved: +/* Available option letters are DEHIJQY and aenqy. Some are reserved: e exit immediately with a nonzero exit status if unexpected errors occur E use extended headers (draft POSIX headers, that is) + I same as T (for compatibility with Solaris tar) n the archive is quickly seekable, so don't worry about random seeks q stop after extracting the first occurrence of the named file y per-file gzip compression Y per-block gzip compression */ #define OPTION_STRING \ - "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxz" + "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxyz" static void set_subcommand_option (enum subcommand subcommand) @@ -460,35 +545,26 @@ set_use_compress_program_option (const char *string) use_compress_program_option = string; } -/* Ignore DUMMY (which will always be null in practice), and add - PATTERN to the proper set of patterns to be excluded -- either - patterns with slashes, or patterns without. */ -static void -add_filtered_exclude (struct exclude *dummy, char const *pattern) -{ - add_exclude ((strchr (pattern, '/') - ? excluded_with_slash - : excluded_without_slash), - pattern); -} - static void decode_options (int argc, char **argv) { int optchar; /* option letter */ int input_files; /* number of input files */ - const char *backup_suffix_string; - const char *version_control_string = 0; - + char const *textual_date_option = 0; + char const *backup_suffix_string; + char const *version_control_string = 0; + int exclude_options = EXCLUDE_WILDCARDS; + bool o_option = 0; + /* Set some default option values. */ subcommand_option = UNKNOWN_SUBCOMMAND; archive_format = DEFAULT_FORMAT; blocking_factor = DEFAULT_BLOCKING; record_size = DEFAULT_BLOCKING * BLOCKSIZE; - excluded_with_slash = new_exclude (); - excluded_without_slash = new_exclude (); + excluded = new_exclude (); newer_mtime_option = TYPE_MINIMUM (time_t); + recursion_option = FNM_LEADING_DIR; owner_option = -1; group_option = -1; @@ -516,7 +592,7 @@ decode_options (int argc, char **argv) /* Allocate a new argument array, and copy program name in it. */ new_argc = argc - 1 + strlen (argv[1]); - new_argv = xmalloc (new_argc * sizeof (char *)); + new_argv = xmalloc ((new_argc + 1) * sizeof (char *)); in = argv; out = new_argv; *out++ = *in++; @@ -543,6 +619,7 @@ decode_options (int argc, char **argv) while (in < argv + argc) *out++ = *in++; + *out = 0; /* Replace the old option list by the new one. */ @@ -578,14 +655,6 @@ decode_options (int argc, char **argv) set_subcommand_option (CAT_SUBCOMMAND); break; - case OBSOLETE_BLOCK_COMPRESS: - WARN ((0, 0, _("Obsolete option, now implied by --blocking-factor"))); - break; - - case OBSOLETE_BLOCKING_FACTOR: - WARN ((0, 0, _("Obsolete option name replaced by --blocking-factor"))); - /* Fall through. */ - case 'b': { uintmax_t u; @@ -598,11 +667,6 @@ decode_options (int argc, char **argv) } break; - case OBSOLETE_READ_FULL_RECORDS: - WARN ((0, 0, - _("Obsolete option name replaced by --read-full-records"))); - /* Fall through. */ - case 'B': /* Try to reblock input records. For reading 4.2BSD pipes. */ @@ -611,7 +675,7 @@ decode_options (int argc, char **argv) BSD-derived systems. This is a consequence of the block/record terminology confusion. */ - read_full_records_option = 1; + read_full_records_option = true; break; case 'c': @@ -643,12 +707,12 @@ decode_options (int argc, char **argv) script at the end of each tape. */ info_script_option = optarg; - multi_volume_option = 1; + multi_volume_option = true; break; case 'g': listed_incremental_option = optarg; - after_date_option = 1; + after_date_option = true; /* Fall through. */ case 'G': @@ -656,13 +720,12 @@ decode_options (int argc, char **argv) directories at the beginning of the archive, and include in each directory its contents. */ - incremental_option = 1; + incremental_option = true; break; case 'h': /* Follow symbolic links. */ - - dereference_option = 1; + dereference_option = true; break; case 'i': @@ -670,7 +733,13 @@ decode_options (int argc, char **argv) because Unix tar writes two blocks of zeros, then pads out the record with garbage. */ - ignore_zeros_option = 1; + ignore_zeros_option = true; + break; + + case 'I': + USAGE_ERROR ((0, 0, + _("Warning: the -I option is not supported;" + " perhaps you meant -j or -T?"))); break; case 'j': @@ -683,7 +752,7 @@ decode_options (int argc, char **argv) break; case 'K': - starting_file_option = 1; + starting_file_option = true; addname (optarg, 0); break; @@ -691,7 +760,7 @@ decode_options (int argc, char **argv) /* When dumping directories, don't dump files/subdirectories that are on other filesystems. */ - one_file_system_option = 1; + one_file_system_option = true; break; case 'L': @@ -701,73 +770,75 @@ decode_options (int argc, char **argv) USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg), _("Invalid tape length"))); tape_length_option = 1024 * (tarlong) u; - multi_volume_option = 1; + multi_volume_option = true; } break; - case OBSOLETE_TOUCH: - WARN ((0, 0, _("Obsolete option name replaced by --touch"))); - /* Fall through. */ - case 'm': - touch_option = 1; + touch_option = true; break; case 'M': /* Make multivolume archive: when we can't write any more into the archive, re-open it, and continue writing. */ - multi_volume_option = 1; + multi_volume_option = true; break; #if !MSDOS case 'N': - after_date_option = 1; + after_date_option = true; /* Fall through. */ case NEWER_MTIME_OPTION: if (newer_mtime_option != TYPE_MINIMUM (time_t)) USAGE_ERROR ((0, 0, _("More than one threshold date"))); - newer_mtime_option = get_date (optarg, 0); - if (newer_mtime_option == (time_t) -1) - WARN ((0, 0, _("Substituting %s for unknown date format %s"), - tartime (newer_mtime_option), quote (optarg))); + if (FILESYSTEM_PREFIX_LEN (optarg) != 0 + || ISSLASH (*optarg) + || *optarg == '.') + { + struct stat st; + if (deref_stat (dereference_option, optarg, &st) != 0) + { + stat_error (optarg); + USAGE_ERROR ((0, 0, _("Date file not found"))); + } + newer_mtime_option = st.st_mtime; + } + else + { + newer_mtime_option = get_date (optarg, 0); + if (newer_mtime_option == (time_t) -1) + WARN ((0, 0, _("Substituting %s for unknown date format %s"), + tartime (newer_mtime_option), quote (optarg))); + else + textual_date_option = optarg; + } break; #endif /* not MSDOS */ case 'o': - if (archive_format == DEFAULT_FORMAT) - archive_format = V7_FORMAT; - else if (archive_format != V7_FORMAT) - USAGE_ERROR ((0, 0, _("Conflicting archive format options"))); + o_option = true; break; case 'O': - to_stdout_option = 1; + to_stdout_option = true; break; case 'p': - same_permissions_option = 1; + same_permissions_option = true; break; - case OBSOLETE_ABSOLUTE_NAMES: - WARN ((0, 0, _("Obsolete option name replaced by --absolute-names"))); - /* Fall through. */ - case 'P': - absolute_names_option = 1; + absolute_names_option = true; break; case 'r': set_subcommand_option (APPEND_SUBCOMMAND); break; - case OBSOLETE_BLOCK_NUMBER: - WARN ((0, 0, _("Obsolete option name replaced by --block-number"))); - /* Fall through. */ - case 'R': /* Print block numbers for debugging bad tar archives. */ @@ -776,17 +847,17 @@ decode_options (int argc, char **argv) BSD-derived systems. This is a consequence of the block/record terminology confusion. */ - block_number_option = 1; + block_number_option = true; break; case 's': /* Names to extr are sorted. */ - same_order_option = 1; + same_order_option = true; break; case 'S': - sparse_option = 1; + sparse_option = true; break; case 't': @@ -795,7 +866,6 @@ decode_options (int argc, char **argv) break; case 'T': - case 'I': /* for compatibility with Solaris tar */ files_from_option = optarg; break; @@ -816,11 +886,11 @@ decode_options (int argc, char **argv) break; case 'w': - interactive_option = 1; + interactive_option = true; break; case 'W': - verify_option = 1; + verify_option = true; break; case 'x': @@ -828,13 +898,21 @@ decode_options (int argc, char **argv) break; case 'X': - if (add_exclude_file (add_filtered_exclude, 0, optarg, '\n') != 0) + if (add_exclude_file (add_exclude, excluded, optarg, + exclude_options | recursion_option, '\n') + != 0) { int e = errno; FATAL_ERROR ((0, e, "%s", quotearg_colon (optarg))); } break; + case 'y': + USAGE_ERROR ((0, 0, + _("Warning: the -y option is not supported;" + " perhaps you meant -j?"))); + break; + case 'z': set_use_compress_program_option ("gzip"); break; @@ -843,12 +921,20 @@ decode_options (int argc, char **argv) set_use_compress_program_option ("compress"); break; - case OBSOLETE_VERSION_CONTROL: - WARN ((0, 0, _("Obsolete option name replaced by --backup"))); - /* Fall through. */ + case ANCHORED_OPTION: + exclude_options |= EXCLUDE_ANCHORED; + break; + + case ATIME_PRESERVE_OPTION: + atime_preserve_option = true; + break; + + case CHECKPOINT_OPTION: + checkpoint_option = true; + break; case BACKUP_OPTION: - backup_option = 1; + backup_option = true; if (optarg) version_control_string = optarg; break; @@ -858,7 +944,27 @@ decode_options (int argc, char **argv) break; case EXCLUDE_OPTION: - add_filtered_exclude (0, optarg); + add_exclude (excluded, optarg, exclude_options | recursion_option); + break; + + case FORCE_LOCAL_OPTION: + force_local_option = true; + break; + + case FORMAT_OPTION: + set_archive_format (optarg); + break; + + case INDEX_FILE_OPTION: + index_file_name = optarg; + break; + + case IGNORE_CASE_OPTION: + exclude_options |= FNM_CASEFOLD; + break; + + case IGNORE_FAILED_READ_OPTION: + ignore_failed_read_option = true; break; case GROUP_OPTION: @@ -885,14 +991,34 @@ decode_options (int argc, char **argv) xalloc_die (); break; - case NO_RECURSE_OPTION: - no_recurse_option = 1; + case NO_ANCHORED_OPTION: + exclude_options &= ~ EXCLUDE_ANCHORED; + break; + + case NO_IGNORE_CASE_OPTION: + exclude_options &= ~ FNM_CASEFOLD; + break; + + case NO_OVERWRITE_DIR_OPTION: + old_files_option = NO_OVERWRITE_DIR_OLD_FILES; + break; + + case NO_WILDCARDS_OPTION: + exclude_options &= ~ EXCLUDE_WILDCARDS; + break; + + case NO_WILDCARDS_MATCH_SLASH_OPTION: + exclude_options |= FNM_FILE_NAME; break; case NULL_OPTION: filename_terminator = '\0'; break; + case NUMERIC_OWNER_OPTION: + numeric_owner_option = true; + break; + case OVERWRITE_OPTION: old_files_option = OVERWRITE_OLD_FILES; break; @@ -912,22 +1038,12 @@ decode_options (int argc, char **argv) break; case POSIX_OPTION: -#if OLDGNU_COMPATIBILITY - if (archive_format == DEFAULT_FORMAT) - archive_format = GNU_FORMAT; - else if (archive_format != GNU_FORMAT) - USAGE_ERROR ((0, 0, _("Conflicting archive format options"))); -#else - if (archive_format == DEFAULT_FORMAT) - archive_format = POSIX_FORMAT; - else if (archive_format != POSIX_FORMAT) - USAGE_ERROR ((0, 0, _("Conflicting archive format options"))); -#endif + set_archive_format ("posix"); break; case PRESERVE_OPTION: - same_permissions_option = 1; - same_order_option = 1; + same_permissions_option = true; + same_order_option = true; break; case RECORD_SIZE_OPTION: @@ -945,21 +1061,52 @@ decode_options (int argc, char **argv) } break; + case RECURSIVE_UNLINK_OPTION: + recursive_unlink_option = true; + break; + + case REMOVE_FILES_OPTION: + remove_files_option = true; + break; + case RSH_COMMAND_OPTION: rsh_command_option = optarg; break; + case STRIP_PATH_OPTION: + { + uintmax_t u; + if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK + && u == (size_t) u)) + USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg), + _("Invalid number of elements"))); + strip_path_elements = u; + } + break; + case SUFFIX_OPTION: - backup_option = 1; + backup_option = true; backup_suffix_string = optarg; break; + case TOTALS_OPTION: + totals_option = true; + break; + + case USE_COMPRESS_PROGRAM_OPTION: + set_use_compress_program_option (optarg); + break; + case VOLNO_FILE_OPTION: volno_file_option = optarg; break; - case USE_COMPRESS_PROGRAM_OPTION: - set_use_compress_program_option (optarg); + case WILDCARDS_OPTION: + exclude_options |= EXCLUDE_WILDCARDS; + break; + + case WILDCARDS_MATCH_SLASH_OPTION: + exclude_options &= ~ FNM_FILE_NAME; break; case '0': @@ -1026,10 +1173,7 @@ decode_options (int argc, char **argv) xrealloc (archive_name_array, sizeof (const char *) * allocated_archive_names); } - archive_name_array[archive_names++] = buf; - - /* FIXME: How comes this works for many archives when buf is - not xstrdup'ed? */ + archive_name_array[archive_names++] = strdup (buf); } break; @@ -1041,6 +1185,29 @@ decode_options (int argc, char **argv) #endif /* not DEVICE_PREFIX */ } + /* Special handling for 'o' option: + + GNU tar used to say "output old format". + UNIX98 tar says don't chown files after extracting (we use + "--no-same-owner" for this). + + The old GNU tar semantics is retained when used with --create + option, otherwise UNIX98 semantics is assumed */ + + if (o_option) + { + if (subcommand_option == CREATE_SUBCOMMAND) + { + /* GNU Tar <= 1.13 compatibility */ + set_archive_format ("v7"); + } + else + { + /* UNIX98 compatibility */ + same_owner_option = 1; + } + } + /* Handle operands after any "--" argument. */ for (; optind < argc; optind++) { @@ -1052,13 +1219,15 @@ decode_options (int argc, char **argv) if (show_version) { - printf ("tar (GNU %s) %s\n%s\n%s\n%s\n", PACKAGE, VERSION, - "Copyright 2000 Free Software Foundation, Inc.", - _("\ + printf ("tar (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + printf (_("Copyright (C) %d Free Software Foundation, Inc.\n"), 2003); + puts (_("\ This program comes with NO WARRANTY, to the extent permitted by law.\n\ You may redistribute it under the terms of the GNU General Public License;\n\ -see the file named COPYING for details."), - _("Written by John Gilmore and Jay Fenlason.")); +see the file named COPYING for details.")); + + puts (_("Written by John Gilmore and Jay Fenlason.")); + exit (TAREXIT_SUCCESS); } @@ -1068,18 +1237,12 @@ see the file named COPYING for details."), /* Derive option values and check option consistency. */ if (archive_format == DEFAULT_FORMAT) - { -#if OLDGNU_COMPATIBILITY - archive_format = OLDGNU_FORMAT; -#else - archive_format = GNU_FORMAT; -#endif - } + archive_format = DEFAULT_ARCHIVE_FORMAT; if (archive_format == GNU_FORMAT && getenv ("POSIXLY_CORRECT")) archive_format = POSIX_FORMAT; - if ((volume_label_option + if (((volume_label_option && subcommand_option == CREATE_SUBCOMMAND) || incremental_option || multi_volume_option || sparse_option) && archive_format != OLDGNU_FORMAT && archive_format != GNU_FORMAT) USAGE_ERROR ((0, 0, @@ -1173,6 +1336,14 @@ see the file named COPYING for details."), if (backup_option) backup_type = xget_version ("--backup", version_control_string); + + if (verbose_option && textual_date_option) + { + char const *treated_as = tartime (newer_mtime_option); + if (strcmp (textual_date_option, treated_as) != 0) + WARN ((0, 0, _("Treating date `%s' as %s"), + textual_date_option, treated_as)); + } } /* Tar proper. */ @@ -1245,7 +1416,11 @@ main (int argc, char **argv) case EXTRACT_SUBCOMMAND: extr_init (); read_and (extract_archive); + + /* FIXME: should extract_finish () even if an ordinary signal is + received. */ extract_finish (); + break; case LIST_SUBCOMMAND: @@ -1258,6 +1433,9 @@ main (int argc, char **argv) break; } + if (check_links_option) + check_links (); + if (volno_file_option) closeout_volume_number (); @@ -1266,9 +1444,23 @@ main (int argc, char **argv) free (archive_name_array); name_term (); - if (stdlis == stdout && (ferror (stdout) || fclose (stdout) != 0)) + if (stdlis != stderr && (ferror (stdlis) || fclose (stdlis) != 0)) FATAL_ERROR ((0, 0, _("Error in writing to standard output"))); if (exit_status == TAREXIT_FAILURE) error (0, 0, _("Error exit delayed from previous errors")); + if (ferror (stderr) || fclose (stderr) != 0) + exit_status = TAREXIT_FAILURE; exit (exit_status); } + +void +destroy_stat (struct tar_stat_info *st) +{ + free (st->orig_file_name); + free (st->file_name); + free (st->link_name); + free (st->uname); + free (st->gname); + memset (st, 0, sizeof (*st)); +} +