Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/fs/v7fs When rename directory, check hierarchy. Pass t_v...



details:   https://anonhg.NetBSD.org/src/rev/59fd800dff50
branches:  trunk
changeset: 767770:59fd800dff50
user:      uch <uch%NetBSD.org@localhost>
date:      Sat Jul 30 03:52:04 2011 +0000

description:
When rename directory, check hierarchy. Pass t_vnops rename_dir(5)

diffstat:

 sys/fs/v7fs/v7fs_file_util.c |  114 +++++++++++++++++++++++++++++++++++++-----
 1 files changed, 99 insertions(+), 15 deletions(-)

diffs (172 lines):

diff -r 0fd20f574170 -r 59fd800dff50 sys/fs/v7fs/v7fs_file_util.c
--- a/sys/fs/v7fs/v7fs_file_util.c      Sat Jul 30 03:51:53 2011 +0000
+++ b/sys/fs/v7fs/v7fs_file_util.c      Sat Jul 30 03:52:04 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: v7fs_file_util.c,v 1.3 2011/07/18 21:51:49 apb Exp $   */
+/*     $NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $   */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.3 2011/07/18 21:51:49 apb Exp $");
+__KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $");
 #ifdef _KERNEL
 #include <sys/systm.h>
 #include <sys/param.h>
@@ -61,6 +61,9 @@
 static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
 static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t,
     size_t);
+static int can_dirmove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t);
+static int lookup_parent_from_dir_subr(struct v7fs_self *, void *,
+    v7fs_daddr_t, size_t);
 
 int
 v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
@@ -118,26 +121,38 @@
     const char *from, struct v7fs_inode *parent_to, const char *to)
 {
        v7fs_ino_t from_ino, to_ino;
+       struct v7fs_inode inode;
        int error;
+       bool dir_move;
 
+       /* Check source file */
        if ((error = v7fs_file_lookup_by_name(fs, parent_from, from,
            &from_ino))) {
                DPRINTF("%s don't exists\n", from);
                return error;
        }
+       v7fs_inode_load(fs, &inode, from_ino);
+       dir_move = v7fs_inode_isdir(&inode);
 
-       /* If target file exists, remove. */
+       /* Check target file */
        error = v7fs_file_lookup_by_name(fs, parent_to, to, &to_ino);
-       if (error == 0) {
+       if (error == 0) {       /* found */
                DPRINTF("%s already exists\n", to);
                if ((error = v7fs_file_deallocate(fs, parent_to, to))) {
-                       DPRINTF("%s can't remove\n", to);
+                       DPRINTF("%s can't remove %d\n", to, error);
                        return error;
                }
        } else if (error != ENOENT) {
                DPRINTF("error=%d\n", error);
                return error;
        }
+       /* Check directory hierarchy. t_vnops rename_dir(5) */
+       if (dir_move && (error = can_dirmove(fs, from_ino,
+           parent_to->inode_number))) {
+               DPRINTF("dst '%s' is child dir of '%s'. error=%d\n", to, from,
+                   error);
+               return error;
+       }
 
        if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to))) {
                DPRINTF("can't add entry");
@@ -149,18 +164,14 @@
                return error;
        }
 
-       if (parent_from != parent_to) {
+       if (dir_move && (parent_from != parent_to)) {
                /* If directory move, update ".." */
-               struct v7fs_inode inode;
-               v7fs_inode_load(fs, &inode, from_ino);
-               if (v7fs_inode_isdir(&inode)) {
-                       if ((error = v7fs_directory_replace_entry(fs, &inode,
-                           "..", parent_to->inode_number))) {
-                               DPRINTF("can't replace parent dir");
-                               return error;
-                       }
-                       v7fs_inode_writeback(fs, &inode);
+               if ((error = v7fs_directory_replace_entry(fs, &inode, "..",
+                           parent_to->inode_number))) {
+                       DPRINTF("can't replace parent dir");
+                       return error;
                }
+               v7fs_inode_writeback(fs, &inode);
        }
 
        return 0;
@@ -258,3 +269,76 @@
 
        return ret;
 }
+
+struct lookup_parent_arg {
+       v7fs_ino_t parent_ino;
+};
+
+static int
+can_dirmove(struct v7fs_self *fs, v7fs_ino_t from_ino, v7fs_ino_t to_ino)
+{
+       struct v7fs_inode inode;
+       v7fs_ino_t parent;
+       int error;
+
+       /* Start dir. */
+       if ((error = v7fs_inode_load(fs, &inode, to_ino)))
+               return error;
+
+       if (!v7fs_inode_isdir(&inode))
+               return ENOTDIR;
+
+       /* Lookup the parent. */
+       do {
+               struct lookup_parent_arg arg;
+               /* Search parent dir */
+               arg.parent_ino = 0;
+               v7fs_datablock_foreach(fs, &inode, lookup_parent_from_dir_subr,
+                   &arg);
+               if ((parent = arg.parent_ino) == 0) {
+                       DPRINTF("***parent missing\n");
+                       return ENOENT;
+               }
+               /* Load parent dir */
+               if ((error = v7fs_inode_load(fs, &inode, parent)))
+                       return error;
+               if (parent == from_ino) {
+                       DPRINTF("#%d is child dir of #%d\n", to_ino, from_ino);
+                       return EINVAL;
+               }
+       } while (parent != V7FS_ROOT_INODE);
+
+       return 0;
+}
+
+static int
+lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
+    size_t sz)
+{
+       struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx;
+       char name[V7FS_NAME_MAX + 1];
+       void *buf;
+       int ret = 0;
+
+       if (!(buf = scratch_read(fs, blk)))
+               return 0;
+       struct v7fs_dirent *dir = (struct v7fs_dirent *)buf;
+       size_t i, n = sz / sizeof(*dir);
+       if (!v7fs_dirent_endian_convert(fs, dir, n)) {
+               scratch_free(fs, buf);
+               return V7FS_ITERATOR_ERROR;
+       }
+
+       for (i = 0; i < n; i++, dir++) {
+               v7fs_dirent_filename(name, dir->name);
+               if (strncmp(dir->name, "..", V7FS_NAME_MAX) != 0)
+                       continue;
+
+               arg->parent_ino = dir->inode_number;
+               ret = V7FS_ITERATOR_BREAK;
+               break;
+       }
+
+       scratch_free(fs, buf);
+       return ret;
+}



Home | Main Index | Thread Index | Old Index