X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=80091fa2053680e55a0bdcc863e883b71f5831c0;hb=694e8376abff79426bb7e9f69c9662e6ce03c69d;hp=994a0f783d21c9eff84e02cbc6badb1a4d8cacbb;hpb=0ba3b75ad47cc3bcdecd00a103ee97322775217c;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 994a0f7..80091fa 100644 --- a/src/tar.c +++ b/src/tar.c @@ -56,7 +56,7 @@ # define DEFAULT_BLOCKING 20 #endif -static void usage (int) __attribute__ ((noreturn)); +void usage (int) __attribute__ ((noreturn)); /* Miscellaneous. */ @@ -122,7 +122,8 @@ static struct fmttab { enum archive_format fmt; } const fmttab[] = { { "v7", V7_FORMAT }, - { "oldgnu", OLDGNU_FORMAT }, + { "oldgnu", OLDGNU_FORMAT }, + { "ustar", USTAR_FORMAT }, { "posix", POSIX_FORMAT }, #if 0 /* not fully supported yet */ { "star", STAR_FORMAT }, @@ -158,6 +159,17 @@ archive_format_string (enum archive_format fmt) 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. */ @@ -191,8 +203,10 @@ enum NO_WILDCARDS_MATCH_SLASH_OPTION, NULL_OPTION, NUMERIC_OWNER_OPTION, + OCCURRENCE_OPTION, OVERWRITE_OPTION, OWNER_OPTION, + PAX_OPTION, POSIX_OPTION, PRESERVE_OPTION, RECORD_SIZE_OPTION, @@ -200,12 +214,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, + WILDCARDS_MATCH_SLASH_OPTION }; /* If nonzero, display usage information and exit. */ @@ -277,10 +292,12 @@ static struct option long_options[] = {"no-same-owner", no_argument, &same_owner_option, -1}, {"no-same-permissions", no_argument, &same_permissions_option, -1}, {"numeric-owner", no_argument, 0, NUMERIC_OWNER_OPTION}, + {"occurrence", optional_argument, 0, OCCURRENCE_OPTION}, {"old-archive", no_argument, 0, 'o'}, {"one-file-system", no_argument, 0, 'l'}, {"overwrite", no_argument, 0, OVERWRITE_OPTION}, {"owner", required_argument, 0, OWNER_OPTION}, + {"pax-option", required_argument, 0, PAX_OPTION}, {"portability", no_argument, 0, 'o'}, {"posix", no_argument, 0, POSIX_OPTION}, {"preserve", no_argument, 0, PRESERVE_OPTION}, @@ -299,6 +316,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'}, @@ -320,7 +338,7 @@ static struct option long_options[] = }; /* Print a usage message and exit with STATUS. */ -static void +void usage (int status) { if (status != TAREXIT_SUCCESS) @@ -372,7 +390,14 @@ 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\ + --occurrence[=NUM] process only the NUMth occurrence of each file in\n\ + the archive. This option is valid only in\n\ + conjunction with one of the subcommands --delete,\n\ + --diff, --extract or --list and when a list of\n\ + files is given either on the command line or\n\ + via -T option.\n\ + NUM defaults to 1.\n"), stdout); fputs (_("\ \n\ @@ -420,7 +445,8 @@ Archive format selection:\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\ + ustar POSIX 1003.1-1988 (ustar) format\n\ + posix POSIX 1003.1-2001 (pax) format\n\ gnu GNU format\n\ --old-archive, --portability same as --format=v7\n\ --posix same as --format=posix\n\ @@ -451,11 +477,13 @@ 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 (_("\ - -N, --newer=DATE only store files newer than DATE\n\ + -N, --newer=DATE-OR-FILE only store files newer than DATE-OR-FILE\n\ --newer-mtime=DATE compare date and time when data changed only\n\ --after-date=DATE same as -N\n"), stdout); @@ -550,7 +578,7 @@ decode_options (int argc, char **argv) char const *backup_suffix_string; char const *version_control_string = 0; int exclude_options = EXCLUDE_WILDCARDS; - int o_option = 0; + bool o_option = 0; /* Set some default option values. */ @@ -671,7 +699,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': @@ -703,12 +731,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': @@ -716,13 +744,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': @@ -730,7 +757,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': @@ -749,7 +776,7 @@ decode_options (int argc, char **argv) break; case 'K': - starting_file_option = 1; + starting_file_option = true; addname (optarg, 0); break; @@ -757,7 +784,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': @@ -767,24 +794,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 '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: @@ -817,19 +844,19 @@ decode_options (int argc, char **argv) #endif /* not MSDOS */ case 'o': - o_option = 1; + 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 'P': - absolute_names_option = 1; + absolute_names_option = true; break; case 'r': @@ -844,17 +871,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': @@ -883,11 +910,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': @@ -923,15 +950,15 @@ decode_options (int argc, char **argv) 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; @@ -945,7 +972,7 @@ decode_options (int argc, char **argv) break; case FORCE_LOCAL_OPTION: - force_local_option = 1; + force_local_option = true; break; case FORMAT_OPTION: @@ -961,7 +988,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: @@ -1013,9 +1040,23 @@ decode_options (int argc, char **argv) break; case NUMERIC_OWNER_OPTION: - numeric_owner_option = 1; + numeric_owner_option = true; break; + case OCCURRENCE_OPTION: + if (!optarg) + occurrence_option = 1; + else + { + uintmax_t u; + if (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK) + occurrence_option = u; + else + FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg), + _("Invalid number"))); + } + break; + case OVERWRITE_OPTION: old_files_option = OVERWRITE_OLD_FILES; break; @@ -1034,13 +1075,17 @@ decode_options (int argc, char **argv) } break; + case PAX_OPTION: + xheader_set_option (optarg); + break; + case POSIX_OPTION: 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: @@ -1059,22 +1104,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; @@ -1201,8 +1261,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\ @@ -1221,14 +1281,29 @@ see the file named COPYING for details.")); if (archive_format == DEFAULT_FORMAT) archive_format = DEFAULT_ARCHIVE_FORMAT; - if (archive_format == GNU_FORMAT && getenv ("POSIXLY_CORRECT")) - archive_format = POSIX_FORMAT; + if (volume_label_option && subcommand_option == CREATE_SUBCOMMAND) + assert_format (FORMAT_MASK (OLDGNU_FORMAT) + | FORMAT_MASK (GNU_FORMAT)); - if ((volume_label_option - || 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 (incremental_option + || multi_volume_option + || sparse_option) + assert_format (FORMAT_MASK (OLDGNU_FORMAT) + | FORMAT_MASK (GNU_FORMAT) + | FORMAT_MASK (POSIX_FORMAT)); + + if (occurrence_option) + { + if (!input_files && !files_from_option) + USAGE_ERROR ((0, 0, + _("--occurrence 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, + _("--occurrence cannot be used in the requested operation mode"))); + } if (archive_names == 0) { @@ -1245,7 +1320,7 @@ see the file named COPYING for details.")); if (archive_names > 1 && !multi_volume_option) USAGE_ERROR ((0, 0, - _("Multiple archive files requires `-M' option"))); + _("Multiple archive files require `-M' option"))); if (listed_incremental_option && newer_mtime_option != TYPE_MINIMUM (time_t)) @@ -1265,11 +1340,29 @@ 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)); } + if (verify_option) + { + if (multi_volume_option) + USAGE_ERROR ((0, 0, _("Cannot verify multi-volume archives"))); + if (use_compress_program_option) + USAGE_ERROR ((0, 0, _("Cannot verify compressed archives"))); + } + + if (use_compress_program_option) + { + if (multi_volume_option) + USAGE_ERROR ((0, 0, _("Cannot use multi-volume compressed archives"))); + if (subcommand_option == UPDATE_SUBCOMMAND) + USAGE_ERROR ((0, 0, _("Cannot update compressed archives"))); + } + /* If ready to unlink hierarchies, so we are for simpler files. */ if (recursive_unlink_option) old_files_option = UNLINK_FIRST_OLD_FILES; @@ -1327,6 +1420,7 @@ see the file named COPYING for details.")); textual_date_option, treated_as)); } } + /* Tar proper. */ @@ -1432,17 +1526,24 @@ main (int argc, char **argv) error (0, 0, _("Error exit delayed from previous errors")); if (ferror (stderr) || fclose (stderr) != 0) exit_status = TAREXIT_FAILURE; - exit (exit_status); + return exit_status; } void -destroy_stat (struct tar_stat_info *st) +tar_stat_init (struct tar_stat_info *st) +{ + memset (st, 0, sizeof (*st)); +} + +void +tar_stat_destroy (struct tar_stat_info *st) { free (st->orig_file_name); free (st->file_name); free (st->link_name); free (st->uname); free (st->gname); + free (st->sparse_map); memset (st, 0, sizeof (*st)); }