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