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