]> git.cworth.org Git - tar/blob - lib/backupfile.c
Imported Upstream version 1.20
[tar] / lib / backupfile.c
1 /* backupfile.c -- make Emacs style backup file names
2
3    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
5    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 results of opendir() in this file are not used with dirfd and fchdir,
84    therefore save some unnecessary work in fchdir.c.  */
85 #undef opendir
86 #undef closedir
87
88 /* The extension added to file names to produce a simple (as opposed
89    to numbered) backup file name. */
90 char const *simple_backup_suffix = "~";
91
92
93 /* If FILE (which was of length FILELEN before an extension was
94    appended to it) is too long, replace the extension with the single
95    char E.  If the result is still too long, remove the char just
96    before E.  */
97
98 static void
99 check_extension (char *file, size_t filelen, char e)
100 {
101   char *base = last_component (file);
102   size_t baselen = base_len (base);
103   size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
104
105   if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
106     {
107       /* The new base name is long enough to require a pathconf check.  */
108       long name_max;
109
110       /* Temporarily modify the buffer into its parent directory name,
111          invoke pathconf on the directory, and then restore the buffer.  */
112       char tmp[sizeof "."];
113       memcpy (tmp, base, sizeof ".");
114       strcpy (base, ".");
115       errno = 0;
116       name_max = pathconf (file, _PC_NAME_MAX);
117       if (0 <= name_max || errno == 0)
118         {
119           long size = baselen_max = name_max;
120           if (name_max != size)
121             baselen_max = SIZE_MAX;
122         }
123       memcpy (base, tmp, sizeof ".");
124     }
125
126   if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
127     {
128       /* Live within DOS's 8.3 limit.  */
129       char *dot = strchr (base, '.');
130       if (!dot)
131         baselen_max = 8;
132       else
133         {
134           char const *second_dot = strchr (dot + 1, '.');
135           baselen_max = (second_dot
136                          ? second_dot - base
137                          : dot + 1 - base + 3);
138         }
139     }
140
141   if (baselen_max < baselen)
142     {
143       baselen = file + filelen - base;
144       if (baselen_max <= baselen)
145         baselen = baselen_max - 1;
146       base[baselen] = e;
147       base[baselen + 1] = '\0';
148     }
149 }
150
151 /* Returned values for NUMBERED_BACKUP.  */
152
153 enum numbered_backup_result
154   {
155     /* The new backup name is the same length as an existing backup
156        name, so it's valid for that directory.  */
157     BACKUP_IS_SAME_LENGTH,
158
159     /* Some backup names already exist, but the returned name is longer
160        than any of them, and its length should be checked.  */
161     BACKUP_IS_LONGER,
162
163     /* There are no existing backup names.  The new name's length
164        should be checked.  */
165     BACKUP_IS_NEW
166   };
167
168 /* *BUFFER contains a file name.  Store into *BUFFER the next backup
169    name for the named file, with a version number greater than all the
170    existing numbered backups.  Reallocate *BUFFER as necessary; its
171    initial allocated size is BUFFER_SIZE, which must be at least 4
172    bytes longer than the file name to make room for the initially
173    appended ".~1".  FILELEN is the length of the original file name.
174    The returned value indicates what kind of backup was found.  If an
175    I/O or other read error occurs, use the highest backup number that
176    was found.  */
177
178 static enum numbered_backup_result
179 numbered_backup (char **buffer, size_t buffer_size, size_t filelen)
180 {
181   enum numbered_backup_result result = BACKUP_IS_NEW;
182   DIR *dirp;
183   struct dirent *dp;
184   char *buf = *buffer;
185   size_t versionlenmax = 1;
186   char *base = last_component (buf);
187   size_t base_offset = base - buf;
188   size_t baselen = base_len (base);
189
190   /* Temporarily modify the buffer into its parent directory name,
191      open the directory, and then restore the buffer.  */
192   char tmp[sizeof "."];
193   memcpy (tmp, base, sizeof ".");
194   strcpy (base, ".");
195   dirp = opendir (buf);
196   memcpy (base, tmp, sizeof ".");
197   strcpy (base + baselen, ".~1~");
198
199   if (!dirp)
200     return result;
201
202   while ((dp = readdir (dirp)) != NULL)
203     {
204       char const *p;
205       char *q;
206       bool all_9s;
207       size_t versionlen;
208       size_t new_buflen;
209
210       if (! REAL_DIR_ENTRY (dp) || _D_EXACT_NAMLEN (dp) < baselen + 4)
211         continue;
212
213       if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
214         continue;
215
216       p = dp->d_name + baselen + 2;
217
218       /* Check whether this file has a version number and if so,
219          whether it is larger.  Use string operations rather than
220          integer arithmetic, to avoid problems with integer overflow.  */
221
222       if (! ('1' <= *p && *p <= '9'))
223         continue;
224       all_9s = (*p == '9');
225       for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
226         all_9s &= (p[versionlen] == '9');
227
228       if (! (p[versionlen] == '~' && !p[versionlen + 1]
229              && (versionlenmax < versionlen
230                  || (versionlenmax == versionlen
231                      && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
232         continue;
233
234       /* This directory has the largest version number seen so far.
235          Append this highest numbered extension to the file name,
236          prepending '0' to the number if it is all 9s.  */
237
238       versionlenmax = all_9s + versionlen;
239       result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
240       new_buflen = filelen + 2 + versionlenmax + 1;
241       if (buffer_size <= new_buflen)
242         {
243           buf = xnrealloc (buf, 2, new_buflen);
244           buffer_size = new_buflen * 2;
245         }
246       q = buf + filelen;
247       *q++ = '.';
248       *q++ = '~';
249       *q = '0';
250       q += all_9s;
251       memcpy (q, p, versionlen + 2);
252
253       /* Add 1 to the version number.  */
254
255       q += versionlen;
256       while (*--q == '9')
257         *q = '0';
258       ++*q;
259     }
260
261   closedir (dirp);
262   *buffer = buf;
263   return result;
264 }
265
266 /* Return the name of the new backup file for the existing file FILE,
267    allocated with malloc.  Report an error and fail if out of memory.
268    Do not call this function if backup_type == no_backups.  */
269
270 char *
271 find_backup_file_name (char const *file, enum backup_type backup_type)
272 {
273   size_t filelen = strlen (file);
274   char *s;
275   size_t ssize;
276   bool simple = true;
277
278   /* Allow room for simple or ".~N~" backups.  The guess must be at
279      least sizeof ".~1~", but otherwise will be adjusted as needed.  */
280   size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
281   size_t backup_suffix_size_guess = simple_backup_suffix_size;
282   enum { GUESS = sizeof ".~12345~" };
283   if (backup_suffix_size_guess < GUESS)
284     backup_suffix_size_guess = GUESS;
285
286   ssize = filelen + backup_suffix_size_guess + 1;
287   s = xmalloc (ssize);
288   memcpy (s, file, filelen + 1);
289
290   if (backup_type != simple_backups)
291     switch (numbered_backup (&s, ssize, filelen))
292       {
293       case BACKUP_IS_SAME_LENGTH:
294         return s;
295
296       case BACKUP_IS_LONGER:
297         simple = false;
298         break;
299
300       case BACKUP_IS_NEW:
301         simple = (backup_type == numbered_existing_backups);
302         break;
303       }
304
305   if (simple)
306     memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
307   check_extension (s, filelen, '~');
308   return s;
309 }
310
311 static char const * const backup_args[] =
312 {
313   /* In a series of synonyms, present the most meaningful first, so
314      that argmatch_valid be more readable. */
315   "none", "off",
316   "simple", "never",
317   "existing", "nil",
318   "numbered", "t",
319   NULL
320 };
321
322 static const enum backup_type backup_types[] =
323 {
324   no_backups, no_backups,
325   simple_backups, simple_backups,
326   numbered_existing_backups, numbered_existing_backups,
327   numbered_backups, numbered_backups
328 };
329
330 /* Ensure that these two vectors have the same number of elements,
331    not counting the final NULL in the first one.  */
332 ARGMATCH_VERIFY (backup_args, backup_types);
333
334 /* Return the type of backup specified by VERSION.
335    If VERSION is NULL or the empty string, return numbered_existing_backups.
336    If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
337    for the specified CONTEXT.  Unambiguous abbreviations are accepted.  */
338
339 enum backup_type
340 get_version (char const *context, char const *version)
341 {
342   if (version == 0 || *version == 0)
343     return numbered_existing_backups;
344   else
345     return XARGMATCH (context, version, backup_args, backup_types);
346 }
347
348
349 /* Return the type of backup specified by VERSION.
350    If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
351    If the specified string is invalid or ambiguous, fail with a diagnostic
352    appropriate for the specified CONTEXT.
353    Unambiguous abbreviations are accepted.  */
354
355 enum backup_type
356 xget_version (char const *context, char const *version)
357 {
358   if (version && *version)
359     return get_version (context, version);
360   else
361     return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
362 }