X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=c3af7499bfd75c778f1e97249bd8cbd9a40a9873;hb=17878ad672f89e183cc390f06efc8e8da0a10933;hp=059e0c99ce11606332ce7a2a441a8aad2e6a2312;hpb=42d05fcb6e724c52cd66c85828b0b8b9d2338e72;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 059e0c9..c3af749 100644 --- a/src/tar.c +++ b/src/tar.c @@ -44,6 +44,10 @@ /* Local declarations. */ +#ifndef DEFAULT_ARCHIVE_FORMAT +# define DEFAULT_ARCHIVE_FORMAT GNU_FORMAT +#endif + #ifndef DEFAULT_ARCHIVE # define DEFAULT_ARCHIVE "tar.out" #endif @@ -112,6 +116,59 @@ 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?"; +} + +#define FORMAT_MASK(n) (1<<(n)) + +static void +assert_format(unsigned fmt_mask) +{ + if ((FORMAT_MASK(archive_format) & fmt_mask) == 0) + USAGE_ERROR ((0, 0, + _("GNU features wanted on incompatible archive format"))); +} + + /* Options. */ @@ -130,7 +187,9 @@ enum CHECKPOINT_OPTION, DELETE_OPTION, EXCLUDE_OPTION, + FIRST_COPY_OPTION, FORCE_LOCAL_OPTION, + FORMAT_OPTION, GROUP_OPTION, IGNORE_CASE_OPTION, IGNORE_FAILED_READ_OPTION, @@ -153,24 +212,13 @@ enum REMOVE_FILES_OPTION, RSH_COMMAND_OPTION, SHOW_OMITTED_DIRS_OPTION, + STRIP_PATH_OPTION, SUFFIX_OPTION, TOTALS_OPTION, USE_COMPRESS_PROGRAM_OPTION, VOLNO_FILE_OPTION, WILDCARDS_OPTION, WILDCARDS_MATCH_SLASH_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 }; /* If nonzero, display usage information and exit. */ @@ -179,22 +227,24 @@ static int show_help; /* If nonzero, print the version on standard output and exit. */ static int show_version; +/* If nonzero, stop processing when all the files from the namelist + where handled */ +static int first_copy_option; + 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, 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, 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'}, @@ -210,7 +260,9 @@ static struct option long_options[] = {"extract", no_argument, 0, 'x'}, {"file", required_argument, 0, 'f'}, {"files-from", required_argument, 0, 'T'}, + {"first-copy", no_argument, &first_copy_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'}, @@ -229,7 +281,6 @@ 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'}, @@ -255,10 +306,8 @@ static struct option long_options[] = {"preserve-permissions", no_argument, 0, 'p'}, {"recursion", no_argument, &recursion_option, FNM_LEADING_DIR}, {"recursive-unlink", no_argument, 0, RECURSIVE_UNLINK_OPTION}, - {"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS}, {"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, 0, REMOVE_FILES_OPTION}, {"rsh-command", required_argument, 0, RSH_COMMAND_OPTION}, @@ -268,6 +317,7 @@ static struct option long_options[] = {"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'}, @@ -281,11 +331,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} }; @@ -342,7 +391,9 @@ Operation modifiers:\n\ -G, --incremental handle old GNU-format incremental backup\n\ -g, --listed-incremental=FILE\n\ handle new GNU-format incremental backup\n\ - --ignore-failed-read do not exit with nonzero on unreadable files\n"), + --ignore-failed-read do not exit with nonzero on unreadable files\n\ + --first-copy process only the first copy of each file in the\ + archive\n"), stdout); fputs (_("\ \n\ @@ -386,10 +437,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\ @@ -415,7 +472,9 @@ Local file selection:\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 (_("\ @@ -435,6 +494,7 @@ 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\ @@ -443,6 +503,13 @@ Informative output:\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\ @@ -452,12 +519,10 @@ 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; 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 `-f%s -b%d'.\n"), +*This* `tar' defaults to `--format=%s -f%s -b%d'.\n"), + archive_format_string (DEFAULT_ARCHIVE_FORMAT), DEFAULT_ARCHIVE, DEFAULT_BLOCKING); printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); } @@ -508,7 +573,8 @@ decode_options (int argc, char **argv) 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; @@ -608,14 +674,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; @@ -628,11 +686,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. */ @@ -641,7 +694,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': @@ -673,12 +726,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': @@ -686,13 +739,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': @@ -700,7 +752,7 @@ 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': @@ -719,7 +771,7 @@ decode_options (int argc, char **argv) break; case 'K': - starting_file_option = 1; + starting_file_option = true; addname (optarg, 0); break; @@ -727,7 +779,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': @@ -737,28 +789,24 @@ 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: @@ -791,36 +839,25 @@ decode_options (int argc, char **argv) #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. */ @@ -829,17 +866,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': @@ -868,11 +905,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': @@ -903,24 +940,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 = 1; + atime_preserve_option = true; break; case CHECKPOINT_OPTION: - checkpoint_option = 1; + checkpoint_option = true; break; case BACKUP_OPTION: - backup_option = 1; + backup_option = true; if (optarg) version_control_string = optarg; break; @@ -934,9 +967,13 @@ decode_options (int argc, char **argv) break; case FORCE_LOCAL_OPTION: - force_local_option = 1; + force_local_option = true; break; + case FORMAT_OPTION: + set_archive_format (optarg); + break; + case INDEX_FILE_OPTION: index_file_name = optarg; break; @@ -946,7 +983,7 @@ decode_options (int argc, char **argv) break; case IGNORE_FAILED_READ_OPTION: - ignore_failed_read_option = 1; + ignore_failed_read_option = true; break; case GROUP_OPTION: @@ -998,7 +1035,7 @@ decode_options (int argc, char **argv) break; case NUMERIC_OWNER_OPTION: - numeric_owner_option = 1; + numeric_owner_option = true; break; case OVERWRITE_OPTION: @@ -1020,22 +1057,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: @@ -1054,22 +1081,37 @@ decode_options (int argc, char **argv) break; case RECURSIVE_UNLINK_OPTION: - recursive_unlink_option = 1; + recursive_unlink_option = true; break; case REMOVE_FILES_OPTION: - remove_files_option = 1; + 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; @@ -1150,10 +1192,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; @@ -1165,6 +1204,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++) { @@ -1176,8 +1238,8 @@ decode_options (int argc, char **argv) if (show_version) { - printf ("tar (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - printf (_("Copyright (C) %d Free Software Foundation, Inc.\n"), 2003); + printf ("tar (%s) %s\n%s\n", PACKAGE_NAME, PACKAGE_VERSION, + "Copyright (C) 2003 Free Software Foundation, Inc."); 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\ @@ -1194,23 +1256,41 @@ 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, _("GNU features wanted on incompatible archive format"))); + if (volume_label_option && subcommand_option == CREATE_SUBCOMMAND) + assert_format (FORMAT_MASK (OLDGNU_FORMAT) + | FORMAT_MASK (GNU_FORMAT)); + + if (incremental_option + || multi_volume_option + || sparse_option + || subcommand_option == CAT_SUBCOMMAND) + assert_format (FORMAT_MASK (OLDGNU_FORMAT) + | FORMAT_MASK (GNU_FORMAT)); + + if (first_copy_option) + { + if (!input_files && !files_from_option) + USAGE_ERROR ((0, 0, + _("--first-copy is meaningless without file list"))); + if (subcommand_option != DELETE_SUBCOMMAND + && subcommand_option != DIFF_SUBCOMMAND + && subcommand_option != EXTRACT_SUBCOMMAND + && subcommand_option != LIST_SUBCOMMAND) + USAGE_ERROR ((0, 0, + _("--first-copy cannot be used in the requested operation mode"))); + } + if (archive_names == 0) { /* If no archive file name given, try TAPE from the environment, or @@ -1246,7 +1326,9 @@ see the file named COPYING for details.")); : 0)); if (volume_label_max_len < strlen (volume_label_option)) USAGE_ERROR ((0, 0, - _("%s: Volume label is too long (limit is %lu bytes)"), + ngettext ("%s: Volume label is too long (limit is %lu byte)", + "%s: Volume label is too long (limit is %lu bytes)", + volume_label_max_len), quotearg_colon (volume_label_option), (unsigned long) volume_label_max_len)); } @@ -1308,6 +1390,13 @@ see the file named COPYING for details.")); textual_date_option, treated_as)); } } + +bool +all_names_found () +{ + return first_copy_option && names_done (); +} + /* Tar proper. */ @@ -1396,6 +1485,9 @@ main (int argc, char **argv) break; } + if (check_links_option) + check_links (); + if (volno_file_option) closeout_volume_number (); @@ -1412,3 +1504,15 @@ main (int argc, char **argv) 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)); +} +