]> git.saurik.com Git - apple/file_cmds.git/blobdiff - rm/rm.c
file_cmds-272.201.1.tar.gz
[apple/file_cmds.git] / rm / rm.c
diff --git a/rm/rm.c b/rm/rm.c
index 7997af50cd9d2ce7335c02f6f7d197319bb2dade..9022802d5f11ffb26ac5dd24339081089815c1ea 100644 (file)
--- a/rm/rm.c
+++ b/rm/rm.c
@@ -31,8 +31,9 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #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 <sysexits.h>
 #include <unistd.h>
 
+#ifdef __APPLE__
+#include <removefile.h>
+#include <pwd.h>
+#include <grp.h>
+#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,28 @@ 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') { // one or more trailing / -- treat as if not present
+                               for (; (p > *t) && (p[-1] == '/');) {
+                                       len--;
+                                       p--;
+                               }
+                               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");