]> git.cworth.org Git - tar/blob - gnu/backupfile.c
upstream: Fix extraction of device nodes.
[tar] / gnu / backupfile.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* backupfile.c -- make Emacs style backup file names
4
5    Copyright (C) 1990-2006, 2009-2010 Free Software Foundation, Inc.
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 /* Written by Paul Eggert and David MacKenzie.
21    Some algorithms adapted from GNU Emacs.  */
22
23 #include <config.h>
24
25 #include "backupfile.h"
26
27 #include "argmatch.h"
28 #include "dirname.h"
29 #include "xalloc.h"
30
31 #include <errno.h>
32 #include <stdbool.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <limits.h>
37
38 #include <unistd.h>
39
40 #include "dirent--.h"
41 #ifndef _D_EXACT_NAMLEN
42 # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
43 #endif
44 #if D_INO_IN_DIRENT
45 # define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
46 #else
47 # define REAL_DIR_ENTRY(dp) 1
48 #endif
49
50 #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
51 # define pathconf(file, option) (errno = -1)
52 #endif
53
54 #ifndef _POSIX_NAME_MAX
55 # define _POSIX_NAME_MAX 14
56 #endif
57 #ifndef SIZE_MAX
58 # define SIZE_MAX ((size_t) -1)
59 #endif
60
61 #if defined _XOPEN_NAME_MAX
62 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
63 #else
64 # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
65 #endif
66
67 #ifndef HAVE_DOS_FILE_NAMES
68 # define HAVE_DOS_FILE_NAMES 0
69 #endif
70 #ifndef HAVE_LONG_FILE_NAMES
71 # define HAVE_LONG_FILE_NAMES 0
72 #endif
73
74 /* ISDIGIT differs from isdigit, as follows:
75    - Its arg may be any int or unsigned int; it need not be an unsigned char
76      or EOF.
77    - It's typically faster.
78    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
79    ISDIGIT unless it's important to use the locale's definition
80    of `digit' even when the host does not conform to POSIX.  */
81 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
82
83 /* The extension added to file names to produce a simple (as opposed
84    to numbered) backup file name. */
85 char const *simple_backup_suffix = "~";
86
87
88 /* If FILE (which was of length FILELEN before an extension was
89    appended to it) is too long, replace the extension with the single
90    char E.  If the result is still too long, remove the char just
91    before E.  */
92
93 static void
94 check_extension (char *file, size_t filelen, char e)
95 {
96   char *base = last_component (file);
97   size_t baselen = base_len (base);
98   size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
99
100   if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
101     {
102       /* The new base name is long enough to require a pathconf check.  */
103       long name_max;
104
105       /* Temporarily modify the buffer into its parent directory name,
106          invoke pathconf on the directory, and then restore the buffer.  */
107       char tmp[sizeof "."];
108       memcpy (tmp, base, sizeof ".");
109       strcpy (base, ".");
110       errno = 0;
111       name_max = pathconf (file, _PC_NAME_MAX);
112       if (0 <= name_max || errno == 0)
113         {
114           long size = baselen_max = name_max;
115           if (name_max != size)
116             baselen_max = SIZE_MAX;
117         }
118       memcpy (base, tmp, sizeof ".");
119     }
120
121   if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
122     {
123       /* Live within DOS's 8.3 limit.  */
124       char *dot = strchr (base, '.');
125       if (!dot)
126         baselen_max = 8;
127       else
128         {
129           char const *second_dot = strchr (dot + 1, '.');
130           baselen_max = (second_dot
131                          ? second_dot - base
132                          : dot + 1 - base + 3);
133         }
134     }
135
136   if (baselen_max < baselen)
137     {
138       baselen = file + filelen - base;
139       if (baselen_max <= baselen)
140         baselen = baselen_max - 1;
141       base[baselen] = e;
142       base[baselen + 1] = '\0';
143     }
144 }
145
146 /* Returned values for NUMBERED_BACKUP.  */
147
148 enum numbered_backup_result
149   {
150     /* The new backup name is the same length as an existing backup
151        name, so it's valid for that directory.  */
152     BACKUP_IS_SAME_LENGTH,
153
154     /* Some backup names already exist, but the returned name is longer
155        than any of them, and its length should be checked.  */
156     BACKUP_IS_LONGER,
157
158     /* There are no existing backup names.  The new name's length
159        should be checked.  */
160     BACKUP_IS_NEW
161   };
162
163 /* *BUFFER contains a file name.  Store into *BUFFER the next backup
164    name for the named file, with a version number greater than all the
165    existing numbered backups.  Reallocate *BUFFER as necessary; its
166    initial allocated size is BUFFER_SIZE, which must be at least 4
167    bytes longer than the file name to make room for the initially
168    appended ".~1".  FILELEN is the length of the original file name.
169    The returned value indicates what kind of backup was found.  If an
170    I/O or other read error occurs, use the highest backup number that
171    was found.  */
172
173 static enum numbered_backup_result
174 numbered_backup (char **buffer, size_t buffer_size, size_t filelen)
175 {
176   enum numbered_backup_result result = BACKUP_IS_NEW;
177   DIR *dirp;
178   struct dirent *dp;
179   char *buf = *buffer;
180   size_t versionlenmax = 1;
181   char *base = last_component (buf);
182   size_t base_offset = base - buf;
183   size_t baselen = base_len (base);
184
185   /* Temporarily modify the buffer into its parent directory name,
186      open the directory, and then restore the buffer.  */
187   char tmp[sizeof "."];
188   memcpy (tmp, base, sizeof ".");
189   strcpy (base, ".");
190   dirp = opendir (buf);
191   memcpy (base, tmp, sizeof ".");
192   strcpy (base + baselen, ".~1~");
193
194   if (!dirp)
195     return result;
196
197   while ((dp = readdir (dirp)) != NULL)
198     {
199       char const *p;
200       char *q;
201       bool all_9s;
202       size_t versionlen;
203       size_t new_buflen;
204
205       if (! REAL_DIR_ENTRY (dp) || _D_EXACT_NAMLEN (dp) < baselen + 4)
206         continue;
207
208       if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
209         continue;
210
211       p = dp->d_name + baselen + 2;
212
213       /* Check whether this file has a version number and if so,
214          whether it is larger.  Use string operations rather than
215          integer arithmetic, to avoid problems with integer overflow.  */
216
217       if (! ('1' <= *p && *p <= '9'))
218         continue;
219       all_9s = (*p == '9');
220       for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
221         all_9s &= (p[versionlen] == '9');
222
223       if (! (p[versionlen] == '~' && !p[versionlen + 1]
224              && (versionlenmax < versionlen
225                  || (versionlenmax == versionlen
226                      && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
227         continue;
228
229       /* This directory has the largest version number seen so far.
230          Append this highest numbered extension to the file name,
231          prepending '0' to the number if it is all 9s.  */
232
233       versionlenmax = all_9s + versionlen;
234       result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
235       new_buflen = filelen + 2 + versionlenmax + 1;
236       if (buffer_size <= new_buflen)
237         {
238           buf = xnrealloc (buf, 2, new_buflen);
239           buffer_size = new_buflen * 2;
240         }
241       q = buf + filelen;
242       *q++ = '.';
243       *q++ = '~';
244       *q = '0';
245       q += all_9s;
246       memcpy (q, p, versionlen + 2);
247
248       /* Add 1 to the version number.  */
249
250       q += versionlen;
251       while (*--q == '9')
252         *q = '0';
253       ++*q;
254     }
255
256   closedir (dirp);
257   *buffer = buf;
258   return result;
259 }
260
261 /* Return the name of the new backup file for the existing file FILE,
262    allocated with malloc.  Report an error and fail if out of memory.
263    Do not call this function if backup_type == no_backups.  */
264
265 char *
266 find_backup_file_name (char const *file, enum backup_type backup_type)
267 {
268   size_t filelen = strlen (file);
269   char *s;
270   size_t ssize;
271   bool simple = true;
272
273   /* Allow room for simple or ".~N~" backups.  The guess must be at
274      least sizeof ".~1~", but otherwise will be adjusted as needed.  */
275   size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
276   size_t backup_suffix_size_guess = simple_backup_suffix_size;
277   enum { GUESS = sizeof ".~12345~" };
278   if (backup_suffix_size_guess < GUESS)
279     backup_suffix_size_guess = GUESS;
280
281   ssize = filelen + backup_suffix_size_guess + 1;
282   s = xmalloc (ssize);
283   memcpy (s, file, filelen + 1);
284
285   if (backup_type != simple_backups)
286     switch (numbered_backup (&s, ssize, filelen))
287       {
288       case BACKUP_IS_SAME_LENGTH:
289         return s;
290
291       case BACKUP_IS_LONGER:
292         simple = false;
293         break;
294
295       case BACKUP_IS_NEW:
296         simple = (backup_type == numbered_existing_backups);
297         break;
298       }
299
300   if (simple)
301     memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
302   check_extension (s, filelen, '~');
303   return s;
304 }
305
306 static char const * const backup_args[] =
307 {
308   /* In a series of synonyms, present the most meaningful first, so
309      that argmatch_valid be more readable. */
310   "none", "off",
311   "simple", "never",
312   "existing", "nil",
313   "numbered", "t",
314   NULL
315 };
316
317 static const enum backup_type backup_types[] =
318 {
319   no_backups, no_backups,
320   simple_backups, simple_backups,
321   numbered_existing_backups, numbered_existing_backups,
322   numbered_backups, numbered_backups
323 };
324
325 /* Ensure that these two vectors have the same number of elements,
326    not counting the final NULL in the first one.  */
327 ARGMATCH_VERIFY (backup_args, backup_types);
328
329 /* Return the type of backup specified by VERSION.
330    If VERSION is NULL or the empty string, return numbered_existing_backups.
331    If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
332    for the specified CONTEXT.  Unambiguous abbreviations are accepted.  */
333
334 enum backup_type
335 get_version (char const *context, char const *version)
336 {
337   if (version == 0 || *version == 0)
338     return numbered_existing_backups;
339   else
340     return XARGMATCH (context, version, backup_args, backup_types);
341 }
342
343
344 /* Return the type of backup specified by VERSION.
345    If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
346    If the specified string is invalid or ambiguous, fail with a diagnostic
347    appropriate for the specified CONTEXT.
348    Unambiguous abbreviations are accepted.  */
349
350 enum backup_type
351 xget_version (char const *context, char const *version)
352 {
353   if (version && *version)
354     return get_version (context, version);
355   else
356     return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
357 }