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 3 of the License, or
10 (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
20 /* Written by Paul Eggert and David MacKenzie.
21 Some algorithms adapted from GNU Emacs. */
25 #include "backupfile.h"
41 #ifndef _D_EXACT_NAMLEN
42 # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
45 # define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
47 # define REAL_DIR_ENTRY(dp) 1
50 #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
51 # define pathconf(file, option) (errno = -1)
54 #ifndef _POSIX_NAME_MAX
55 # define _POSIX_NAME_MAX 14
58 # define SIZE_MAX ((size_t) -1)
61 #if defined _XOPEN_NAME_MAX
62 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
64 # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
67 #ifndef HAVE_DOS_FILE_NAMES
68 # define HAVE_DOS_FILE_NAMES 0
70 #ifndef HAVE_LONG_FILE_NAMES
71 # define HAVE_LONG_FILE_NAMES 0
74 /* ISDIGIT differs from isdigit, as follows:
75 - Its arg may be any int or unsigned int; it need not be an unsigned char
77 - It's typically faster.
78 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
79 ISDIGIT unless it's important to use the locale's definition
80 of `digit' even when the host does not conform to POSIX. */
81 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
83 /* The results of opendir() in this file are not used with dirfd and fchdir,
84 therefore save some unnecessary work in fchdir.c. */
88 /* The extension added to file names to produce a simple (as opposed
89 to numbered) backup file name. */
90 char const *simple_backup_suffix = "~";
93 /* If FILE (which was of length FILELEN before an extension was
94 appended to it) is too long, replace the extension with the single
95 char E. If the result is still too long, remove the char just
99 check_extension (char *file, size_t filelen, char e)
101 char *base = last_component (file);
102 size_t baselen = base_len (base);
103 size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
105 if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
107 /* The new base name is long enough to require a pathconf check. */
110 /* Temporarily modify the buffer into its parent directory name,
111 invoke pathconf on the directory, and then restore the buffer. */
112 char tmp[sizeof "."];
113 memcpy (tmp, base, sizeof ".");
116 name_max = pathconf (file, _PC_NAME_MAX);
117 if (0 <= name_max || errno == 0)
119 long size = baselen_max = name_max;
120 if (name_max != size)
121 baselen_max = SIZE_MAX;
123 memcpy (base, tmp, sizeof ".");
126 if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
128 /* Live within DOS's 8.3 limit. */
129 char *dot = strchr (base, '.');
134 char const *second_dot = strchr (dot + 1, '.');
135 baselen_max = (second_dot
137 : dot + 1 - base + 3);
141 if (baselen_max < baselen)
143 baselen = file + filelen - base;
144 if (baselen_max <= baselen)
145 baselen = baselen_max - 1;
147 base[baselen + 1] = '\0';
151 /* Returned values for NUMBERED_BACKUP. */
153 enum numbered_backup_result
155 /* The new backup name is the same length as an existing backup
156 name, so it's valid for that directory. */
157 BACKUP_IS_SAME_LENGTH,
159 /* Some backup names already exist, but the returned name is longer
160 than any of them, and its length should be checked. */
163 /* There are no existing backup names. The new name's length
164 should be checked. */
168 /* *BUFFER contains a file name. Store into *BUFFER the next backup
169 name for the named file, with a version number greater than all the
170 existing numbered backups. Reallocate *BUFFER as necessary; its
171 initial allocated size is BUFFER_SIZE, which must be at least 4
172 bytes longer than the file name to make room for the initially
173 appended ".~1". FILELEN is the length of the original file name.
174 The returned value indicates what kind of backup was found. If an
175 I/O or other read error occurs, use the highest backup number that
178 static enum numbered_backup_result
179 numbered_backup (char **buffer, size_t buffer_size, size_t filelen)
181 enum numbered_backup_result result = BACKUP_IS_NEW;
185 size_t versionlenmax = 1;
186 char *base = last_component (buf);
187 size_t base_offset = base - buf;
188 size_t baselen = base_len (base);
190 /* Temporarily modify the buffer into its parent directory name,
191 open the directory, and then restore the buffer. */
192 char tmp[sizeof "."];
193 memcpy (tmp, base, sizeof ".");
195 dirp = opendir (buf);
196 memcpy (base, tmp, sizeof ".");
197 strcpy (base + baselen, ".~1~");
202 while ((dp = readdir (dirp)) != NULL)
210 if (! REAL_DIR_ENTRY (dp) || _D_EXACT_NAMLEN (dp) < baselen + 4)
213 if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
216 p = dp->d_name + baselen + 2;
218 /* Check whether this file has a version number and if so,
219 whether it is larger. Use string operations rather than
220 integer arithmetic, to avoid problems with integer overflow. */
222 if (! ('1' <= *p && *p <= '9'))
224 all_9s = (*p == '9');
225 for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
226 all_9s &= (p[versionlen] == '9');
228 if (! (p[versionlen] == '~' && !p[versionlen + 1]
229 && (versionlenmax < versionlen
230 || (versionlenmax == versionlen
231 && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
234 /* This directory has the largest version number seen so far.
235 Append this highest numbered extension to the file name,
236 prepending '0' to the number if it is all 9s. */
238 versionlenmax = all_9s + versionlen;
239 result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
240 new_buflen = filelen + 2 + versionlenmax + 1;
241 if (buffer_size <= new_buflen)
243 buf = xnrealloc (buf, 2, new_buflen);
244 buffer_size = new_buflen * 2;
251 memcpy (q, p, versionlen + 2);
253 /* Add 1 to the version number. */
266 /* Return the name of the new backup file for the existing file FILE,
267 allocated with malloc. Report an error and fail if out of memory.
268 Do not call this function if backup_type == no_backups. */
271 find_backup_file_name (char const *file, enum backup_type backup_type)
273 size_t filelen = strlen (file);
278 /* Allow room for simple or ".~N~" backups. The guess must be at
279 least sizeof ".~1~", but otherwise will be adjusted as needed. */
280 size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
281 size_t backup_suffix_size_guess = simple_backup_suffix_size;
282 enum { GUESS = sizeof ".~12345~" };
283 if (backup_suffix_size_guess < GUESS)
284 backup_suffix_size_guess = GUESS;
286 ssize = filelen + backup_suffix_size_guess + 1;
288 memcpy (s, file, filelen + 1);
290 if (backup_type != simple_backups)
291 switch (numbered_backup (&s, ssize, filelen))
293 case BACKUP_IS_SAME_LENGTH:
296 case BACKUP_IS_LONGER:
301 simple = (backup_type == numbered_existing_backups);
306 memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
307 check_extension (s, filelen, '~');
311 static char const * const backup_args[] =
313 /* In a series of synonyms, present the most meaningful first, so
314 that argmatch_valid be more readable. */
322 static const enum backup_type backup_types[] =
324 no_backups, no_backups,
325 simple_backups, simple_backups,
326 numbered_existing_backups, numbered_existing_backups,
327 numbered_backups, numbered_backups
330 /* Ensure that these two vectors have the same number of elements,
331 not counting the final NULL in the first one. */
332 ARGMATCH_VERIFY (backup_args, backup_types);
334 /* Return the type of backup specified by VERSION.
335 If VERSION is NULL or the empty string, return numbered_existing_backups.
336 If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
337 for the specified CONTEXT. Unambiguous abbreviations are accepted. */
340 get_version (char const *context, char const *version)
342 if (version == 0 || *version == 0)
343 return numbered_existing_backups;
345 return XARGMATCH (context, version, backup_args, backup_types);
349 /* Return the type of backup specified by VERSION.
350 If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
351 If the specified string is invalid or ambiguous, fail with a diagnostic
352 appropriate for the specified CONTEXT.
353 Unambiguous abbreviations are accepted. */
356 xget_version (char const *context, char const *version)
358 if (version && *version)
359 return get_version (context, version);
361 return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));