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