Source-Changes-HG archive

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

[src/trunk]: src/sys/fs/udf Implement udf_rename() using the new genfs_rename...



details:   https://anonhg.NetBSD.org/src/rev/e5ea585900d5
branches:  trunk
changeset: 787870:e5ea585900d5
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Wed Jul 10 15:10:56 2013 +0000

description:
Implement udf_rename() using the new genfs_rename() framework.

Fixes PR kern/47986

diffstat:

 sys/fs/udf/files.udf    |    3 +-
 sys/fs/udf/udf_rename.c |  671 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/fs/udf/udf_vnops.c  |  266 +------------------
 3 files changed, 683 insertions(+), 257 deletions(-)

diffs (truncated from 1000 to 300 lines):

diff -r 46f1e1b5cba8 -r e5ea585900d5 sys/fs/udf/files.udf
--- a/sys/fs/udf/files.udf      Wed Jul 10 15:08:38 2013 +0000
+++ b/sys/fs/udf/files.udf      Wed Jul 10 15:10:56 2013 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.udf,v 1.4 2010/03/02 16:43:48 pooka Exp $
+#      $NetBSD: files.udf,v 1.5 2013/07/10 15:10:56 reinoud Exp $
 
 deffs  UDF
 
@@ -12,4 +12,5 @@
 file   fs/udf/udf_strat_direct.c       udf
 file   fs/udf/udf_strat_rmw.c          udf
 file   fs/udf/udf_allocation.c         udf
+file   fs/udf/udf_rename.c             udf
 
diff -r 46f1e1b5cba8 -r e5ea585900d5 sys/fs/udf/udf_rename.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/fs/udf/udf_rename.c   Wed Jul 10 15:10:56 2013 +0000
@@ -0,0 +1,671 @@
+/* $NetBSD: udf_rename.c,v 1.1 2013/07/10 15:10:56 reinoud Exp $ */
+
+/*
+ * Copyright (c) 2013 Reinoud Zandijk
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * Comments and trivial code from the reference implementation in tmpfs.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: udf_rename.c,v 1.1 2013/07/10 15:10:56 reinoud Exp $");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/kauth.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/vnode.h>
+#include <sys/vnode_if.h>
+
+#include <miscfs/genfs/genfs.h>
+
+#include <fs/udf/ecma167-udf.h>
+#include <fs/udf/udf_mount.h>
+#include <sys/dirhash.h>
+
+#include "udf.h"
+#include "udf_subr.h"
+#include "udf_bswap.h"
+
+
+/* forwards */
+static int udf_sane_rename( struct vnode *, struct componentname *,
+    struct vnode *, struct componentname *,
+    kauth_cred_t, bool);
+static bool udf_rmdired_p(struct vnode *);
+static int udf_gro_lock_directory(struct mount *, struct vnode *);
+
+static const struct genfs_rename_ops udf_genfs_rename_ops;
+
+
+#define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
+
+
+/*
+ * udf_sane_rename: The hairiest vop, with the saner API.
+ *
+ * Arguments:
+ *
+ * . fdvp (from directory vnode),
+ * . fcnp (from component name),
+ * . tdvp (to directory vnode),
+ * . tcnp (to component name),
+ * . cred (credentials structure), and
+ * . posixly_correct (flag for behaviour if target & source link same file).
+ *
+ * fdvp and tdvp may be the same, and must be referenced and unlocked.
+ */
+static int
+udf_sane_rename( struct vnode *fdvp, struct componentname *fcnp,
+    struct vnode *tdvp, struct componentname *tcnp,
+    kauth_cred_t cred, bool posixly_correct)
+{
+       struct dirent fdirent, tdirent; /* XXX OK? XXX */
+
+       DPRINTF(CALL, ("udf_sane_rename '%s' -> '%s'\n",
+               fcnp->cn_nameptr, tcnp->cn_nameptr));
+       return genfs_sane_rename(&udf_genfs_rename_ops,
+           fdvp, fcnp, &fdirent, tdvp, tcnp, &tdirent,
+           cred, posixly_correct);
+}
+
+
+/*
+ * udf_rename: the hairiest vop, with the insanest API. Pass to
+ * genfs_insane_rename immediately.
+ */
+int
+udf_rename(void *v)
+{
+       struct vop_rename_args /* {
+               struct vnode *a_fdvp;
+               struct vnode *a_fvp;
+               struct componentname *a_fcnp;
+               struct vnode *a_tdvp;
+               struct vnode *a_tvp;
+               struct componentname *a_tcnp;
+       } */ *ap = v;
+       DPRINTF(CALL, ("udf_rename called\n"));
+       return genfs_insane_rename(ap, &udf_sane_rename);
+}
+
+
+/*
+ * udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is
+ * its parent.
+ *
+ * vp and dvp must be locked and referenced.
+ */
+static bool
+udf_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
+    struct vnode *vp, struct vnode *dvp)
+{
+       struct udf_node *udf_node = VTOI(vp);
+       int error, isempty;
+
+       KASSERT(mp != NULL);
+       KASSERT(vp != NULL);
+       KASSERT(dvp != NULL);
+       KASSERT(vp != dvp);
+       KASSERT(vp->v_mount == mp);
+       KASSERT(dvp->v_mount == mp);
+       KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
+
+       DPRINTF(CALL, ("udf_gro_directory_empty_p called\n"));
+       /* make sure our `leaf' node's hash is populated */
+       dirhash_get(&udf_node->dir_hash);
+       error = udf_dirhash_fill(udf_node);
+       if (error) {
+               dirhash_put(udf_node->dir_hash);
+               return error;
+       }
+
+       /* check to see if the directory is empty */
+       isempty = dirhash_dir_isempty(udf_node->dir_hash);
+       dirhash_put(udf_node->dir_hash);
+
+       return isempty;
+}
+
+
+/*
+ * udf_gro_rename_check_possible: check whether a rename is possible
+ * independent of credentials.
+ */
+static int
+udf_gro_rename_check_possible(struct mount *mp,
+    struct vnode *fdvp, struct vnode *fvp,
+    struct vnode *tdvp, struct vnode *tvp)
+{
+       (void)mp;
+       KASSERT(mp != NULL);
+       KASSERT(fdvp != NULL);
+       KASSERT(fvp != NULL);
+       KASSERT(tdvp != NULL);
+       KASSERT(fdvp != fvp);
+       KASSERT(fdvp != tvp);
+       KASSERT(tdvp != fvp);
+       KASSERT(tdvp != tvp);
+       KASSERT(fvp != tvp);
+       KASSERT(fdvp->v_type == VDIR);
+       KASSERT(tdvp->v_type == VDIR);
+       KASSERT(fdvp->v_mount == mp);
+       KASSERT(fvp->v_mount == mp);
+       KASSERT(tdvp->v_mount == mp);
+       KASSERT((tvp == NULL) || (tvp->v_mount == mp));
+       KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
+       KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
+
+       DPRINTF(CALL, ("udf_gro_rename_check_possible called\n"));
+       if (mp->mnt_flag & MNT_RDONLY)
+               return EROFS;
+
+       /* flags not implemented since they are not defined (yet) in UDF */
+       return 0;
+}
+
+
+/*
+ * udf_gro_rename_check_permitted: check whether a rename is permitted given
+ * our credentials.
+ */
+static int
+udf_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
+    struct vnode *fdvp, struct vnode *fvp,
+    struct vnode *tdvp, struct vnode *tvp)
+{
+       struct udf_node *fdir_node = VTOI(fdvp);
+       struct udf_node *tdir_node = VTOI(tdvp);
+       struct udf_node *f_node = VTOI(fvp);
+       struct udf_node *t_node = (tvp? VTOI(tvp): NULL);
+       mode_t fdmode, tdmode;
+       uid_t fduid, tduid, fuid, tuid;
+       gid_t gdummy;
+
+       (void)mp;
+       KASSERT(mp != NULL);
+       KASSERT(fdvp != NULL);
+       KASSERT(fvp != NULL);
+       KASSERT(tdvp != NULL);
+       KASSERT(fdvp != fvp);
+       KASSERT(fdvp != tvp);
+       KASSERT(tdvp != fvp);
+       KASSERT(tdvp != tvp);
+       KASSERT(fvp != tvp);
+       KASSERT(fdvp->v_type == VDIR);
+       KASSERT(tdvp->v_type == VDIR);
+       KASSERT(fdvp->v_mount == mp);
+       KASSERT(fvp->v_mount == mp);
+       KASSERT(tdvp->v_mount == mp);
+       KASSERT((tvp == NULL) || (tvp->v_mount == mp));
+       KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
+       KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
+
+       DPRINTF(CALL, ("udf_gro_rename_check_permitted called\n"));
+       fdmode = udf_getaccessmode(fdir_node);
+       tdmode = udf_getaccessmode(tdir_node);
+
+       udf_getownership(fdir_node, &fduid, &gdummy);
+       udf_getownership(tdir_node, &tduid, &gdummy);
+       udf_getownership(f_node,    &fuid, &gdummy);
+
+       tuid = 0;
+       if (t_node)
+               udf_getownership(t_node, &tuid, &gdummy);
+
+       return genfs_ufslike_rename_check_permitted(cred,
+           fdvp, fdmode, fduid,
+           fvp,  fuid,
+           tdvp, tdmode, tduid,
+           tvp,  tuid);
+}
+
+
+/*
+ * udf_gro_remove_check_possible: check whether a remove is possible
+ * independent of credentials.
+ *
+ * XXX could check for special attributes?
+ */
+static int
+udf_gro_remove_check_possible(struct mount *mp,
+    struct vnode *dvp, struct vnode *vp)
+{
+       (void)mp;
+       KASSERT(mp != NULL);
+       KASSERT(dvp != NULL);
+       KASSERT(vp != NULL);
+       KASSERT(dvp != vp);
+       KASSERT(dvp->v_type == VDIR);
+       KASSERT(vp->v_type != VDIR);
+       KASSERT(dvp->v_mount == mp);
+       KASSERT(vp->v_mount == mp);
+       KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
+       KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
+
+       DPRINTF(CALL, ("udf_gro_remove_check_possible called\n"));
+       if (mp->mnt_flag & MNT_RDONLY)
+               return EROFS;
+
+       /* flags not implemented since they are not defined (yet) in UDF */
+       return 0;
+}



Home | Main Index | Thread Index | Old Index