OpenCoverage

remove.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/remove.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* remove.c -- core functions for removing files and directories-
2 Copyright (C) 1988-2018 Free Software Foundation, Inc.-
3-
4 This program is free software: you can redistribute it and/or modify-
5 it under the terms of the GNU General Public License as published by-
6 the Free Software Foundation, either version 3 of the License, or-
7 (at your option) any later version.-
8-
9 This program is distributed in the hope that it will be useful,-
10 but WITHOUT ANY WARRANTY; without even the implied warranty of-
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
12 GNU General Public License for more details.-
13-
14 You should have received a copy of the GNU General Public License-
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */-
16-
17/* Extracted from rm.c, librarified, then rewritten twice by Jim Meyering. */-
18-
19#include <config.h>-
20#include <stdio.h>-
21#include <sys/types.h>-
22#include <assert.h>-
23-
24#include "system.h"-
25#include "error.h"-
26#include "file-type.h"-
27#include "ignore-value.h"-
28#include "remove.h"-
29#include "root-dev-ino.h"-
30#include "write-any-file.h"-
31#include "xfts.h"-
32#include "yesno.h"-
33-
34enum Ternary-
35 {-
36 T_UNKNOWN = 2,-
37 T_NO,-
38 T_YES-
39 };-
40typedef enum Ternary Ternary;-
41-
42/* The prompt function may be called twice for a given directory.-
43 The first time, we ask whether to descend into it, and the-
44 second time, we ask whether to remove it. */-
45enum Prompt_action-
46 {-
47 PA_DESCEND_INTO_DIR = 2,-
48 PA_REMOVE_DIR-
49 };-
50-
51/* D_TYPE(D) is the type of directory entry D if known, DT_UNKNOWN-
52 otherwise. */-
53#if ! HAVE_STRUCT_DIRENT_D_TYPE-
54/* Any int values will do here, so long as they're distinct.-
55 Undef any existing macros out of the way. */-
56# undef DT_UNKNOWN-
57# undef DT_DIR-
58# undef DT_LNK-
59# define DT_UNKNOWN 0-
60# define DT_DIR 1-
61# define DT_LNK 2-
62#endif-
63-
64/* Like fstatat, but cache the result. If ST->st_size is -1, the-
65 status has not been gotten yet. If less than -1, fstatat failed-
66 with errno == ST->st_ino. Otherwise, the status has already-
67 been gotten, so return 0. */-
68static int-
69cache_fstatat (int fd, char const *file, struct stat *st, int flag)-
70{-
71 if (st->st_size == -1 && fstatat (fd, file, st, flag) != 0)
st->st_size == -1Description
TRUEevaluated 143 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 44 times by 1 test
Evaluated by:
  • rm
fstatat (fd, f...st, flag) != 0Description
TRUEnever evaluated
FALSEevaluated 143 times by 1 test
Evaluated by:
  • rm
0-143
72 {-
73 st->st_size = -2;-
74 st->st_ino = errno;-
75 }
never executed: end of block
0
76 if (0 <= st->st_size)
0 <= st->st_sizeDescription
TRUEevaluated 187 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-187
77 return 0;
executed 187 times by 1 test: return 0;
Executed by:
  • rm
187
78 errno = (int) st->st_ino;-
79 return -1;
never executed: return -1;
0
80}-
81-
82/* Initialize a fstatat cache *ST. Return ST for convenience. */-
83static inline struct stat *-
84cache_stat_init (struct stat *st)-
85{-
86 st->st_size = -1;-
87 return st;
executed 322552 times by 2 tests: return st;
Executed by:
  • mv
  • rm
322552
88}-
89-
90/* Return 1 if FILE is an unwritable non-symlink,-
91 0 if it is writable or some other type of file,-
92 -1 and set errno if there is some problem in determining the answer.-
93 Set *BUF to the file status. */-
94static int-
95write_protected_non_symlink (int fd_cwd,-
96 char const *file,-
97 struct stat *buf)-
98{-
99 if (can_write_any_file ())
can_write_any_file ()Description
TRUEnever evaluated
FALSEevaluated 143 times by 1 test
Evaluated by:
  • rm
0-143
100 return 0;
never executed: return 0;
0
101 if (cache_fstatat (fd_cwd, file, buf, AT_SYMLINK_NOFOLLOW) != 0)
cache_fstatat ..., 0x100 ) != 0Description
TRUEnever evaluated
FALSEevaluated 143 times by 1 test
Evaluated by:
  • rm
0-143
102 return -1;
never executed: return -1;
0
103 if (S_ISLNK (buf->st_mode))
(((( buf->st_m... == (0120000))Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 139 times by 1 test
Evaluated by:
  • rm
4-139
104 return 0;
executed 4 times by 1 test: return 0;
Executed by:
  • rm
4
105 /* Here, we know FILE is not a symbolic link. */-
106-
107 /* In order to be reentrant -- i.e., to avoid changing the working-
108 directory, and at the same time to be able to deal with alternate-
109 access control mechanisms (ACLs, xattr-style attributes) and-
110 arbitrarily deep trees -- we need a function like eaccessat, i.e.,-
111 like Solaris' eaccess, but fd-relative, in the spirit of openat. */-
112-
113 /* In the absence of a native eaccessat function, here are some of-
114 the implementation choices [#4 and #5 were suggested by Paul Eggert]:-
115 1) call openat with O_WRONLY|O_NOCTTY-
116 Disadvantage: may create the file and doesn't work for directory,-
117 may mistakenly report 'unwritable' for EROFS or ACLs even though-
118 perm bits say the file is writable.-
119-
120 2) fake eaccessat (save_cwd, fchdir, call euidaccess, restore_cwd)-
121 Disadvantage: changes working directory (not reentrant) and can't-
122 work if save_cwd fails.-
123-
124 3) if (euidaccess (full_name, W_OK) == 0)-
125 Disadvantage: doesn't work if full_name is too long.-
126 Inefficient for very deep trees (O(Depth^2)).-
127-
128 4) If the full pathname is sufficiently short (say, less than-
129 PATH_MAX or 8192 bytes, whichever is shorter):-
130 use method (3) (i.e., euidaccess (full_name, W_OK));-
131 Otherwise: vfork, fchdir in the child, run euidaccess in the-
132 child, then the child exits with a status that tells the parent-
133 whether euidaccess succeeded.-
134-
135 This avoids the O(N**2) algorithm of method (3), and it also avoids-
136 the failure-due-to-too-long-file-names of method (3), but it's fast-
137 in the normal shallow case. It also avoids the lack-of-reentrancy-
138 and the save_cwd problems.-
139 Disadvantage; it uses a process slot for very-long file names,-
140 and would be very slow for hierarchies with many such files.-
141-
142 5) If the full file name is sufficiently short (say, less than-
143 PATH_MAX or 8192 bytes, whichever is shorter):-
144 use method (3) (i.e., euidaccess (full_name, W_OK));-
145 Otherwise: look just at the file bits. Perhaps issue a warning-
146 the first time this occurs.-
147-
148 This is like (4), except for the "Otherwise" case where it isn't as-
149 "perfect" as (4) but is considerably faster. It conforms to current-
150 POSIX, and is uniformly better than what Solaris and FreeBSD do (they-
151 mess up with long file names). */-
152-
153 {-
154 if (faccessat (fd_cwd, file, W_OK, AT_EACCESS) == 0)
faccessat (fd_..., 0x200 ) == 0Description
TRUEevaluated 133 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 6 times by 1 test
Evaluated by:
  • rm
6-133
155 return 0;
executed 133 times by 1 test: return 0;
Executed by:
  • rm
133
156-
157 return errno == EACCES ? 1 : -1;
executed 6 times by 1 test: return (*__errno_location ()) == 13 ? 1 : -1;
Executed by:
  • rm
6
158 }-
159}-
160-
161/* Prompt whether to remove FILENAME (ent->, if required via a combination of-
162 the options specified by X and/or file attributes. If the file may-
163 be removed, return RM_OK. If the user declines to remove the file,-
164 return RM_USER_DECLINED. If not ignoring missing files and we-
165 cannot lstat FILENAME, then return RM_ERROR.-
166-
167 IS_DIR is true if ENT designates a directory, false otherwise.-
168-
169 Depending on MODE, ask whether to 'descend into' or to 'remove' the-
170 directory FILENAME. MODE is ignored when FILENAME is not a directory.-
171 Set *IS_EMPTY_P to T_YES if FILENAME is an empty directory, and it is-
172 appropriate to try to remove it with rmdir (e.g. recursive mode).-
173 Don't even try to set *IS_EMPTY_P when MODE == PA_REMOVE_DIR. */-
174static enum RM_status-
175prompt (FTS const *fts, FTSENT const *ent, bool is_dir,-
176 struct rm_options const *x, enum Prompt_action mode,-
177 Ternary *is_empty_p)-
178{-
179 int fd_cwd = fts->fts_cwd_fd;-
180 char const *full_name = ent->fts_path;-
181 char const *filename = ent->fts_accpath;-
182 if (is_empty_p)
is_empty_pDescription
TRUEevaluated 56489 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 266063 times by 2 tests
Evaluated by:
  • mv
  • rm
56489-266063
183 *is_empty_p = T_UNKNOWN;
executed 56489 times by 2 tests: *is_empty_p = T_UNKNOWN;
Executed by:
  • mv
  • rm
56489
184-
185 struct stat st;-
186 struct stat *sbuf = &st;-
187 cache_stat_init (sbuf);-
188-
189 int dirent_type = is_dir ? DT_DIR : DT_UNKNOWN;
is_dirDescription
TRUEevaluated 72734 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 249818 times by 2 tests
Evaluated by:
  • mv
  • rm
72734-249818
190 int write_protected = 0;-
191-
192 bool is_empty = false;-
193 if (is_empty_p)
is_empty_pDescription
TRUEevaluated 56489 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 266063 times by 2 tests
Evaluated by:
  • mv
  • rm
56489-266063
194 {-
195 is_empty = is_empty_dir (fd_cwd, filename);-
196 *is_empty_p = is_empty ? T_YES : T_NO;
is_emptyDescription
TRUEevaluated 40242 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 16247 times by 2 tests
Evaluated by:
  • mv
  • rm
16247-40242
197 }
executed 56489 times by 2 tests: end of block
Executed by:
  • mv
  • rm
56489
198-
199 /* When nonzero, this indicates that we failed to remove a child entry,-
200 either because the user declined an interactive prompt, or due to-
201 some other failure, like permissions. */-
202 if (ent->fts_number)
ent->fts_numberDescription
TRUEevaluated 9 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 322543 times by 2 tests
Evaluated by:
  • mv
  • rm
9-322543
203 return RM_USER_DECLINED;
executed 9 times by 1 test: return RM_USER_DECLINED;
Executed by:
  • rm
9
204-
205 if (x->interactive == RMI_NEVER)
x->interactive == RMI_NEVERDescription
TRUEevaluated 298049 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 24494 times by 1 test
Evaluated by:
  • rm
24494-298049
206 return RM_OK;
executed 298049 times by 2 tests: return RM_OK;
Executed by:
  • mv
  • rm
298049
207-
208 int wp_errno = 0;-
209 if (!x->ignore_missing_files
!x->ignore_missing_filesDescription
TRUEevaluated 24494 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-24494
210 && ((x->interactive == RMI_ALWAYS) || x->stdin_tty)
(x->interactive == RMI_ALWAYS)Description
TRUEevaluated 30 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 24464 times by 1 test
Evaluated by:
  • rm
x->stdin_ttyDescription
TRUEevaluated 113 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 24351 times by 1 test
Evaluated by:
  • rm
30-24464
211 && dirent_type != DT_LNK)
dirent_type != DT_LNKDescription
TRUEevaluated 143 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-143
212 {-
213 write_protected = write_protected_non_symlink (fd_cwd, filename, sbuf);-
214 wp_errno = errno;-
215 }
executed 143 times by 1 test: end of block
Executed by:
  • rm
143
216-
217 if (write_protected || x->interactive == RMI_ALWAYS)
write_protectedDescription
TRUEevaluated 6 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 24488 times by 1 test
Evaluated by:
  • rm
x->interactive == RMI_ALWAYSDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 24461 times by 1 test
Evaluated by:
  • rm
6-24488
218 {-
219 if (0 <= write_protected && dirent_type == DT_UNKNOWN)
0 <= write_protectedDescription
TRUEevaluated 33 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
dirent_type == DT_UNKNOWNDescription
TRUEevaluated 17 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 16 times by 1 test
Evaluated by:
  • rm
0-33
220 {-
221 if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) == 0)
cache_fstatat ..., 0x100 ) == 0Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-17
222 {-
223 if (S_ISLNK (sbuf->st_mode))
(((( sbuf->st_... == (0120000))Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 15 times by 1 test
Evaluated by:
  • rm
2-15
224 dirent_type = DT_LNK;
executed 2 times by 1 test: dirent_type = DT_LNK ;
Executed by:
  • rm
2
225 else if (S_ISDIR (sbuf->st_mode))
(((( sbuf->st_... == (0040000))Description
TRUEnever evaluated
FALSEevaluated 15 times by 1 test
Evaluated by:
  • rm
0-15
226 dirent_type = DT_DIR;
never executed: dirent_type = DT_DIR ;
0
227 /* Otherwise it doesn't matter, so leave it DT_UNKNOWN. */-
228 }
executed 17 times by 1 test: end of block
Executed by:
  • rm
17
229 else-
230 {-
231 /* This happens, e.g., with 'rm '''. */-
232 write_protected = -1;-
233 wp_errno = errno;-
234 }
never executed: end of block
0
235 }-
236-
237 if (0 <= write_protected)
0 <= write_protectedDescription
TRUEevaluated 33 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-33
238 switch (dirent_type)-
239 {-
240 case DT_LNK:
executed 2 times by 1 test: case DT_LNK :
Executed by:
  • rm
2
241 /* Using permissions doesn't make sense for symlinks. */-
242 if (x->interactive != RMI_ALWAYS)
x->interactive != RMI_ALWAYSDescription
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • rm
0-2
243 return RM_OK;
never executed: return RM_OK;
0
244 break;
executed 2 times by 1 test: break;
Executed by:
  • rm
2
245-
246 case DT_DIR:
executed 16 times by 1 test: case DT_DIR :
Executed by:
  • rm
16
247 /* Unless we're either deleting directories or deleting-
248 recursively, we want to raise an EISDIR error rather than-
249 prompting the user */-
250 if ( ! (x->recursive || (x->remove_empty_directories && is_empty)))
x->recursiveDescription
TRUEevaluated 15 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 1 time by 1 test
Evaluated by:
  • rm
x->remove_empty_directoriesDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
is_emptyDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
0-15
251 {-
252 write_protected = -1;-
253 wp_errno = EISDIR;-
254 }
never executed: end of block
0
255 break;
executed 16 times by 1 test: break;
Executed by:
  • rm
16
256 }
never executed: end of block
0
257-
258 char const *quoted_name = quoteaf (full_name);-
259-
260 if (write_protected < 0)
write_protected < 0Description
TRUEnever evaluated
FALSEevaluated 33 times by 1 test
Evaluated by:
  • rm
0-33
261 {-
262 error (0, wp_errno, _("cannot remove %s"), quoted_name);-
263 return RM_ERROR;
never executed: return RM_ERROR;
0
264 }-
265-
266 /* Issue the prompt. */-
267 if (dirent_type == DT_DIR
dirent_type == DT_DIRDescription
TRUEevaluated 16 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 17 times by 1 test
Evaluated by:
  • rm
16-17
268 && mode == PA_DESCEND_INTO_DIR
mode == PA_DESCEND_INTO_DIRDescription
TRUEevaluated 10 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 6 times by 1 test
Evaluated by:
  • rm
6-10
269 && !is_empty)
!is_emptyDescription
TRUEevaluated 6 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 4 times by 1 test
Evaluated by:
  • rm
4-6
270 fprintf (stderr,
executed 6 times by 1 test: fprintf ( stderr , (write_protected ? dcgettext (((void *)0), "%s: descend into write-protected directory %s? " , 5) : dcgettext (((void *)0), "%s: descend into directory %s? " , 5) ), program_name, quoted_name);
Executed by:
  • rm
6
271 (write_protected
executed 6 times by 1 test: fprintf ( stderr , (write_protected ? dcgettext (((void *)0), "%s: descend into write-protected directory %s? " , 5) : dcgettext (((void *)0), "%s: descend into directory %s? " , 5) ), program_name, quoted_name);
Executed by:
  • rm
6
272 ? _("%s: descend into write-protected directory %s? ")
executed 6 times by 1 test: fprintf ( stderr , (write_protected ? dcgettext (((void *)0), "%s: descend into write-protected directory %s? " , 5) : dcgettext (((void *)0), "%s: descend into directory %s? " , 5) ), program_name, quoted_name);
Executed by:
  • rm
6
273 : _("%s: descend into directory %s? ")),
executed 6 times by 1 test: fprintf ( stderr , (write_protected ? dcgettext (((void *)0), "%s: descend into write-protected directory %s? " , 5) : dcgettext (((void *)0), "%s: descend into directory %s? " , 5) ), program_name, quoted_name);
Executed by:
  • rm
6
274 program_name, quoted_name);
executed 6 times by 1 test: fprintf ( stderr , (write_protected ? dcgettext (((void *)0), "%s: descend into write-protected directory %s? " , 5) : dcgettext (((void *)0), "%s: descend into directory %s? " , 5) ), program_name, quoted_name);
Executed by:
  • rm
6
275 else-
276 {-
277 if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
cache_fstatat ..., 0x100 ) != 0Description
TRUEnever evaluated
FALSEevaluated 27 times by 1 test
Evaluated by:
  • rm
0-27
278 {-
279 error (0, errno, _("cannot remove %s"), quoted_name);-
280 return RM_ERROR;
never executed: return RM_ERROR;
0
281 }-
282-
283 fprintf (stderr,-
284 (write_protected-
285 /* TRANSLATORS: In the next two strings the second %s is-
286 replaced by the type of the file. To avoid grammatical-
287 problems, it may be more convenient to translate these-
288 strings instead as: "%1$s: %3$s is write-protected and-
289 is of type '%2$s' -- remove it? ". */-
290 ? _("%s: remove write-protected %s %s? ")-
291 : _("%s: remove %s %s? ")),-
292 program_name, file_type (sbuf), quoted_name);-
293 }
executed 27 times by 1 test: end of block
Executed by:
  • rm
27
294-
295 if (!yesno ())
!yesno ()Description
TRUEevaluated 9 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 24 times by 1 test
Evaluated by:
  • rm
9-24
296 return RM_USER_DECLINED;
executed 9 times by 1 test: return RM_USER_DECLINED;
Executed by:
  • rm
9
297 }
executed 24 times by 1 test: end of block
Executed by:
  • rm
24
298 return RM_OK;
executed 24485 times by 1 test: return RM_OK;
Executed by:
  • rm
24485
299}-
300-
301/* When a function like unlink, rmdir, or fstatat fails with an errno-
302 value of ERRNUM, return true if the specified file system object-
303 is guaranteed not to exist; otherwise, return false. */-
304static inline bool-
305nonexistent_file_errno (int errnum)-
306{-
307 /* Do not include ELOOP here, since the specified file may indeed-
308 exist, but be (in)accessible only via too long a symlink chain.-
309 Likewise for ENAMETOOLONG, since rm -f ./././.../foo may fail-
310 if the "..." part expands to a long enough sequence of "./"s,-
311 even though ./foo does indeed exist.-
312-
313 Another case to consider is when a particular name is invalid for-
314 a given file system. In 2011, smbfs returns EINVAL, but the next-
315 revision of POSIX will require EILSEQ for that situation:-
316 http://austingroupbugs.net/view.php?id=293-
317 */-
318-
319 switch (errnum)-
320 {-
321 case EILSEQ:
never executed: case 84 :
0
322 case EINVAL:
never executed: case 22 :
0
323 case ENOENT:
executed 492 times by 1 test: case 2 :
Executed by:
  • rm
492
324 case ENOTDIR:
executed 1 time by 1 test: case 20 :
Executed by:
  • rm
1
325 return true;
executed 493 times by 1 test: return 1 ;
Executed by:
  • rm
493
326 default:
executed 11 times by 1 test: default:
Executed by:
  • rm
11
327 return false;
executed 11 times by 1 test: return 0 ;
Executed by:
  • rm
11
328 }-
329}-
330-
331/* Encapsulate the test for whether the errno value, ERRNUM, is ignorable. */-
332static inline bool-
333ignorable_missing (struct rm_options const *x, int errnum)-
334{-
335 return x->ignore_missing_files && nonexistent_file_errno (errnum);
executed 509 times by 1 test: return x->ignore_missing_files && nonexistent_file_errno (errnum);
Executed by:
  • rm
509
336}-
337-
338/* Tell fts not to traverse into the hierarchy at ENT. */-
339static void-
340fts_skip_tree (FTS *fts, FTSENT *ent)-
341{-
342 fts_set (fts, ent, FTS_SKIP);-
343 /* Ensure that we do not process ENT a second time. */-
344 ignore_value (fts_read (fts));-
345}
executed 40254 times by 2 tests: end of block
Executed by:
  • mv
  • rm
40254
346-
347/* Upon unlink failure, or when the user declines to remove ENT, mark-
348 each of its ancestor directories, so that we know not to prompt for-
349 its removal. */-
350static void-
351mark_ancestor_dirs (FTSENT *ent)-
352{-
353 FTSENT *p;-
354 for (p = ent->fts_parent; FTS_ROOTLEVEL <= p->fts_level; p = p->fts_parent)
0 <= p->fts_levelDescription
TRUEevaluated 11 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 21 times by 1 test
Evaluated by:
  • rm
11-21
355 {-
356 if (p->fts_number)
p->fts_numberDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEevaluated 10 times by 1 test
Evaluated by:
  • rm
1-10
357 break;
executed 1 time by 1 test: break;
Executed by:
  • rm
1
358 p->fts_number = 1;-
359 }
executed 10 times by 1 test: end of block
Executed by:
  • rm
10
360}
executed 22 times by 1 test: end of block
Executed by:
  • rm
22
361-
362/* Remove the file system object specified by ENT. IS_DIR specifies-
363 whether it is expected to be a directory or non-directory.-
364 Return RM_OK upon success, else RM_ERROR. */-
365static enum RM_status-
366excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir)-
367{-
368 int flag = is_dir ? AT_REMOVEDIR : 0;
is_dirDescription
TRUEevaluated 56476 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 249811 times by 2 tests
Evaluated by:
  • mv
  • rm
56476-249811
369 if (unlinkat (fts->fts_cwd_fd, ent->fts_accpath, flag) == 0)
unlinkat (fts-...th, flag) == 0Description
TRUEevaluated 305778 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 509 times by 1 test
Evaluated by:
  • rm
509-305778
370 {-
371 if (x->verbose)
x->verboseDescription
TRUEevaluated 26 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 305752 times by 2 tests
Evaluated by:
  • mv
  • rm
26-305752
372 {-
373 printf ((is_dir-
374 ? _("removed directory %s\n")-
375 : _("removed %s\n")), quoteaf (ent->fts_path));-
376 }
executed 26 times by 2 tests: end of block
Executed by:
  • mv
  • rm
26
377 return RM_OK;
executed 305778 times by 2 tests: return RM_OK;
Executed by:
  • mv
  • rm
305778
378 }-
379-
380 /* The unlinkat from kernels like linux-2.6.32 reports EROFS even for-
381 nonexistent files. When the file is indeed missing, map that to ENOENT,-
382 so that rm -f ignores it, as required. Even without -f, this is useful-
383 because it makes rm print the more precise diagnostic. */-
384 if (errno == EROFS)
(*__errno_location ()) == 30Description
TRUEnever evaluated
FALSEevaluated 509 times by 1 test
Evaluated by:
  • rm
0-509
385 {-
386 struct stat st;-
387 if ( ! (lstatat (fts->fts_cwd_fd, ent->fts_accpath, &st)
lstatat (fts->..._accpath, &st)Description
TRUEnever evaluated
FALSEnever evaluated
0
388 && errno == ENOENT))
(*__errno_location ()) == 2Description
TRUEnever evaluated
FALSEnever evaluated
0
389 errno = EROFS;
never executed: (*__errno_location ()) = 30 ;
0
390 }
never executed: end of block
0
391-
392 if (ignorable_missing (x, errno))
ignorable_miss...location ()) )Description
TRUEevaluated 493 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 16 times by 1 test
Evaluated by:
  • rm
16-493
393 return RM_OK;
executed 493 times by 1 test: return RM_OK;
Executed by:
  • rm
493
394-
395 /* When failing to rmdir an unreadable directory, we see errno values-
396 like EISDIR or ENOTDIR (or, on Solaris 10, EEXIST), but they would be-
397 meaningless in a diagnostic. When that happens and the errno value-
398 from the failed open is EPERM or EACCES, use the earlier, more-
399 descriptive errno value. */-
400 if (ent->fts_info == FTS_DNR
ent->fts_info == 4Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 13 times by 1 test
Evaluated by:
  • rm
3-13
401 && (errno == ENOTEMPTY || errno == EISDIR || errno == ENOTDIR
(*__errno_location ()) == 39Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • rm
FALSEnever evaluated
(*__errno_location ()) == 21Description
TRUEnever evaluated
FALSEnever evaluated
(*__errno_location ()) == 20Description
TRUEnever evaluated
FALSEnever evaluated
0-3
402 || errno == EEXIST)
(*__errno_location ()) == 17Description
TRUEnever evaluated
FALSEnever evaluated
0
403 && (ent->fts_errno == EPERM || ent->fts_errno == EACCES))
ent->fts_errno == 1Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • rm
ent->fts_errno == 13Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 1 time by 1 test
Evaluated by:
  • rm
0-3
404 errno = ent->fts_errno;
executed 2 times by 1 test: (*__errno_location ()) = ent->fts_errno;
Executed by:
  • rm
2
405 error (0, errno, _("cannot remove %s"), quoteaf (ent->fts_path));-
406 mark_ancestor_dirs (ent);-
407 return RM_ERROR;
executed 16 times by 1 test: return RM_ERROR;
Executed by:
  • rm
16
408}-
409-
410/* This function is called once for every file system object that fts-
411 encounters. fts performs a depth-first traversal.-
412 A directory is usually processed twice, first with fts_info == FTS_D,-
413 and later, after all of its entries have been processed, with FTS_DP.-
414 Return RM_ERROR upon error, RM_USER_DECLINED for a negative response-
415 to an interactive prompt, and otherwise, RM_OK. */-
416static enum RM_status-
417rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)-
418{-
419 switch (ent->fts_info)-
420 {-
421 case FTS_D: /* preorder directory */
executed 56499 times by 2 tests: case 1:
Executed by:
  • mv
  • rm
56499
422 if (! x->recursive
! x->recursiveDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 56492 times by 2 tests
Evaluated by:
  • mv
  • rm
7-56492
423 && !(x->remove_empty_directories
x->remove_empty_directoriesDescription
TRUEevaluated 3 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 4 times by 1 test
Evaluated by:
  • rm
3-4
424 && is_empty_dir (fts->fts_cwd_fd, ent->fts_accpath)))
is_empty_dir (...->fts_accpath)Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 1 time by 1 test
Evaluated by:
  • rm
1-2
425 {-
426 /* This is the first (pre-order) encounter with a directory-
427 that we cannot delete.-
428 Not recursive, and it's not an empty directory (if we're removing-
429 them) so arrange to skip contents. */-
430 int err = x->remove_empty_directories ? ENOTEMPTY : EISDIR;
x->remove_empty_directoriesDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEevaluated 4 times by 1 test
Evaluated by:
  • rm
1-4
431 error (0, err, _("cannot remove %s"), quoteaf (ent->fts_path));-
432 mark_ancestor_dirs (ent);-
433 fts_skip_tree (fts, ent);-
434 return RM_ERROR;
executed 5 times by 1 test: return RM_ERROR;
Executed by:
  • rm
5
435 }-
436-
437 /* Perform checks that can apply only for command-line arguments. */-
438 if (ent->fts_level == FTS_ROOTLEVEL)
ent->fts_level == 0Description
TRUEevaluated 4172 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 52322 times by 2 tests
Evaluated by:
  • mv
  • rm
4172-52322
439 {-
440 /* POSIX says:-
441 If the basename of a command line argument is "." or "..",-
442 diagnose it and do nothing more with that argument. */-
443 if (dot_or_dotdot (last_component (ent->fts_accpath)))
dot_or_dotdot ...>fts_accpath))Description
TRUEevaluated 5 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 4167 times by 2 tests
Evaluated by:
  • mv
  • rm
5-4167
444 {-
445 error (0, 0,-
446 _("refusing to remove %s or %s directory: skipping %s"),-
447 quoteaf_n (0, "."), quoteaf_n (1, ".."),-
448 quoteaf_n (2, ent->fts_path));-
449 fts_skip_tree (fts, ent);-
450 return RM_ERROR;
executed 5 times by 1 test: return RM_ERROR;
Executed by:
  • rm
5
451 }-
452-
453 /* POSIX also says:-
454 If a command line argument resolves to "/" (and --preserve-root-
455 is in effect -- default) diagnose and skip it. */-
456 if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp))
x->root_dev_inoDescription
TRUEevaluated 4165 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 2 times by 1 test
Evaluated by:
  • rm
(*ent->fts_sta...ev_ino).st_inoDescription
TRUEnever evaluated
FALSEevaluated 4165 times by 2 tests
Evaluated by:
  • mv
  • rm
(*ent->fts_sta...ev_ino).st_devDescription
TRUEnever evaluated
FALSEnever evaluated
0-4165
457 {-
458 ROOT_DEV_INO_WARN (ent->fts_path);
never executed: __result = (((const unsigned char *) (const char *) ( ent->fts_path ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "/" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: error (0, 0, dcgettext (((void *)0), "it is dangerous to operate recursively on %s" , 5) , quotearg_style (shell_escape_always_quoting_style, ent->fts_path));
never executed: error (0, 0, dcgettext (((void *)0), "it is dangerous to operate recursively on %s (same as %s)" , 5) , quotearg_n_style (0, shell_escape_always_quoting_style, ent->fts_path), quotearg_n_style (1, shell_escape_always_quoting_style, "/"));
( __extension_...)))); }) == 0)Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
459 fts_skip_tree (fts, ent);-
460 return RM_ERROR;
never executed: return RM_ERROR;
0
461 }-
462 }
executed 4167 times by 2 tests: end of block
Executed by:
  • mv
  • rm
4167
463-
464 {-
465 Ternary is_empty_directory;-
466 enum RM_status s = prompt (fts, ent, true /*is_dir*/, x,-
467 PA_DESCEND_INTO_DIR, &is_empty_directory);-
468-
469 if (s == RM_OK && is_empty_directory == T_YES)
s == RM_OKDescription
TRUEevaluated 56489 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEnever evaluated
is_empty_directory == T_YESDescription
TRUEevaluated 40242 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 16247 times by 2 tests
Evaluated by:
  • mv
  • rm
0-56489
470 {-
471 /* When we know (from prompt when in interactive mode)-
472 that this is an empty directory, don't prompt twice. */-
473 s = excise (fts, ent, x, true);-
474 fts_skip_tree (fts, ent);-
475 }
executed 40242 times by 2 tests: end of block
Executed by:
  • mv
  • rm
40242
476-
477 if (s != RM_OK)
s != RM_OKDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEevaluated 56488 times by 2 tests
Evaluated by:
  • mv
  • rm
1-56488
478 {-
479 mark_ancestor_dirs (ent);-
480 fts_skip_tree (fts, ent);-
481 }
executed 1 time by 1 test: end of block
Executed by:
  • rm
1
482-
483 return s;
executed 56489 times by 2 tests: return s;
Executed by:
  • mv
  • rm
56489
484 }-
485-
486 case FTS_F: /* regular file */
executed 789 times by 2 tests: case 8:
Executed by:
  • mv
  • rm
789
487 case FTS_NS: /* stat(2) failed */
executed 500 times by 1 test: case 10:
Executed by:
  • rm
500
488 case FTS_SL: /* symbolic link */
executed 4 times by 2 tests: case 12:
Executed by:
  • mv
  • rm
4
489 case FTS_SLNONE: /* symbolic link without target */
never executed: case 13:
0
490 case FTS_DP: /* postorder directory */
executed 16239 times by 2 tests: case 6:
Executed by:
  • mv
  • rm
16239
491 case FTS_DNR: /* unreadable directory */
executed 6 times by 1 test: case 4:
Executed by:
  • rm
6
492 case FTS_NSOK: /* e.g., dangling symlink */
executed 248524 times by 2 tests: case 11:
Executed by:
  • mv
  • rm
248524
493 case FTS_DEFAULT: /* none of the above */
executed 1 time by 1 test: case 3:
Executed by:
  • mv
1
494 {-
495 /* With --one-file-system, do not attempt to remove a mount point.-
496 fts' FTS_XDEV ensures that we don't process any entries under-
497 the mount point. */-
498 if (ent->fts_info == FTS_DP
ent->fts_info == 6Description
TRUEevaluated 16239 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 249824 times by 2 tests
Evaluated by:
  • mv
  • rm
16239-249824
499 && x->one_file_system
x->one_file_systemDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEevaluated 16238 times by 2 tests
Evaluated by:
  • mv
  • rm
1-16238
500 && FTS_ROOTLEVEL < ent->fts_level
0 < ent->fts_levelDescription
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • rm
0-1
501 && ent->fts_statp->st_dev != fts->fts_dev)
ent->fts_statp...= fts->fts_devDescription
TRUEnever evaluated
FALSEnever evaluated
0
502 {-
503 mark_ancestor_dirs (ent);-
504 error (0, 0, _("skipping %s, since it's on a different device"),-
505 quoteaf (ent->fts_path));-
506 return RM_ERROR;
never executed: return RM_ERROR;
0
507 }-
508-
509 bool is_dir = ent->fts_info == FTS_DP || ent->fts_info == FTS_DNR;
ent->fts_info == 6Description
TRUEevaluated 16239 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 249824 times by 2 tests
Evaluated by:
  • mv
  • rm
ent->fts_info == 4Description
TRUEevaluated 6 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 249818 times by 2 tests
Evaluated by:
  • mv
  • rm
6-249824
510 enum RM_status s = prompt (fts, ent, is_dir, x, PA_REMOVE_DIR, NULL);-
511 if (s != RM_OK)
s != RM_OKDescription
TRUEevaluated 18 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 266045 times by 2 tests
Evaluated by:
  • mv
  • rm
18-266045
512 return s;
executed 18 times by 1 test: return s;
Executed by:
  • rm
18
513 return excise (fts, ent, x, is_dir);
executed 266045 times by 2 tests: return excise (fts, ent, x, is_dir);
Executed by:
  • mv
  • rm
266045
514 }-
515-
516 case FTS_DC: /* directory that causes cycles */
never executed: case 2:
0
517 emit_cycle_warning (ent->fts_path);-
518 fts_skip_tree (fts, ent);-
519 return RM_ERROR;
never executed: return RM_ERROR;
0
520-
521 case FTS_ERR:
executed 1 time by 1 test: case 7:
Executed by:
  • rm
1
522 /* Various failures, from opendir to ENOMEM, to failure to "return"-
523 to preceding directory, can provoke this. */-
524 error (0, ent->fts_errno, _("traversal failed: %s"),-
525 quotef (ent->fts_path));-
526 fts_skip_tree (fts, ent);-
527 return RM_ERROR;
executed 1 time by 1 test: return RM_ERROR;
Executed by:
  • rm
1
528-
529 default:
never executed: default:
0
530 error (0, 0, _("unexpected failure: fts_info=%d: %s\n"-
531 "please report to %s"),-
532 ent->fts_info,-
533 quotef (ent->fts_path),-
534 PACKAGE_BUGREPORT);-
535 abort ();
never executed: abort ();
0
536 }-
537}-
538-
539/* Remove FILEs, honoring options specified via X.-
540 Return RM_OK if successful. */-
541enum RM_status-
542rm (char *const *file, struct rm_options const *x)-
543{-
544 enum RM_status rm_status = RM_OK;-
545-
546 if (*file)
*fileDescription
TRUEevaluated 4403 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEnever evaluated
0-4403
547 {-
548 int bit_flags = (FTS_CWDFD-
549 | FTS_NOSTAT-
550 | FTS_PHYSICAL);-
551-
552 if (x->one_file_system)
x->one_file_systemDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • rm
FALSEevaluated 4402 times by 2 tests
Evaluated by:
  • mv
  • rm
1-4402
553 bit_flags |= FTS_XDEV;
executed 1 time by 1 test: bit_flags |= 0x0040;
Executed by:
  • rm
1
554-
555 FTS *fts = xfts_open (file, bit_flags, NULL);-
556-
557 while (1)-
558 {-
559 FTSENT *ent;-
560-
561 ent = fts_read (fts);-
562 if (ent == NULL)
ent == ((void *)0)Description
TRUEevaluated 4403 times by 2 tests
Evaluated by:
  • mv
  • rm
FALSEevaluated 322563 times by 2 tests
Evaluated by:
  • mv
  • rm
4403-322563
563 {-
564 if (errno != 0)
(*__errno_location ()) != 0Description
TRUEnever evaluated
FALSEevaluated 4403 times by 2 tests
Evaluated by:
  • mv
  • rm
0-4403
565 {-
566 error (0, errno, _("fts_read failed"));-
567 rm_status = RM_ERROR;-
568 }
never executed: end of block
0
569 break;
executed 4403 times by 2 tests: break;
Executed by:
  • mv
  • rm
4403
570 }-
571-
572 enum RM_status s = rm_fts (fts, ent, x);-
573-
574 assert (VALID_STATUS (s));-
575 UPDATE_STATUS (rm_status, s);
executed 34 times by 1 test: (rm_status) = (s);
Executed by:
  • rm
(s) == RM_ERRORDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 322536 times by 2 tests
Evaluated by:
  • mv
  • rm
(s) == RM_USER_DECLINEDDescription
TRUEevaluated 18 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 322518 times by 2 tests
Evaluated by:
  • mv
  • rm
(rm_status) == RM_OKDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • rm
FALSEevaluated 11 times by 1 test
Evaluated by:
  • rm
7-322536
576 }
executed 322563 times by 2 tests: end of block
Executed by:
  • mv
  • rm
322563
577-
578 if (fts_close (fts) != 0)
fts_close (fts) != 0Description
TRUEnever evaluated
FALSEevaluated 4403 times by 2 tests
Evaluated by:
  • mv
  • rm
0-4403
579 {-
580 error (0, errno, _("fts_close failed"));-
581 rm_status = RM_ERROR;-
582 }
never executed: end of block
0
583 }
executed 4403 times by 2 tests: end of block
Executed by:
  • mv
  • rm
4403
584-
585 return rm_status;
executed 4403 times by 2 tests: return rm_status;
Executed by:
  • mv
  • rm
4403
586}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2