add the -P (paranoid) option, overwrite regular files
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 18 Apr 1994 21:21:47 +0000 (13:21 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 18 Apr 1994 21:21:47 +0000 (13:21 -0800)
SCCS-vsn: bin/rm/rm.c 8.5
SCCS-vsn: bin/rm/rm.1 8.2

usr/src/bin/rm/rm.1
usr/src/bin/rm/rm.c

index 54d98f2..6e948ce 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1990, 1993
+.\" Copyright (c) 1990, 1993, 1994
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" This code is derived from software contributed to Berkeley by
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" This code is derived from software contributed to Berkeley by
@@ -6,7 +6,7 @@
 .\"
 .\" %sccs.include.redist.roff%
 .\"
 .\"
 .\" %sccs.include.redist.roff%
 .\"
-.\"    @(#)rm.1        8.1 (Berkeley) %G%
+.\"    @(#)rm.1        8.2 (Berkeley) %G%
 .\"
 .Dd 
 .Dt RM 1
 .\"
 .Dd 
 .Dt RM 1
@@ -17,7 +17,7 @@
 .Sh SYNOPSIS
 .Nm rm
 .Op Fl f | Fl i
 .Sh SYNOPSIS
 .Nm rm
 .Op Fl f | Fl i
-.Op Fl dRr
+.Op Fl dPRr
 .Ar file ...
 .Sh DESCRIPTION
 The
 .Ar file ...
 .Sh DESCRIPTION
 The
@@ -51,6 +51,10 @@ The
 option overrides any previous
 .Fl f 
 options.
 option overrides any previous
 .Fl f 
 options.
+.It Fl P
+Overwrite regular files before deleting them.
+Files are overwritten three times, first with the byte pattern 0xff,
+then 0x00, and then 0xff again, before they are deleted.
 .It Fl R
 Attempt to remove the file hierarchy rooted in each file argument.
 The 
 .It Fl R
 Attempt to remove the file hierarchy rooted in each file argument.
 The 
@@ -92,6 +96,14 @@ exits with a value >0.
 .Xr unlink 2 ,
 .Xr fts 3 ,
 .Xr symlink 7
 .Xr unlink 2 ,
 .Xr fts 3 ,
 .Xr symlink 7
+.Sh BUGS
+The
+.Fl P
+option assumes that the underlying file system is a fixed-block file
+system.
+UFS is a fixed-block file system, LFS is not.
+In addition, only regular files are overwritten, other types of files
+are not.
 .Sh COMPATIBILITY
 The
 .Nm rm
 .Sh COMPATIBILITY
 The
 .Nm rm
index 1efc0bb..4698447 100644 (file)
@@ -12,7 +12,7 @@ static char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)rm.c       8.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)rm.c       8.5 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -20,18 +20,20 @@ static char sccsid[] = "@(#)rm.c    8.4 (Berkeley) %G%";
 
 #include <err.h>
 #include <errno.h>
 
 #include <err.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <fts.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <fts.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-int dflag, fflag, iflag, eval, stdin_ok;
+int dflag, eval, fflag, iflag, Pflag, stdin_ok;
 
 int    check __P((char *, char *, struct stat *));
 void   checkdot __P((char **));
 
 int    check __P((char *, char *, struct stat *));
 void   checkdot __P((char **));
-void   rmfile __P((char **));
-void   rmtree __P((char **));
+void   rm_file __P((char **));
+void   rm_overwrite __P((char *, struct stat *));
+void   rm_tree __P((char **));
 void   usage __P((void));
 
 /*
 void   usage __P((void));
 
 /*
@@ -48,8 +50,8 @@ main(argc, argv)
 {
        int ch, rflag;
 
 {
        int ch, rflag;
 
-       rflag = 0;
-       while ((ch = getopt(argc, argv, "dfiRr")) != EOF)
+       Pflag = rflag = 0;
+       while ((ch = getopt(argc, argv, "dfiPRr")) != EOF)
                switch(ch) {
                case 'd':
                        dflag = 1;
                switch(ch) {
                case 'd':
                        dflag = 1;
@@ -62,8 +64,11 @@ main(argc, argv)
                        fflag = 0;
                        iflag = 1;
                        break;
                        fflag = 0;
                        iflag = 1;
                        break;
+               case 'P':
+                       Pflag = 1;
+                       break;
                case 'R':
                case 'R':
-               case 'r':                       /* compatibility */
+               case 'r':                       /* Compatibility. */
                        rflag = 1;
                        break;
                case '?':
                        rflag = 1;
                        break;
                case '?':
@@ -83,14 +88,14 @@ main(argc, argv)
        stdin_ok = isatty(STDIN_FILENO);
 
        if (rflag)
        stdin_ok = isatty(STDIN_FILENO);
 
        if (rflag)
-               rmtree(argv);
+               rm_tree(argv);
        else
        else
-               rmfile(argv);
+               rm_file(argv);
        exit (eval);
 }
 
 void
        exit (eval);
 }
 
 void
-rmtree(argv)
+rm_tree(argv)
        char **argv;
 {
        FTS *fts;
        char **argv;
 {
        FTS *fts;
@@ -168,8 +173,12 @@ rmtree(argv)
                                        continue;
                        } else if (p->fts_info != FTS_DP)
                                warnx("%s: unable to read", p->fts_path);
                                        continue;
                        } else if (p->fts_info != FTS_DP)
                                warnx("%s: unable to read", p->fts_path);
-               } else if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
-                       continue;
+               } else {
+                       if (Pflag)
+                               rm_overwrite(p->fts_accpath, NULL);
+                       if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
+                               continue;
+               }
                warn("%s", p->fts_path);
                eval = 1;
        }
                warn("%s", p->fts_path);
                eval = 1;
        }
@@ -178,12 +187,12 @@ rmtree(argv)
 }
 
 void
 }
 
 void
-rmfile(argv)
+rm_file(argv)
        char **argv;
 {
        char **argv;
 {
-       int df;
-       char *f;
        struct stat sb;
        struct stat sb;
+       int df, rval;
+       char *f;
 
        df = dflag;
        /*
 
        df = dflag;
        /*
@@ -206,14 +215,75 @@ rmfile(argv)
                }
                if (!fflag && !check(f, f, &sb))
                        continue;
                }
                if (!fflag && !check(f, f, &sb))
                        continue;
-               if ((S_ISDIR(sb.st_mode) ? rmdir(f) : unlink(f)) &&
-                   (!fflag || errno != ENOENT)) {
+               if (S_ISDIR(sb.st_mode))
+                       rval = rmdir(f);
+               else {
+                       if (Pflag)
+                               rm_overwrite(f, &sb);
+                       rval = unlink(f);
+               }
+               if (rval && (!fflag || errno != ENOENT)) {
                        warn("%s", f);
                        eval = 1;
                }
        }
 }
 
                        warn("%s", f);
                        eval = 1;
                }
        }
 }
 
+/*
+ * rm_overwrite --
+ *     Overwrite the file 3 times with varying bit patterns.
+ *
+ * XXX
+ * This is a cheap way to *really* delete files.  Note that only regular
+ * files are deleted, directories (and therefore names) will remain.
+ * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
+ * System V file system).  In a logging file system, you'll have to have
+ * kernel support.
+ */
+void
+rm_overwrite(file, sbp)
+       char *file;
+       struct stat *sbp;
+{
+       struct stat sb;
+       off_t len;
+       int fd, wlen;
+       char buf[8 * 1024];
+
+       fd = -1;
+       if (sbp == NULL) {
+               if (lstat(file, &sb))
+                       goto err;
+               sbp = &sb;
+       }
+       if (!S_ISREG(sbp->st_mode))
+               return;
+       if ((fd = open(file, O_WRONLY, 0)) == -1)
+               goto err;
+
+#define        PASS(byte) {                                                    \
+       memset(buf, byte, sizeof(buf));                                 \
+       for (len = sbp->st_size; len > 0; len -= wlen) {                \
+               wlen = len < sizeof(buf) ? len : sizeof(buf);           \
+               if (write(fd, buf, wlen) != wlen)                       \
+                       goto err;                                       \
+       }                                                               \
+}
+       PASS(0xff);
+       if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+               goto err;
+       PASS(0x00);
+       if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+               goto err;
+       PASS(0xff);
+       if (!fsync(fd) && !close(fd))
+               return;
+
+err:   eval = 1;
+       warn("%s", file);
+}
+
+
 int
 check(path, name, sp)
        char *path, *name;
 int
 check(path, name, sp)
        char *path, *name;