patch from Lunar to add --clamp-mtime option for reproducible builds effort
[debian/tar] / debian / patches / add-clamp-mtime.diff
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
5
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`.
9
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.
15
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).
19
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.
24 ---
25  src/common.h | 17 ++++++++++++-----
26  src/create.c | 15 ++++++++++++++-
27  src/list.c   |  2 +-
28  src/tar.c    | 23 ++++++++++++++++++++---
29  4 files changed, 47 insertions(+), 10 deletions(-)
30
31 diff --git a/src/common.h b/src/common.h
32 index 42fd539..962ce1d 100644
33 --- a/src/common.h
34 +++ b/src/common.h
35 @@ -211,13 +211,20 @@ GLOBAL bool multi_volume_option;
36     do not get archived (also see after_date_option above).  */
37  GLOBAL struct timespec newer_mtime_option;
38  
39 -/* If true, override actual mtime (see below) */
40 -GLOBAL bool set_mtime_option;
41 -/* Value to be put in mtime header field instead of the actual mtime */
42 +enum set_mtime_option_mode
43 +{
44 +  USE_FILE_MTIME,
45 +  FORCE_MTIME,
46 +  CLAMP_MTIME,
47 +};
48 +
49 +/* Override actual mtime if set to FORCE_MTIME or CLAMP_MTIME */
50 +GLOBAL enum set_mtime_option_mode set_mtime_option;
51 +/* Value to use when forcing or clamping the mtime header field. */
52  GLOBAL struct timespec mtime_option;
53  
54 -/* Return true if newer_mtime_option is initialized.  */
55 -#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
56 +/* Return true if mtime_option or newer_mtime_option is initialized.  */
57 +#define TIME_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
58  
59  /* Return true if the struct stat ST's M time is less than
60     newer_mtime_option.  */
61 diff --git a/src/create.c b/src/create.c
62 index 4344a24..63585a1 100644
63 --- a/src/create.c
64 +++ b/src/create.c
65 @@ -822,7 +822,20 @@ start_header (struct tar_stat_info *st)
66    }
67  
68    {
69 -    struct timespec mtime = set_mtime_option ? mtime_option : st->mtime;
70 +    struct timespec mtime;
71 +    switch (set_mtime_option)
72 +      {
73 +        case FORCE_MTIME:
74 +          mtime = mtime_option;
75 +          break;
76 +        case CLAMP_MTIME:
77 +          mtime = timespec_cmp (st->mtime, mtime_option) > 0 ? mtime_option : st->mtime;
78 +          break;
79 +        default:
80 +          mtime = st->mtime;
81 +          break;
82 +      }
83 +
84      if (archive_format == POSIX_FORMAT)
85        {
86         if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
87 diff --git a/src/list.c b/src/list.c
88 index 858aa73..ce2d304 100644
89 --- a/src/list.c
90 +++ b/src/list.c
91 @@ -166,7 +166,7 @@ read_and (void (*do_something) (void))
92           decode_header (current_header, &current_stat_info,
93                          &current_format, 1);
94           if (! name_match (current_stat_info.file_name)
95 -             || (NEWER_OPTION_INITIALIZED (newer_mtime_option)
96 +             || (TIME_OPTION_INITIALIZED (newer_mtime_option)
97                   /* FIXME: We get mtime now, and again later; this causes
98                      duplicate diagnostics if header.mtime is bogus.  */
99                   && ((mtime.tv_sec
100 diff --git a/src/tar.c b/src/tar.c
101 index 4f5017d..cbaa9df 100644
102 --- a/src/tar.c
103 +++ b/src/tar.c
104 @@ -267,6 +267,7 @@ enum
105    CHECK_DEVICE_OPTION,
106    CHECKPOINT_OPTION,
107    CHECKPOINT_ACTION_OPTION,
108 +  CLAMP_MTIME_OPTION,
109    DELAY_DIRECTORY_RESTORE_OPTION,
110    HARD_DEREFERENCE_OPTION,
111    DELETE_OPTION,
112 @@ -515,6 +516,8 @@ static struct argp_option options[] = {
113     N_("force NAME as group for added files"), GRID+1 },
114    {"mtime", MTIME_OPTION, N_("DATE-OR-FILE"), 0,
115     N_("set mtime for added files from DATE-OR-FILE"), GRID+1 },
116 +  {"clamp-mtime", CLAMP_MTIME_OPTION, 0, 0,
117 +   N_("only set time when the file is more recent than what was given with --mtime"), GRID+1 },
118    {"mode", MODE_OPTION, N_("CHANGES"), 0,
119     N_("force (symbolic) mode CHANGES for added files"), GRID+1 },
120    {"atime-preserve", ATIME_PRESERVE_OPTION,
121 @@ -1355,6 +1358,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
122        set_subcommand_option (CREATE_SUBCOMMAND);
123        break;
124  
125 +    case CLAMP_MTIME_OPTION:
126 +      set_mtime_option = CLAMP_MTIME;
127 +      break;
128 +
129      case 'C':
130        name_add_dir (arg);
131        break;
132 @@ -1492,7 +1499,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
133  
134      case MTIME_OPTION:
135        get_date_or_file (args, "--mtime", arg, &mtime_option);
136 -      set_mtime_option = true;
137 +      if (set_mtime_option == USE_FILE_MTIME)
138 +        set_mtime_option = FORCE_MTIME;
139        break;
140  
141      case 'n':
142 @@ -1508,7 +1516,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
143        /* Fall through.  */
144  
145      case NEWER_MTIME_OPTION:
146 -      if (NEWER_OPTION_INITIALIZED (newer_mtime_option))
147 +      if (TIME_OPTION_INITIALIZED (newer_mtime_option))
148         USAGE_ERROR ((0, 0, _("More than one threshold date")));
149        get_date_or_file (args,
150                         key == NEWER_MTIME_OPTION ? "--newer-mtime"
151 @@ -2249,6 +2257,8 @@ decode_options (int argc, char **argv)
152    excluded = new_exclude ();
153    newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
154    newer_mtime_option.tv_nsec = -1;
155 +  mtime_option.tv_sec = TYPE_MINIMUM (time_t);
156 +  mtime_option.tv_nsec = -1;
157    recursion_option = FNM_LEADING_DIR;
158    unquote_option = true;
159    tar_sparse_major = 1;
160 @@ -2408,7 +2418,7 @@ decode_options (int argc, char **argv)
161                   _("Multiple archive files require '-M' option")));
162  
163    if (listed_incremental_option
164 -      && NEWER_OPTION_INITIALIZED (newer_mtime_option))
165 +      && TIME_OPTION_INITIALIZED (newer_mtime_option))
166      USAGE_ERROR ((0, 0,
167                   _("Cannot combine --listed-incremental with --newer")));
168    if (incremental_level != -1 && !listed_incremental_option)
169 @@ -2461,6 +2471,13 @@ decode_options (int argc, char **argv)
170         USAGE_ERROR ((0, 0, _("Cannot concatenate compressed archives")));
171      }
172  
173 +  if (set_mtime_option == CLAMP_MTIME)
174 +    {
175 +      if (!TIME_OPTION_INITIALIZED (mtime_option))
176 +       USAGE_ERROR ((0, 0,
177 +                     _("--clamp-mtime needs a date specified using --mtime")));
178 +    }
179 +
180    /* It is no harm to use --pax-option on non-pax archives in archive
181       reading mode. It may even be useful, since it allows to override
182       file attributes from tar headers. Therefore I allow such usage.
183 -- 
184 2.1.4
185