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