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