backupfile: Use idx_t for nonnegative ptrdiff_t variables.
[gnulib.git] / lib / backupfile.c
blobdfc29e84863d16f28ccc3813ca591a7399e903a7
1 /* backupfile.c -- make Emacs style backup file names
3 Copyright (C) 1990-2006, 2009-2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert and David MacKenzie.
19 Some algorithms adapted from GNU Emacs. */
21 #include <config.h>
23 #include "backup-internal.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
33 #include "attribute.h"
34 #include "basename-lgpl.h"
35 #include "idx.h"
36 #include "opendirat.h"
37 #include "renameatu.h"
38 #include "xalloc-oversized.h"
40 #ifndef _D_EXACT_NAMLEN
41 # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
42 #endif
44 #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
45 # define pathconf(file, option) (errno = -1)
46 #endif
48 #ifndef _POSIX_NAME_MAX
49 # define _POSIX_NAME_MAX 14
50 #endif
52 #if defined _XOPEN_NAME_MAX
53 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
54 #else
55 # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
56 #endif
58 #ifndef HAVE_DOS_FILE_NAMES
59 # define HAVE_DOS_FILE_NAMES 0
60 #endif
61 #ifndef HAVE_LONG_FILE_NAMES
62 # define HAVE_LONG_FILE_NAMES 0
63 #endif
65 /* ISDIGIT differs from isdigit, as follows:
66 - Its arg may be any int or unsigned int; it need not be an unsigned char
67 or EOF.
68 - It's typically faster.
69 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
70 ISDIGIT unless it's important to use the locale's definition
71 of "digit" even when the host does not conform to POSIX. */
72 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
74 /* The extension added to file names to produce a simple (as opposed
75 to numbered) backup file name. */
76 char const *simple_backup_suffix = NULL;
78 /* Set SIMPLE_BACKUP_SUFFIX to S, or to a default specified by the
79 environment if S is null. If S or the environment does not specify
80 a valid backup suffix, use "~". */
81 void
82 set_simple_backup_suffix (char const *s)
84 if (!s)
85 s = getenv ("SIMPLE_BACKUP_SUFFIX");
86 simple_backup_suffix = s && *s && s == last_component (s) ? s : "~";
89 /* If FILE (which was of length FILELEN before an extension was
90 appended to it) is too long, replace the extension with the single
91 char E. If the result is still too long, remove the char just
92 before E.
94 If DIR_FD is nonnegative, it is a file descriptor for FILE's parent.
95 *NAME_MAX is either 0, or the cached result of a previous call for
96 FILE's parent's _PC_NAME_MAX. */
98 static void
99 check_extension (char *file, size_t filelen, char e,
100 int dir_fd, size_t *base_max)
102 char *base = last_component (file);
103 size_t baselen = base_len (base);
104 size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
106 if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
108 /* The new base name is long enough to require a pathconf check. */
109 if (*base_max == 0)
111 long name_max;
112 if (dir_fd < 0)
114 /* Temporarily modify the buffer into its parent
115 directory name, invoke pathconf on the directory, and
116 then restore the buffer. */
117 char tmp[sizeof "."];
118 memcpy (tmp, base, sizeof ".");
119 strcpy (base, ".");
120 errno = 0;
121 name_max = pathconf (file, _PC_NAME_MAX);
122 name_max -= !errno;
123 memcpy (base, tmp, sizeof ".");
125 else
127 errno = 0;
128 name_max = fpathconf (dir_fd, _PC_NAME_MAX);
129 name_max -= !errno;
132 *base_max = (0 <= name_max && name_max <= SIZE_MAX ? name_max
133 : name_max < -1 ? NAME_MAX_MINIMUM : SIZE_MAX);
136 baselen_max = *base_max;
139 if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
141 /* Live within DOS's 8.3 limit. */
142 char *dot = strchr (base, '.');
143 if (!dot)
144 baselen_max = 8;
145 else
147 char const *second_dot = strchr (dot + 1, '.');
148 baselen_max = (second_dot
149 ? second_dot - base
150 : dot + 1 - base + 3);
154 if (baselen_max < baselen)
156 baselen = file + filelen - base;
157 if (baselen_max <= baselen)
158 baselen = baselen_max - 1;
159 base[baselen] = e;
160 base[baselen + 1] = '\0';
164 /* Returned values for NUMBERED_BACKUP. */
166 enum numbered_backup_result
168 /* The new backup name is the same length as an existing backup
169 name, so it's valid for that directory. */
170 BACKUP_IS_SAME_LENGTH,
172 /* Some backup names already exist, but the returned name is longer
173 than any of them, and its length should be checked. */
174 BACKUP_IS_LONGER,
176 /* There are no existing backup names. The new name's length
177 should be checked. */
178 BACKUP_IS_NEW,
180 /* Memory allocation failure. */
181 BACKUP_NOMEM
184 /* Relative to DIR_FD, *BUFFER contains a file name.
185 Store into *BUFFER the next backup name for the named file,
186 with a version number greater than all the
187 existing numbered backups. Reallocate *BUFFER as necessary; its
188 initial allocated size is BUFFER_SIZE, which must be at least 4
189 bytes longer than the file name to make room for the initially
190 appended ".~1". FILELEN is the length of the original file name.
191 BASE_OFFSET is the offset of the basename in *BUFFER.
192 The returned value indicates what kind of backup was found. If an
193 I/O or other read error occurs, use the highest backup number that
194 was found.
196 *DIRPP is the destination directory. If *DIRPP is null, open the
197 destination directory and store the resulting stream into *DIRPP
198 and its file descriptor into *PNEW_FD without closing the stream. */
200 static enum numbered_backup_result
201 numbered_backup (int dir_fd, char **buffer, size_t buffer_size, size_t filelen,
202 idx_t base_offset, DIR **dirpp, int *pnew_fd)
204 enum numbered_backup_result result = BACKUP_IS_NEW;
205 DIR *dirp = *dirpp;
206 struct dirent *dp;
207 char *buf = *buffer;
208 size_t versionlenmax = 1;
209 char *base = buf + base_offset;
210 size_t baselen = base_len (base);
212 if (dirp)
213 rewinddir (dirp);
214 else
216 /* Temporarily modify the buffer into its parent directory name,
217 open the directory, and then restore the buffer. */
218 char tmp[sizeof "."];
219 memcpy (tmp, base, sizeof ".");
220 strcpy (base, ".");
221 dirp = opendirat (dir_fd, buf, 0, pnew_fd);
222 if (!dirp && errno == ENOMEM)
223 result = BACKUP_NOMEM;
224 memcpy (base, tmp, sizeof ".");
225 strcpy (base + baselen, ".~1~");
226 if (!dirp)
227 return result;
228 *dirpp = dirp;
231 while ((dp = readdir (dirp)) != NULL)
233 char const *p;
234 char *q;
235 bool all_9s;
236 size_t versionlen;
238 if (_D_EXACT_NAMLEN (dp) < baselen + 4)
239 continue;
241 if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
242 continue;
244 p = dp->d_name + baselen + 2;
246 /* Check whether this file has a version number and if so,
247 whether it is larger. Use string operations rather than
248 integer arithmetic, to avoid problems with integer overflow. */
250 if (! ('1' <= *p && *p <= '9'))
251 continue;
252 all_9s = (*p == '9');
253 for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
254 all_9s &= (p[versionlen] == '9');
256 if (! (p[versionlen] == '~' && !p[versionlen + 1]
257 && (versionlenmax < versionlen
258 || (versionlenmax == versionlen
259 && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
260 continue;
262 /* This entry has the largest version number seen so far.
263 Append this highest numbered extension to the file name,
264 prepending '0' to the number if it is all 9s. */
266 versionlenmax = all_9s + versionlen;
267 result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
268 size_t new_buffer_size = filelen + 2 + versionlenmax + 2;
269 if (buffer_size < new_buffer_size)
271 if (! xalloc_oversized (new_buffer_size, 2))
272 new_buffer_size *= 2;
273 char *new_buf = realloc (buf, new_buffer_size);
274 if (!new_buf)
276 *buffer = buf;
277 return BACKUP_NOMEM;
279 buf = new_buf;
280 buffer_size = new_buffer_size;
282 q = buf + filelen;
283 *q++ = '.';
284 *q++ = '~';
285 *q = '0';
286 q += all_9s;
287 memcpy (q, p, versionlen + 2);
289 /* Add 1 to the version number. */
291 q += versionlen;
292 while (*--q == '9')
293 *q = '0';
294 ++*q;
297 *buffer = buf;
298 return result;
301 /* Relative to DIR_FD, return the name of the new backup file for the
302 existing file FILE, allocated with malloc.
303 If RENAME, also rename FILE to the new name.
304 On failure, return NULL and set errno.
305 Do not call this function if backup_type == no_backups. */
307 char *
308 backupfile_internal (int dir_fd, char const *file,
309 enum backup_type backup_type, bool rename)
311 idx_t base_offset = last_component (file) - file;
312 size_t filelen = base_offset + strlen (file + base_offset);
314 if (! simple_backup_suffix)
315 set_simple_backup_suffix (NULL);
317 /* Allow room for simple or ".~N~" backups. The guess must be at
318 least sizeof ".~1~", but otherwise will be adjusted as needed. */
319 size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
320 size_t backup_suffix_size_guess = simple_backup_suffix_size;
321 enum { GUESS = sizeof ".~12345~" };
322 if (backup_suffix_size_guess < GUESS)
323 backup_suffix_size_guess = GUESS;
325 ssize_t ssize = filelen + backup_suffix_size_guess + 1;
326 char *s = malloc (ssize);
327 if (!s)
328 return s;
330 DIR *dirp = NULL;
331 int sdir = -1;
332 size_t base_max = 0;
333 while (true)
335 memcpy (s, file, filelen + 1);
337 if (backup_type == simple_backups)
338 memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
339 else
340 switch (numbered_backup (dir_fd, &s, ssize, filelen, base_offset,
341 &dirp, &sdir))
343 case BACKUP_IS_SAME_LENGTH:
344 break;
346 case BACKUP_IS_NEW:
347 if (backup_type == numbered_existing_backups)
349 backup_type = simple_backups;
350 memcpy (s + filelen, simple_backup_suffix,
351 simple_backup_suffix_size);
353 FALLTHROUGH;
354 case BACKUP_IS_LONGER:
355 check_extension (s, filelen, '~', sdir, &base_max);
356 break;
358 case BACKUP_NOMEM:
359 if (dirp)
360 closedir (dirp);
361 free (s);
362 errno = ENOMEM;
363 return NULL;
366 if (! rename)
367 break;
369 if (sdir < 0)
371 sdir = AT_FDCWD;
372 base_offset = 0;
374 unsigned flags = backup_type == simple_backups ? 0 : RENAME_NOREPLACE;
375 if (renameatu (AT_FDCWD, file, sdir, s + base_offset, flags) == 0)
376 break;
377 int e = errno;
378 if (e != EEXIST)
380 if (dirp)
381 closedir (dirp);
382 free (s);
383 errno = e;
384 return NULL;
388 if (dirp)
389 closedir (dirp);
390 return s;