1 /* $NetBSD: udf_rename.c,v 1.12 2014/11/10 19:44:08 riz Exp $ */
4 * Copyright (c) 2013 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * Comments and trivial code from the reference implementation in tmpfs.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: udf_rename.c,v 1.12 2014/11/10 19:44:08 riz Exp $");
33 #include <sys/param.h>
34 #include <sys/errno.h>
35 #include <sys/kauth.h>
36 #include <sys/mount.h>
37 #include <sys/namei.h>
39 #include <sys/malloc.h>
40 #include <sys/dirent.h>
41 #include <sys/vnode.h>
42 #include <sys/vnode_if.h>
44 #include <miscfs/genfs/genfs.h>
46 #include <fs/udf/ecma167-udf.h>
47 #include <fs/udf/udf_mount.h>
48 #include <sys/dirhash.h>
52 #include "udf_bswap.h"
56 static int udf_sane_rename( struct vnode
*, struct componentname
*,
57 struct vnode
*, struct componentname
*,
59 static bool udf_rmdired_p(struct vnode
*);
60 static int udf_gro_lock_directory(struct mount
*, struct vnode
*);
62 static const struct genfs_rename_ops udf_genfs_rename_ops
;
65 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
69 * udf_sane_rename: The hairiest vop, with the saner API.
73 * . fdvp (from directory vnode),
74 * . fcnp (from component name),
75 * . tdvp (to directory vnode),
76 * . tcnp (to component name),
77 * . cred (credentials structure), and
78 * . posixly_correct (flag for behaviour if target & source link same file).
80 * fdvp and tdvp may be the same, and must be referenced and unlocked.
83 udf_sane_rename( struct vnode
*fdvp
, struct componentname
*fcnp
,
84 struct vnode
*tdvp
, struct componentname
*tcnp
,
85 kauth_cred_t cred
, bool posixly_correct
)
87 DPRINTF(CALL
, ("udf_sane_rename '%s' -> '%s'\n",
88 fcnp
->cn_nameptr
, tcnp
->cn_nameptr
));
89 return genfs_sane_rename(&udf_genfs_rename_ops
,
90 fdvp
, fcnp
, NULL
, tdvp
, tcnp
, NULL
,
91 cred
, posixly_correct
);
96 * udf_rename: the hairiest vop, with the insanest API. Pass to
97 * genfs_insane_rename immediately.
102 struct vop_rename_args
/* {
103 struct vnode *a_fdvp;
105 struct componentname *a_fcnp;
106 struct vnode *a_tdvp;
108 struct componentname *a_tcnp;
110 DPRINTF(CALL
, ("udf_rename called\n"));
111 return genfs_insane_rename(ap
, &udf_sane_rename
);
116 * udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is
119 * vp and dvp must be locked and referenced.
122 udf_gro_directory_empty_p(struct mount
*mp
, kauth_cred_t cred
,
123 struct vnode
*vp
, struct vnode
*dvp
)
125 struct udf_node
*udf_node
= VTOI(vp
);
130 KASSERT(dvp
!= NULL
);
132 KASSERT(vp
->v_mount
== mp
);
133 KASSERT(dvp
->v_mount
== mp
);
134 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
135 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
137 DPRINTF(CALL
, ("udf_gro_directory_empty_p called\n"));
138 /* make sure our `leaf' node's hash is populated */
139 dirhash_get(&udf_node
->dir_hash
);
140 error
= udf_dirhash_fill(udf_node
);
142 dirhash_put(udf_node
->dir_hash
);
143 /* VERY unlikely, answer its not empty */
147 /* check to see if the directory is empty */
148 isempty
= dirhash_dir_isempty(udf_node
->dir_hash
);
149 dirhash_put(udf_node
->dir_hash
);
156 * udf_gro_rename_check_possible: check whether a rename is possible
157 * independent of credentials.
160 udf_gro_rename_check_possible(struct mount
*mp
,
161 struct vnode
*fdvp
, struct vnode
*fvp
,
162 struct vnode
*tdvp
, struct vnode
*tvp
)
166 KASSERT(fdvp
!= NULL
);
167 KASSERT(fvp
!= NULL
);
168 KASSERT(tdvp
!= NULL
);
169 KASSERT(fdvp
!= fvp
);
170 KASSERT(fdvp
!= tvp
);
171 KASSERT(tdvp
!= fvp
);
172 KASSERT(tdvp
!= tvp
);
174 KASSERT(fdvp
->v_type
== VDIR
);
175 KASSERT(tdvp
->v_type
== VDIR
);
176 KASSERT(fdvp
->v_mount
== mp
);
177 KASSERT(fvp
->v_mount
== mp
);
178 KASSERT(tdvp
->v_mount
== mp
);
179 KASSERT((tvp
== NULL
) || (tvp
->v_mount
== mp
));
180 KASSERT(VOP_ISLOCKED(fdvp
) == LK_EXCLUSIVE
);
181 KASSERT(VOP_ISLOCKED(fvp
) == LK_EXCLUSIVE
);
182 KASSERT(VOP_ISLOCKED(tdvp
) == LK_EXCLUSIVE
);
183 KASSERT((tvp
== NULL
) || (VOP_ISLOCKED(tvp
) == LK_EXCLUSIVE
));
185 DPRINTF(CALL
, ("udf_gro_rename_check_possible called\n"));
187 /* flags not implemented since they are not defined (yet) in UDF */
193 * udf_gro_rename_check_permitted: check whether a rename is permitted given
197 udf_gro_rename_check_permitted(struct mount
*mp
, kauth_cred_t cred
,
198 struct vnode
*fdvp
, struct vnode
*fvp
,
199 struct vnode
*tdvp
, struct vnode
*tvp
)
201 struct udf_node
*fdir_node
= VTOI(fdvp
);
202 struct udf_node
*tdir_node
= VTOI(tdvp
);
203 struct udf_node
*f_node
= VTOI(fvp
);
204 struct udf_node
*t_node
= (tvp
? VTOI(tvp
): NULL
);
205 mode_t fdmode
, tdmode
;
206 uid_t fduid
, tduid
, fuid
, tuid
;
211 KASSERT(fdvp
!= NULL
);
212 KASSERT(fvp
!= NULL
);
213 KASSERT(tdvp
!= NULL
);
214 KASSERT(fdvp
!= fvp
);
215 KASSERT(fdvp
!= tvp
);
216 KASSERT(tdvp
!= fvp
);
217 KASSERT(tdvp
!= tvp
);
219 KASSERT(fdvp
->v_type
== VDIR
);
220 KASSERT(tdvp
->v_type
== VDIR
);
221 KASSERT(fdvp
->v_mount
== mp
);
222 KASSERT(fvp
->v_mount
== mp
);
223 KASSERT(tdvp
->v_mount
== mp
);
224 KASSERT((tvp
== NULL
) || (tvp
->v_mount
== mp
));
225 KASSERT(VOP_ISLOCKED(fdvp
) == LK_EXCLUSIVE
);
226 KASSERT(VOP_ISLOCKED(fvp
) == LK_EXCLUSIVE
);
227 KASSERT(VOP_ISLOCKED(tdvp
) == LK_EXCLUSIVE
);
228 KASSERT((tvp
== NULL
) || (VOP_ISLOCKED(tvp
) == LK_EXCLUSIVE
));
230 DPRINTF(CALL
, ("udf_gro_rename_check_permitted called\n"));
231 fdmode
= udf_getaccessmode(fdir_node
);
232 tdmode
= udf_getaccessmode(tdir_node
);
234 udf_getownership(fdir_node
, &fduid
, &gdummy
);
235 udf_getownership(tdir_node
, &tduid
, &gdummy
);
236 udf_getownership(f_node
, &fuid
, &gdummy
);
240 udf_getownership(t_node
, &tuid
, &gdummy
);
242 return genfs_ufslike_rename_check_permitted(cred
,
251 * udf_gro_remove_check_possible: check whether a remove is possible
252 * independent of credentials.
254 * XXX could check for special attributes?
257 udf_gro_remove_check_possible(struct mount
*mp
,
258 struct vnode
*dvp
, struct vnode
*vp
)
262 KASSERT(dvp
!= NULL
);
265 KASSERT(dvp
->v_type
== VDIR
);
266 KASSERT(vp
->v_type
!= VDIR
);
267 KASSERT(dvp
->v_mount
== mp
);
268 KASSERT(vp
->v_mount
== mp
);
269 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
270 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
272 DPRINTF(CALL
, ("udf_gro_remove_check_possible called\n"));
274 /* flags not implemented since they are not defined (yet) in UDF */
280 * udf_gro_remove_check_permitted: check whether a remove is permitted given
284 udf_gro_remove_check_permitted(struct mount
*mp
, kauth_cred_t cred
,
285 struct vnode
*dvp
, struct vnode
*vp
)
287 struct udf_node
*dir_node
= VTOI(dvp
);
288 struct udf_node
*udf_node
= VTOI(vp
);
295 KASSERT(dvp
!= NULL
);
298 KASSERT(dvp
->v_type
== VDIR
);
299 KASSERT(vp
->v_type
!= VDIR
);
300 KASSERT(dvp
->v_mount
== mp
);
301 KASSERT(vp
->v_mount
== mp
);
302 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
303 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
305 DPRINTF(CALL
, ("udf_gro_remove_check_permitted called\n"));
306 dmode
= udf_getaccessmode(dir_node
);
308 udf_getownership(dir_node
, &duid
, &gdummy
);
309 udf_getownership(udf_node
, &uid
, &gdummy
);
311 return genfs_ufslike_remove_check_permitted(cred
,
318 * udf_gro_rename: actually perform the rename operation.
321 udf_gro_rename(struct mount
*mp
, kauth_cred_t cred
,
322 struct vnode
*fdvp
, struct componentname
*fcnp
,
323 void *fde
, struct vnode
*fvp
,
324 struct vnode
*tdvp
, struct componentname
*tcnp
,
325 void *tde
, struct vnode
*tvp
)
327 struct udf_node
*fnode
, *fdnode
, *tnode
, *tdnode
;
333 KASSERT(fdvp
!= NULL
);
334 KASSERT(fcnp
!= NULL
);
335 KASSERT(fvp
!= NULL
);
336 KASSERT(tdvp
!= NULL
);
337 KASSERT(tcnp
!= NULL
);
338 KASSERT(fdvp
!= fvp
);
339 KASSERT(fdvp
!= tvp
);
340 KASSERT(tdvp
!= fvp
);
341 KASSERT(tdvp
!= tvp
);
343 KASSERT(fdvp
->v_mount
== mp
);
344 KASSERT(fvp
->v_mount
== mp
);
345 KASSERT(tdvp
->v_mount
== mp
);
346 KASSERT((tvp
== NULL
) || (tvp
->v_mount
== mp
));
347 KASSERT(VOP_ISLOCKED(fdvp
) == LK_EXCLUSIVE
);
348 KASSERT(VOP_ISLOCKED(fvp
) == LK_EXCLUSIVE
);
349 KASSERT(VOP_ISLOCKED(tdvp
) == LK_EXCLUSIVE
);
350 KASSERT((tvp
== NULL
) || (VOP_ISLOCKED(tvp
) == LK_EXCLUSIVE
));
352 DPRINTF(CALL
, ("udf_gro_rename called\n"));
353 DPRINTF(NODE
, ("udf_gro_rename called : %s -> %s\n",
354 fcnp
->cn_nameptr
, tcnp
->cn_nameptr
));
358 tnode
= (tvp
== NULL
) ? NULL
: VTOI(tvp
);
361 /* get attribute information */
362 error
= VOP_GETATTR(fvp
, &fvap
, NULL
);
366 /* remove existing entry if present */
368 udf_dir_detach(tdnode
->ump
, tdnode
, tnode
, tcnp
);
370 /* create new directory entry for the node */
371 error
= udf_dir_attach(tdnode
->ump
, tdnode
, fnode
, &fvap
, tcnp
);
375 /* unlink old directory entry for the node, if failing, unattach new */
376 error
= udf_dir_detach(tdnode
->ump
, fdnode
, fnode
, fcnp
);
378 goto rollback_attach
;
380 if ((fdnode
!= tdnode
) && (fvp
->v_type
== VDIR
)) {
381 /* update fnode's '..' entry */
382 error
= udf_dir_update_rootentry(fnode
->ump
, fnode
, tdnode
);
387 VN_KNOTE(fvp
, NOTE_RENAME
);
388 genfs_rename_cache_purge(fdvp
, fvp
, tdvp
, tvp
);
392 /* 'try' to recover from this situation */
393 udf_dir_attach(tdnode
->ump
, fdnode
, fnode
, &fvap
, fcnp
);
395 udf_dir_detach(tdnode
->ump
, tdnode
, fnode
, tcnp
);
402 * udf_gro_remove: rename an object over another link to itself, effectively
403 * removing just the original link.
406 udf_gro_remove(struct mount
*mp
, kauth_cred_t cred
,
407 struct vnode
*dvp
, struct componentname
*cnp
, void *de
, struct vnode
*vp
)
409 struct udf_node
*dir_node
, *udf_node
;
412 KASSERT(dvp
!= NULL
);
413 KASSERT(cnp
!= NULL
);
416 KASSERT(dvp
->v_mount
== mp
);
417 KASSERT(vp
->v_mount
== mp
);
418 KASSERT(dvp
->v_type
== VDIR
);
419 KASSERT(vp
->v_type
!= VDIR
);
420 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
421 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
423 DPRINTF(CALL
, ("udf_gro_remove called\n"));
425 dir_node
= VTOI(dvp
);
427 udf_dir_detach(dir_node
->ump
, dir_node
, udf_node
, cnp
);
434 * udf_gro_lookup: look up and save the lookup results.
437 udf_gro_lookup(struct mount
*mp
, struct vnode
*dvp
,
438 struct componentname
*cnp
, void *de_ret
, struct vnode
**vp_ret
)
440 struct udf_node
*dir_node
, *res_node
;
441 struct long_ad icb_loc
;
448 KASSERT(dvp
!= NULL
);
449 KASSERT(cnp
!= NULL
);
450 KASSERT(vp_ret
!= NULL
);
451 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
453 dir_node
= VTOI(dvp
);
455 DPRINTF(CALL
, ("udf_gro_lookup called\n"));
457 /* lookup filename in the directory; location icb_loc */
458 name
= cnp
->cn_nameptr
;
459 namelen
= cnp
->cn_namelen
;
460 error
= udf_lookup_name_in_dir(dvp
, name
, namelen
,
467 DPRINTF(LOOKUP
, ("udf_gro_lookup found '%s'\n", name
));
468 error
= udf_get_node(dir_node
->ump
, &icb_loc
, &res_node
);
471 *vp_ret
= res_node
->vnode
;
472 VOP_UNLOCK(res_node
->vnode
);
479 * udf_rmdired_p: check whether the directory vp has been rmdired.
481 * vp must be locked and referenced.
484 udf_rmdired_p(struct vnode
*vp
)
486 DPRINTF(CALL
, ("udf_rmdired_p called\n"));
489 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
490 KASSERT(vp
->v_type
== VDIR
);
492 return (VTOI(vp
)->i_flags
& IN_DELETED
);
497 * udf_gro_genealogy: analyze the genealogy of the source and target
501 udf_gro_genealogy(struct mount
*mp
, kauth_cred_t cred
,
502 struct vnode
*fdvp
, struct vnode
*tdvp
,
503 struct vnode
**intermediate_node_ret
)
505 struct udf_mount
*ump
;
506 struct udf_node
*parent_node
;
507 struct vnode
*vp
, *dvp
;
508 struct long_ad parent_loc
;
515 KASSERT(fdvp
!= NULL
);
516 KASSERT(tdvp
!= NULL
);
517 KASSERT(fdvp
!= tdvp
);
518 KASSERT(intermediate_node_ret
!= NULL
);
519 KASSERT(fdvp
->v_mount
== mp
);
520 KASSERT(tdvp
->v_mount
== mp
);
521 KASSERT(fdvp
->v_type
== VDIR
);
522 KASSERT(tdvp
->v_type
== VDIR
);
524 DPRINTF(CALL
, ("udf_gro_genealogy called\n"));
527 * We need to provisionally lock tdvp to keep rmdir from deleting it
528 * -- or any ancestor -- at an inopportune moment.
530 * XXX WHY is this not in genfs's rename? XXX
532 error
= udf_gro_lock_directory(mp
, tdvp
);
540 ump
= VTOI(tdvp
)->ump
;
542 /* if nodes are equal, it is no use looking */
543 KASSERT(udf_compare_icb(&VTOI(fdvp
)->loc
, &VTOI(tdvp
)->loc
) != 0);
545 /* start at destination vnode and walk up the tree */
551 KASSERT(VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
552 KASSERT(vp
->v_mount
== mp
);
553 KASSERT(vp
->v_type
== VDIR
);
554 KASSERT(!udf_rmdired_p(vp
));
556 DPRINTF(NODE
, ("udf_gro_genealogy : "
557 "fdvp %p, looking at vp %p\n",
561 if (vp
->v_type
!= VDIR
) {
566 /* go down one level */
567 error
= udf_lookup_name_in_dir(vp
, name
, namelen
,
568 &parent_loc
, &found
);
569 DPRINTF(NODE
, ("\tlookup of parent '..' resulted in error %d, "
570 "found %d\n", error
, found
));
578 /* did we encounter the root node? i.e. loop back */
579 if (udf_compare_icb(&parent_loc
, &VTOI(vp
)->loc
) == 0) {
580 DPRINTF(NODE
, ("ROOT found!\n"));
582 *intermediate_node_ret
= NULL
;
586 /* Did we find that fdvp is an ancestor of tdvp? */
587 if (udf_compare_icb(&parent_loc
, &VTOI(fdvp
)->loc
) == 0) {
588 DPRINTF(NODE
, ("fdvp is ancestor of tdvp\n"));
589 *intermediate_node_ret
= vp
;
595 * Unlock vp so that we can lock the parent, but keep child vp
596 * referenced until after we have found the parent, so that
597 * parent_node will not be recycled.
599 DPRINTF(NODE
, ("\tgetting the parent node\n"));
601 error
= udf_get_node(ump
, &parent_loc
, &parent_node
);
606 dvp
= parent_node
->vnode
;
609 KASSERT(dvp
!= NULL
);
610 KASSERT(VOP_ISLOCKED(dvp
) == LK_EXCLUSIVE
);
614 if (vp
->v_type
!= VDIR
) {
616 * Odd, but can happen if we loose the race and the
617 * '..' node has been recycled.
623 if (udf_rmdired_p(vp
)) {
632 * udf_gro_lock_directory: lock the directory vp, but fail if it has been
636 udf_gro_lock_directory(struct mount
*mp
, struct vnode
*vp
)
642 KASSERT(vp
->v_mount
== mp
);
644 DPRINTF(CALL
, ("udf_gro_lock_directory called\n"));
645 DPRINTF(LOCKING
, ("udf_gro_lock_directory called\n"));
647 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
649 if (udf_rmdired_p(vp
)) {
658 static const struct genfs_rename_ops udf_genfs_rename_ops
= {
659 .gro_directory_empty_p
= udf_gro_directory_empty_p
,
660 .gro_rename_check_possible
= udf_gro_rename_check_possible
,
661 .gro_rename_check_permitted
= udf_gro_rename_check_permitted
,
662 .gro_remove_check_possible
= udf_gro_remove_check_possible
,
663 .gro_remove_check_permitted
= udf_gro_remove_check_permitted
,
664 .gro_rename
= udf_gro_rename
,
665 .gro_remove
= udf_gro_remove
,
666 .gro_lookup
= udf_gro_lookup
,
667 .gro_genealogy
= udf_gro_genealogy
,
668 .gro_lock_directory
= udf_gro_lock_directory
,