Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/backupfile.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* backupfile.c -- make Emacs style backup file names | - | ||||||||||||||||||
2 | - | |||||||||||||||||||
3 | Copyright (C) 1990-2006, 2009-2018 Free Software Foundation, Inc. | - | ||||||||||||||||||
4 | - | |||||||||||||||||||
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. | - | ||||||||||||||||||
9 | - | |||||||||||||||||||
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. | - | ||||||||||||||||||
14 | - | |||||||||||||||||||
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/>. */ | - | ||||||||||||||||||
17 | - | |||||||||||||||||||
18 | /* Written by Paul Eggert and David MacKenzie. | - | ||||||||||||||||||
19 | Some algorithms adapted from GNU Emacs. */ | - | ||||||||||||||||||
20 | - | |||||||||||||||||||
21 | #include <config.h> | - | ||||||||||||||||||
22 | - | |||||||||||||||||||
23 | #include "backup-internal.h" | - | ||||||||||||||||||
24 | - | |||||||||||||||||||
25 | #include "dirname.h" | - | ||||||||||||||||||
26 | #include "renameat2.h" | - | ||||||||||||||||||
27 | #include "xalloc-oversized.h" | - | ||||||||||||||||||
28 | - | |||||||||||||||||||
29 | #include <fcntl.h> | - | ||||||||||||||||||
30 | #include <errno.h> | - | ||||||||||||||||||
31 | #include <stdbool.h> | - | ||||||||||||||||||
32 | #include <stdlib.h> | - | ||||||||||||||||||
33 | #include <string.h> | - | ||||||||||||||||||
34 | - | |||||||||||||||||||
35 | #include <limits.h> | - | ||||||||||||||||||
36 | - | |||||||||||||||||||
37 | #include <unistd.h> | - | ||||||||||||||||||
38 | - | |||||||||||||||||||
39 | #include "dirent--.h" | - | ||||||||||||||||||
40 | #ifndef _D_EXACT_NAMLEN | - | ||||||||||||||||||
41 | # define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name) | - | ||||||||||||||||||
42 | #endif | - | ||||||||||||||||||
43 | - | |||||||||||||||||||
44 | #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX) | - | ||||||||||||||||||
45 | # define pathconf(file, option) (errno = -1) | - | ||||||||||||||||||
46 | #endif | - | ||||||||||||||||||
47 | - | |||||||||||||||||||
48 | #ifndef _POSIX_NAME_MAX | - | ||||||||||||||||||
49 | # define _POSIX_NAME_MAX 14 | - | ||||||||||||||||||
50 | #endif | - | ||||||||||||||||||
51 | #ifndef SIZE_MAX | - | ||||||||||||||||||
52 | # define SIZE_MAX ((size_t) -1) | - | ||||||||||||||||||
53 | #endif | - | ||||||||||||||||||
54 | - | |||||||||||||||||||
55 | #if defined _XOPEN_NAME_MAX | - | ||||||||||||||||||
56 | # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX | - | ||||||||||||||||||
57 | #else | - | ||||||||||||||||||
58 | # define NAME_MAX_MINIMUM _POSIX_NAME_MAX | - | ||||||||||||||||||
59 | #endif | - | ||||||||||||||||||
60 | - | |||||||||||||||||||
61 | #ifndef HAVE_DOS_FILE_NAMES | - | ||||||||||||||||||
62 | # define HAVE_DOS_FILE_NAMES 0 | - | ||||||||||||||||||
63 | #endif | - | ||||||||||||||||||
64 | #ifndef HAVE_LONG_FILE_NAMES | - | ||||||||||||||||||
65 | # define HAVE_LONG_FILE_NAMES 0 | - | ||||||||||||||||||
66 | #endif | - | ||||||||||||||||||
67 | - | |||||||||||||||||||
68 | /* ISDIGIT differs from isdigit, as follows: | - | ||||||||||||||||||
69 | - Its arg may be any int or unsigned int; it need not be an unsigned char | - | ||||||||||||||||||
70 | or EOF. | - | ||||||||||||||||||
71 | - It's typically faster. | - | ||||||||||||||||||
72 | POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to | - | ||||||||||||||||||
73 | ISDIGIT unless it's important to use the locale's definition | - | ||||||||||||||||||
74 | of "digit" even when the host does not conform to POSIX. */ | - | ||||||||||||||||||
75 | #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) | - | ||||||||||||||||||
76 | - | |||||||||||||||||||
77 | /* The extension added to file names to produce a simple (as opposed | - | ||||||||||||||||||
78 | to numbered) backup file name. */ | - | ||||||||||||||||||
79 | char const *simple_backup_suffix = NULL; | - | ||||||||||||||||||
80 | - | |||||||||||||||||||
81 | /* Set SIMPLE_BACKUP_SUFFIX to S, or to a default specified by the | - | ||||||||||||||||||
82 | environment if S is null. If S or the environment does not specify | - | ||||||||||||||||||
83 | a valid backup suffix, use "~". */ | - | ||||||||||||||||||
84 | void | - | ||||||||||||||||||
85 | set_simple_backup_suffix (char const *s) | - | ||||||||||||||||||
86 | { | - | ||||||||||||||||||
87 | if (!s)
| 6-2119 | ||||||||||||||||||
88 | s = getenv ("SIMPLE_BACKUP_SUFFIX"); executed 2119 times by 4 tests: s = getenv ("SIMPLE_BACKUP_SUFFIX"); Executed by:
| 2119 | ||||||||||||||||||
89 | simple_backup_suffix = s && *s && s == last_component (s) ? s : "~";
| 0-2119 | ||||||||||||||||||
90 | } executed 2125 times by 4 tests: end of block Executed by:
| 2125 | ||||||||||||||||||
91 | - | |||||||||||||||||||
92 | /* If FILE (which was of length FILELEN before an extension was | - | ||||||||||||||||||
93 | appended to it) is too long, replace the extension with the single | - | ||||||||||||||||||
94 | char E. If the result is still too long, remove the char just | - | ||||||||||||||||||
95 | before E. */ | - | ||||||||||||||||||
96 | - | |||||||||||||||||||
97 | static void | - | ||||||||||||||||||
98 | check_extension (char *file, size_t filelen, char e) | - | ||||||||||||||||||
99 | { | - | ||||||||||||||||||
100 | char *base = last_component (file); | - | ||||||||||||||||||
101 | size_t baselen = base_len (base); | - | ||||||||||||||||||
102 | size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM; dead code: 14 | - | ||||||||||||||||||
103 | - | |||||||||||||||||||
104 | if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
| 0-62 | ||||||||||||||||||
105 | { | - | ||||||||||||||||||
106 | /* The new base name is long enough to require a pathconf check. */ | - | ||||||||||||||||||
107 | long name_max; | - | ||||||||||||||||||
108 | - | |||||||||||||||||||
109 | /* Temporarily modify the buffer into its parent directory name, | - | ||||||||||||||||||
110 | invoke pathconf on the directory, and then restore the buffer. */ | - | ||||||||||||||||||
111 | char tmp[sizeof "."]; | - | ||||||||||||||||||
112 | memcpy (tmp, base, sizeof "."); | - | ||||||||||||||||||
113 | strcpy (base, "."); | - | ||||||||||||||||||
114 | errno = 0; | - | ||||||||||||||||||
115 | name_max = pathconf (file, _PC_NAME_MAX); | - | ||||||||||||||||||
116 | if (0 <= name_max || errno == 0)
| 0 | ||||||||||||||||||
117 | { | - | ||||||||||||||||||
118 | long size = baselen_max = name_max; | - | ||||||||||||||||||
119 | if (name_max != size)
| 0 | ||||||||||||||||||
120 | baselen_max = SIZE_MAX; never executed: baselen_max = (18446744073709551615UL) ; | 0 | ||||||||||||||||||
121 | } never executed: end of block | 0 | ||||||||||||||||||
122 | memcpy (base, tmp, sizeof "."); | - | ||||||||||||||||||
123 | } never executed: end of block | 0 | ||||||||||||||||||
124 | - | |||||||||||||||||||
125 | if (HAVE_DOS_FILE_NAMES && baselen_max <= 12) dead code: baselen_max <= 12 dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
126 | { dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
127 | /* Live within DOS's 8.3 limit. */ dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
128 | char *dot = strchr (base, '.'); dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
129 | if (!dot) dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
130 | baselen_max = 8; dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
131 | else dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
132 | { dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
133 | char const *second_dot = strchr (dot + 1, '.'); dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
134 | baselen_max = (second_dot dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
135 | ? second_dot - base dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
136 | : dot + 1 - base + 3); dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
137 | } dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
138 | } dead code: { char *dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( base ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( base , '.' ) : __builtin_strchr ( base , '.' ))) ; if (!dot) baselen_max = 8; else { char const *second_dot = (__extension__ (__builtin_constant_p ( '.' ) && !__builtin_constant_p ( dot + 1 ) && ( '.' ) == '\0' ? (char *) __rawmemchr ( dot + 1 , '.' ) : __builtin_strchr ( dot + 1 , '.' ))) ; baselen_max = (second_dot ? second_dot - base : dot + 1 - base + 3); } } | - | ||||||||||||||||||
139 | - | |||||||||||||||||||
140 | if (baselen_max < baselen)
| 0-62 | ||||||||||||||||||
141 | { | - | ||||||||||||||||||
142 | baselen = file + filelen - base; | - | ||||||||||||||||||
143 | if (baselen_max <= baselen)
| 0 | ||||||||||||||||||
144 | baselen = baselen_max - 1; never executed: baselen = baselen_max - 1; | 0 | ||||||||||||||||||
145 | base[baselen] = e; | - | ||||||||||||||||||
146 | base[baselen + 1] = '\0'; | - | ||||||||||||||||||
147 | } never executed: end of block | 0 | ||||||||||||||||||
148 | } executed 62 times by 2 tests: end of block Executed by:
| 62 | ||||||||||||||||||
149 | - | |||||||||||||||||||
150 | /* Returned values for NUMBERED_BACKUP. */ | - | ||||||||||||||||||
151 | - | |||||||||||||||||||
152 | enum numbered_backup_result | - | ||||||||||||||||||
153 | { | - | ||||||||||||||||||
154 | /* The new backup name is the same length as an existing backup | - | ||||||||||||||||||
155 | name, so it's valid for that directory. */ | - | ||||||||||||||||||
156 | BACKUP_IS_SAME_LENGTH, | - | ||||||||||||||||||
157 | - | |||||||||||||||||||
158 | /* Some backup names already exist, but the returned name is longer | - | ||||||||||||||||||
159 | than any of them, and its length should be checked. */ | - | ||||||||||||||||||
160 | BACKUP_IS_LONGER, | - | ||||||||||||||||||
161 | - | |||||||||||||||||||
162 | /* There are no existing backup names. The new name's length | - | ||||||||||||||||||
163 | should be checked. */ | - | ||||||||||||||||||
164 | BACKUP_IS_NEW, | - | ||||||||||||||||||
165 | - | |||||||||||||||||||
166 | /* Memory allocation failure. */ | - | ||||||||||||||||||
167 | BACKUP_NOMEM | - | ||||||||||||||||||
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 | BASE_OFFSET is the offset of the basename in *BUFFER. | - | ||||||||||||||||||
177 | The returned value indicates what kind of backup was found. If an | - | ||||||||||||||||||
178 | I/O or other read error occurs, use the highest backup number that | - | ||||||||||||||||||
179 | was found. | - | ||||||||||||||||||
180 | - | |||||||||||||||||||
181 | *DIRPP is the destination directory. If *DIRPP is null, open the | - | ||||||||||||||||||
182 | destination directory and store the resulting stream into *DIRPP | - | ||||||||||||||||||
183 | without closing the stream. */ | - | ||||||||||||||||||
184 | - | |||||||||||||||||||
185 | static enum numbered_backup_result | - | ||||||||||||||||||
186 | numbered_backup (char **buffer, size_t buffer_size, size_t filelen, | - | ||||||||||||||||||
187 | ptrdiff_t base_offset, DIR **dirpp) | - | ||||||||||||||||||
188 | { | - | ||||||||||||||||||
189 | enum numbered_backup_result result = BACKUP_IS_NEW; | - | ||||||||||||||||||
190 | DIR *dirp = *dirpp; | - | ||||||||||||||||||
191 | struct dirent *dp; | - | ||||||||||||||||||
192 | char *buf = *buffer; | - | ||||||||||||||||||
193 | size_t versionlenmax = 1; | - | ||||||||||||||||||
194 | char *base = buf + base_offset; | - | ||||||||||||||||||
195 | size_t baselen = base_len (base); | - | ||||||||||||||||||
196 | - | |||||||||||||||||||
197 | if (dirp)
| 0-78 | ||||||||||||||||||
198 | rewinddir (dirp); never executed: rewinddir (dirp); | 0 | ||||||||||||||||||
199 | else | - | ||||||||||||||||||
200 | { | - | ||||||||||||||||||
201 | /* Temporarily modify the buffer into its parent directory name, | - | ||||||||||||||||||
202 | open the directory, and then restore the buffer. */ | - | ||||||||||||||||||
203 | char tmp[sizeof "."]; | - | ||||||||||||||||||
204 | memcpy (tmp, base, sizeof "."); | - | ||||||||||||||||||
205 | strcpy (base, "."); | - | ||||||||||||||||||
206 | dirp = opendir (buf); | - | ||||||||||||||||||
207 | if (!dirp && errno == ENOMEM)
| 0-78 | ||||||||||||||||||
208 | result = BACKUP_NOMEM; never executed: result = BACKUP_NOMEM; | 0 | ||||||||||||||||||
209 | memcpy (base, tmp, sizeof "."); | - | ||||||||||||||||||
210 | strcpy (base + baselen, ".~1~"); | - | ||||||||||||||||||
211 | if (!dirp)
| 0-78 | ||||||||||||||||||
212 | return result; never executed: return result; | 0 | ||||||||||||||||||
213 | *dirpp = dirp; | - | ||||||||||||||||||
214 | } executed 78 times by 2 tests: end of block Executed by:
| 78 | ||||||||||||||||||
215 | - | |||||||||||||||||||
216 | while ((dp = readdir (dirp)) != NULL)
| 78-413 | ||||||||||||||||||
217 | { | - | ||||||||||||||||||
218 | char const *p; | - | ||||||||||||||||||
219 | char *q; | - | ||||||||||||||||||
220 | bool all_9s; | - | ||||||||||||||||||
221 | size_t versionlen; | - | ||||||||||||||||||
222 | - | |||||||||||||||||||
223 | if (_D_EXACT_NAMLEN (dp) < baselen + 4)
| 50-363 | ||||||||||||||||||
224 | continue; executed 363 times by 2 tests: continue; Executed by:
| 363 | ||||||||||||||||||
225 | - | |||||||||||||||||||
226 | if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
| 16-34 | ||||||||||||||||||
227 | continue; executed 34 times by 2 tests: continue; Executed by:
| 34 | ||||||||||||||||||
228 | - | |||||||||||||||||||
229 | p = dp->d_name + baselen + 2; | - | ||||||||||||||||||
230 | - | |||||||||||||||||||
231 | /* Check whether this file has a version number and if so, | - | ||||||||||||||||||
232 | whether it is larger. Use string operations rather than | - | ||||||||||||||||||
233 | integer arithmetic, to avoid problems with integer overflow. */ | - | ||||||||||||||||||
234 | - | |||||||||||||||||||
235 | if (! ('1' <= *p && *p <= '9'))
| 0-16 | ||||||||||||||||||
236 | continue; never executed: continue; | 0 | ||||||||||||||||||
237 | all_9s = (*p == '9'); | - | ||||||||||||||||||
238 | for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
| 0-16 | ||||||||||||||||||
239 | all_9s &= (p[versionlen] == '9'); never executed: all_9s &= (p[versionlen] == '9'); | 0 | ||||||||||||||||||
240 | - | |||||||||||||||||||
241 | if (! (p[versionlen] == '~' && !p[versionlen + 1]
| 0-16 | ||||||||||||||||||
242 | && (versionlenmax < versionlen
| 0-16 | ||||||||||||||||||
243 | || (versionlenmax == versionlen
| 0-16 | ||||||||||||||||||
244 | && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
| 0-16 | ||||||||||||||||||
245 | continue; never executed: continue; | 0 | ||||||||||||||||||
246 | - | |||||||||||||||||||
247 | /* This entry has the largest version number seen so far. | - | ||||||||||||||||||
248 | Append this highest numbered extension to the file name, | - | ||||||||||||||||||
249 | prepending '0' to the number if it is all 9s. */ | - | ||||||||||||||||||
250 | - | |||||||||||||||||||
251 | versionlenmax = all_9s + versionlen; | - | ||||||||||||||||||
252 | result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
| 0-16 | ||||||||||||||||||
253 | size_t new_buffer_size = filelen + 2 + versionlenmax + 2; | - | ||||||||||||||||||
254 | if (buffer_size < new_buffer_size)
| 0-16 | ||||||||||||||||||
255 | { | - | ||||||||||||||||||
256 | if (! xalloc_oversized (new_buffer_size, 2))
| 0 | ||||||||||||||||||
257 | new_buffer_size *= 2; never executed: new_buffer_size *= 2; | 0 | ||||||||||||||||||
258 | char *new_buf = realloc (buf, new_buffer_size); | - | ||||||||||||||||||
259 | if (!new_buf)
| 0 | ||||||||||||||||||
260 | { | - | ||||||||||||||||||
261 | *buffer = buf; | - | ||||||||||||||||||
262 | return BACKUP_NOMEM; never executed: return BACKUP_NOMEM; | 0 | ||||||||||||||||||
263 | } | - | ||||||||||||||||||
264 | buf = new_buf; | - | ||||||||||||||||||
265 | buffer_size = new_buffer_size; | - | ||||||||||||||||||
266 | } never executed: end of block | 0 | ||||||||||||||||||
267 | q = buf + filelen; | - | ||||||||||||||||||
268 | *q++ = '.'; | - | ||||||||||||||||||
269 | *q++ = '~'; | - | ||||||||||||||||||
270 | *q = '0'; | - | ||||||||||||||||||
271 | q += all_9s; | - | ||||||||||||||||||
272 | memcpy (q, p, versionlen + 2); | - | ||||||||||||||||||
273 | - | |||||||||||||||||||
274 | /* Add 1 to the version number. */ | - | ||||||||||||||||||
275 | - | |||||||||||||||||||
276 | q += versionlen; | - | ||||||||||||||||||
277 | while (*--q == '9')
| 0-16 | ||||||||||||||||||
278 | *q = '0'; never executed: *q = '0'; | 0 | ||||||||||||||||||
279 | ++*q; | - | ||||||||||||||||||
280 | } executed 16 times by 2 tests: end of block Executed by:
| 16 | ||||||||||||||||||
281 | - | |||||||||||||||||||
282 | *buffer = buf; | - | ||||||||||||||||||
283 | return result; executed 78 times by 2 tests: return result; Executed by:
| 78 | ||||||||||||||||||
284 | } | - | ||||||||||||||||||
285 | - | |||||||||||||||||||
286 | /* Return the name of the new backup file for the existing file FILE, | - | ||||||||||||||||||
287 | allocated with malloc. If RENAME, also rename FILE to the new name. | - | ||||||||||||||||||
288 | On failure, return NULL and set errno. | - | ||||||||||||||||||
289 | Do not call this function if backup_type == no_backups. */ | - | ||||||||||||||||||
290 | - | |||||||||||||||||||
291 | char * | - | ||||||||||||||||||
292 | backupfile_internal (char const *file, enum backup_type backup_type, bool rename) | - | ||||||||||||||||||
293 | { | - | ||||||||||||||||||
294 | ptrdiff_t base_offset = last_component (file) - file; | - | ||||||||||||||||||
295 | size_t filelen = base_offset + strlen (file + base_offset); | - | ||||||||||||||||||
296 | - | |||||||||||||||||||
297 | if (! simple_backup_suffix)
| 0-103 | ||||||||||||||||||
298 | set_simple_backup_suffix (NULL); never executed: set_simple_backup_suffix ( ((void *)0) ); | 0 | ||||||||||||||||||
299 | - | |||||||||||||||||||
300 | /* Allow room for simple or ".~N~" backups. The guess must be at | - | ||||||||||||||||||
301 | least sizeof ".~1~", but otherwise will be adjusted as needed. */ | - | ||||||||||||||||||
302 | size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1; | - | ||||||||||||||||||
303 | size_t backup_suffix_size_guess = simple_backup_suffix_size; | - | ||||||||||||||||||
304 | enum { GUESS = sizeof ".~12345~" }; | - | ||||||||||||||||||
305 | if (backup_suffix_size_guess < GUESS)
| 0-103 | ||||||||||||||||||
306 | backup_suffix_size_guess = GUESS; executed 103 times by 4 tests: backup_suffix_size_guess = GUESS; Executed by:
| 103 | ||||||||||||||||||
307 | - | |||||||||||||||||||
308 | ssize_t ssize = filelen + backup_suffix_size_guess + 1; | - | ||||||||||||||||||
309 | char *s = malloc (ssize); | - | ||||||||||||||||||
310 | if (!s)
| 0-103 | ||||||||||||||||||
311 | return s; never executed: return s; | 0 | ||||||||||||||||||
312 | - | |||||||||||||||||||
313 | DIR *dirp = NULL; | - | ||||||||||||||||||
314 | while (true) | - | ||||||||||||||||||
315 | { | - | ||||||||||||||||||
316 | memcpy (s, file, filelen + 1); | - | ||||||||||||||||||
317 | - | |||||||||||||||||||
318 | if (backup_type == simple_backups)
| 25-78 | ||||||||||||||||||
319 | memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size); executed 25 times by 4 tests: memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size); Executed by:
| 25 | ||||||||||||||||||
320 | else | - | ||||||||||||||||||
321 | switch (numbered_backup (&s, ssize, filelen, base_offset, &dirp)) | - | ||||||||||||||||||
322 | { | - | ||||||||||||||||||
323 | case BACKUP_IS_SAME_LENGTH: executed 16 times by 2 tests: case BACKUP_IS_SAME_LENGTH: Executed by:
| 16 | ||||||||||||||||||
324 | break; executed 16 times by 2 tests: break; Executed by:
| 16 | ||||||||||||||||||
325 | - | |||||||||||||||||||
326 | case BACKUP_IS_NEW: executed 62 times by 2 tests: case BACKUP_IS_NEW: Executed by:
| 62 | ||||||||||||||||||
327 | if (backup_type == numbered_existing_backups)
| 21-41 | ||||||||||||||||||
328 | { | - | ||||||||||||||||||
329 | backup_type = simple_backups; | - | ||||||||||||||||||
330 | memcpy (s + filelen, simple_backup_suffix, | - | ||||||||||||||||||
331 | simple_backup_suffix_size); | - | ||||||||||||||||||
332 | } executed 21 times by 2 tests: end of block Executed by:
| 21 | ||||||||||||||||||
333 | check_extension (s, filelen, '~'); | - | ||||||||||||||||||
334 | break; executed 62 times by 2 tests: break; Executed by:
| 62 | ||||||||||||||||||
335 | - | |||||||||||||||||||
336 | case BACKUP_IS_LONGER: never executed: case BACKUP_IS_LONGER: | 0 | ||||||||||||||||||
337 | check_extension (s, filelen, '~'); | - | ||||||||||||||||||
338 | break; never executed: break; | 0 | ||||||||||||||||||
339 | - | |||||||||||||||||||
340 | case BACKUP_NOMEM: never executed: case BACKUP_NOMEM: | 0 | ||||||||||||||||||
341 | free (s); | - | ||||||||||||||||||
342 | errno = ENOMEM; | - | ||||||||||||||||||
343 | return NULL; never executed: return ((void *)0) ; | 0 | ||||||||||||||||||
344 | } never executed: end of block | 0 | ||||||||||||||||||
345 | - | |||||||||||||||||||
346 | if (! rename)
| 9-94 | ||||||||||||||||||
347 | break; executed 9 times by 2 tests: break; Executed by:
| 9 | ||||||||||||||||||
348 | - | |||||||||||||||||||
349 | int sdir = dirp ? dirfd (dirp) : -1;
| 20-74 | ||||||||||||||||||
350 | if (sdir < 0)
| 20-74 | ||||||||||||||||||
351 | { | - | ||||||||||||||||||
352 | sdir = AT_FDCWD; | - | ||||||||||||||||||
353 | base_offset = 0; | - | ||||||||||||||||||
354 | } executed 20 times by 3 tests: end of block Executed by:
| 20 | ||||||||||||||||||
355 | unsigned flags = backup_type == simple_backups ? 0 : RENAME_NOREPLACE;
| 41-53 | ||||||||||||||||||
356 | if (renameat2 (AT_FDCWD, file, sdir, s + base_offset, flags) == 0)
| 0-94 | ||||||||||||||||||
357 | break; executed 94 times by 3 tests: break; Executed by:
| 94 | ||||||||||||||||||
358 | int e = errno; | - | ||||||||||||||||||
359 | if (e != EEXIST)
| 0 | ||||||||||||||||||
360 | { | - | ||||||||||||||||||
361 | if (dirp)
| 0 | ||||||||||||||||||
362 | closedir (dirp); never executed: closedir (dirp); | 0 | ||||||||||||||||||
363 | free (s); | - | ||||||||||||||||||
364 | errno = e; | - | ||||||||||||||||||
365 | return NULL; never executed: return ((void *)0) ; | 0 | ||||||||||||||||||
366 | } | - | ||||||||||||||||||
367 | } never executed: end of block | 0 | ||||||||||||||||||
368 | - | |||||||||||||||||||
369 | if (dirp)
| 25-78 | ||||||||||||||||||
370 | closedir (dirp); executed 78 times by 2 tests: closedir (dirp); Executed by:
| 78 | ||||||||||||||||||
371 | return s; executed 103 times by 4 tests: return s; Executed by:
| 103 | ||||||||||||||||||
372 | } | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |