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