1 /* backupfile.c -- make Emacs style backup file names
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
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)
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.
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. */
22 /* Written by Paul Eggert and David MacKenzie.
23 Some algorithms adapted from GNU Emacs. */
27 #include "backupfile.h"
43 #ifndef _D_EXACT_NAMLEN
44 # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
47 # define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
49 # define REAL_DIR_ENTRY(dp) 1
52 #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
53 # define pathconf(file, option) (errno = -1)
56 #ifndef _POSIX_NAME_MAX
57 # define _POSIX_NAME_MAX 14
60 # define SIZE_MAX ((size_t) -1)
63 #if defined _XOPEN_NAME_MAX
64 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
66 # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
69 #ifndef HAVE_DOS_FILE_NAMES
70 # define HAVE_DOS_FILE_NAMES 0
72 #ifndef HAVE_LONG_FILE_NAMES
73 # define HAVE_LONG_FILE_NAMES 0
76 /* ISDIGIT differs from isdigit, as follows:
77 - Its arg may be any int or unsigned int; it need not be an unsigned char
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)
85 /* The results of opendir() in this file are not used with dirfd and fchdir,
86 therefore save some unnecessary work in fchdir.c. */
90 /* The extension added to file names to produce a simple (as opposed
91 to numbered) backup file name. */
92 char const *simple_backup_suffix = "~";
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
101 check_extension (char *file, size_t filelen, char e)
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;
107 if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
109 /* The new base name is long enough to require a pathconf check. */
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 ".");
118 name_max = pathconf (file, _PC_NAME_MAX);
119 if (0 <= name_max || errno == 0)
121 long size = baselen_max = name_max;
122 if (name_max != size)
123 baselen_max = SIZE_MAX;
125 memcpy (base, tmp, sizeof ".");
128 if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
130 /* Live within DOS's 8.3 limit. */
131 char *dot = strchr (base, '.');
136 char const *second_dot = strchr (dot + 1, '.');
137 baselen_max = (second_dot
139 : dot + 1 - base + 3);
143 if (baselen_max < baselen)
145 baselen = file + filelen - base;
146 if (baselen_max <= baselen)
147 baselen = baselen_max - 1;
149 base[baselen + 1] = '\0';
153 /* Returned values for NUMBERED_BACKUP. */
155 enum numbered_backup_result
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,
161 /* Some backup names already exist, but the returned name is longer
162 than any of them, and its length should be checked. */
165 /* There are no existing backup names. The new name's length
166 should be checked. */
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
180 static enum numbered_backup_result
181 numbered_backup (char **buffer, size_t buffer_size, size_t filelen)
183 enum numbered_backup_result result = BACKUP_IS_NEW;
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);
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 ".");
197 dirp = opendir (buf);
198 memcpy (base, tmp, sizeof ".");
199 strcpy (base + baselen, ".~1~");
204 while ((dp = readdir (dirp)) != NULL)
212 if (! REAL_DIR_ENTRY (dp) || _D_EXACT_NAMLEN (dp) < baselen + 4)
215 if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
218 p = dp->d_name + baselen + 2;
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. */
224 if (! ('1' <= *p && *p <= '9'))
226 all_9s = (*p == '9');
227 for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
228 all_9s &= (p[versionlen] == '9');
230 if (! (p[versionlen] == '~' && !p[versionlen + 1]
231 && (versionlenmax < versionlen
232 || (versionlenmax == versionlen
233 && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
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. */
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)
245 buf = xnrealloc (buf, 2, new_buflen);
246 buffer_size = new_buflen * 2;
253 memcpy (q, p, versionlen + 2);
255 /* Add 1 to the version number. */
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. */
273 find_backup_file_name (char const *file, enum backup_type backup_type)
275 size_t filelen = strlen (file);
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;
288 ssize = filelen + backup_suffix_size_guess + 1;
290 memcpy (s, file, filelen + 1);
292 if (backup_type != simple_backups)
293 switch (numbered_backup (&s, ssize, filelen))
295 case BACKUP_IS_SAME_LENGTH:
298 case BACKUP_IS_LONGER:
303 simple = (backup_type == numbered_existing_backups);
308 memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
309 check_extension (s, filelen, '~');
313 static char const * const backup_args[] =
315 /* In a series of synonyms, present the most meaningful first, so
316 that argmatch_valid be more readable. */
324 static const enum backup_type backup_types[] =
326 no_backups, no_backups,
327 simple_backups, simple_backups,
328 numbered_existing_backups, numbered_existing_backups,
329 numbered_backups, numbered_backups
332 /* Ensure that these two vectors have the same number of elements,
333 not counting the final NULL in the first one. */
334 ARGMATCH_VERIFY (backup_args, backup_types);
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. */
342 get_version (char const *context, char const *version)
344 if (version == 0 || *version == 0)
345 return numbered_existing_backups;
347 return XARGMATCH (context, version, backup_args, backup_types);
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. */
358 xget_version (char const *context, char const *version)
360 if (version && *version)
361 return get_version (context, version);
363 return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));