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