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