1 From d9bea5154e28817f7c42e7fb7798df17eca483ff Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lunar@debian.org>
3 Date: Thu, 4 Jun 2015 11:05:20 +0000
4 Subject: [PATCH] Add --clamp-mtime option
6 The new `--clamp-mtime` option will change the behavior of `--mtime` to
7 only use the time specified if the file mtime is newer than the given time.
8 The `--clamp-mtime` option can only be used together with `--mtime`.
10 Typical use case is to make builds reproducible: to loose less
11 information, it's better to keep the original date of an archive, except for
12 files modified during the build process. In that case, using a reference (and
13 thus reproducible) timestamps for the latter is good enough. See
14 <https://wiki.debian.org/ReproducibleBuilds> for more information.
16 In order to implement the option, we transform `set_mtime_option` from
17 a bool to an enum with three values: use original file mtime, force all mtimes
18 to be of the same value, and clamp mtimes (as explained above).
20 To verify that `--clamp-mtime` is used together with `--mtime`, `mtime_option`
21 is now initialized to a minimal value as done for `newer_mtime_option`. As
22 the same macro can now be used for both options, NEWER_OPTION_INITIALIZED
23 has been renamed to TIME_OPTION_INITIALIZED.
25 src/common.h | 17 ++++++++++++-----
26 src/create.c | 15 ++++++++++++++-
28 src/tar.c | 23 ++++++++++++++++++++---
29 4 files changed, 47 insertions(+), 10 deletions(-)
34 do not get archived (also see after_date_option above). */
35 GLOBAL struct timespec newer_mtime_option;
37 -/* If true, override actual mtime (see below) */
38 -GLOBAL bool set_mtime_option;
39 -/* Value to be put in mtime header field instead of the actual mtime */
40 +enum set_mtime_option_mode
47 +/* Override actual mtime if set to FORCE_MTIME or CLAMP_MTIME */
48 +GLOBAL enum set_mtime_option_mode set_mtime_option;
49 +/* Value to use when forcing or clamping the mtime header field. */
50 GLOBAL struct timespec mtime_option;
52 -/* Return true if newer_mtime_option is initialized. */
53 -#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
54 +/* Return true if mtime_option or newer_mtime_option is initialized. */
55 +#define TIME_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
57 /* Return true if the struct stat ST's M time is less than
58 newer_mtime_option. */
65 - struct timespec mtime = set_mtime_option ? mtime_option : st->mtime;
66 + struct timespec mtime;
67 + switch (set_mtime_option)
70 + mtime = mtime_option;
73 + mtime = timespec_cmp (st->mtime, mtime_option) > 0 ? mtime_option : st->mtime;
80 if (archive_format == POSIX_FORMAT)
82 if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
86 decode_header (current_header, ¤t_stat_info,
88 if (! name_match (current_stat_info.file_name)
89 - || (NEWER_OPTION_INITIALIZED (newer_mtime_option)
90 + || (TIME_OPTION_INITIALIZED (newer_mtime_option)
91 /* FIXME: We get mtime now, and again later; this causes
92 duplicate diagnostics if header.mtime is bogus. */
99 CHECKPOINT_ACTION_OPTION,
100 + CLAMP_MTIME_OPTION,
101 DELAY_DIRECTORY_RESTORE_OPTION,
102 HARD_DEREFERENCE_OPTION,
105 N_("force NAME as group for added files"), GRID+1 },
106 {"mtime", MTIME_OPTION, N_("DATE-OR-FILE"), 0,
107 N_("set mtime for added files from DATE-OR-FILE"), GRID+1 },
108 + {"clamp-mtime", CLAMP_MTIME_OPTION, 0, 0,
109 + N_("only set time when the file is more recent than what was given with --mtime"), GRID+1 },
110 {"mode", MODE_OPTION, N_("CHANGES"), 0,
111 N_("force (symbolic) mode CHANGES for added files"), GRID+1 },
112 {"atime-preserve", ATIME_PRESERVE_OPTION,
113 @@ -1425,6 +1428,10 @@
114 set_subcommand_option (CREATE_SUBCOMMAND);
117 + case CLAMP_MTIME_OPTION:
118 + set_mtime_option = CLAMP_MTIME;
124 @@ -1567,7 +1574,8 @@
127 get_date_or_file (args, "--mtime", arg, &mtime_option);
128 - set_mtime_option = true;
129 + if (set_mtime_option == USE_FILE_MTIME)
130 + set_mtime_option = FORCE_MTIME;
134 @@ -1583,7 +1591,7 @@
137 case NEWER_MTIME_OPTION:
138 - if (NEWER_OPTION_INITIALIZED (newer_mtime_option))
139 + if (TIME_OPTION_INITIALIZED (newer_mtime_option))
140 USAGE_ERROR ((0, 0, _("More than one threshold date")));
141 get_date_or_file (args,
142 key == NEWER_MTIME_OPTION ? "--newer-mtime"
143 @@ -2350,6 +2358,8 @@
145 newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
146 newer_mtime_option.tv_nsec = -1;
147 + mtime_option.tv_sec = TYPE_MINIMUM (time_t);
148 + mtime_option.tv_nsec = -1;
149 recursion_option = FNM_LEADING_DIR;
150 unquote_option = true;
151 tar_sparse_major = 1;
152 @@ -2510,7 +2520,7 @@
153 _("Multiple archive files require '-M' option")));
155 if (listed_incremental_option
156 - && NEWER_OPTION_INITIALIZED (newer_mtime_option))
157 + && TIME_OPTION_INITIALIZED (newer_mtime_option))
158 option_conflict_error ("--listed-incremental", "--newer");
160 if (incremental_level != -1 && !listed_incremental_option)
161 @@ -2563,6 +2573,13 @@
162 USAGE_ERROR ((0, 0, _("Cannot concatenate compressed archives")));
165 + if (set_mtime_option == CLAMP_MTIME)
167 + if (!TIME_OPTION_INITIALIZED (mtime_option))
168 + USAGE_ERROR ((0, 0,
169 + _("--clamp-mtime needs a date specified using --mtime")));
172 /* It is no harm to use --pax-option on non-pax archives in archive
173 reading mode. It may even be useful, since it allows to override
174 file attributes from tar headers. Therefore I allow such usage.