changes for whiteouts and union filesystem
authorJan-Simon Pendry <pendry@ucbvax.Berkeley.EDU>
Thu, 28 Jul 1994 18:39:31 +0000 (10:39 -0800)
committerJan-Simon Pendry <pendry@ucbvax.Berkeley.EDU>
Thu, 28 Jul 1994 18:39:31 +0000 (10:39 -0800)
SCCS-vsn: bin/ls/ls.c 8.6
SCCS-vsn: bin/ls/util.c 8.4
SCCS-vsn: bin/ls/print.c 8.5
SCCS-vsn: bin/ls/stat_flags.c 8.2
SCCS-vsn: bin/rm/rm.c 8.6
SCCS-vsn: include/dirent.h 8.2
SCCS-vsn: include/fts.h 8.2
SCCS-vsn: include/unistd.h 8.11
SCCS-vsn: lib/libc/gen/opendir.c 8.5
SCCS-vsn: lib/libc/gen/fts.c 8.5
SCCS-vsn: lib/libc/gen/readdir.c 8.2
SCCS-vsn: lib/libc/sys/chflags.2 8.2
SCCS-vsn: lib/libc/sys/Makefile.inc 8.2
SCCS-vsn: lib/libc/sys/undelete.2 8.2
SCCS-vsn: lib/libc/string/strmode.c 8.2
SCCS-vsn: usr.bin/chflags/chflags.1 8.3
SCCS-vsn: usr.bin/find/find.c 8.4
SCCS-vsn: usr.bin/find/function.c 8.7
SCCS-vsn: sbin/fsck/pass2.c 8.3
SCCS-vsn: sys/ufs/ffs/ffs_vnops.c 8.9
SCCS-vsn: sys/ufs/ufs/ufs_lookup.c 8.8
SCCS-vsn: sys/ufs/ufs/ufs_vnops.c 8.12
SCCS-vsn: sys/ufs/ufs/ufs_extern.h 8.5
SCCS-vsn: sys/ufs/lfs/lfs_vnops.c 8.7
SCCS-vsn: sys/ufs/mfs/mfs_vnops.c 8.5
SCCS-vsn: sys/kern/vfs_syscalls.c 8.19
SCCS-vsn: sys/miscfs/union/union.h 8.7
SCCS-vsn: sys/miscfs/union/union_vnops.c 8.19
SCCS-vsn: sys/miscfs/union/union_vfsops.c 8.12
SCCS-vsn: sys/miscfs/union/union_subr.c 8.12
SCCS-vsn: sys/sys/namei.h 8.3
SCCS-vsn: sys/sys/vnode.h 8.8

32 files changed:
usr/src/bin/ls/ls.c
usr/src/bin/ls/print.c
usr/src/bin/ls/stat_flags.c
usr/src/bin/ls/util.c
usr/src/bin/rm/rm.c
usr/src/include/dirent.h
usr/src/include/fts.h
usr/src/include/unistd.h
usr/src/lib/libc/gen/fts.c
usr/src/lib/libc/gen/opendir.c
usr/src/lib/libc/gen/readdir.c
usr/src/lib/libc/string/strmode.c
usr/src/lib/libc/sys/Makefile.inc
usr/src/lib/libc/sys/chflags.2
usr/src/lib/libc/sys/undelete.2
usr/src/sbin/fsck/pass2.c
usr/src/sys/kern/vfs_syscalls.c
usr/src/sys/miscfs/union/union.h
usr/src/sys/miscfs/union/union_subr.c
usr/src/sys/miscfs/union/union_vfsops.c
usr/src/sys/miscfs/union/union_vnops.c
usr/src/sys/sys/namei.h
usr/src/sys/sys/vnode.h
usr/src/sys/ufs/ffs/ffs_vnops.c
usr/src/sys/ufs/lfs/lfs_vnops.c
usr/src/sys/ufs/mfs/mfs_vnops.c
usr/src/sys/ufs/ufs/ufs_extern.h
usr/src/sys/ufs/ufs/ufs_lookup.c
usr/src/sys/ufs/ufs/ufs_vnops.c
usr/src/usr.bin/chflags/chflags.1
usr/src/usr.bin/find/find.c
usr/src/usr.bin/find/function.c

index 9628f7c..c3ec9b7 100644 (file)
@@ -15,7 +15,7 @@ static char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)ls.c       8.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)ls.c       8.6 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -64,6 +64,7 @@ int f_statustime;             /* use time of last mode change */
 int f_dirname;                 /* if precede with directory name */
 int f_timesort;                        /* sort by time vice name */
 int f_type;                    /* add type character for non-regular files */
 int f_dirname;                 /* if precede with directory name */
 int f_timesort;                        /* sort by time vice name */
 int f_type;                    /* add type character for non-regular files */
+int f_whiteout;                        /* show whiteout entries */
 
 int
 main(argc, argv)
 
 int
 main(argc, argv)
@@ -93,7 +94,7 @@ main(argc, argv)
                f_listdot = 1;
 
        fts_options = FTS_PHYSICAL;
                f_listdot = 1;
 
        fts_options = FTS_PHYSICAL;
-       while ((ch = getopt(argc, argv, "1ACFLRTacdfgiloqrstu")) != EOF) {
+       while ((ch = getopt(argc, argv, "1ACFLRTWacdfgiloqrstu")) != EOF) {
                switch (ch) {
                /*
                 * The -1, -C and -l options all override each other so shell
                switch (ch) {
                /*
                 * The -1, -C and -l options all override each other so shell
@@ -169,6 +170,9 @@ main(argc, argv)
                case 't':
                        f_timesort = 1;
                        break;
                case 't':
                        f_timesort = 1;
                        break;
+               case 'W':
+                       f_whiteout = 1;
+                       break;
                default:
                case '?':
                        usage();
                default:
                case '?':
                        usage();
@@ -191,6 +195,12 @@ main(argc, argv)
        if (!f_longform && !f_listdir && !f_type)
                fts_options |= FTS_COMFOLLOW;
 
        if (!f_longform && !f_listdir && !f_type)
                fts_options |= FTS_COMFOLLOW;
 
+       /*
+        * If -W, show whiteout entries
+        */
+       if (f_whiteout)
+               fts_options |= FTS_WHITEOUT;
+
        /* If -l or -s, figure out block size. */
        if (f_longform || f_size) {
                (void)getbsize(&notused, &blocksize);
        /* If -l or -s, figure out block size. */
        if (f_longform || f_size) {
                (void)getbsize(&notused, &blocksize);
index 2a62872..2a1cfd7 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)print.c    8.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)print.c    8.5 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -238,6 +238,9 @@ printtype(mode)
        case S_IFSOCK:
                (void)putchar('=');
                return (1);
        case S_IFSOCK:
                (void)putchar('=');
                return (1);
+       case S_IFWHT:
+               (void)putchar('%');
+               return (1);
        }
        if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
                (void)putchar('*');
        }
        if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
                (void)putchar('*');
index 852e09a..93e6f13 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)stat_flags.c       8.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)stat_flags.c       8.2 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -43,6 +43,8 @@ flags_to_string(flags, def)
                SAPPEND("uchg");
        if (flags & UF_NODUMP)
                SAPPEND("nodump");
                SAPPEND("uchg");
        if (flags & UF_NODUMP)
                SAPPEND("nodump");
+       if (flags & UF_OPAQUE)
+               SAPPEND("opaque");
        if (flags & SF_APPEND)
                SAPPEND("sappnd");
        if (flags & SF_ARCHIVED)
        if (flags & SF_APPEND)
                SAPPEND("sappnd");
        if (flags & SF_ARCHIVED)
@@ -100,6 +102,9 @@ string_to_flags(stringp, setp, clrp)
                        clear = !clear;
                        TEST(p, "dump", UF_NODUMP);
                        return (1);
                        clear = !clear;
                        TEST(p, "dump", UF_NODUMP);
                        return (1);
+               case 'o':
+                       TEST(p, "opaque", UF_OPAQUE);
+                       return (1);
                case 's':
                        TEST(p, "sappnd", SF_APPEND);
                        TEST(p, "sappend", SF_APPEND);
                case 's':
                        TEST(p, "sappnd", SF_APPEND);
                        TEST(p, "sappend", SF_APPEND);
index a3c2d32..fdd6937 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)util.c     8.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)util.c     8.4 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -40,6 +40,6 @@ prcopy(src, dest, len)
 void
 usage()
 {
 void
 usage()
 {
-       (void)fprintf(stderr, "usage: ls [-1ACFLRTacdfiklqrstu] [file ...]\n");
+       (void)fprintf(stderr, "usage: ls [-1ACFLRTWacdfiklqrstu] [file ...]\n");
        exit(1);
 }
        exit(1);
 }
index 4698447..299a23c 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.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)rm.c       8.6 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -27,7 +27,7 @@ static char sccsid[] = "@(#)rm.c      8.5 (Berkeley) %G%";
 #include <string.h>
 #include <unistd.h>
 
 #include <string.h>
 #include <unistd.h>
 
-int dflag, eval, fflag, iflag, Pflag, stdin_ok;
+int dflag, eval, fflag, iflag, Pflag, Wflag, stdin_ok;
 
 int    check __P((char *, char *, struct stat *));
 void   checkdot __P((char **));
 
 int    check __P((char *, char *, struct stat *));
 void   checkdot __P((char **));
@@ -51,7 +51,7 @@ main(argc, argv)
        int ch, rflag;
 
        Pflag = rflag = 0;
        int ch, rflag;
 
        Pflag = rflag = 0;
-       while ((ch = getopt(argc, argv, "dfiPRr")) != EOF)
+       while ((ch = getopt(argc, argv, "dfiPRrW")) != EOF)
                switch(ch) {
                case 'd':
                        dflag = 1;
                switch(ch) {
                case 'd':
                        dflag = 1;
@@ -71,6 +71,9 @@ main(argc, argv)
                case 'r':                       /* Compatibility. */
                        rflag = 1;
                        break;
                case 'r':                       /* Compatibility. */
                        rflag = 1;
                        break;
+               case 'W':
+                       Wflag = 1;
+                       break;
                case '?':
                default:
                        usage();
                case '?':
                default:
                        usage();
@@ -101,6 +104,7 @@ rm_tree(argv)
        FTS *fts;
        FTSENT *p;
        int needstat;
        FTS *fts;
        FTSENT *p;
        int needstat;
+       int flags;
 
        /*
         * Remove a file hierarchy.  If forcing removal (-f), or interactive
 
        /*
         * Remove a file hierarchy.  If forcing removal (-f), or interactive
@@ -114,9 +118,12 @@ rm_tree(argv)
         */
 #define        SKIPPED 1
 
         */
 #define        SKIPPED 1
 
-       if (!(fts = fts_open(argv,
-           needstat ? FTS_PHYSICAL : FTS_PHYSICAL|FTS_NOSTAT,
-           (int (*)())NULL)))
+       flags = FTS_PHYSICAL;
+       if (!needstat)
+               flags |= FTS_NOSTAT;
+       if (Wflag)
+               flags |= FTS_WHITEOUT;
+       if (!(fts = fts_open(argv, flags, (int (*)())NULL)))
                err(1, NULL);
        while ((p = fts_read(fts)) != NULL) {
                switch (p->fts_info) {
                err(1, NULL);
        while ((p = fts_read(fts)) != NULL) {
                switch (p->fts_info) {
@@ -165,7 +172,9 @@ rm_tree(argv)
                 * able to remove it.  Don't print out the un{read,search}able
                 * message unless the remove fails.
                 */
                 * able to remove it.  Don't print out the un{read,search}able
                 * message unless the remove fails.
                 */
-               if (p->fts_info == FTS_DP || p->fts_info == FTS_DNR) {
+               switch (p->fts_info) {
+               case FTS_DP:
+               case FTS_DNR:
                        if (!rmdir(p->fts_accpath))
                                continue;
                        if (errno == ENOENT) {
                        if (!rmdir(p->fts_accpath))
                                continue;
                        if (errno == ENOENT) {
@@ -173,7 +182,15 @@ rm_tree(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 {
+                       break;
+
+               case FTS_W:
+                       if (!unwhiteout(p->fts_accpath) ||
+                           fflag && errno == ENOENT)
+                               continue;
+                       break;
+
+               default:
                        if (Pflag)
                                rm_overwrite(p->fts_accpath, NULL);
                        if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
                        if (Pflag)
                                rm_overwrite(p->fts_accpath, NULL);
                        if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
@@ -202,20 +219,31 @@ rm_file(argv)
        while ((f = *argv++) != NULL) {
                /* Assume if can't stat the file, can't unlink it. */
                if (lstat(f, &sb)) {
        while ((f = *argv++) != NULL) {
                /* Assume if can't stat the file, can't unlink it. */
                if (lstat(f, &sb)) {
-                       if (!fflag || errno != ENOENT) {
-                               warn("%s", f);
-                               eval = 1;
+                       if (Wflag) {
+                               sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
+                       } else {
+                               if (!fflag || errno != ENOENT) {
+                                       warn("%s", f);
+                                       eval = 1;
+                               }
+                               continue;
                        }
                        }
+               } else if (Wflag) {
+                       warnx("%s: %s", f, strerror(EEXIST));
+                       eval = 1;
                        continue;
                }
                        continue;
                }
+
                if (S_ISDIR(sb.st_mode) && !df) {
                        warnx("%s: is a directory", f);
                        eval = 1;
                        continue;
                }
                if (S_ISDIR(sb.st_mode) && !df) {
                        warnx("%s: is a directory", f);
                        eval = 1;
                        continue;
                }
-               if (!fflag && !check(f, f, &sb))
+               if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
                        continue;
                        continue;
-               if (S_ISDIR(sb.st_mode))
+               if (S_ISWHT(sb.st_mode))
+                       rval = unwhiteout(f);
+               else if (S_ISDIR(sb.st_mode))
                        rval = rmdir(f);
                else {
                        if (Pflag)
                        rval = rmdir(f);
                else {
                        if (Pflag)
index 873df55..37dbea5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)dirent.h    8.1 (Berkeley) %G%
+ *     @(#)dirent.h    8.2 (Berkeley) %G%
  */
 
 #ifndef _DIRENT_H_
  */
 
 #ifndef _DIRENT_H_
@@ -34,10 +34,17 @@ typedef struct _dirdesc {
        int     dd_len;         /* size of data buffer */
        long    dd_seek;        /* magic cookie returned by getdirentries */
        long    dd_rewind;      /* magic cookie for rewinding */
        int     dd_len;         /* size of data buffer */
        long    dd_seek;        /* magic cookie returned by getdirentries */
        long    dd_rewind;      /* magic cookie for rewinding */
+       int     dd_flags;       /* flags for readdir */
 } DIR;
 
 #define        dirfd(dirp)     ((dirp)->dd_fd)
 
 } DIR;
 
 #define        dirfd(dirp)     ((dirp)->dd_fd)
 
+/* flags for opendir2 */
+#define DTF_HIDEW      0x0001  /* hide whiteout entries */
+#define DTF_NODUP      0x0002  /* don't return duplicate names */
+#define DTF_REWIND     0x0004  /* rewind after reading union stack */
+#define __DTF_READALL  0x0008  /* everything has been read */
+
 #ifndef NULL
 #define        NULL    0
 #endif
 #ifndef NULL
 #define        NULL    0
 #endif
@@ -54,6 +61,7 @@ struct dirent *readdir __P((DIR *));
 void rewinddir __P((DIR *));
 int closedir __P((DIR *));
 #ifndef _POSIX_SOURCE
 void rewinddir __P((DIR *));
 int closedir __P((DIR *));
 #ifndef _POSIX_SOURCE
+DIR *__opendir2 __P((const char *, int));
 long telldir __P((const DIR *));
 void seekdir __P((DIR *, long));
 int scandir __P((const char *, struct dirent ***,
 long telldir __P((const DIR *));
 void seekdir __P((DIR *, long));
 int scandir __P((const char *, struct dirent ***,
index f4f7a18..7d7377b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)fts.h       8.1 (Berkeley) %G%
+ *     @(#)fts.h       8.2 (Berkeley) %G%
  */
 
 #ifndef        _FTS_H_
  */
 
 #ifndef        _FTS_H_
@@ -28,10 +28,11 @@ typedef struct {
 #define        FTS_PHYSICAL    0x010           /* physical walk */
 #define        FTS_SEEDOT      0x020           /* return dot and dot-dot */
 #define        FTS_XDEV        0x040           /* don't cross devices */
 #define        FTS_PHYSICAL    0x010           /* physical walk */
 #define        FTS_SEEDOT      0x020           /* return dot and dot-dot */
 #define        FTS_XDEV        0x040           /* don't cross devices */
-#define        FTS_OPTIONMASK  0x07f           /* valid user option mask */
+#define        FTS_WHITEOUT    0x080           /* return whiteout information */
+#define        FTS_OPTIONMASK  0x0ff           /* valid user option mask */
 
 
-#define        FTS_NAMEONLY    0x080           /* (private) child names only */
-#define        FTS_STOP        0x100           /* (private) unrecoverable error */
+#define        FTS_NAMEONLY    0x100           /* (private) child names only */
+#define        FTS_STOP        0x200           /* (private) unrecoverable error */
        int fts_options;                /* fts_open options, global flags */
 } FTS;
 
        int fts_options;                /* fts_open options, global flags */
 } FTS;
 
@@ -69,10 +70,13 @@ typedef struct _ftsent {
 #define        FTS_NSOK        11              /* no stat(2) requested */
 #define        FTS_SL          12              /* symbolic link */
 #define        FTS_SLNONE      13              /* symbolic link without target */
 #define        FTS_NSOK        11              /* no stat(2) requested */
 #define        FTS_SL          12              /* symbolic link */
 #define        FTS_SLNONE      13              /* symbolic link without target */
+#define        FTS_W           14              /* whiteout object */
        u_short fts_info;               /* user flags for FTSENT structure */
 
 #define        FTS_DONTCHDIR    0x01           /* don't chdir .. to the parent */
 #define        FTS_SYMFOLLOW    0x02           /* followed a symlink to get here */
        u_short fts_info;               /* user flags for FTSENT structure */
 
 #define        FTS_DONTCHDIR    0x01           /* don't chdir .. to the parent */
 #define        FTS_SYMFOLLOW    0x02           /* followed a symlink to get here */
+#define        FTS_ISW          0x04           /* this is a whiteout object */
+#define        FTS_ISWD         0x08           /* this is a whiteout dir object */
        u_short fts_flags;              /* private flags for FTSENT structure */
 
 #define        FTS_AGAIN        1              /* read node again */
        u_short fts_flags;              /* private flags for FTSENT structure */
 
 #define        FTS_AGAIN        1              /* read node again */
index e4fe6ca..427ff50 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)unistd.h    8.10 (Berkeley) %G%
+ *     @(#)unistd.h    8.11 (Berkeley) %G%
  */
 
 #ifndef _UNISTD_H_
  */
 
 #ifndef _UNISTD_H_
@@ -140,6 +140,7 @@ int  syscall __P((int, ...));
 int     truncate __P((const char *, off_t));
 int     ttyslot __P((void));
 unsigned int    ualarm __P((unsigned int, unsigned int));
 int     truncate __P((const char *, off_t));
 int     ttyslot __P((void));
 unsigned int    ualarm __P((unsigned int, unsigned int));
+int     unwhiteout __P((const char *));
 void    usleep __P((unsigned int));
 void   *valloc __P((size_t));                  /* obsoleted by malloc() */
 pid_t   vfork __P((void));
 void    usleep __P((unsigned int));
 void   *valloc __P((size_t));                  /* obsoleted by malloc() */
 pid_t   vfork __P((void));
index da68f91..0a22d54 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)fts.c      8.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)fts.c      8.5 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
@@ -530,7 +530,7 @@ fts_build(sp, type)
        FTSENT *cur, *tail;
        DIR *dirp;
        void *adjaddr;
        FTSENT *cur, *tail;
        DIR *dirp;
        void *adjaddr;
-       int cderrno, descend, len, level, maxlen, nlinks, saved_errno;
+       int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno;
        char *cp;
 
        /* Set current node pointer. */
        char *cp;
 
        /* Set current node pointer. */
@@ -540,7 +540,15 @@ fts_build(sp, type)
         * Open the directory for reading.  If this fails, we're done.
         * If being called from fts_read, set the fts_info field.
         */
         * Open the directory for reading.  If this fails, we're done.
         * If being called from fts_read, set the fts_info field.
         */
-       if ((dirp = opendir(cur->fts_accpath)) == NULL) {
+#ifdef FTS_WHITEOUT
+       if (ISSET(FTS_WHITEOUT))
+               oflag = DTF_NODUP|DTF_REWIND;
+       else
+               oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
+#else
+#define __opendir2(path, flag) opendir(path)
+#endif
+       if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
                if (type == BREAD) {
                        cur->fts_info = FTS_DNR;
                        cur->fts_errno = errno;
                if (type == BREAD) {
                        cur->fts_info = FTS_DNR;
                        cur->fts_errno = errno;
@@ -645,6 +653,17 @@ mem1:                              saved_errno = errno;
                p->fts_parent = sp->fts_cur;
                p->fts_level = level;
 
                p->fts_parent = sp->fts_cur;
                p->fts_level = level;
 
+#ifdef FTS_WHITEOUT
+               switch (dp->d_type) {
+               case DT_WHT:
+                       p->fts_flags |= FTS_ISW;
+                       break;
+               case DT_WHTD:
+                       p->fts_flags |= FTS_ISWD;
+                       break;
+               }
+#endif
+
                if (cderrno) {
                        if (nlinks) {
                                p->fts_info = FTS_NS;
                if (cderrno) {
                        if (nlinks) {
                                p->fts_info = FTS_NS;
@@ -748,6 +767,17 @@ fts_stat(sp, p, follow)
 
        /* If user needs stat info, stat buffer already allocated. */
        sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
 
        /* If user needs stat info, stat buffer already allocated. */
        sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#ifdef FTS_WHITEOUT
+       /* check for whiteout */
+       if (p->fts_flags & (FTS_ISW|FTS_ISWD)) {
+               if (sbp != &sb) {
+                       memset(sbp, '\0', sizeof (*sbp));
+                       sbp->st_mode = S_IFWHT;
+               }
+               return (FTS_W);
+       }
+#endif
        
        /*
         * If doing a logical walk, or application requested FTS_FOLLOW, do
        
        /*
         * If doing a logical walk, or application requested FTS_FOLLOW, do
index a2f2bc3..9e6e08c 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)opendir.c  8.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)opendir.c  8.5 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
@@ -24,12 +24,21 @@ DIR *
 opendir(name)
        const char *name;
 {
 opendir(name)
        const char *name;
 {
+
+       return (__opendir2(name, DTF_HIDEW|DTF_NODUP));
+}
+
+DIR *
+__opendir2(name, flags)
+       const char *name;
+       int flags;
+{
        DIR *dirp;
        int fd;
        int incr;
        DIR *dirp;
        int fd;
        int incr;
-       struct statfs sfb;
+       int unionstack;
 
 
-       if ((fd = open(name, 0)) == -1)
+       if ((fd = open(name, O_RDONLY)) == -1)
                return (NULL);
        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
            (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
                return (NULL);
        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
            (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
@@ -48,17 +57,23 @@ opendir(name)
        else
                incr = DIRBLKSIZ;
 
        else
                incr = DIRBLKSIZ;
 
-#ifdef MOUNT_UNION
        /*
         * Determine whether this directory is the top of a union stack.
         */
        /*
         * Determine whether this directory is the top of a union stack.
         */
-       if (fstatfs(fd, &sfb) < 0) {
-               free(dirp);
-               close(fd);
-               return (NULL);
+       if (flags & DTF_NODUP) {
+               struct statfs sfb;
+
+               if (fstatfs(fd, &sfb) < 0) {
+                       free(dirp);
+                       close(fd);
+                       return (NULL);
+               }
+               unionstack = (sfb.f_type == MOUNT_UNION);
+       } else {
+               unionstack = 0;
        }
 
        }
 
-       if (sfb.f_type == MOUNT_UNION) {
+       if (unionstack) {
                int len = 0;
                int space = 0;
                char *buf = 0;
                int len = 0;
                int space = 0;
                char *buf = 0;
@@ -73,11 +88,6 @@ opendir(name)
                 * number to zero.
                 */
 
                 * number to zero.
                 */
 
-               /*
-                * Fixup dd_loc to be non-zero to fake out readdir
-                */
-               dirp->dd_loc = sizeof(void *);
-
                do {
                        /*
                         * Always make at least DIRBLKSIZ bytes
                do {
                        /*
                         * Always make at least DIRBLKSIZ bytes
@@ -92,7 +102,7 @@ opendir(name)
                                        close(fd);
                                        return (NULL);
                                }
                                        close(fd);
                                        return (NULL);
                                }
-                               ddptr = buf + (len - space) + dirp->dd_loc;
+                               ddptr = buf + (len - space);
                        }
 
                        n = getdirentries(fd, ddptr, space, &dirp->dd_seek);
                        }
 
                        n = getdirentries(fd, ddptr, space, &dirp->dd_seek);
@@ -102,6 +112,24 @@ opendir(name)
                        }
                } while (n > 0);
 
                        }
                } while (n > 0);
 
+               flags |= __DTF_READALL;
+
+               /*
+                * Re-open the directory.
+                * This has the effect of rewinding back to the
+                * top of the union stack and is needed by
+                * programs which plan to fchdir to a descriptor
+                * which has also been read -- see fts.c.
+                */
+               if (flags & DTF_REWIND) {
+                       (void) close(fd);
+                       if ((fd = open(name, O_RDONLY)) == -1) {
+                               free(buf);
+                               free(dirp);
+                               return (NULL);
+                       }
+               }
+
                /*
                 * There is now a buffer full of (possibly) duplicate
                 * names.
                /*
                 * There is now a buffer full of (possibly) duplicate
                 * names.
@@ -117,7 +145,7 @@ opendir(name)
                 */
                for (dpv = 0;;) {
                        n = 0;
                 */
                for (dpv = 0;;) {
                        n = 0;
-                       ddptr = buf + dirp->dd_loc;
+                       ddptr = buf;
                        while (ddptr < buf + len) {
                                struct dirent *dp;
 
                        while (ddptr < buf + len) {
                                struct dirent *dp;
 
@@ -155,9 +183,13 @@ opendir(name)
                                        struct dirent *dp = dpv[n];
 
                                        if ((xp == NULL) ||
                                        struct dirent *dp = dpv[n];
 
                                        if ((xp == NULL) ||
-                                           strcmp(dp->d_name, xp->d_name))
+                                           strcmp(dp->d_name, xp->d_name)) {
                                                xp = dp;
                                                xp = dp;
-                                       else
+                                       } else {
+                                               dp->d_fileno = 0;
+                                       }
+                                       if (DT_ISWHT(dp->d_type) &&
+                                           (flags & DTF_HIDEW))
                                                dp->d_fileno = 0;
                                }
 
                                                dp->d_fileno = 0;
                                }
 
@@ -172,9 +204,7 @@ opendir(name)
 
                dirp->dd_len = len;
                dirp->dd_size = ddptr - dirp->dd_buf;
 
                dirp->dd_len = len;
                dirp->dd_size = ddptr - dirp->dd_buf;
-       } else
-#endif /* MOUNT_UNION */
-       {
+       } else {
                dirp->dd_len = incr;
                dirp->dd_buf = malloc(dirp->dd_len);
                if (dirp->dd_buf == NULL) {
                dirp->dd_len = incr;
                dirp->dd_buf = malloc(dirp->dd_len);
                if (dirp->dd_buf == NULL) {
@@ -183,10 +213,12 @@ opendir(name)
                        return (NULL);
                }
                dirp->dd_seek = 0;
                        return (NULL);
                }
                dirp->dd_seek = 0;
-               dirp->dd_loc = 0;
+               flags &= ~DTF_REWIND;
        }
 
        }
 
+       dirp->dd_loc = 0;
        dirp->dd_fd = fd;
        dirp->dd_fd = fd;
+       dirp->dd_flags = flags;
 
        /*
         * Set up seek point for rewinddir.
 
        /*
         * Set up seek point for rewinddir.
index a3748b7..cab7e54 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)readdir.c  8.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)readdir.c  8.2 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
@@ -22,22 +22,23 @@ readdir(dirp)
        register struct dirent *dp;
 
        for (;;) {
        register struct dirent *dp;
 
        for (;;) {
-               if (dirp->dd_loc == 0) {
+               if (dirp->dd_loc >= dirp->dd_size) {
+                       if (dirp->dd_flags & __DTF_READALL)
+                               return (NULL);
+                       dirp->dd_loc = 0;
+               }
+               if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) {
                        dirp->dd_size = getdirentries(dirp->dd_fd,
                            dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
                        if (dirp->dd_size <= 0)
                        dirp->dd_size = getdirentries(dirp->dd_fd,
                            dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
                        if (dirp->dd_size <= 0)
-                               return NULL;
-               }
-               if (dirp->dd_loc >= dirp->dd_size) {
-                       dirp->dd_loc = 0;
-                       continue;
+                               return (NULL);
                }
                dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
                if ((int)dp & 03)       /* bogus pointer check */
                }
                dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
                if ((int)dp & 03)       /* bogus pointer check */
-                       return NULL;
+                       return (NULL);
                if (dp->d_reclen <= 0 ||
                    dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
                if (dp->d_reclen <= 0 ||
                    dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
-                       return NULL;
+                       return (NULL);
                dirp->dd_loc += dp->d_reclen;
                if (dp->d_ino == 0)
                        continue;
                dirp->dd_loc += dp->d_reclen;
                if (dp->d_ino == 0)
                        continue;
index 43055eb..4bba876 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strmode.c  8.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)strmode.c  8.2 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
@@ -42,6 +42,12 @@ strmode(mode, p)
        case S_IFIFO:                   /* fifo */
                *p++ = 'p';
                break;
        case S_IFIFO:                   /* fifo */
                *p++ = 'p';
                break;
+#endif
+#ifdef S_IFWHT
+       case S_IFWHT:                   /* whiteout */
+       case S_IFWHTD:
+               *p++ = 'w';
+               break;
 #endif
        default:                        /* unknown */
                *p++ = '?';
 #endif
        default:                        /* unknown */
                *p++ = '?';
index d75812f..3615507 100644 (file)
@@ -1,4 +1,4 @@
-#      @(#)Makefile.inc        8.1 (Berkeley) %G%
+#      @(#)Makefile.inc        8.2 (Berkeley) %G%
 
 # Missing: profil.0, ptrace.0
 
 
 # Missing: profil.0, ptrace.0
 
@@ -31,7 +31,7 @@ ASM=  accept.o access.o acct.o adjtime.o bind.o chdir.o chflags.o chmod.o \
        setgroups.o setitimer.o setpgid.o setpriority.o setrlimit.o \
        setsid.o setsockopt.o settimeofday.o setuid.o shutdown.o \
        sigaction.o sigaltstack.o socket.o socketpair.o stat.o statfs.o \
        setgroups.o setitimer.o setpgid.o setpriority.o setrlimit.o \
        setsid.o setsockopt.o settimeofday.o setuid.o shutdown.o \
        sigaction.o sigaltstack.o socket.o socketpair.o stat.o statfs.o \
-       swapon.o symlink.o sync.o umask.o unlink.o unmount.o \
+       swapon.o symlink.o sync.o umask.o unlink.o unmount.o unwhiteout.o \
        utimes.o vadvise.o wait4.o write.o writev.o __syscall.o __sysctl.o
 
 PSEUDO=        _exit.o _getlogin.o
        utimes.o vadvise.o wait4.o write.o writev.o __syscall.o __sysctl.o
 
 PSEUDO=        _exit.o _getlogin.o
@@ -80,7 +80,7 @@ MAN2+=        accept.0 access.0 acct.0 adjtime.0 bind.0 brk.0 chdir.0 chflags.0 \
        sigaction.0 sigpending.0 sigprocmask.0 sigreturn.0 sigaltstack.0 \
        sigstack.0 sigsuspend.0 socket.0 socketpair.0 stat.0 statfs.0 \
        swapon.0 symlink.0 sync.0 syscall.0 truncate.0 umask.0 unlink.0 \
        sigaction.0 sigpending.0 sigprocmask.0 sigreturn.0 sigaltstack.0 \
        sigstack.0 sigsuspend.0 socket.0 socketpair.0 stat.0 statfs.0 \
        swapon.0 symlink.0 sync.0 syscall.0 truncate.0 umask.0 unlink.0 \
-       utimes.0 vfork.0 wait.0 write.0
+       unwhiteout.0 utimes.0 vfork.0 wait.0 write.0
 
 MLINKS+=brk.2 sbrk.2
 MLINKS+=dup.2 dup2.2
 
 MLINKS+=brk.2 sbrk.2
 MLINKS+=dup.2 dup2.2
index 9fc37c4..87ee2e7 100644 (file)
@@ -3,7 +3,7 @@
 .\"
 .\" %sccs.include.redist.roff%
 .\"
 .\"
 .\" %sccs.include.redist.roff%
 .\"
-.\"    @(#)chflags.2   8.1 (Berkeley) %G%
+.\"    @(#)chflags.2   8.2 (Berkeley) %G%
 .\"
 .Dd 
 .Dt CHFLAGS 2
 .\"
 .Dd 
 .Dt CHFLAGS 2
@@ -39,6 +39,8 @@ Do not dump the file.
 The file may not be changed.
 .It UF_APPEND
 The file may only be appended to.
 The file may not be changed.
 .It UF_APPEND
 The file may only be appended to.
+.It UF_OPAQUE
+The directory is opaque when viewed through a union stack.
 .\".It ARCHIVED
 .\"File is archived.
 .It SF_IMMUTABLE
 .\".It ARCHIVED
 .\"File is archived.
 .It SF_IMMUTABLE
@@ -118,8 +120,9 @@ An
 error occurred while reading from or writing to the file system.
 .El
 .Sh SEE ALSO
 error occurred while reading from or writing to the file system.
 .El
 .Sh SEE ALSO
-.Xr chflags 1,
-.Xr init 8
+.Xr chflags 1 ,
+.Xr init 8 ,
+.Xr mount_union 8
 .Sh HISTORY
 The
 .Nm chflags
 .Sh HISTORY
 The
 .Nm chflags
index 4cb0139..da6f610 100644 (file)
@@ -4,7 +4,7 @@
 .\"
 .\" %sccs.include.redist.man%
 .\"
 .\"
 .\" %sccs.include.redist.man%
 .\"
-.\"     @(#)undelete.2 8.1 (Berkeley) %G%
+.\"     @(#)undelete.2 8.2 (Berkeley) %G%
 .\"
 .Dd 
 .Dt UNWHITEOUT 2
 .\"
 .Dd 
 .Dt UNWHITEOUT 2
index cc35d99..44a5b20 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)pass2.c    8.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)pass2.c    8.3 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -317,6 +317,14 @@ chk2:
        if (dirp->d_ino > maxino) {
                fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
                n = reply("REMOVE");
        if (dirp->d_ino > maxino) {
                fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
                n = reply("REMOVE");
+       } else if (newinofmt &&
+                  ((dirp->d_ino == WINO && !DT_ISWHT(dirp->d_type)) ||
+                   (dirp->d_ino != WINO && DT_ISWHT(dirp->d_type)))) {
+               fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
+               dirp->d_ino = WINO;
+               dirp->d_type = DT_WHT;
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
        } else {
 again:
                switch (statemap[dirp->d_ino]) {
        } else {
 again:
                switch (statemap[dirp->d_ino]) {
index 32d4e82..055b5a5 100644 (file)
@@ -9,7 +9,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vfs_syscalls.c      8.18 (Berkeley) %G%
+ *     @(#)vfs_syscalls.c      8.19 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -699,6 +699,7 @@ mknod(p, uap, retval)
        register struct vnode *vp;
        struct vattr vattr;
        int error;
        register struct vnode *vp;
        struct vattr vattr;
        int error;
+       int whiteout;
        struct nameidata nd;
 
        CHECKPOINTREF;
        struct nameidata nd;
 
        CHECKPOINTREF;
@@ -714,6 +715,7 @@ mknod(p, uap, retval)
                VATTR_NULL(&vattr);
                vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
                vattr.va_rdev = uap->dev;
                VATTR_NULL(&vattr);
                vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
                vattr.va_rdev = uap->dev;
+               whiteout = 0;
 
                switch (uap->mode & S_IFMT) {
                case S_IFMT:    /* used by badsect to flag bad sectors */
 
                switch (uap->mode & S_IFMT) {
                case S_IFMT:    /* used by badsect to flag bad sectors */
@@ -725,12 +727,18 @@ mknod(p, uap, retval)
                case S_IFBLK:
                        vattr.va_type = VBLK;
                        break;
                case S_IFBLK:
                        vattr.va_type = VBLK;
                        break;
+               case S_IFWHT:
+                       whiteout = 1;
+                       break;
                default:
                        error = EINVAL;
                        break;
                }
        }
                default:
                        error = EINVAL;
                        break;
                }
        }
-       if (!error) {
+       if (whiteout) {
+               error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
+               vput(nd.ni_dvp);
+       } else if (!error) {
                LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
                error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
        } else {
                LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
                error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
        } else {
@@ -898,10 +906,12 @@ unwhiteout(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
-       if (error = namei(&nd))
+       NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p);
+       error = namei(&nd);
+       if (error)
                return (error);
                return (error);
-       if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) {
+
+       if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                if (nd.ni_dvp == nd.ni_vp)
                        vrele(nd.ni_dvp);
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                if (nd.ni_dvp == nd.ni_vp)
                        vrele(nd.ni_dvp);
@@ -911,8 +921,11 @@ unwhiteout(p, uap, retval)
                        vrele(nd.ni_vp);
                return (EEXIST);
        }
                        vrele(nd.ni_vp);
                return (EEXIST);
        }
+
        LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
        LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
+       if (error != 0)
+               VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
        vput(nd.ni_dvp);
        return (error);
 }
        vput(nd.ni_dvp);
        return (error);
 }
@@ -961,7 +974,8 @@ unlink(p, uap, retval)
                        vrele(nd.ni_dvp);
                else
                        vput(nd.ni_dvp);
                        vrele(nd.ni_dvp);
                else
                        vput(nd.ni_dvp);
-               vput(vp);
+               if (vp != NULLVP)
+                       vput(vp);
        }
        CHECKREFS("unlink");
        return (error);
        }
        CHECKREFS("unlink");
        return (error);
@@ -2021,6 +2035,20 @@ unionread:
                struct vnode *lvp;
 
                lvp = union_lowervp(vp);
                struct vnode *lvp;
 
                lvp = union_lowervp(vp);
+               if (lvp != NULLVP) {
+                       struct vattr va;
+
+                       /*
+                        * If the directory is opaque,
+                        * then don't show lower entries
+                        */
+                       error = VOP_GETATTR(vp, &va, fp->f_cred, p);
+                       if (va.va_flags & OPAQUE) {
+                               vrele(lvp);
+                               lvp = NULL;
+                       }
+               }
+               
                if (lvp != NULLVP) {
                        VOP_LOCK(lvp);
                        error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
                if (lvp != NULLVP) {
                        VOP_LOCK(lvp);
                        error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
@@ -2114,6 +2142,20 @@ unionread:
                struct vnode *lvp;
 
                lvp = union_lowervp(vp);
                struct vnode *lvp;
 
                lvp = union_lowervp(vp);
+               if (lvp != NULLVP) {
+                       struct vattr va;
+
+                       /*
+                        * If the directory is opaque,
+                        * then don't show lower entries
+                        */
+                       error = VOP_GETATTR(vp, &va, fp->f_cred, p);
+                       if (va.va_flags & OPAQUE) {
+                               vrele(lvp);
+                               lvp = NULL;
+                       }
+               }
+               
                if (lvp != NULLVP) {
                        VOP_LOCK(lvp);
                        error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
                if (lvp != NULLVP) {
                        VOP_LOCK(lvp);
                        error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
index a39ad69..6788324 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union.h     8.6 (Berkeley) %G%
+ *     @(#)union.h     8.7 (Berkeley) %G%
  */
 
 struct union_args {
  */
 
 struct union_args {
@@ -76,6 +76,8 @@ extern int union_copyup __P((struct union_node *, int, struct ucred *,
                                struct proc *));
 extern int union_mkshadow __P((struct union_mount *, struct vnode *,
                                struct componentname *, struct vnode **));
                                struct proc *));
 extern int union_mkshadow __P((struct union_mount *, struct vnode *,
                                struct componentname *, struct vnode **));
+extern int union_mkwhiteout __P((struct union_mount *, struct vnode *,
+                               struct componentname *, char *));
 extern int union_vn_create __P((struct vnode **, struct union_node *,
                                struct proc *));
 extern int union_cn_close __P((struct vnode *, int, struct ucred *,
 extern int union_vn_create __P((struct vnode **, struct union_node *,
                                struct proc *));
 extern int union_cn_close __P((struct vnode *, int, struct ucred *,
index a07ae68..d89ad7d 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_subr.c        8.11 (Berkeley) %G%
+ *     @(#)union_subr.c        8.12 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -391,8 +391,7 @@ loop:
                 */
                if (lowervp != un->un_lowervp) {
                        union_newlower(un, lowervp);
                 */
                if (lowervp != un->un_lowervp) {
                        union_newlower(un, lowervp);
-                       if (cnp && (lowervp != NULLVP) &&
-                           (lowervp->v_type == VREG)) {
+                       if (cnp && (lowervp != NULLVP)) {
                                un->un_hash = cnp->cn_hash;
                                un->un_path = malloc(cnp->cn_namelen+1,
                                                M_TEMP, M_WAITOK);
                                un->un_hash = cnp->cn_hash;
                                un->un_path = malloc(cnp->cn_namelen+1,
                                                M_TEMP, M_WAITOK);
@@ -459,7 +458,7 @@ loop:
        else
                un->un_pid = -1;
 #endif
        else
                un->un_pid = -1;
 #endif
-       if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {
+       if (cnp && (lowervp != NULLVP)) {
                un->un_hash = cnp->cn_hash;
                un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
                bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
                un->un_hash = cnp->cn_hash;
                un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
                bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
@@ -655,6 +654,52 @@ union_copyup(un, docopy, cred, p)
 
 }
 
 
 }
 
+static int
+union_relookup(um, dvp, vpp, cnp, cn, path)
+       struct union_mount *um;
+       struct vnode *dvp;
+       struct vnode **vpp;
+       struct componentname *cnp;
+       struct componentname *cn;
+       char *path;
+{
+       int error;
+
+       /*
+        * A new componentname structure must be faked up because
+        * there is no way to know where the upper level cnp came
+        * from or what it is being used for.  This must duplicate
+        * some of the work done by NDINIT, some of the work done
+        * by namei, some of the work done by lookup and some of
+        * the work done by VOP_LOOKUP when given a CREATE flag.
+        * Conclusion: Horrible.
+        *
+        * The pathname buffer will be FREEed by VOP_MKDIR.
+        */
+       cn->cn_namelen = strlen(path);
+       cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK);
+       bcopy(path, cn->cn_pnbuf, cn->cn_namelen);
+       cn->cn_pnbuf[cn->cn_namelen] = '\0';
+
+       cn->cn_nameiop = CREATE;
+       cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
+       cn->cn_proc = cnp->cn_proc;
+       if (um->um_op == UNMNT_ABOVE)
+               cn->cn_cred = cnp->cn_cred;
+       else
+               cn->cn_cred = um->um_cred;
+       cn->cn_nameptr = cn->cn_pnbuf;
+       cn->cn_hash = cnp->cn_hash;
+       cn->cn_consume = cnp->cn_consume;
+
+       VREF(dvp);
+       error = relookup(dvp, vpp, cn);
+       if (!error)
+               vrele(dvp);
+
+       return (error);
+}
+
 /*
  * Create a shadow directory in the upper layer.
  * The new vnode is returned locked.
 /*
  * Create a shadow directory in the upper layer.
  * The new vnode is returned locked.
@@ -679,6 +724,18 @@ union_mkshadow(um, dvp, cnp, vpp)
        struct proc *p = cnp->cn_proc;
        struct componentname cn;
 
        struct proc *p = cnp->cn_proc;
        struct componentname cn;
 
+       error = union_relookup(um, dvp, vpp, cnp, &cn, cnp->cn_nameptr);
+       if (error)
+               return (error);
+
+       if (*vpp) {
+               VOP_ABORTOP(dvp, &cn);
+               VOP_UNLOCK(dvp);
+               vrele(*vpp);
+               *vpp = NULLVP;
+               return (EEXIST);
+       }
+
        /*
         * policy: when creating the shadow directory in the
         * upper layer, create it owned by the user who did
        /*
         * policy: when creating the shadow directory in the
         * upper layer, create it owned by the user who did
@@ -687,54 +744,61 @@ union_mkshadow(um, dvp, cnp, vpp)
         * mkdir syscall).  (jsp, kb)
         */
 
         * mkdir syscall).  (jsp, kb)
         */
 
-       /*
-        * A new componentname structure must be faked up because
-        * there is no way to know where the upper level cnp came
-        * from or what it is being used for.  This must duplicate
-        * some of the work done by NDINIT, some of the work done
-        * by namei, some of the work done by lookup and some of
-        * the work done by VOP_LOOKUP when given a CREATE flag.
-        * Conclusion: Horrible.
-        *
-        * The pathname buffer will be FREEed by VOP_MKDIR.
-        */
-       cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);
-       bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);
-       cn.cn_pnbuf[cnp->cn_namelen] = '\0';
+       VATTR_NULL(&va);
+       va.va_type = VDIR;
+       va.va_mode = um->um_cmode;
 
 
-       cn.cn_nameiop = CREATE;
-       cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
-       cn.cn_proc = cnp->cn_proc;
-       if (um->um_op == UNMNT_ABOVE)
-               cn.cn_cred = cnp->cn_cred;
-       else
-               cn.cn_cred = um->um_cred;
-       cn.cn_nameptr = cn.cn_pnbuf;
-       cn.cn_namelen = cnp->cn_namelen;
-       cn.cn_hash = cnp->cn_hash;
-       cn.cn_consume = cnp->cn_consume;
+       /* LEASE_CHECK: dvp is locked */
+       LEASE_CHECK(dvp, p, cn.cn_cred, LEASE_WRITE);
 
 
-       VREF(dvp);
-       if (error = relookup(dvp, vpp, &cn))
+       error = VOP_MKDIR(dvp, vpp, &cn, &va);
+       return (error);
+}
+
+/*
+ * Create a whiteout entry in the upper layer.
+ *
+ * (um) points to the union mount structure for access to the
+ * the mounting process's credentials.
+ * (dvp) is the directory in which to create the whiteout.
+ * it is locked on entry and exit.
+ * (cnp) is the componentname to be created.
+ */
+int
+union_mkwhiteout(um, dvp, cnp, path)
+       struct union_mount *um;
+       struct vnode *dvp;
+       struct componentname *cnp;
+       char *path;
+{
+       int error;
+       struct vattr va;
+       struct proc *p = cnp->cn_proc;
+       struct vnode **vpp;
+       struct componentname cn;
+
+       VOP_UNLOCK(dvp);
+       error = union_relookup(um, dvp, vpp, cnp, &cn, path);
+       if (error)
                return (error);
                return (error);
-       vrele(dvp);
 
        if (*vpp) {
                VOP_ABORTOP(dvp, &cn);
 
        if (*vpp) {
                VOP_ABORTOP(dvp, &cn);
-               VOP_UNLOCK(dvp);
+               vrele(dvp);
                vrele(*vpp);
                *vpp = NULLVP;
                return (EEXIST);
        }
 
                vrele(*vpp);
                *vpp = NULLVP;
                return (EEXIST);
        }
 
-       VATTR_NULL(&va);
-       va.va_type = VDIR;
-       va.va_mode = um->um_cmode;
-
        /* LEASE_CHECK: dvp is locked */
        LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
 
        /* LEASE_CHECK: dvp is locked */
        LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
 
-       error = VOP_MKDIR(dvp, vpp, &cn, &va);
+       error = VOP_WHITEOUT(dvp, &cn, CREATE);
+       if (error != 0)
+               VOP_ABORTOP(dvp, &cn);
+
+       vrele(dvp);
+
        return (error);
 }
 
        return (error);
 }
 
@@ -833,6 +897,7 @@ union_vn_close(vp, fmode, cred, p)
        struct ucred *cred;
        struct proc *p;
 {
        struct ucred *cred;
        struct proc *p;
 {
+
        if (fmode & FWRITE)
                --vp->v_writecount;
        return (VOP_CLOSE(vp, fmode));
        if (fmode & FWRITE)
                --vp->v_writecount;
        return (VOP_CLOSE(vp, fmode));
index 9d1122b..be5abd6 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_vfsops.c      8.11 (Berkeley) %G%
+ *     @(#)union_vfsops.c      8.12 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -43,7 +43,7 @@ union_mount(mp, path, data, ndp, p)
        struct union_args args;
        struct vnode *lowerrootvp = NULLVP;
        struct vnode *upperrootvp = NULLVP;
        struct union_args args;
        struct vnode *lowerrootvp = NULLVP;
        struct vnode *upperrootvp = NULLVP;
-       struct union_mount *um;
+       struct union_mount *um = 0;
        struct ucred *cred = 0;
        struct ucred *scred;
        struct vattr va;
        struct ucred *cred = 0;
        struct ucred *scred;
        struct vattr va;
@@ -68,34 +68,6 @@ union_mount(mp, path, data, ndp, p)
                goto bad;
        }
 
                goto bad;
        }
 
-       /*
-        * Take a copy of the process's credentials.  This isn't
-        * quite right since the euid will always be zero and we
-        * want to get the "real" users credentials.  So fix up
-        * the uid field after taking the copy.
-        */
-       cred = crdup(p->p_ucred);
-       cred->cr_uid = p->p_cred->p_ruid;
-
-       /*
-        * Ensure the *real* user has write permission on the
-        * mounted-on directory.  This allows the mount_union
-        * command to be made setuid root so allowing anyone
-        * to do union mounts onto any directory on which they
-        * have write permission and which they also own.
-        */
-       error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
-       if (error)
-               goto bad;
-       if ((va.va_uid != cred->cr_uid) && 
-           (cred->cr_uid != 0)) {
-               error = EACCES;
-               goto bad;
-       }
-       error = VOP_ACCESS(mp->mnt_vnodecovered, VWRITE, cred, p);
-       if (error)
-               goto bad;
-
        /*
         * Get argument
         */
        /*
         * Get argument
         */
@@ -106,18 +78,10 @@ union_mount(mp, path, data, ndp, p)
        VREF(lowerrootvp);
 
        /*
        VREF(lowerrootvp);
 
        /*
-        * Find upper node.  Use the real process credentials,
-        * not the effective ones since this will have come
-        * through a setuid process (mount_union).  All this
-        * messing around with permissions is entirely bogus
-        * and should be removed by allowing any user straight
-        * past the mount system call.
+        * Find upper node.
         */
         */
-       scred = p->p_ucred;
-       p->p_ucred = cred;
        NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
               UIO_USERSPACE, args.target, p);
        NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
               UIO_USERSPACE, args.target, p);
-       p->p_ucred = scred;
 
        if (error = namei(ndp))
                goto bad;
 
        if (error = namei(ndp))
                goto bad;
@@ -167,7 +131,18 @@ union_mount(mp, path, data, ndp, p)
                goto bad;
        }
 
                goto bad;
        }
 
-       um->um_cred = cred;
+       /*
+        * Unless the mount is readonly, ensure that the top layer
+        * supports whiteout operations
+        */
+       if ((mp->mnt_flag & MNT_RDONLY) == 0) {
+               error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
+               if (error)
+                       goto bad;
+       }
+
+       um->um_cred = p->p_ucred;
+       crhold(um->um_cred);
        um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
 
        /*
        um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
 
        /*
@@ -195,12 +170,6 @@ union_mount(mp, path, data, ndp, p)
         */
        mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
 
         */
        mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
 
-       /*
-        * This is a user mount.  Privilege check for unmount
-        * will be done in union_unmount.
-        */
-       mp->mnt_flag |= MNT_USER;
-
        mp->mnt_data = (qaddr_t) um;
        getnewfsid(mp, MOUNT_UNION);
 
        mp->mnt_data = (qaddr_t) um;
        getnewfsid(mp, MOUNT_UNION);
 
@@ -234,6 +203,8 @@ union_mount(mp, path, data, ndp, p)
        return (0);
 
 bad:
        return (0);
 
 bad:
+       if (um)
+               free(um, M_UFSMNT);
        if (cred)
                crfree(cred);
        if (upperrootvp)
        if (cred)
                crfree(cred);
        if (upperrootvp)
@@ -278,11 +249,6 @@ union_unmount(mp, mntflags, p)
        printf("union_unmount(mp = %x)\n", mp);
 #endif
 
        printf("union_unmount(mp = %x)\n", mp);
 #endif
 
-       /* only the mounter, or superuser can unmount */
-       if ((p->p_cred->p_ruid != um->um_cred->cr_uid) &&
-           (error = suser(p->p_ucred, &p->p_acflag)))
-               return (error);
-
        if (mntflags & MNT_FORCE) {
                /* union can never be rootfs so don't check for it */
                if (!doforce)
        if (mntflags & MNT_FORCE) {
                /* union can never be rootfs so don't check for it */
                if (!doforce)
index 75c237c..fa576fb 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_vnops.c       8.18 (Berkeley) %G%
+ *     @(#)union_vnops.c       8.19 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -16,6 +16,7 @@
 #include <sys/proc.h>
 #include <sys/file.h>
 #include <sys/time.h>
 #include <sys/proc.h>
 #include <sys/file.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/vnode.h>
 #include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/vnode.h>
 #include <sys/mount.h>
@@ -137,6 +138,8 @@ union_lookup(ap)
        int rdonly = cnp->cn_flags & RDONLY;
        struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
        struct ucred *saved_cred;
        int rdonly = cnp->cn_flags & RDONLY;
        struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
        struct ucred *saved_cred;
+       int iswhiteout;
+       struct vattr va;
 
 #ifdef notyet
        if (cnp->cn_namelen == 3 &&
 
 #ifdef notyet
        if (cnp->cn_namelen == 3 &&
@@ -160,6 +163,7 @@ union_lookup(ap)
        lowerdvp = dun->un_lowervp;
        uppervp = NULLVP;
        lowervp = NULLVP;
        lowerdvp = dun->un_lowervp;
        uppervp = NULLVP;
        lowervp = NULLVP;
+       iswhiteout = 0;
 
        /*
         * do the lookup in the upper level.
 
        /*
         * do the lookup in the upper level.
@@ -180,6 +184,16 @@ union_lookup(ap)
                                cnp->cn_flags &= ~LOCKPARENT;
                        return (uerror);
                }
                                cnp->cn_flags &= ~LOCKPARENT;
                        return (uerror);
                }
+               if (uerror == ENOENT || uerror == EJUSTRETURN) {
+                       if (cnp->cn_flags & ISWHITEOUT) {
+                               iswhiteout = 1;
+                       } else if (lowerdvp != NULLVP) {
+                               lerror = VOP_GETATTR(upperdvp, &va,
+                                       cnp->cn_cred, cnp->cn_proc);
+                               if (lerror == 0 && (va.va_flags & OPAQUE))
+                                       iswhiteout = 1;
+                       }
+               }
        } else {
                uerror = ENOENT;
        }
        } else {
                uerror = ENOENT;
        }
@@ -191,7 +205,7 @@ union_lookup(ap)
         * back from the upper layer and return the lower vnode
         * instead.
         */
         * back from the upper layer and return the lower vnode
         * instead.
         */
-       if (lowerdvp != NULLVP) {
+       if (lowerdvp != NULLVP && !iswhiteout) {
                int nameiop;
 
                VOP_LOCK(lowerdvp);
                int nameiop;
 
                VOP_LOCK(lowerdvp);
@@ -355,6 +369,23 @@ union_create(ap)
        return (EROFS);
 }
 
        return (EROFS);
 }
 
+int
+union_whiteout(ap)
+       struct vop_whiteout_args /* {
+               struct vnode *a_dvp;
+               struct componentname *a_cnp;
+               int a_flags;
+       } */ *ap;
+{
+       struct union_node *un = VTOUNION(ap->a_dvp);
+
+       if (un->un_uppervp == NULLVP)
+               return (EOPNOTSUPP);
+
+       FIXUP(un);
+       return (VOP_WHITEOUT(un->un_uppervp, ap->a_cnp, ap->a_flags));
+}
+
 int
 union_mknod(ap)
        struct vop_mknod_args /* {
 int
 union_mknod(ap)
        struct vop_mknod_args /* {
@@ -617,21 +648,11 @@ union_setattr(ap)
         */
        if ((un->un_uppervp == NULLVP) &&
            /* assert(un->un_lowervp != NULLVP) */
         */
        if ((un->un_uppervp == NULLVP) &&
            /* assert(un->un_lowervp != NULLVP) */
-           (un->un_lowervp->v_type == VREG) &&
-           (ap->a_vap->va_size == 0)) {
-               struct vnode *vp;
-
-               error = union_vn_create(&vp, un, ap->a_p);
+           (un->un_lowervp->v_type == VREG)) {
+               error = union_copyup(un, (ap->a_vap->va_size != 0),
+                                               ap->a_cred, ap->a_p);
                if (error)
                        return (error);
                if (error)
                        return (error);
-
-               /* at this point, uppervp is locked */
-               union_newupper(un, vp);
-
-               VOP_UNLOCK(vp);
-               union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p);
-               VOP_LOCK(vp);
-               un->un_flags |= UN_ULOCK;
        }
 
        /*
        }
 
        /*
@@ -704,32 +725,25 @@ union_write(ap)
        } */ *ap;
 {
        int error;
        } */ *ap;
 {
        int error;
-       struct vnode *vp = OTHERVP(ap->a_vp);
-       int dolock = (vp == LOWERVP(ap->a_vp));
+       struct vnode *vp;
+       struct union_node *un = VTOUNION(ap->a_vp);
 
 
-       if (dolock)
-               VOP_LOCK(vp);
-       else
-               FIXUP(VTOUNION(ap->a_vp));
+       vp = UPPERVP(ap->a_vp);
+       if (vp == NULLVP)
+               panic("union: missing upper layer in write");
+
+       FIXUP(un);
        error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
        error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
-       if (dolock)
-               VOP_UNLOCK(vp);
 
        /*
         * the size of the underlying object may be changed by the
         * write.
         */
        if (error == 0) {
 
        /*
         * the size of the underlying object may be changed by the
         * write.
         */
        if (error == 0) {
-               struct union_node *un = VTOUNION(ap->a_vp);
                off_t cur = ap->a_uio->uio_offset;
 
                off_t cur = ap->a_uio->uio_offset;
 
-               if (vp == un->un_uppervp) {
-                       if (cur > un->un_uppersz)
-                               union_newsize(ap->a_vp, cur, VNOVAL);
-               } else {
-                       if (cur > un->un_lowersz)
-                               union_newsize(ap->a_vp, VNOVAL, cur);
-               }
+               if (cur > un->un_uppersz)
+                       union_newsize(ap->a_vp, cur, VNOVAL);
        }
 
        return (error);
        }
 
        return (error);
@@ -833,7 +847,10 @@ union_remove(ap)
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
 
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
 
-       if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
+       if (dun->un_uppervp == NULLVP)
+               panic("union remove: null upper vnode");
+
+       if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
@@ -846,20 +863,18 @@ union_remove(ap)
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
+               if (un->un_lowervp != NULLVP)
+                       ap->a_cnp->cn_flags |= DOWHITEOUT;
                error = VOP_REMOVE(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
                error = VOP_REMOVE(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
-
-               /*
-                * XXX: should create a whiteout here
-                */
        } else {
        } else {
-               /*
-                * XXX: should create a whiteout here
-                */
+               FIXUP(dun);
+               error = union_mkwhiteout(
+                       MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
+                       dun->un_uppervp, ap->a_cnp, un->un_path);
                vput(ap->a_dvp);
                vput(ap->a_vp);
                vput(ap->a_dvp);
                vput(ap->a_vp);
-               error = EROFS;
        }
 
        return (error);
        }
 
        return (error);
@@ -939,7 +954,13 @@ union_rename(ap)
        if (fdvp->v_op == union_vnodeop_p) {    /* always true */
                struct union_node *un = VTOUNION(fdvp);
                if (un->un_uppervp == NULLVP) {
        if (fdvp->v_op == union_vnodeop_p) {    /* always true */
                struct union_node *un = VTOUNION(fdvp);
                if (un->un_uppervp == NULLVP) {
-                       error = EROFS;
+                       /*
+                        * this should never happen in normal
+                        * operation but might if there was
+                        * a problem creating the top-level shadow
+                        * directory.
+                        */
+                       error = EXDEV;
                        goto bad;
                }
 
                        goto bad;
                }
 
@@ -951,10 +972,14 @@ union_rename(ap)
        if (fvp->v_op == union_vnodeop_p) {     /* always true */
                struct union_node *un = VTOUNION(fvp);
                if (un->un_uppervp == NULLVP) {
        if (fvp->v_op == union_vnodeop_p) {     /* always true */
                struct union_node *un = VTOUNION(fvp);
                if (un->un_uppervp == NULLVP) {
-                       error = EROFS;
+                       /* XXX: should do a copyup */
+                       error = EXDEV;
                        goto bad;
                }
 
                        goto bad;
                }
 
+               if (un->un_lowervp != NULLVP)
+                       ap->a_fcnp->cn_flags |= DOWHITEOUT;
+
                fvp = un->un_uppervp;
                VREF(fvp);
                vrele(ap->a_fvp);
                fvp = un->un_uppervp;
                VREF(fvp);
                vrele(ap->a_fvp);
@@ -969,7 +994,7 @@ union_rename(ap)
                         * a problem creating the top-level shadow
                         * directory.
                         */
                         * a problem creating the top-level shadow
                         * directory.
                         */
-                       error = EROFS;
+                       error = EXDEV;
                        goto bad;
                }
 
                        goto bad;
                }
 
@@ -1055,7 +1080,10 @@ union_rmdir(ap)
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
 
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
 
-       if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
+       if (dun->un_uppervp == NULLVP)
+               panic("union rmdir: null upper vnode");
+
+       if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
@@ -1068,20 +1096,18 @@ union_rmdir(ap)
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
+               if (un->un_lowervp != NULLVP)
+                       ap->a_cnp->cn_flags |= DOWHITEOUT;
                error = VOP_RMDIR(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
                error = VOP_RMDIR(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
-
-               /*
-                * XXX: should create a whiteout here
-                */
        } else {
        } else {
-               /*
-                * XXX: should create a whiteout here
-                */
+               FIXUP(dun);
+               error = union_mkwhiteout(
+                       MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
+                       dun->un_uppervp, ap->a_cnp, un->un_path);
                vput(ap->a_dvp);
                vput(ap->a_vp);
                vput(ap->a_dvp);
                vput(ap->a_vp);
-               error = EROFS;
        }
 
        return (error);
        }
 
        return (error);
@@ -1453,6 +1479,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = {
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, union_lookup },             /* lookup */
        { &vop_create_desc, union_create },             /* create */
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, union_lookup },             /* lookup */
        { &vop_create_desc, union_create },             /* create */
+       { &vop_whiteout_desc, union_whiteout },         /* whiteout */
        { &vop_mknod_desc, union_mknod },               /* mknod */
        { &vop_open_desc, union_open },                 /* open */
        { &vop_close_desc, union_close },               /* close */
        { &vop_mknod_desc, union_mknod },               /* mknod */
        { &vop_open_desc, union_open },                 /* open */
        { &vop_close_desc, union_close },               /* close */
index 26e253c..8a6c547 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)namei.h     8.2 (Berkeley) %G%
+ *     @(#)namei.h     8.3 (Berkeley) %G%
  */
 
 #ifndef _SYS_NAMEI_H_
  */
 
 #ifndef _SYS_NAMEI_H_
@@ -105,6 +105,8 @@ struct nameidata {
 #define MAKEENTRY      0x04000 /* entry is to be added to name cache */
 #define ISLASTCN       0x08000 /* this is last component of pathname */
 #define ISSYMLINK      0x10000 /* symlink needs interpretation */
 #define MAKEENTRY      0x04000 /* entry is to be added to name cache */
 #define ISLASTCN       0x08000 /* this is last component of pathname */
 #define ISSYMLINK      0x10000 /* symlink needs interpretation */
+#define        ISWHITEOUT      0x20000 /* found whiteout */
+#define        DOWHITEOUT      0x40000 /* do whiteouts */
 #define PARAMASK       0xfff00 /* mask of parameter descriptors */
 /*
  * Initialization of an nameidata structure.
 #define PARAMASK       0xfff00 /* mask of parameter descriptors */
 /*
  * Initialization of an nameidata structure.
index ee88f6f..08e27fc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vnode.h     8.7 (Berkeley) %G%
+ *     @(#)vnode.h     8.8 (Berkeley) %G%
  */
 
 #include <sys/queue.h>
  */
 
 #include <sys/queue.h>
index 72013a1..f49458c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ffs_vnops.c 8.8 (Berkeley) %G%
+ *     @(#)ffs_vnops.c 8.9 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -40,6 +40,7 @@ struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
        { &vop_create_desc, ufs_create },               /* create */
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
        { &vop_create_desc, ufs_create },               /* create */
+       { &vop_whiteout_desc, ufs_whiteout },           /* whiteout */
        { &vop_mknod_desc, ufs_mknod },                 /* mknod */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, ufs_close },                 /* close */
        { &vop_mknod_desc, ufs_mknod },                 /* mknod */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, ufs_close },                 /* close */
index aea23a5..ba59712 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_vnops.c 8.6 (Berkeley) %G%
+ *     @(#)lfs_vnops.c 8.7 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -41,6 +41,7 @@ struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
        { &vop_create_desc, ufs_create },               /* create */
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
        { &vop_create_desc, ufs_create },               /* create */
+       { &vop_whiteout_desc, ufs_whiteout },           /* whiteout */
        { &vop_mknod_desc, ufs_mknod },                 /* mknod */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, lfs_close },                 /* close */
        { &vop_mknod_desc, ufs_mknod },                 /* mknod */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, lfs_close },                 /* close */
index fafb7a3..012c7aa 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)mfs_vnops.c 8.4 (Berkeley) %G%
+ *     @(#)mfs_vnops.c 8.5 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
index f2822c8..df54cc3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ufs_extern.h        8.4 (Berkeley) %G%
+ *     @(#)ufs_extern.h        8.5 (Berkeley) %G%
  */
 
 struct buf;
  */
 
 struct buf;
@@ -85,6 +85,7 @@ int    ufs_start __P((struct mount *, int, struct proc *));
 int     ufs_strategy __P((struct vop_strategy_args *));
 int     ufs_symlink __P((struct vop_symlink_args *));
 int     ufs_unlock __P((struct vop_unlock_args *));
 int     ufs_strategy __P((struct vop_strategy_args *));
 int     ufs_symlink __P((struct vop_symlink_args *));
 int     ufs_unlock __P((struct vop_unlock_args *));
+int     ufs_whiteout __P((struct vop_whiteout_args *));
 int     ufs_vinit __P((struct mount *,
            int (**)(), int (**)(), struct vnode **));
 int     ufsspec_close __P((struct vop_close_args *));
 int     ufs_vinit __P((struct mount *,
            int (**)(), int (**)(), struct vnode **));
 int     ufsspec_close __P((struct vop_close_args *));
index d723f90..fd860bd 100644 (file)
@@ -9,7 +9,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ufs_lookup.c        8.7 (Berkeley) %G%
+ *     @(#)ufs_lookup.c        8.8 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -303,6 +303,16 @@ searchloop:
                                 * reclen in ndp->ni_ufs area, and release
                                 * directory buffer.
                                 */
                                 * reclen in ndp->ni_ufs area, and release
                                 * directory buffer.
                                 */
+                               if (DT_ISWHT(ep->d_type)) {
+                                       slotstatus = FOUND;
+                                       slotoffset = dp->i_offset;
+                                       slotsize = ep->d_reclen;
+                                       dp->i_reclen = slotsize;
+                                       enduseful = slotoffset + slotsize;
+                                       ap->a_cnp->cn_flags |= ISWHITEOUT;
+                                       numdirpasses--;
+                                       goto notfound;
+                               }
                                dp->i_ino = ep->d_ino;
                                dp->i_reclen = ep->d_reclen;
                                brelse(bp);
                                dp->i_ino = ep->d_ino;
                                dp->i_reclen = ep->d_reclen;
                                brelse(bp);
@@ -315,7 +325,7 @@ searchloop:
                if (ep->d_ino)
                        enduseful = dp->i_offset;
        }
                if (ep->d_ino)
                        enduseful = dp->i_offset;
        }
-/* notfound: */
+notfound:
        /*
         * If we started in the middle of the directory and failed
         * to find our target, we must check the beginning as well.
        /*
         * If we started in the middle of the directory and failed
         * to find our target, we must check the beginning as well.
@@ -333,7 +343,10 @@ searchloop:
         * directory has not been removed, then can consider
         * allowing file to be created.
         */
         * directory has not been removed, then can consider
         * allowing file to be created.
         */
-       if ((nameiop == CREATE || nameiop == RENAME) &&
+       if ((nameiop == CREATE || nameiop == RENAME ||
+            (nameiop == DELETE &&
+             (ap->a_cnp->cn_flags & DOWHITEOUT) &&
+             (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
            (flags & ISLASTCN) && dp->i_nlink != 0) {
                /*
                 * Access for write is interpreted as allowing
            (flags & ISLASTCN) && dp->i_nlink != 0) {
                /*
                 * Access for write is interpreted as allowing
@@ -354,6 +367,12 @@ searchloop:
                        dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
                        dp->i_count = 0;
                        enduseful = dp->i_offset;
                        dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
                        dp->i_count = 0;
                        enduseful = dp->i_offset;
+               } else if (nameiop == DELETE) {
+                       dp->i_offset = slotoffset;
+                       if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
+                               dp->i_count = 0;
+                       else
+                               dp->i_count = dp->i_offset - prevoff;
                } else {
                        dp->i_offset = slotoffset;
                        dp->i_count = slotsize;
                } else {
                        dp->i_offset = slotoffset;
                        dp->i_count = slotsize;
@@ -609,15 +628,8 @@ ufs_direnter(ip, dvp, cnp)
        struct vnode *dvp;
        register struct componentname *cnp;
 {
        struct vnode *dvp;
        register struct componentname *cnp;
 {
-       register struct direct *ep, *nep;
        register struct inode *dp;
        register struct inode *dp;
-       struct buf *bp;
        struct direct newdir;
        struct direct newdir;
-       struct iovec aiov;
-       struct uio auio;
-       u_int dsize;
-       int error, loc, newentrysize, spacefree;
-       char *dirbuf;
 
 #ifdef DIAGNOSTIC
        if ((cnp->cn_flags & SAVENAME) == 0)
 
 #ifdef DIAGNOSTIC
        if ((cnp->cn_flags & SAVENAME) == 0)
@@ -637,7 +649,32 @@ ufs_direnter(ip, dvp, cnp)
                        newdir.d_type = tmp; }
 #              endif
        }
                        newdir.d_type = tmp; }
 #              endif
        }
-       newentrysize = DIRSIZ(FSFMT(dvp), &newdir);
+       return (ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc));
+}
+
+/*
+ * Common entry point for directory entry removal used by ufs_direnter
+ * and ufs_whiteout
+ */
+ufs_direnter2(dvp, dirp, cr, p)
+       struct vnode *dvp;
+       struct direct *dirp;
+       struct ucred *cr;
+       struct proc *p;
+{
+       int newentrysize;
+       struct inode *dp;
+       struct buf *bp;
+       struct iovec aiov;
+       struct uio auio;
+       u_int dsize;
+       struct direct *ep, *nep;
+       int error, loc, spacefree;
+       char *dirbuf;
+
+       dp = VTOI(dvp);
+       newentrysize = DIRSIZ(FSFMT(dvp), dirp);
+
        if (dp->i_count == 0) {
                /*
                 * If dp->i_count is 0, then namei could find no
        if (dp->i_count == 0) {
                /*
                 * If dp->i_count is 0, then namei could find no
@@ -646,22 +683,22 @@ ufs_direnter(ip, dvp, cnp)
                 * new entry into a fresh block.
                 */
                if (dp->i_offset & (DIRBLKSIZ - 1))
                 * new entry into a fresh block.
                 */
                if (dp->i_offset & (DIRBLKSIZ - 1))
-                       panic("ufs_direnter: newblk");
+                       panic("ufs_direnter2: newblk");
                auio.uio_offset = dp->i_offset;
                auio.uio_offset = dp->i_offset;
-               newdir.d_reclen = DIRBLKSIZ;
+               dirp->d_reclen = DIRBLKSIZ;
                auio.uio_resid = newentrysize;
                aiov.iov_len = newentrysize;
                auio.uio_resid = newentrysize;
                aiov.iov_len = newentrysize;
-               aiov.iov_base = (caddr_t)&newdir;
+               aiov.iov_base = (caddr_t)dirp;
                auio.uio_iov = &aiov;
                auio.uio_iovcnt = 1;
                auio.uio_rw = UIO_WRITE;
                auio.uio_segflg = UIO_SYSSPACE;
                auio.uio_procp = (struct proc *)0;
                auio.uio_iov = &aiov;
                auio.uio_iovcnt = 1;
                auio.uio_rw = UIO_WRITE;
                auio.uio_segflg = UIO_SYSSPACE;
                auio.uio_procp = (struct proc *)0;
-               error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
+               error = VOP_WRITE(dvp, &auio, IO_SYNC, cr);
                if (DIRBLKSIZ >
                    VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                        /* XXX should grow with balloc() */
                if (DIRBLKSIZ >
                    VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                        /* XXX should grow with balloc() */
-                       panic("ufs_direnter: frag size");
+                       panic("ufs_direnter2: frag size");
                else if (!error) {
                        dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
                        dp->i_flag |= IN_CHANGE;
                else if (!error) {
                        dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
                        dp->i_flag |= IN_CHANGE;
@@ -721,23 +758,24 @@ ufs_direnter(ip, dvp, cnp)
         * Update the pointer fields in the previous entry (if any),
         * copy in the new entry, and write out the block.
         */
         * Update the pointer fields in the previous entry (if any),
         * copy in the new entry, and write out the block.
         */
-       if (ep->d_ino == 0) {
+       if (ep->d_ino == 0 ||
+           (ep->d_ino == WINO &&
+            bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) {
                if (spacefree + dsize < newentrysize)
                if (spacefree + dsize < newentrysize)
-                       panic("ufs_direnter: compact1");
-               newdir.d_reclen = spacefree + dsize;
+                       panic("ufs_direnter2: compact1");
+               dirp->d_reclen = spacefree + dsize;
        } else {
                if (spacefree < newentrysize)
        } else {
                if (spacefree < newentrysize)
-                       panic("ufs_direnter: compact2");
-               newdir.d_reclen = spacefree;
+                       panic("ufs_direnter2: compact2");
+               dirp->d_reclen = spacefree;
                ep->d_reclen = dsize;
                ep = (struct direct *)((char *)ep + dsize);
        }
                ep->d_reclen = dsize;
                ep = (struct direct *)((char *)ep + dsize);
        }
-       bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
+       bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize);
        error = VOP_BWRITE(bp);
        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
        error = VOP_BWRITE(bp);
        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
-               error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
-                   cnp->cn_cred, cnp->cn_proc);
+               error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p);
        return (error);
 }
 
        return (error);
 }
 
@@ -764,6 +802,24 @@ ufs_dirremove(dvp, cnp)
        int error;
 
        dp = VTOI(dvp);
        int error;
 
        dp = VTOI(dvp);
+
+       if (cnp->cn_flags & DOWHITEOUT) {
+               /*
+                * First entry in block: set d_ino to zero.
+                */
+               if (error =
+                   VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp))
+                       return (error);
+               ep->d_ino = WINO;
+               if (ep->d_type == DT_DIR)
+                       ep->d_type = DT_WHTD;
+               else
+                       ep->d_type = DT_WHT;
+               error = VOP_BWRITE(bp);
+               dp->i_flag |= IN_CHANGE | IN_UPDATE;
+               return (error);
+       }
+
        if (dp->i_count == 0) {
                /*
                 * First entry in block: set d_ino to zero.
        if (dp->i_count == 0) {
                /*
                 * First entry in block: set d_ino to zero.
@@ -847,7 +903,7 @@ ufs_dirempty(ip, parentino, cred)
                if (dp->d_reclen == 0)
                        return (0);
                /* skip empty entries */
                if (dp->d_reclen == 0)
                        return (0);
                /* skip empty entries */
-               if (dp->d_ino == 0)
+               if (dp->d_ino == 0 || dp->d_ino == WINO)
                        continue;
                /* accept only "." and ".." */
 #              if (BYTE_ORDER == LITTLE_ENDIAN)
                        continue;
                /* accept only "." and ".." */
 #              if (BYTE_ORDER == LITTLE_ENDIAN)
index e65d4d0..1c9d66c 100644 (file)
@@ -9,7 +9,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ufs_vnops.c 8.11 (Berkeley) %G%
+ *     @(#)ufs_vnops.c 8.12 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -681,6 +681,63 @@ out2:
        return (error);
 }
 
        return (error);
 }
 
+/*
+ * whiteout vnode call
+ */
+int
+ufs_whiteout(ap)
+       struct vop_whiteout_args /* {
+               struct vnode *a_dvp;
+               struct componentname *a_cnp;
+               int a_flags;
+       } */ *ap;
+{
+       struct vnode *dvp = ap->a_dvp;
+       struct componentname *cnp = ap->a_cnp;
+       struct direct newdir;
+       int error;
+
+       switch (ap->a_flags) {
+       case LOOKUP:
+               /* 4.4 format directories support whiteout operations */
+               if (dvp->v_mount->mnt_maxsymlinklen > 0)
+                       return (0);
+               return (EOPNOTSUPP);
+
+       case CREATE:
+               /* create a new directory whiteout */
+#ifdef DIAGNOSTIC
+               if ((cnp->cn_flags & SAVENAME) == 0)
+                       panic("ufs_whiteout: missing name");
+               if (dvp->v_mount->mnt_maxsymlinklen <= 0)
+                       panic("ufs_whiteout: old format filesystem");
+#endif
+
+               newdir.d_ino = WINO;
+               newdir.d_namlen = cnp->cn_namelen;
+               bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
+               newdir.d_type = DT_WHT;
+               error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc);
+               break;
+
+       case DELETE:
+               /* remove an existing directory whiteout */
+#ifdef DIAGNOSTIC
+               if (dvp->v_mount->mnt_maxsymlinklen <= 0)
+                       panic("ufs_whiteout: old format filesystem");
+#endif
+
+               cnp->cn_flags &= ~DOWHITEOUT;
+               error = ufs_dirremove(dvp, cnp);
+               break;
+       }
+       if (cnp->cn_flags & HASBUF) {
+               FREE(cnp->cn_pnbuf, M_NAMEI);
+               cnp->cn_flags &= ~HASBUF;
+       }
+       return (error);
+}
+
 
 
 /*
 
 
 /*
@@ -1295,6 +1352,8 @@ ufs_mkdir(ap)
        ip->i_mode = dmode;
        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
        ip->i_nlink = 2;
        ip->i_mode = dmode;
        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
        ip->i_nlink = 2;
+       if (cnp->cn_flags & ISWHITEOUT)
+               ip->i_flags |= UF_OPAQUE;
        tv = time;
        error = VOP_UPDATE(tvp, &tv, &tv, 1);
 
        tv = time;
        error = VOP_UPDATE(tvp, &tv, &tv, 1);
 
@@ -2169,6 +2228,9 @@ ufs_makeinode(mode, dvp, vpp, cnp)
            suser(cnp->cn_cred, NULL))
                ip->i_mode &= ~ISGID;
 
            suser(cnp->cn_cred, NULL))
                ip->i_mode &= ~ISGID;
 
+       if (cnp->cn_flags & ISWHITEOUT)
+               ip->i_flags |= UF_OPAQUE;
+
        /*
         * Make sure inode goes to disk before directory entry.
         */
        /*
         * Make sure inode goes to disk before directory entry.
         */
index 7375133..269d101 100644 (file)
@@ -6,7 +6,7 @@
 .\"
 .\" %sccs.include.redist.roff%
 .\"
 .\"
 .\" %sccs.include.redist.roff%
 .\"
-.\"    @(#)chflags.1   8.2 (Berkeley) %G%
+.\"    @(#)chflags.1   8.3 (Berkeley) %G%
 .\"
 .Dd 
 .Dt CHFLAGS 1
 .\"
 .Dd 
 .Dt CHFLAGS 1
@@ -54,6 +54,7 @@ Flags are a comma separated list of keywords.
 The following keywords are currently defined:
 .Bd -literal -offset indent compact
 .\"arch        nothing yet.
 The following keywords are currently defined:
 .Bd -literal -offset indent compact
 .\"arch        nothing yet.
+opaque set the opaque flag
 dump   set the dump flag
 sappnd set the system append-only flag (super-user only)
 schg   set the system immutable flag (super-user only)
 dump   set the dump flag
 sappnd set the system append-only flag (super-user only)
 schg   set the system immutable flag (super-user only)
index f80aef8..4f7978d 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)find.c     8.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)find.c     8.4 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -144,6 +144,8 @@ find_execute(plan, paths)
                            entry->fts_path, strerror(entry->fts_errno));
                        rval = 1;
                        continue;
                            entry->fts_path, strerror(entry->fts_errno));
                        rval = 1;
                        continue;
+               case FTS_W:
+                       continue;
                }
 #define        BADCH   " \t\n\\'\""
                if (isxargs && strpbrk(entry->fts_path, BADCH)) {
                }
 #define        BADCH   " \t\n\\'\""
                if (isxargs && strpbrk(entry->fts_path, BADCH)) {
index 4beb024..d69764a 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)function.c 8.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)function.c 8.7 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -832,9 +832,9 @@ c_size(arg)
 /*
  * -type c functions --
  *
 /*
  * -type c functions --
  *
- *     True if the type of the file is c, where c is b, c, d, p, or f for
- *     block special file, character special file, directory, FIFO, or
- *     regular file, respectively.
+ *     True if the type of the file is c, where c is b, c, d, p, f or w
+ *     for block special file, character special file, directory, FIFO,
+ *     regular file or whiteout respectively.
  */
 int
 f_type(plan, entry)
  */
 int
 f_type(plan, entry)
@@ -875,6 +875,10 @@ c_type(typestring)
        case 's':
                mask = S_IFSOCK;
                break;
        case 's':
                mask = S_IFSOCK;
                break;
+       case 'w':
+               mask = S_IFWHT;
+               ftsoptions |= FTS_WHITEOUT;
+               break;
        default:
                errx(1, "-type: %s: unknown type", typestring);
        }
        default:
                errx(1, "-type: %s: unknown type", typestring);
        }