This function is called once for every file system object that fts encounters. fts performs a depth-first traversal. A directory is usually processed twice, first with fts_info == FTS_D, and later, after all of its entries have been processed, with FTS_DP. Return RM_ERROR upon error, RM_USER_DECLINED for a negative response to an interactive prompt, and otherwise, RM_OK. */
| 439 | Return RM_ERROR upon error, RM_USER_DECLINED for a negative response |
| 440 | to an interactive prompt, and otherwise, RM_OK. */ |
| 441 | static enum RM_status |
| 442 | rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x) |
| 443 | { |
| 444 | int dir_status = DS_UNKNOWN; |
| 445 | |
| 446 | switch (ent->fts_info) |
| 447 | { |
| 448 | case FTS_D: /* preorder directory */ |
| 449 | if (!x->recursive) |
| 450 | { |
| 451 | /* Not recursive, so skip contents, and fail now unless |
| 452 | removing empty directories. */ |
| 453 | fts_set (fts, ent, FTS_SKIP); |
| 454 | if (x->remove_empty_directories) |
| 455 | return RM_OK; |
| 456 | error (0, EISDIR, _("cannot remove %s"), quoteaf (ent->fts_path)); |
| 457 | ignore_value (fts_read (fts)); |
| 458 | return RM_ERROR; |
| 459 | } |
| 460 | |
| 461 | /* Perform checks that can apply only for command-line arguments. */ |
| 462 | if (ent->fts_level == FTS_ROOTLEVEL) |
| 463 | { |
| 464 | /* POSIX says: |
| 465 | If the basename of a command line argument is "." or "..", |
| 466 | diagnose it and do nothing more with that argument. */ |
| 467 | if (dot_or_dotdot (last_component (ent->fts_accpath))) |
| 468 | { |
| 469 | error (0, 0, |
| 470 | _("refusing to remove %s or %s directory: skipping %s"), |
| 471 | quoteaf_n (0, "."), quoteaf_n (1, ".."), |
| 472 | quoteaf_n (2, ent->fts_path)); |
| 473 | fts_skip_tree (fts, ent); |
| 474 | return RM_ERROR; |
| 475 | } |
| 476 | |
| 477 | /* POSIX also says: |
| 478 | If a command line argument resolves to "/" (and --preserve-root |
| 479 | is in effect -- default) diagnose and skip it. */ |
| 480 | if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp)) |
| 481 | { |
| 482 | ROOT_DEV_INO_WARN (ent->fts_path); |
| 483 | fts_skip_tree (fts, ent); |
| 484 | return RM_ERROR; |
| 485 | } |
| 486 | |
| 487 | /* If a command line argument is a mount point and |
| 488 | --preserve-root=all is in effect, diagnose and skip it. |
| 489 | This doesn't handle "/", but that's handled above. */ |
| 490 | if (x->preserve_all_root) |
| 491 | { |
| 492 | bool failed = false; |
| 493 | char *parent = file_name_concat (ent->fts_accpath, "..", NULL); |
| 494 | struct stat statbuf; |
| 495 | |
| 496 | if (!parent || lstat (parent, &statbuf)) |
| 497 | { |
| 498 | error (0, 0, |
no test coverage detected