Home | History | Annotate | Line # | Download | only in udf
udf_rename.c revision 1.14
      1  1.14  thorpej /* $NetBSD: udf_rename.c,v 1.14 2021/10/20 03:08:17 thorpej Exp $ */
      2   1.1  reinoud 
      3   1.1  reinoud /*
      4   1.1  reinoud  * Copyright (c) 2013 Reinoud Zandijk
      5   1.1  reinoud  * All rights reserved.
      6   1.1  reinoud  *
      7   1.1  reinoud  * Redistribution and use in source and binary forms, with or without
      8   1.1  reinoud  * modification, are permitted provided that the following conditions
      9   1.1  reinoud  * are met:
     10   1.1  reinoud  * 1. Redistributions of source code must retain the above copyright
     11   1.1  reinoud  *    notice, this list of conditions and the following disclaimer.
     12   1.1  reinoud  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  reinoud  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  reinoud  *    documentation and/or other materials provided with the distribution.
     15   1.1  reinoud  *
     16   1.1  reinoud  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17   1.1  reinoud  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18   1.1  reinoud  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19   1.1  reinoud  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20   1.1  reinoud  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21   1.1  reinoud  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22   1.1  reinoud  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23   1.1  reinoud  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24   1.1  reinoud  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25   1.1  reinoud  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26   1.1  reinoud  *
     27   1.1  reinoud  * Comments and trivial code from the reference implementation in tmpfs.
     28   1.1  reinoud  */
     29   1.1  reinoud 
     30   1.1  reinoud #include <sys/cdefs.h>
     31  1.14  thorpej __KERNEL_RCSID(0, "$NetBSD: udf_rename.c,v 1.14 2021/10/20 03:08:17 thorpej Exp $");
     32   1.1  reinoud 
     33   1.1  reinoud #include <sys/param.h>
     34   1.1  reinoud #include <sys/errno.h>
     35   1.1  reinoud #include <sys/kauth.h>
     36   1.1  reinoud #include <sys/mount.h>
     37   1.1  reinoud #include <sys/namei.h>
     38   1.1  reinoud #include <sys/stat.h>
     39  1.12      riz #include <sys/malloc.h>
     40   1.1  reinoud #include <sys/dirent.h>
     41   1.1  reinoud #include <sys/vnode.h>
     42   1.1  reinoud #include <sys/vnode_if.h>
     43   1.1  reinoud 
     44   1.1  reinoud #include <miscfs/genfs/genfs.h>
     45   1.1  reinoud 
     46   1.1  reinoud #include <fs/udf/ecma167-udf.h>
     47   1.1  reinoud #include <fs/udf/udf_mount.h>
     48   1.1  reinoud #include <sys/dirhash.h>
     49   1.1  reinoud 
     50   1.1  reinoud #include "udf.h"
     51   1.1  reinoud #include "udf_subr.h"
     52   1.1  reinoud #include "udf_bswap.h"
     53   1.1  reinoud 
     54   1.1  reinoud 
     55   1.1  reinoud /* forwards */
     56   1.1  reinoud static int udf_sane_rename( struct vnode *, struct componentname *,
     57   1.1  reinoud     struct vnode *, struct componentname *,
     58   1.1  reinoud     kauth_cred_t, bool);
     59   1.1  reinoud static bool udf_rmdired_p(struct vnode *);
     60   1.1  reinoud static int udf_gro_lock_directory(struct mount *, struct vnode *);
     61   1.1  reinoud 
     62   1.1  reinoud static const struct genfs_rename_ops udf_genfs_rename_ops;
     63   1.1  reinoud 
     64   1.1  reinoud 
     65   1.1  reinoud #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
     66   1.1  reinoud 
     67   1.1  reinoud 
     68   1.1  reinoud /*
     69   1.1  reinoud  * udf_sane_rename: The hairiest vop, with the saner API.
     70   1.1  reinoud  *
     71   1.1  reinoud  * Arguments:
     72   1.1  reinoud  *
     73   1.1  reinoud  * . fdvp (from directory vnode),
     74   1.1  reinoud  * . fcnp (from component name),
     75   1.1  reinoud  * . tdvp (to directory vnode),
     76   1.1  reinoud  * . tcnp (to component name),
     77   1.1  reinoud  * . cred (credentials structure), and
     78   1.1  reinoud  * . posixly_correct (flag for behaviour if target & source link same file).
     79   1.1  reinoud  *
     80   1.1  reinoud  * fdvp and tdvp may be the same, and must be referenced and unlocked.
     81   1.1  reinoud  */
     82   1.1  reinoud static int
     83   1.1  reinoud udf_sane_rename( struct vnode *fdvp, struct componentname *fcnp,
     84   1.1  reinoud     struct vnode *tdvp, struct componentname *tcnp,
     85   1.1  reinoud     kauth_cred_t cred, bool posixly_correct)
     86   1.1  reinoud {
     87   1.1  reinoud 	DPRINTF(CALL, ("udf_sane_rename '%s' -> '%s'\n",
     88   1.1  reinoud 		fcnp->cn_nameptr, tcnp->cn_nameptr));
     89   1.1  reinoud 	return genfs_sane_rename(&udf_genfs_rename_ops,
     90   1.3  reinoud 	    fdvp, fcnp, NULL, tdvp, tcnp, NULL,
     91   1.1  reinoud 	    cred, posixly_correct);
     92   1.1  reinoud }
     93   1.1  reinoud 
     94   1.1  reinoud 
     95   1.1  reinoud /*
     96   1.1  reinoud  * udf_rename: the hairiest vop, with the insanest API. Pass to
     97   1.1  reinoud  * genfs_insane_rename immediately.
     98   1.1  reinoud  */
     99   1.1  reinoud int
    100   1.1  reinoud udf_rename(void *v)
    101   1.1  reinoud {
    102   1.1  reinoud 	struct vop_rename_args /* {
    103   1.1  reinoud 		struct vnode *a_fdvp;
    104   1.1  reinoud 		struct vnode *a_fvp;
    105   1.1  reinoud 		struct componentname *a_fcnp;
    106   1.1  reinoud 		struct vnode *a_tdvp;
    107   1.1  reinoud 		struct vnode *a_tvp;
    108   1.1  reinoud 		struct componentname *a_tcnp;
    109   1.1  reinoud 	} */ *ap = v;
    110   1.1  reinoud 	DPRINTF(CALL, ("udf_rename called\n"));
    111   1.1  reinoud 	return genfs_insane_rename(ap, &udf_sane_rename);
    112   1.1  reinoud }
    113   1.1  reinoud 
    114   1.1  reinoud 
    115   1.1  reinoud /*
    116   1.1  reinoud  * udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is
    117   1.1  reinoud  * its parent.
    118   1.1  reinoud  *
    119   1.1  reinoud  * vp and dvp must be locked and referenced.
    120   1.1  reinoud  */
    121   1.1  reinoud static bool
    122   1.1  reinoud udf_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
    123   1.1  reinoud     struct vnode *vp, struct vnode *dvp)
    124   1.1  reinoud {
    125   1.1  reinoud 	struct udf_node *udf_node = VTOI(vp);
    126   1.1  reinoud 	int error, isempty;
    127   1.1  reinoud 
    128   1.1  reinoud 	KASSERT(mp != NULL);
    129   1.1  reinoud 	KASSERT(vp != NULL);
    130   1.1  reinoud 	KASSERT(dvp != NULL);
    131   1.1  reinoud 	KASSERT(vp != dvp);
    132   1.1  reinoud 	KASSERT(vp->v_mount == mp);
    133   1.1  reinoud 	KASSERT(dvp->v_mount == mp);
    134   1.1  reinoud 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    135   1.1  reinoud 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    136   1.1  reinoud 
    137   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_directory_empty_p called\n"));
    138   1.1  reinoud 	/* make sure our `leaf' node's hash is populated */
    139   1.1  reinoud 	dirhash_get(&udf_node->dir_hash);
    140   1.1  reinoud 	error = udf_dirhash_fill(udf_node);
    141   1.1  reinoud 	if (error) {
    142   1.1  reinoud 		dirhash_put(udf_node->dir_hash);
    143   1.5  reinoud 		/* VERY unlikely, answer its not empty */
    144   1.5  reinoud 		return 0;
    145   1.1  reinoud 	}
    146   1.1  reinoud 
    147   1.1  reinoud 	/* check to see if the directory is empty */
    148   1.1  reinoud 	isempty = dirhash_dir_isempty(udf_node->dir_hash);
    149   1.1  reinoud 	dirhash_put(udf_node->dir_hash);
    150   1.1  reinoud 
    151   1.1  reinoud 	return isempty;
    152   1.1  reinoud }
    153   1.1  reinoud 
    154   1.1  reinoud 
    155   1.1  reinoud /*
    156   1.1  reinoud  * udf_gro_rename_check_possible: check whether a rename is possible
    157   1.1  reinoud  * independent of credentials.
    158   1.1  reinoud  */
    159   1.1  reinoud static int
    160   1.1  reinoud udf_gro_rename_check_possible(struct mount *mp,
    161   1.1  reinoud     struct vnode *fdvp, struct vnode *fvp,
    162   1.1  reinoud     struct vnode *tdvp, struct vnode *tvp)
    163   1.1  reinoud {
    164   1.1  reinoud 	(void)mp;
    165   1.1  reinoud 	KASSERT(mp != NULL);
    166   1.1  reinoud 	KASSERT(fdvp != NULL);
    167   1.1  reinoud 	KASSERT(fvp != NULL);
    168   1.1  reinoud 	KASSERT(tdvp != NULL);
    169   1.1  reinoud 	KASSERT(fdvp != fvp);
    170   1.1  reinoud 	KASSERT(fdvp != tvp);
    171   1.1  reinoud 	KASSERT(tdvp != fvp);
    172   1.1  reinoud 	KASSERT(tdvp != tvp);
    173   1.1  reinoud 	KASSERT(fvp != tvp);
    174   1.1  reinoud 	KASSERT(fdvp->v_type == VDIR);
    175   1.1  reinoud 	KASSERT(tdvp->v_type == VDIR);
    176   1.1  reinoud 	KASSERT(fdvp->v_mount == mp);
    177   1.1  reinoud 	KASSERT(fvp->v_mount == mp);
    178   1.1  reinoud 	KASSERT(tdvp->v_mount == mp);
    179   1.1  reinoud 	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
    180   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    181   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    182   1.1  reinoud 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    183   1.1  reinoud 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    184   1.1  reinoud 
    185   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_rename_check_possible called\n"));
    186   1.1  reinoud 
    187   1.1  reinoud 	/* flags not implemented since they are not defined (yet) in UDF */
    188   1.1  reinoud 	return 0;
    189   1.1  reinoud }
    190   1.1  reinoud 
    191   1.1  reinoud 
    192   1.1  reinoud /*
    193   1.1  reinoud  * udf_gro_rename_check_permitted: check whether a rename is permitted given
    194   1.1  reinoud  * our credentials.
    195   1.1  reinoud  */
    196   1.1  reinoud static int
    197   1.1  reinoud udf_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
    198   1.1  reinoud     struct vnode *fdvp, struct vnode *fvp,
    199   1.1  reinoud     struct vnode *tdvp, struct vnode *tvp)
    200   1.1  reinoud {
    201   1.1  reinoud 	struct udf_node *fdir_node = VTOI(fdvp);
    202   1.1  reinoud 	struct udf_node *tdir_node = VTOI(tdvp);
    203   1.1  reinoud 	struct udf_node *f_node = VTOI(fvp);
    204   1.1  reinoud 	struct udf_node *t_node = (tvp? VTOI(tvp): NULL);
    205   1.1  reinoud 	mode_t fdmode, tdmode;
    206   1.1  reinoud 	uid_t fduid, tduid, fuid, tuid;
    207   1.1  reinoud 	gid_t gdummy;
    208   1.1  reinoud 
    209   1.1  reinoud 	(void)mp;
    210   1.1  reinoud 	KASSERT(mp != NULL);
    211   1.1  reinoud 	KASSERT(fdvp != NULL);
    212   1.1  reinoud 	KASSERT(fvp != NULL);
    213   1.1  reinoud 	KASSERT(tdvp != NULL);
    214   1.1  reinoud 	KASSERT(fdvp != fvp);
    215   1.1  reinoud 	KASSERT(fdvp != tvp);
    216   1.1  reinoud 	KASSERT(tdvp != fvp);
    217   1.1  reinoud 	KASSERT(tdvp != tvp);
    218   1.1  reinoud 	KASSERT(fvp != tvp);
    219   1.1  reinoud 	KASSERT(fdvp->v_type == VDIR);
    220   1.1  reinoud 	KASSERT(tdvp->v_type == VDIR);
    221   1.1  reinoud 	KASSERT(fdvp->v_mount == mp);
    222   1.1  reinoud 	KASSERT(fvp->v_mount == mp);
    223   1.1  reinoud 	KASSERT(tdvp->v_mount == mp);
    224   1.1  reinoud 	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
    225   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    226   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    227   1.1  reinoud 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    228   1.1  reinoud 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    229   1.1  reinoud 
    230   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_rename_check_permitted called\n"));
    231   1.1  reinoud 	fdmode = udf_getaccessmode(fdir_node);
    232   1.1  reinoud 	tdmode = udf_getaccessmode(tdir_node);
    233   1.1  reinoud 
    234   1.1  reinoud 	udf_getownership(fdir_node, &fduid, &gdummy);
    235   1.1  reinoud 	udf_getownership(tdir_node, &tduid, &gdummy);
    236   1.1  reinoud 	udf_getownership(f_node,    &fuid, &gdummy);
    237   1.1  reinoud 
    238   1.1  reinoud 	tuid = 0;
    239   1.1  reinoud 	if (t_node)
    240   1.1  reinoud 		udf_getownership(t_node, &tuid, &gdummy);
    241   1.1  reinoud 
    242   1.1  reinoud 	return genfs_ufslike_rename_check_permitted(cred,
    243   1.1  reinoud 	    fdvp, fdmode, fduid,
    244   1.1  reinoud 	    fvp,  fuid,
    245   1.1  reinoud 	    tdvp, tdmode, tduid,
    246   1.1  reinoud 	    tvp,  tuid);
    247   1.1  reinoud }
    248   1.1  reinoud 
    249   1.1  reinoud 
    250   1.1  reinoud /*
    251   1.1  reinoud  * udf_gro_remove_check_possible: check whether a remove is possible
    252   1.1  reinoud  * independent of credentials.
    253   1.1  reinoud  *
    254   1.1  reinoud  * XXX could check for special attributes?
    255   1.1  reinoud  */
    256   1.1  reinoud static int
    257   1.1  reinoud udf_gro_remove_check_possible(struct mount *mp,
    258   1.1  reinoud     struct vnode *dvp, struct vnode *vp)
    259   1.1  reinoud {
    260   1.1  reinoud 	(void)mp;
    261   1.1  reinoud 	KASSERT(mp != NULL);
    262   1.1  reinoud 	KASSERT(dvp != NULL);
    263   1.1  reinoud 	KASSERT(vp != NULL);
    264   1.1  reinoud 	KASSERT(dvp != vp);
    265   1.1  reinoud 	KASSERT(dvp->v_type == VDIR);
    266   1.1  reinoud 	KASSERT(vp->v_type != VDIR);
    267   1.1  reinoud 	KASSERT(dvp->v_mount == mp);
    268   1.1  reinoud 	KASSERT(vp->v_mount == mp);
    269   1.1  reinoud 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    270   1.1  reinoud 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    271   1.1  reinoud 
    272   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_remove_check_possible called\n"));
    273   1.1  reinoud 
    274   1.1  reinoud 	/* flags not implemented since they are not defined (yet) in UDF */
    275   1.1  reinoud 	return 0;
    276   1.1  reinoud }
    277   1.1  reinoud 
    278   1.1  reinoud 
    279   1.1  reinoud /*
    280   1.1  reinoud  * udf_gro_remove_check_permitted: check whether a remove is permitted given
    281   1.1  reinoud  * our credentials.
    282   1.1  reinoud  */
    283   1.1  reinoud static int
    284   1.1  reinoud udf_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
    285   1.1  reinoud     struct vnode *dvp, struct vnode *vp)
    286   1.1  reinoud {
    287   1.1  reinoud 	struct udf_node *dir_node = VTOI(dvp);
    288   1.1  reinoud 	struct udf_node *udf_node = VTOI(vp);
    289   1.1  reinoud 	mode_t dmode;
    290   1.1  reinoud 	uid_t duid, uid;
    291   1.1  reinoud 	gid_t gdummy;
    292   1.1  reinoud 
    293   1.1  reinoud 	(void)mp;
    294   1.1  reinoud 	KASSERT(mp != NULL);
    295   1.1  reinoud 	KASSERT(dvp != NULL);
    296   1.1  reinoud 	KASSERT(vp != NULL);
    297   1.1  reinoud 	KASSERT(dvp != vp);
    298   1.1  reinoud 	KASSERT(dvp->v_type == VDIR);
    299   1.1  reinoud 	KASSERT(vp->v_type != VDIR);
    300   1.1  reinoud 	KASSERT(dvp->v_mount == mp);
    301   1.1  reinoud 	KASSERT(vp->v_mount == mp);
    302   1.1  reinoud 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    303   1.1  reinoud 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    304   1.1  reinoud 
    305   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_remove_check_permitted called\n"));
    306   1.1  reinoud 	dmode = udf_getaccessmode(dir_node);
    307   1.1  reinoud 
    308   1.1  reinoud 	udf_getownership(dir_node, &duid, &gdummy);
    309   1.1  reinoud 	udf_getownership(udf_node, &uid,  &gdummy);
    310   1.1  reinoud 
    311   1.1  reinoud 	return genfs_ufslike_remove_check_permitted(cred,
    312   1.1  reinoud 	    dvp, dmode, duid,
    313   1.1  reinoud 	    vp, uid);
    314   1.1  reinoud }
    315   1.1  reinoud 
    316   1.1  reinoud 
    317   1.1  reinoud /*
    318   1.1  reinoud  * udf_gro_rename: actually perform the rename operation.
    319   1.1  reinoud  */
    320   1.1  reinoud static int
    321   1.1  reinoud udf_gro_rename(struct mount *mp, kauth_cred_t cred,
    322   1.1  reinoud     struct vnode *fdvp, struct componentname *fcnp,
    323   1.1  reinoud     void *fde, struct vnode *fvp,
    324   1.1  reinoud     struct vnode *tdvp, struct componentname *tcnp,
    325  1.14  thorpej     void *tde, struct vnode *tvp, nlink_t *tvp_nlinkp)
    326   1.1  reinoud {
    327   1.1  reinoud 	struct udf_node *fnode, *fdnode, *tnode, *tdnode;
    328   1.1  reinoud 	struct vattr fvap;
    329   1.1  reinoud 	int error;
    330   1.1  reinoud 
    331   1.1  reinoud 	(void)cred;
    332   1.1  reinoud 	KASSERT(mp != NULL);
    333   1.1  reinoud 	KASSERT(fdvp != NULL);
    334   1.1  reinoud 	KASSERT(fcnp != NULL);
    335   1.1  reinoud 	KASSERT(fvp != NULL);
    336   1.1  reinoud 	KASSERT(tdvp != NULL);
    337   1.1  reinoud 	KASSERT(tcnp != NULL);
    338   1.1  reinoud 	KASSERT(fdvp != fvp);
    339   1.1  reinoud 	KASSERT(fdvp != tvp);
    340   1.1  reinoud 	KASSERT(tdvp != fvp);
    341   1.1  reinoud 	KASSERT(tdvp != tvp);
    342   1.1  reinoud 	KASSERT(fvp != tvp);
    343   1.1  reinoud 	KASSERT(fdvp->v_mount == mp);
    344   1.1  reinoud 	KASSERT(fvp->v_mount == mp);
    345   1.1  reinoud 	KASSERT(tdvp->v_mount == mp);
    346   1.1  reinoud 	KASSERT((tvp == NULL) || (tvp->v_mount == mp));
    347   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    348   1.1  reinoud 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    349   1.1  reinoud 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    350   1.1  reinoud 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    351   1.1  reinoud 
    352   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_rename called\n"));
    353   1.1  reinoud 	DPRINTF(NODE, ("udf_gro_rename called : %s -> %s\n",
    354   1.1  reinoud 		fcnp->cn_nameptr, tcnp->cn_nameptr));
    355   1.1  reinoud 
    356   1.1  reinoud 	fnode  = VTOI(fvp);
    357   1.1  reinoud 	fdnode = VTOI(fdvp);
    358   1.1  reinoud 	tnode  = (tvp == NULL) ? NULL : VTOI(tvp);
    359   1.1  reinoud 	tdnode = VTOI(tdvp);
    360   1.1  reinoud 
    361   1.1  reinoud 	/* get attribute information */
    362   1.1  reinoud 	error = VOP_GETATTR(fvp, &fvap, NULL);
    363   1.1  reinoud 	if (error)
    364   1.1  reinoud 		return error;
    365   1.1  reinoud 
    366   1.1  reinoud 	/* remove existing entry if present */
    367  1.14  thorpej 	if (tvp) {
    368   1.1  reinoud 		udf_dir_detach(tdnode->ump, tdnode, tnode, tcnp);
    369  1.14  thorpej 		if (tnode->fe) {
    370  1.14  thorpej 			*tvp_nlinkp = udf_rw16(tnode->fe->link_cnt);
    371  1.14  thorpej 		} else {
    372  1.14  thorpej 			KASSERT(tnode->efe != NULL);
    373  1.14  thorpej 			*tvp_nlinkp = udf_rw16(tnode->efe->link_cnt);
    374  1.14  thorpej 		}
    375  1.14  thorpej 	}
    376   1.1  reinoud 
    377   1.1  reinoud 	/* create new directory entry for the node */
    378   1.1  reinoud 	error = udf_dir_attach(tdnode->ump, tdnode, fnode, &fvap, tcnp);
    379   1.1  reinoud 	if (error)
    380   1.1  reinoud 		return error;
    381   1.1  reinoud 
    382   1.1  reinoud 	/* unlink old directory entry for the node, if failing, unattach new */
    383   1.1  reinoud 	error = udf_dir_detach(tdnode->ump, fdnode, fnode, fcnp);
    384   1.6  reinoud 	if (error)
    385   1.6  reinoud 		goto rollback_attach;
    386   1.6  reinoud 
    387   1.6  reinoud 	if ((fdnode != tdnode) && (fvp->v_type == VDIR)) {
    388   1.1  reinoud 		/* update fnode's '..' entry */
    389   1.1  reinoud 		error = udf_dir_update_rootentry(fnode->ump, fnode, tdnode);
    390   1.6  reinoud 		if (error)
    391   1.6  reinoud 			goto rollback;
    392   1.1  reinoud 	}
    393   1.1  reinoud 
    394   1.6  reinoud 	genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp);
    395   1.6  reinoud 	return 0;
    396   1.6  reinoud 
    397   1.6  reinoud rollback:
    398   1.6  reinoud 	/* 'try' to recover from this situation */
    399   1.6  reinoud 	udf_dir_attach(tdnode->ump, fdnode, fnode, &fvap, fcnp);
    400   1.6  reinoud rollback_attach:
    401   1.6  reinoud 	udf_dir_detach(tdnode->ump, tdnode, fnode, tcnp);
    402   1.1  reinoud 
    403   1.1  reinoud 	return error;
    404   1.1  reinoud }
    405   1.1  reinoud 
    406   1.1  reinoud 
    407   1.1  reinoud /*
    408   1.1  reinoud  * udf_gro_remove: rename an object over another link to itself, effectively
    409   1.1  reinoud  * removing just the original link.
    410   1.1  reinoud  */
    411   1.1  reinoud static int
    412   1.1  reinoud udf_gro_remove(struct mount *mp, kauth_cred_t cred,
    413  1.14  thorpej     struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp,
    414  1.14  thorpej     nlink_t *tvp_nlinkp)
    415   1.1  reinoud {
    416   1.1  reinoud 	struct udf_node *dir_node, *udf_node;
    417   1.1  reinoud 
    418   1.1  reinoud 	KASSERT(mp != NULL);
    419   1.1  reinoud 	KASSERT(dvp != NULL);
    420   1.1  reinoud 	KASSERT(cnp != NULL);
    421   1.1  reinoud 	KASSERT(vp != NULL);
    422   1.1  reinoud 	KASSERT(dvp != vp);
    423   1.1  reinoud 	KASSERT(dvp->v_mount == mp);
    424   1.1  reinoud 	KASSERT(vp->v_mount == mp);
    425   1.1  reinoud 	KASSERT(dvp->v_type == VDIR);
    426   1.1  reinoud 	KASSERT(vp->v_type != VDIR);
    427   1.1  reinoud 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    428   1.1  reinoud 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    429   1.1  reinoud 
    430   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_remove called\n"));
    431   1.1  reinoud 
    432   1.1  reinoud 	dir_node = VTOI(dvp);
    433   1.1  reinoud 	udf_node = VTOI(vp);
    434   1.1  reinoud 	udf_dir_detach(dir_node->ump, dir_node, udf_node, cnp);
    435   1.1  reinoud 
    436  1.14  thorpej 	if (udf_node->fe) {
    437  1.14  thorpej 		*tvp_nlinkp = udf_rw16(udf_node->fe->link_cnt);
    438  1.14  thorpej 	} else {
    439  1.14  thorpej 		KASSERT(udf_node->efe != NULL);
    440  1.14  thorpej 		*tvp_nlinkp = udf_rw16(udf_node->efe->link_cnt);
    441  1.14  thorpej 	}
    442  1.14  thorpej 
    443   1.1  reinoud 	return 0;
    444   1.1  reinoud }
    445   1.1  reinoud 
    446   1.1  reinoud 
    447   1.1  reinoud /*
    448   1.1  reinoud  * udf_gro_lookup: look up and save the lookup results.
    449   1.1  reinoud  */
    450   1.1  reinoud static int
    451   1.1  reinoud udf_gro_lookup(struct mount *mp, struct vnode *dvp,
    452   1.1  reinoud     struct componentname *cnp, void *de_ret, struct vnode **vp_ret)
    453   1.1  reinoud {
    454   1.1  reinoud 	struct udf_node *dir_node, *res_node;
    455   1.1  reinoud 	struct long_ad   icb_loc;
    456   1.1  reinoud 	const char *name;
    457   1.1  reinoud 	int namelen, error;
    458   1.1  reinoud 	int found;
    459   1.1  reinoud 
    460   1.1  reinoud 	(void)mp;
    461   1.1  reinoud 	KASSERT(mp != NULL);
    462   1.1  reinoud 	KASSERT(dvp != NULL);
    463   1.1  reinoud 	KASSERT(cnp != NULL);
    464   1.1  reinoud 	KASSERT(vp_ret != NULL);
    465   1.1  reinoud 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    466   1.1  reinoud 
    467   1.1  reinoud 	dir_node = VTOI(dvp);
    468   1.1  reinoud 
    469   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_lookup called\n"));
    470   1.1  reinoud 
    471   1.1  reinoud 	/* lookup filename in the directory; location icb_loc */
    472   1.1  reinoud 	name    = cnp->cn_nameptr;
    473   1.1  reinoud 	namelen = cnp->cn_namelen;
    474   1.1  reinoud 	error = udf_lookup_name_in_dir(dvp, name, namelen,
    475   1.1  reinoud 			&icb_loc, &found);
    476   1.1  reinoud 	if (error)
    477   1.1  reinoud 		return error;
    478   1.1  reinoud 	if (!found)
    479   1.1  reinoud 		return ENOENT;
    480   1.1  reinoud 
    481   1.1  reinoud 	DPRINTF(LOOKUP, ("udf_gro_lookup found '%s'\n", name));
    482  1.13       ad 	error = udf_get_node(dir_node->ump, &icb_loc, &res_node, LK_EXCLUSIVE);
    483   1.1  reinoud 	if (error)
    484   1.1  reinoud 		return error;
    485   1.1  reinoud 	*vp_ret = res_node->vnode;
    486   1.1  reinoud 	VOP_UNLOCK(res_node->vnode);
    487   1.1  reinoud 
    488   1.1  reinoud 	return 0;
    489   1.1  reinoud }
    490   1.1  reinoud 
    491   1.1  reinoud 
    492   1.1  reinoud /*
    493   1.1  reinoud  * udf_rmdired_p: check whether the directory vp has been rmdired.
    494   1.1  reinoud  *
    495   1.1  reinoud  * vp must be locked and referenced.
    496   1.1  reinoud  */
    497   1.1  reinoud static bool
    498   1.1  reinoud udf_rmdired_p(struct vnode *vp)
    499   1.1  reinoud {
    500   1.1  reinoud 	DPRINTF(CALL, ("udf_rmdired_p called\n"));
    501   1.1  reinoud 
    502   1.1  reinoud 	KASSERT(vp != NULL);
    503   1.1  reinoud 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    504   1.1  reinoud 	KASSERT(vp->v_type == VDIR);
    505   1.1  reinoud 
    506   1.4  reinoud 	return (VTOI(vp)->i_flags & IN_DELETED);
    507   1.1  reinoud }
    508   1.1  reinoud 
    509   1.1  reinoud 
    510   1.1  reinoud /*
    511   1.1  reinoud  * udf_gro_genealogy: analyze the genealogy of the source and target
    512   1.1  reinoud  * directories.
    513   1.1  reinoud  */
    514   1.1  reinoud static int
    515   1.1  reinoud udf_gro_genealogy(struct mount *mp, kauth_cred_t cred,
    516   1.1  reinoud     struct vnode *fdvp, struct vnode *tdvp,
    517   1.1  reinoud     struct vnode **intermediate_node_ret)
    518   1.1  reinoud {
    519   1.1  reinoud 	struct udf_mount *ump;
    520  1.10  reinoud 	struct udf_node *parent_node;
    521  1.10  reinoud 	struct vnode *vp, *dvp;
    522   1.1  reinoud 	struct long_ad parent_loc;
    523   1.1  reinoud 	const char *name;
    524   1.1  reinoud 	int namelen;
    525   1.1  reinoud 	int error, found;
    526   1.1  reinoud 
    527   1.1  reinoud 	(void)cred;
    528   1.1  reinoud 	KASSERT(mp != NULL);
    529   1.1  reinoud 	KASSERT(fdvp != NULL);
    530   1.1  reinoud 	KASSERT(tdvp != NULL);
    531   1.1  reinoud 	KASSERT(fdvp != tdvp);
    532   1.1  reinoud 	KASSERT(intermediate_node_ret != NULL);
    533   1.1  reinoud 	KASSERT(fdvp->v_mount == mp);
    534   1.1  reinoud 	KASSERT(tdvp->v_mount == mp);
    535   1.1  reinoud 	KASSERT(fdvp->v_type == VDIR);
    536   1.1  reinoud 	KASSERT(tdvp->v_type == VDIR);
    537   1.1  reinoud 
    538   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_genealogy called\n"));
    539   1.1  reinoud 
    540   1.1  reinoud 	/*
    541   1.1  reinoud 	 * We need to provisionally lock tdvp to keep rmdir from deleting it
    542   1.1  reinoud 	 * -- or any ancestor -- at an inopportune moment.
    543   1.1  reinoud 	 *
    544   1.1  reinoud 	 * XXX WHY is this not in genfs's rename? XXX
    545   1.1  reinoud 	 */
    546   1.1  reinoud 	error = udf_gro_lock_directory(mp, tdvp);
    547   1.1  reinoud 	if (error)
    548   1.1  reinoud 		return error;
    549   1.1  reinoud 
    550   1.1  reinoud 	name     = "..";
    551   1.1  reinoud 	namelen  = 2;
    552   1.1  reinoud 	error    = 0;
    553   1.1  reinoud 
    554  1.10  reinoud 	ump = VTOI(tdvp)->ump;
    555   1.1  reinoud 
    556   1.1  reinoud 	/* if nodes are equal, it is no use looking */
    557  1.10  reinoud 	KASSERT(udf_compare_icb(&VTOI(fdvp)->loc, &VTOI(tdvp)->loc) != 0);
    558   1.1  reinoud 
    559  1.10  reinoud 	/* start at destination vnode and walk up the tree */
    560  1.10  reinoud 	vp = tdvp;
    561  1.10  reinoud 	vref(vp);
    562   1.1  reinoud 
    563   1.1  reinoud 	for (;;) {
    564  1.10  reinoud 		KASSERT(vp != NULL);
    565  1.10  reinoud 		KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    566  1.10  reinoud 		KASSERT(vp->v_mount == mp);
    567  1.10  reinoud 		KASSERT(vp->v_type == VDIR);
    568  1.10  reinoud 		KASSERT(!udf_rmdired_p(vp));
    569  1.10  reinoud 
    570   1.1  reinoud 		DPRINTF(NODE, ("udf_gro_genealogy : "
    571  1.10  reinoud 			"fdvp %p, looking at vp %p\n",
    572  1.10  reinoud 			fdvp, vp));
    573   1.1  reinoud 
    574   1.1  reinoud 		/* sanity check */
    575  1.10  reinoud 		if (vp->v_type != VDIR) {
    576  1.10  reinoud 			vput(vp);
    577   1.1  reinoud 			return ENOTDIR;
    578   1.1  reinoud 		}
    579   1.1  reinoud 
    580   1.1  reinoud 		/* go down one level */
    581  1.10  reinoud 		error = udf_lookup_name_in_dir(vp, name, namelen,
    582   1.1  reinoud 			&parent_loc, &found);
    583   1.1  reinoud 		DPRINTF(NODE, ("\tlookup of parent '..' resulted in error %d, "
    584   1.1  reinoud 			"found %d\n", error, found));
    585   1.1  reinoud 		if (!found)
    586   1.1  reinoud 			error = ENOENT;
    587   1.1  reinoud 		if (error) {
    588  1.10  reinoud 			vput(vp);
    589   1.1  reinoud 			return error;
    590   1.1  reinoud 		}
    591   1.1  reinoud 
    592   1.1  reinoud 		/* did we encounter the root node? i.e. loop back */
    593  1.10  reinoud 		if (udf_compare_icb(&parent_loc, &VTOI(vp)->loc) == 0) {
    594   1.1  reinoud 			DPRINTF(NODE, ("ROOT found!\n"));
    595  1.10  reinoud 			vput(vp);
    596   1.1  reinoud 			*intermediate_node_ret = NULL;
    597   1.1  reinoud 			return 0;
    598   1.1  reinoud 		}
    599   1.1  reinoud 
    600  1.10  reinoud 		/* Did we find that fdvp is an ancestor of tdvp? */
    601  1.10  reinoud 		if (udf_compare_icb(&parent_loc, &VTOI(fdvp)->loc) == 0) {
    602  1.10  reinoud 			DPRINTF(NODE, ("fdvp is ancestor of tdvp\n"));
    603  1.10  reinoud 			*intermediate_node_ret = vp;
    604  1.10  reinoud 			VOP_UNLOCK(vp);
    605   1.1  reinoud 			return 0;
    606   1.1  reinoud 		}
    607   1.1  reinoud 
    608   1.9  reinoud 		/*
    609   1.9  reinoud 		 * Unlock vp so that we can lock the parent, but keep child vp
    610   1.9  reinoud 		 * referenced until after we have found the parent, so that
    611  1.10  reinoud 		 * parent_node will not be recycled.
    612   1.9  reinoud 		 */
    613   1.1  reinoud 		DPRINTF(NODE, ("\tgetting the parent node\n"));
    614  1.10  reinoud 		VOP_UNLOCK(vp);
    615  1.13       ad 		error = udf_get_node(ump, &parent_loc, &parent_node,
    616  1.13       ad 		    LK_EXCLUSIVE);
    617  1.10  reinoud 		vrele(vp);
    618   1.9  reinoud 		if (error)
    619   1.9  reinoud 			return error;
    620   1.9  reinoud 
    621  1.10  reinoud 		dvp = parent_node->vnode;
    622  1.10  reinoud 
    623  1.10  reinoud 		/* switch */
    624  1.10  reinoud 		KASSERT(dvp != NULL);
    625  1.10  reinoud 		KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    626  1.10  reinoud 		vp  = dvp;
    627  1.10  reinoud 
    628   1.9  reinoud 		/* sanity check */
    629  1.10  reinoud 		if (vp->v_type != VDIR) {
    630   1.9  reinoud 			/*
    631   1.9  reinoud 			 * Odd, but can happen if we loose the race and the
    632   1.9  reinoud 			 * '..' node has been recycled.
    633   1.9  reinoud 			 */
    634  1.10  reinoud 			vput(vp);
    635   1.9  reinoud 			return ENOTDIR;
    636   1.1  reinoud 		}
    637   1.1  reinoud 
    638  1.10  reinoud 		if (udf_rmdired_p(vp)) {
    639  1.10  reinoud 			vput(vp);
    640   1.1  reinoud 			return ENOENT;
    641   1.1  reinoud 		}
    642   1.1  reinoud 	}
    643   1.1  reinoud }
    644   1.1  reinoud 
    645   1.1  reinoud 
    646   1.1  reinoud /*
    647   1.1  reinoud  * udf_gro_lock_directory: lock the directory vp, but fail if it has been
    648   1.1  reinoud  * rmdir'd.
    649   1.1  reinoud  */
    650   1.1  reinoud static int
    651   1.1  reinoud udf_gro_lock_directory(struct mount *mp, struct vnode *vp)
    652   1.1  reinoud {
    653   1.1  reinoud 
    654   1.1  reinoud 	(void)mp;
    655   1.1  reinoud 	KASSERT(mp != NULL);
    656   1.1  reinoud 	KASSERT(vp != NULL);
    657   1.1  reinoud 	KASSERT(vp->v_mount == mp);
    658   1.1  reinoud 
    659   1.1  reinoud 	DPRINTF(CALL, ("udf_gro_lock_directory called\n"));
    660   1.1  reinoud 	DPRINTF(LOCKING, ("udf_gro_lock_directory called\n"));
    661   1.1  reinoud 
    662   1.1  reinoud 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    663   1.1  reinoud 
    664   1.1  reinoud 	if (udf_rmdired_p(vp)) {
    665   1.1  reinoud 		VOP_UNLOCK(vp);
    666   1.1  reinoud 		return ENOENT;
    667   1.1  reinoud 	}
    668   1.1  reinoud 
    669   1.1  reinoud 	return 0;
    670   1.1  reinoud }
    671   1.1  reinoud 
    672   1.1  reinoud 
    673   1.1  reinoud static const struct genfs_rename_ops udf_genfs_rename_ops = {
    674   1.1  reinoud 	.gro_directory_empty_p		= udf_gro_directory_empty_p,
    675   1.1  reinoud 	.gro_rename_check_possible	= udf_gro_rename_check_possible,
    676   1.1  reinoud 	.gro_rename_check_permitted	= udf_gro_rename_check_permitted,
    677   1.1  reinoud 	.gro_remove_check_possible	= udf_gro_remove_check_possible,
    678   1.1  reinoud 	.gro_remove_check_permitted	= udf_gro_remove_check_permitted,
    679   1.1  reinoud 	.gro_rename			= udf_gro_rename,
    680   1.1  reinoud 	.gro_remove			= udf_gro_remove,
    681   1.1  reinoud 	.gro_lookup			= udf_gro_lookup,
    682   1.1  reinoud 	.gro_genealogy			= udf_gro_genealogy,
    683   1.1  reinoud 	.gro_lock_directory		= udf_gro_lock_directory,
    684   1.1  reinoud };
    685