static void rm_file(char **argv) { struct stat sb; int rval; char *f; /* * Remove a file. POSIX 1003.2 states that, by default, attempting * to remove a directory is an error, so must always stat the file. */ while ((f = *argv++) != NULL) { /* Assume if can't stat the file, can't unlink it. */ if (lstat(f, &sb)) { if (Wflag) { sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; } else { if (!fflag || !NONEXISTENT(errno)) { warn("%s", f); eval = 1; } continue; } } else if (Wflag) { warnx("%s: %s", f, strerror(EEXIST)); eval = 1; continue; } if (S_ISDIR(sb.st_mode) && !dflag) { warnx("%s: is a directory", f); eval = 1; continue; } if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) continue; if (S_ISWHT(sb.st_mode)) #ifdef HAVE_FUNC1_UNDELETE_UNISTD_H rval = undelete(f); #else rval = EPERM; #endif else if (S_ISDIR(sb.st_mode)) rval = rmdir(f); else { if (Pflag) { if (rm_overwrite(f, &sb)) continue; } rval = unlink(f); } if (rval && (!fflag || !NONEXISTENT(errno))) { warn("%s", f); eval = 1; } if (vflag && rval == 0) (void)printf("%s\n", f); }
static void rm_tree(char **argv) { FTS *fts; FTSENT *p; int flags, needstat, rval; /* * Remove a file hierarchy. If forcing removal (-f), or interactive * (-i) or can't ask anyway (stdin_ok), don't stat the file. */ needstat = !fflag && !iflag && stdin_ok; /* * If the -i option is specified, the user can skip on the pre-order * visit. The fts_number field flags skipped directories. */ #define SKIPPED 1 flags = FTS_PHYSICAL; if (!needstat) flags |= FTS_NOSTAT; #ifndef __ANDROID__ if (Wflag) flags |= FTS_WHITEOUT; #endif if (xflag) flags |= FTS_XDEV; if ((fts = fts_open(argv, flags, NULL)) == NULL) err(1, "fts_open failed"); while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_DNR: if (!fflag || p->fts_errno != ENOENT) { warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); eval = 1; } continue; case FTS_ERR: errx(EXIT_FAILURE, "%s: %s", p->fts_path, strerror(p->fts_errno)); /* NOTREACHED */ case FTS_NS: /* * FTS_NS: assume that if can't stat the file, it * can't be unlinked. */ if (fflag && NONEXISTENT(p->fts_errno)) continue; if (needstat) { warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); eval = 1; continue; } break; case FTS_D: /* Pre-order: give user chance to skip. */ if (!fflag && !check(p->fts_path, p->fts_accpath, p->fts_statp)) { (void)fts_set(fts, p, FTS_SKIP); p->fts_number = SKIPPED; } continue; case FTS_DP: /* Post-order: see if user skipped. */ if (p->fts_number == SKIPPED) continue; break; default: if (!fflag && !check(p->fts_path, p->fts_accpath, p->fts_statp)) continue; } rval = 0; /* * If we can't read or search the directory, may still be * able to remove it. Don't print out the un{read,search}able * message unless the remove fails. */ switch (p->fts_info) { case FTS_DP: case FTS_DNR: rval = rmdir(p->fts_accpath); if (rval != 0 && fflag && errno == ENOENT) continue; break; #ifndef __ANDROID__ case FTS_W: rval = undelete(p->fts_accpath); if (rval != 0 && fflag && errno == ENOENT) continue; break; #endif default: if (Pflag) { if (rm_overwrite(p->fts_accpath, NULL)) continue; } rval = unlink(p->fts_accpath); if (rval != 0 && fflag && NONEXISTENT(errno)) continue; break; } if (rval != 0) { warn("%s", p->fts_path); eval = 1; } else if (vflag || pinfo) { pinfo = 0; (void)printf("%s\n", p->fts_path); } } if (errno) err(1, "fts_read"); fts_close(fts); }