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