X-Git-Url: https://git.saurik.com/apple/file_cmds.git/blobdiff_plain/f383e97b3f95842c6ff58e791aa34856880a1a41..39aaa94bf0a1c68b3fe15e3622c96766f0f22ff2:/rm/rm.c diff --git a/rm/rm.c b/rm/rm.c index 7997af5..ec13b2a 100644 --- a/rm/rm.c +++ b/rm/rm.c @@ -31,8 +31,9 @@ * SUCH DAMAGE. */ +#include #ifndef lint -static const char copyright[] = +__used static const char copyright[] = "@(#) Copyright (c) 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ @@ -41,7 +42,7 @@ static const char copyright[] = #if 0 static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94"; #else -static const char rcsid[] = +__used static const char rcsid[] = "$FreeBSD: src/bin/rm/rm.c,v 1.33 2001/06/13 15:01:25 ru Exp $"; #endif #endif /* not lint */ @@ -60,10 +61,21 @@ static const char rcsid[] = #include #include +#ifdef __APPLE__ +#include +#include +#include +#include "get_compat.h" +#else +#define COMPAT_MODE(func, mode) 1 +#endif + int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok; uid_t uid; int check __P((char *, char *, struct stat *)); +int checkdir __P((char *)); +int yes_or_no __P((void)); void checkdot __P((char **)); void rm_file __P((char **)); void rm_overwrite __P((char *, struct stat *)); @@ -85,6 +97,9 @@ main(argc, argv) int ch, rflag; char *p; + if (argc < 1) + usage(); + /* * Test for the special case where the utility is called as * "unlink", for which the functionality provided is greatly @@ -94,6 +109,7 @@ main(argc, argv) p = argv[0]; else ++p; + uid = geteuid(); if (strcmp(p, "unlink") == 0) { if (argc == 2) { rm_file(&argv[1]); @@ -142,7 +158,6 @@ main(argc, argv) } checkdot(argv); - uid = geteuid(); if (*argv) { stdin_ok = isatty(STDIN_FILENO); @@ -165,7 +180,7 @@ rm_tree(argv) int needstat; int flags; int rval; - + int wantConformance = COMPAT_MODE("bin/rm", "unix2003"); /* * Remove a file hierarchy. If forcing removal (-f), or interactive * (-i) or can't ask anyway (stdin_ok), don't stat the file. @@ -183,8 +198,11 @@ rm_tree(argv) flags |= FTS_NOSTAT; if (Wflag) flags |= FTS_WHITEOUT; - if (!(fts = fts_open(argv, flags, NULL))) + if (!(fts = fts_open(argv, flags, NULL))) { + if (fflag && errno == ENOENT) + return; err(1, NULL); + } while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_DNR: @@ -211,8 +229,13 @@ rm_tree(argv) continue; case FTS_D: /* Pre-order: give user chance to skip. */ - if (!fflag && !check(p->fts_path, p->fts_accpath, - p->fts_statp)) { + /* In conformance mode the user is prompted to skip processing the contents. + * Then the option to delete the dir is presented post-order */ + if (!fflag && + ( (wantConformance && !checkdir(p->fts_path)) || + (!wantConformance && !check(p->fts_path, p->fts_accpath, p->fts_statp)) + ) + ){ (void)fts_set(fts, p, FTS_SKIP); p->fts_number = SKIPPED; } @@ -225,8 +248,16 @@ rm_tree(argv) continue; case FTS_DP: /* Post-order: see if user skipped. */ - if (p->fts_number == SKIPPED) + if(p->fts_number == SKIPPED)/*in legacy mode, the user was prompted pre-order */ continue; + else if(wantConformance) + { + /* delete directory if force is on, or if user answers Y to prompt */ + if(fflag || check(p->fts_path, p->fts_accpath, p->fts_statp)) + break; + else + continue; + } break; default: if (!fflag && @@ -269,9 +300,17 @@ rm_tree(argv) break; default: +#ifdef __APPLE__ + if (Pflag) { + if (removefile(p->fts_accpath, NULL, REMOVEFILE_SECURE_7_PASS)) /* overwrites and unlinks */ + eval = rval = 1; + } else + rval = unlink(p->fts_accpath); +#else /* !__APPLE_ */ if (Pflag) rm_overwrite(p->fts_accpath, NULL); rval = unlink(p->fts_accpath); +#endif /* __APPLE__ */ if (rval == 0 || (fflag && errno == ENOENT)) { if (rval == 0 && vflag) (void)printf("%s\n", @@ -286,6 +325,7 @@ err: } if (errno) err(1, "fts_read"); + fts_close(fts); } void @@ -336,9 +376,17 @@ rm_file(argv) else if (S_ISDIR(sb.st_mode)) rval = rmdir(f); else { +#ifdef __APPLE__ + if (Pflag) { + if (removefile(f, NULL, REMOVEFILE_SECURE_7_PASS)) /* overwrites and unlinks */ + eval = rval = 1; + } else + rval = unlink(f); +#else /* !__APPLE__ */ if (Pflag) rm_overwrite(f, &sb); rval = unlink(f); +#endif /* __APPLE__ */ } } if (rval && (!fflag || errno != ENOENT)) { @@ -372,7 +420,6 @@ rm_overwrite(file, sbp) int bsize, fd, wlen; char *buf = NULL; - fd = -1; if (sbp == NULL) { if (lstat(file, &sb)) goto err; @@ -391,7 +438,7 @@ rm_overwrite(file, sbp) #define PASS(byte) { \ memset(buf, byte, bsize); \ for (len = sbp->st_size; len > 0; len -= wlen) { \ - wlen = len < bsize ? len : bsize; \ + wlen = len < bsize ? (int)len : bsize; \ if (write(fd, buf, wlen) != wlen) \ goto err; \ } \ @@ -414,13 +461,33 @@ err: eval = 1; warn("%s", file); } +int +yes_or_no() +{ + int ch, first; + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +int +checkdir(path) + char *path; +{ + if(!iflag) + return 1; //if not interactive, process directory's contents + (void)fprintf(stderr, "examine files in directory %s? ", path); + return yes_or_no(); +} int check(path, name, sp) char *path, *name; struct stat *sp; { - int ch, first; char modep[15], *flagsp; /* Check -i first. */ @@ -449,14 +516,10 @@ check(path, name, sp) path); free(flagsp); } - (void)fflush(stderr); - - first = ch = getchar(); - while (ch != '\n' && ch != EOF) - ch = getchar(); - return (first == 'y' || first == 'Y'); + return yes_or_no(); } + #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) void checkdot(argv) @@ -467,10 +530,24 @@ checkdot(argv) complained = 0; for (t = argv; *t;) { - if ((p = strrchr(*t, '/')) != NULL) - ++p; - else + size_t len = strlen(*t); + char truncated[len]; + + if ((p = strrchr(*t, '/')) != NULL) { + if (p[1] == '\0') { // trailing / -- treat as if not present + strlcpy(truncated, *t, len); + p = strrchr(truncated, '/'); + if (p) { + ++p; + } else { + p = truncated; + } + } else { + ++p; + } + } else { p = *t; + } if (ISDOT(p)) { if (!complained++) warnx("\".\" and \"..\" may not be removed");