diff --git a/NEWS b/NEWS index 5cbd1270..ec9c8a75 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2014-02-13 +GNU tar NEWS - User visible changes. 2014-02-14 Please send GNU tar bug reports to @@ -35,6 +35,19 @@ supplied DIRectory. This ensures that no archive members are extracted outside of the specified directory, even if the archive is crafted so as to put them elsewhere. +* New option --sort + +The --sort=ORDER option instructs tar to sort directory entries +according to ORDER. It takes effect when creating archives. +Available ORDERs are: none (the default), name and inode. The +latter may be absent, if the underlying system does not provide +the necessary information. + +Using --sort=name ensures the member ordering in the created archive +is uniform and reproducible. Using --sort=inode reduces the number +of disk seeks made when creating the archive and thus can considerably +speed up archivation. + * Manpages This release includes official tar(1) and rmt(8) manpages. diff --git a/doc/tar.1 b/doc/tar.1 index 14268ed8..b33f55b9 100644 --- a/doc/tar.1 +++ b/doc/tar.1 @@ -13,7 +13,7 @@ .\" .\" You should have received a copy of the GNU General Public License .\" along with this program. If not, see . -.TH TAR 1 "January 28, 2014" "TAR" "GNU TAR Manual" +.TH TAR 1 "February 14, 2014" "TAR" "GNU TAR Manual" .SH NAME tar \- an archiving utility .SH SYNOPSIS @@ -506,6 +506,24 @@ Try extracting files with the same ownership as exists in the archive .TP \fB\-s\fR, \fB\-\-preserve\-order\fR, \fB\-\-same\-order\fR Sort names to extract to match archive +.TP +\fB\-\-sort=\fIORDER\fR +When creating an archive, sort directory entries according to +\fIORDER\fR, which is one of +.BR none , +.BR name ", or" +.BR inode . + +The default is \fB\-\-sort=none\fR, which stores archive members in +the same order as returned by the operating system. + +Using \fB\-\-sort=name\fR ensures the member ordering in the created archive +is uniform and reproducible. + +Using \fB\-\-sort=inode\fR reduces the number of disk seeks made when +creating the archive and thus can considerably speed up archivation. +This sorting order is supported only if the underlying system provides +the necessary information. .SS Device selection and switching .TP \fB\-f\fR, \fB\-\-file\fR=\fIARCHIVE\fR diff --git a/doc/tar.texi b/doc/tar.texi index 2be123ac..9bb5a833 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -3319,6 +3319,27 @@ The @option{--warning=existing-file} option can be used together with this option to produce warning messages about existing old files (@pxref{warnings}). +@opsummary{sort} +@item --sort=@var{order} +Specify the directory sorting order when reading directories. +@var{Order} may be one of the following: + +@table @samp +@item none +No directory sorting is performed. This is the default. + +@item name +Sort the directory entries on name. The operating system may deliver +directory entries in a more or less random order, and sorting them +makes archive creation reproducible. + +@item inode +Sort the directory entries on inode number. Sorting directories on +inode number may reduce the amount of disk seek operations when +creating an archive for some file systems. + +@end table + @opsummary{sparse} @item --sparse @itemx -S diff --git a/src/common.h b/src/common.h index 14ae2cad..4d2c3994 100644 --- a/src/common.h +++ b/src/common.h @@ -386,6 +386,8 @@ GLOBAL dev_t root_device; /* Unquote filenames */ GLOBAL bool unquote_option; +GLOBAL int savedir_sort_order; + /* Show file or archive names after transformation. In particular, when creating archive in verbose mode, list member names as stored in the archive */ diff --git a/src/create.c b/src/create.c index 24920db3..3455bddc 100644 --- a/src/create.c +++ b/src/create.c @@ -1288,7 +1288,7 @@ get_directory_entries (struct tar_stat_info *st) while (! (st->dirstream = fdopendir (st->fd))) if (! open_failure_recover (st)) return 0; - return streamsavedir (st->dirstream); + return streamsavedir (st->dirstream, savedir_sort_order); } /* Dump the directory ST. Return true if successful, false (emitting diff --git a/src/misc.c b/src/misc.c index e92c8aa8..cc2fef85 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1239,7 +1239,7 @@ tar_savedir (const char *name, int must_exist) open_error (name); } else if (! ((dir = fdopendir (fd)) - && (ret = streamsavedir (dir)))) + && (ret = streamsavedir (dir, savedir_sort_order)))) savedir_error (name); if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0) diff --git a/src/tar.c b/src/tar.c index 7cd25c04..f36e1518 100644 --- a/src/tar.c +++ b/src/tar.c @@ -51,6 +51,7 @@ #include #include #include +#include /* Local declarations. */ @@ -342,6 +343,7 @@ enum SHOW_SNAPSHOT_FIELD_RANGES_OPTION, SHOW_TRANSFORMED_NAMES_OPTION, SKIP_OLD_FILES_OPTION, + SORT_OPTION, SPARSE_VERSION_OPTION, STRIP_COMPONENTS_OPTION, SUFFIX_OPTION, @@ -551,6 +553,13 @@ static struct argp_option options[] = { " directories until the end of extraction"), GRID+1 }, {"no-delay-directory-restore", NO_DELAY_DIRECTORY_RESTORE_OPTION, 0, 0, N_("cancel the effect of --delay-directory-restore option"), GRID+1 }, + {"sort", SORT_OPTION, N_("ORDER"), 0, +#if D_INO_IN_DIRENT + N_("directory sorting order: none (default), name or inode" +#else + N_("directory sorting order: none (default) or name" +#endif + ), GRID+1 }, #undef GRID #define GRID 55 @@ -1310,6 +1319,21 @@ parse_owner_group (char *arg, uintmax_t field_max, char const **name_option) /* Either NL or NUL, as decided by the --null option. */ static char filename_terminator; +static char const *const sort_mode_arg[] = { + "none", + "name", + "inode", + NULL +}; + +static int sort_mode_flag[] = { + SAVEDIR_SORT_NONE, + SAVEDIR_SORT_NAME, + SAVEDIR_SORT_INODE +}; + +ARGMATCH_VERIFY (sort_mode_arg, sort_mode_flag); + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -1997,6 +2021,11 @@ parse_opt (int key, char *arg, struct argp_state *state) show_transformed_names_option = true; break; + case SORT_OPTION: + savedir_sort_order = XARGMATCH ("--sort", arg, + sort_mode_arg, sort_mode_flag); + break; + case SUFFIX_OPTION: backup_option = true; args->backup_suffix_string = arg; @@ -2274,6 +2303,8 @@ decode_options (int argc, char **argv) tar_sparse_major = 1; tar_sparse_minor = 0; + savedir_sort_order = SAVEDIR_SORT_NONE; + owner_option = -1; owner_name_option = NULL; group_option = -1; group_name_option = NULL;