genfs_rename.c revision 1.6 1 1.6 thorpej /* $NetBSD: genfs_rename.c,v 1.6 2021/10/20 03:08:18 thorpej Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation
8 1.1 riastrad * by Taylor R Campbell.
9 1.1 riastrad *
10 1.1 riastrad * Redistribution and use in source and binary forms, with or without
11 1.1 riastrad * modification, are permitted provided that the following conditions
12 1.1 riastrad * are met:
13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
14 1.1 riastrad * notice, this list of conditions and the following disclaimer.
15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
17 1.1 riastrad * documentation and/or other materials provided with the distribution.
18 1.1 riastrad *
19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
30 1.1 riastrad */
31 1.1 riastrad
32 1.1 riastrad /*
33 1.1 riastrad * Generic rename abstraction.
34 1.1 riastrad *
35 1.1 riastrad * Rename is unbelievably hairy. Try to use this if you can --
36 1.1 riastrad * otherwise you are practically guaranteed to get it wrong.
37 1.1 riastrad */
38 1.1 riastrad
39 1.1 riastrad #include <sys/cdefs.h>
40 1.6 thorpej __KERNEL_RCSID(0, "$NetBSD: genfs_rename.c,v 1.6 2021/10/20 03:08:18 thorpej Exp $");
41 1.1 riastrad
42 1.1 riastrad #include <sys/param.h>
43 1.1 riastrad #include <sys/kauth.h>
44 1.1 riastrad #include <sys/mount.h>
45 1.1 riastrad #include <sys/namei.h>
46 1.1 riastrad #include <sys/stat.h>
47 1.1 riastrad #include <sys/vnode.h>
48 1.1 riastrad #include <sys/types.h>
49 1.1 riastrad
50 1.1 riastrad #include <miscfs/genfs/genfs.h>
51 1.1 riastrad
52 1.1 riastrad /*
53 1.1 riastrad * Sample copypasta for implementing VOP_RENAME via genfs_rename.
54 1.1 riastrad * Don't change this template without carefully considering whether
55 1.1 riastrad * every other file system that already uses it needs to change too.
56 1.1 riastrad * That way, once we have changed all the file systems to use it, we
57 1.1 riastrad * can easily replace mumblefs_rename by mumblefs_sane_rename and
58 1.1 riastrad * eliminate the insane API altogether.
59 1.1 riastrad */
60 1.1 riastrad
61 1.1 riastrad /* begin sample copypasta */
62 1.1 riastrad #if 0
63 1.1 riastrad
64 1.1 riastrad static const struct genfs_rename_ops mumblefs_genfs_rename_ops;
65 1.1 riastrad
66 1.1 riastrad /*
67 1.1 riastrad * mumblefs_sane_rename: The hairiest vop, with the saner API.
68 1.1 riastrad *
69 1.1 riastrad * Arguments:
70 1.1 riastrad *
71 1.1 riastrad * . fdvp (from directory vnode),
72 1.1 riastrad * . fcnp (from component name),
73 1.1 riastrad * . tdvp (to directory vnode),
74 1.1 riastrad * . tcnp (to component name),
75 1.1 riastrad * . cred (credentials structure), and
76 1.1 riastrad * . posixly_correct (flag for behaviour if target & source link same file).
77 1.1 riastrad *
78 1.1 riastrad * fdvp and tdvp may be the same, and must be referenced and unlocked.
79 1.1 riastrad */
80 1.1 riastrad static int
81 1.1 riastrad mumblefs_sane_rename(
82 1.1 riastrad struct vnode *fdvp, struct componentname *fcnp,
83 1.1 riastrad struct vnode *tdvp, struct componentname *tcnp,
84 1.1 riastrad kauth_cred_t cred, bool posixly_correct)
85 1.1 riastrad {
86 1.1 riastrad struct mumblefs_lookup_results fulr, tulr;
87 1.1 riastrad
88 1.1 riastrad return genfs_sane_rename(&mumblefs_genfs_rename_ops,
89 1.1 riastrad fdvp, fcnp, &fulr, tdvp, tcnp, &tulr,
90 1.1 riastrad cred, posixly_correct);
91 1.1 riastrad }
92 1.1 riastrad
93 1.1 riastrad /*
94 1.1 riastrad * mumblefs_rename: The hairiest vop, with the insanest API. Defer to
95 1.1 riastrad * genfs_insane_rename immediately.
96 1.1 riastrad */
97 1.1 riastrad int
98 1.1 riastrad mumblefs_rename(void *v)
99 1.1 riastrad {
100 1.1 riastrad
101 1.1 riastrad return genfs_insane_rename(v, &mumblefs_sane_rename);
102 1.1 riastrad }
103 1.1 riastrad
104 1.1 riastrad #endif
105 1.1 riastrad /* end sample copypasta */
106 1.1 riastrad
107 1.1 riastrad /*
108 1.1 riastrad * Forward declarations
109 1.1 riastrad */
110 1.1 riastrad
111 1.1 riastrad static int genfs_rename_enter(const struct genfs_rename_ops *, struct mount *,
112 1.1 riastrad kauth_cred_t,
113 1.1 riastrad struct vnode *, struct componentname *, void *, struct vnode **,
114 1.1 riastrad struct vnode *, struct componentname *, void *, struct vnode **);
115 1.1 riastrad static int genfs_rename_enter_common(const struct genfs_rename_ops *,
116 1.1 riastrad struct mount *, kauth_cred_t, struct vnode *,
117 1.1 riastrad struct componentname *, void *, struct vnode **,
118 1.1 riastrad struct componentname *, void *, struct vnode **);
119 1.1 riastrad static int genfs_rename_enter_separate(const struct genfs_rename_ops *,
120 1.1 riastrad struct mount *, kauth_cred_t,
121 1.1 riastrad struct vnode *, struct componentname *, void *, struct vnode **,
122 1.1 riastrad struct vnode *, struct componentname *, void *, struct vnode **);
123 1.1 riastrad static int genfs_rename_lock(const struct genfs_rename_ops *, struct mount *,
124 1.1 riastrad kauth_cred_t, int, int, int,
125 1.1 riastrad struct vnode *, struct componentname *, bool, void *, struct vnode **,
126 1.1 riastrad struct vnode *, struct componentname *, bool, void *, struct vnode **);
127 1.1 riastrad static void genfs_rename_exit(const struct genfs_rename_ops *, struct mount *,
128 1.1 riastrad struct vnode *, struct vnode *,
129 1.1 riastrad struct vnode *, struct vnode *);
130 1.1 riastrad static int genfs_rename_remove(const struct genfs_rename_ops *, struct mount *,
131 1.1 riastrad kauth_cred_t,
132 1.6 thorpej struct vnode *, struct componentname *, void *, struct vnode *, nlink_t *);
133 1.1 riastrad
134 1.1 riastrad /*
135 1.1 riastrad * genfs_insane_rename: Generic implementation of the insane API for
136 1.1 riastrad * the rename vop.
137 1.1 riastrad *
138 1.1 riastrad * Arguments:
139 1.1 riastrad *
140 1.1 riastrad * . fdvp (from directory vnode),
141 1.1 riastrad * . fvp (from vnode),
142 1.1 riastrad * . fcnp (from component name),
143 1.1 riastrad * . tdvp (to directory vnode),
144 1.1 riastrad * . tvp (to vnode, or NULL), and
145 1.1 riastrad * . tcnp (to component name).
146 1.1 riastrad *
147 1.1 riastrad * Any pair of vnode parameters may have the same vnode.
148 1.1 riastrad *
149 1.1 riastrad * On entry,
150 1.1 riastrad *
151 1.1 riastrad * . fdvp, fvp, tdvp, and tvp are referenced,
152 1.1 riastrad * . fdvp and fvp are unlocked, and
153 1.1 riastrad * . tdvp and tvp (if nonnull) are locked.
154 1.1 riastrad *
155 1.1 riastrad * On exit,
156 1.1 riastrad *
157 1.1 riastrad * . fdvp, fvp, tdvp, and tvp (if nonnull) are unreferenced, and
158 1.1 riastrad * . tdvp and tvp (if nonnull) are unlocked.
159 1.1 riastrad */
160 1.1 riastrad int
161 1.1 riastrad genfs_insane_rename(void *v,
162 1.1 riastrad int (*sane_rename)(struct vnode *fdvp, struct componentname *fcnp,
163 1.1 riastrad struct vnode *tdvp, struct componentname *tcnp,
164 1.1 riastrad kauth_cred_t cred, bool posixly_correct))
165 1.1 riastrad {
166 1.6 thorpej struct vop_rename_args /* {
167 1.1 riastrad struct vnode *a_fdvp;
168 1.1 riastrad struct vnode *a_fvp;
169 1.1 riastrad struct componentname *a_fcnp;
170 1.1 riastrad struct vnode *a_tdvp;
171 1.1 riastrad struct vnode *a_tvp;
172 1.1 riastrad struct componentname *a_tcnp;
173 1.1 riastrad } */ *ap = v;
174 1.1 riastrad struct vnode *fdvp = ap->a_fdvp;
175 1.1 riastrad struct vnode *fvp = ap->a_fvp;
176 1.1 riastrad struct componentname *fcnp = ap->a_fcnp;
177 1.1 riastrad struct vnode *tdvp = ap->a_tdvp;
178 1.1 riastrad struct vnode *tvp = ap->a_tvp;
179 1.1 riastrad struct componentname *tcnp = ap->a_tcnp;
180 1.1 riastrad kauth_cred_t cred;
181 1.1 riastrad int error;
182 1.1 riastrad
183 1.1 riastrad KASSERT(fdvp != NULL);
184 1.1 riastrad KASSERT(fvp != NULL);
185 1.1 riastrad KASSERT(fcnp != NULL);
186 1.1 riastrad KASSERT(fcnp->cn_nameptr != NULL);
187 1.1 riastrad KASSERT(tdvp != NULL);
188 1.1 riastrad KASSERT(tcnp != NULL);
189 1.1 riastrad KASSERT(fcnp->cn_nameptr != NULL);
190 1.1 riastrad /* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
191 1.1 riastrad /* KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
192 1.1 riastrad KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
193 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
194 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
195 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
196 1.1 riastrad
197 1.1 riastrad cred = fcnp->cn_cred;
198 1.1 riastrad
199 1.1 riastrad /*
200 1.1 riastrad * XXX Want a better equality test. `tcnp->cn_cred == cred'
201 1.1 riastrad * hoses p2k because puffs transmits the creds separately and
202 1.1 riastrad * allocates distinct but equivalent structures for them.
203 1.1 riastrad */
204 1.1 riastrad KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
205 1.1 riastrad
206 1.1 riastrad /*
207 1.1 riastrad * Sanitize our world from the VFS insanity. Unlock the target
208 1.1 riastrad * directory and node, which are locked. Release the children,
209 1.1 riastrad * which are referenced, since we'll be looking them up again
210 1.1 riastrad * later.
211 1.1 riastrad */
212 1.1 riastrad
213 1.1 riastrad VOP_UNLOCK(tdvp);
214 1.1 riastrad if ((tvp != NULL) && (tvp != tdvp))
215 1.1 riastrad VOP_UNLOCK(tvp);
216 1.1 riastrad
217 1.1 riastrad vrele(fvp);
218 1.1 riastrad if (tvp != NULL)
219 1.1 riastrad vrele(tvp);
220 1.1 riastrad
221 1.1 riastrad error = (*sane_rename)(fdvp, fcnp, tdvp, tcnp, cred, false);
222 1.1 riastrad
223 1.1 riastrad /*
224 1.1 riastrad * All done, whether with success or failure. Release the
225 1.1 riastrad * directory nodes now, as the caller expects from the VFS
226 1.1 riastrad * protocol.
227 1.1 riastrad */
228 1.1 riastrad vrele(fdvp);
229 1.1 riastrad vrele(tdvp);
230 1.1 riastrad
231 1.1 riastrad return error;
232 1.1 riastrad }
233 1.1 riastrad
234 1.1 riastrad /*
235 1.1 riastrad * genfs_sane_rename: Generic implementation of the saner API for the
236 1.1 riastrad * rename vop. Handles ancestry checks, locking, and permissions
237 1.1 riastrad * checks. Caller is responsible for implementing the genfs rename
238 1.1 riastrad * operations.
239 1.1 riastrad *
240 1.1 riastrad * fdvp and tdvp must be referenced and unlocked.
241 1.1 riastrad */
242 1.1 riastrad int
243 1.1 riastrad genfs_sane_rename(const struct genfs_rename_ops *ops,
244 1.1 riastrad struct vnode *fdvp, struct componentname *fcnp, void *fde,
245 1.1 riastrad struct vnode *tdvp, struct componentname *tcnp, void *tde,
246 1.1 riastrad kauth_cred_t cred, bool posixly_correct)
247 1.1 riastrad {
248 1.1 riastrad struct mount *mp;
249 1.1 riastrad struct vnode *fvp = NULL, *tvp = NULL;
250 1.6 thorpej nlink_t tvp_new_nlink = 0;
251 1.1 riastrad int error;
252 1.1 riastrad
253 1.1 riastrad KASSERT(ops != NULL);
254 1.1 riastrad KASSERT(fdvp != NULL);
255 1.1 riastrad KASSERT(fcnp != NULL);
256 1.1 riastrad KASSERT(tdvp != NULL);
257 1.1 riastrad KASSERT(tcnp != NULL);
258 1.1 riastrad /* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
259 1.1 riastrad /* KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
260 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
261 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
262 1.1 riastrad KASSERT(fdvp->v_mount == tdvp->v_mount);
263 1.1 riastrad KASSERT(fcnp != tcnp);
264 1.1 riastrad KASSERT(fcnp->cn_nameiop == DELETE);
265 1.1 riastrad KASSERT(tcnp->cn_nameiop == RENAME);
266 1.1 riastrad
267 1.1 riastrad /* XXX Want a better equality test. */
268 1.1 riastrad KASSERT(kauth_cred_uidmatch(cred, fcnp->cn_cred));
269 1.1 riastrad KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
270 1.1 riastrad
271 1.1 riastrad mp = fdvp->v_mount;
272 1.1 riastrad KASSERT(mp != NULL);
273 1.1 riastrad KASSERT(mp == tdvp->v_mount);
274 1.1 riastrad /* XXX How can we be sure this stays true? */
275 1.1 riastrad KASSERT((mp->mnt_flag & MNT_RDONLY) == 0);
276 1.1 riastrad
277 1.1 riastrad /* Reject rename("x/..", ...) and rename(..., "x/..") early. */
278 1.1 riastrad if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)
279 1.1 riastrad return EINVAL; /* XXX EISDIR? */
280 1.1 riastrad
281 1.1 riastrad error = genfs_rename_enter(ops, mp, cred,
282 1.1 riastrad fdvp, fcnp, fde, &fvp,
283 1.1 riastrad tdvp, tcnp, tde, &tvp);
284 1.1 riastrad if (error)
285 1.1 riastrad return error;
286 1.1 riastrad
287 1.1 riastrad /*
288 1.1 riastrad * Check that everything is locked and looks right.
289 1.1 riastrad */
290 1.1 riastrad KASSERT(fvp != NULL);
291 1.1 riastrad KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
292 1.1 riastrad KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
293 1.1 riastrad KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
294 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
295 1.1 riastrad
296 1.1 riastrad /*
297 1.1 riastrad * If the source and destination are the same object, we need
298 1.1 riastrad * only at most delete the source entry. We are guaranteed at
299 1.1 riastrad * this point that the entries are distinct.
300 1.1 riastrad */
301 1.1 riastrad if (fvp == tvp) {
302 1.1 riastrad KASSERT(tvp != NULL);
303 1.1 riastrad if (fvp->v_type == VDIR)
304 1.1 riastrad /* XXX This shouldn't be possible. */
305 1.1 riastrad error = EINVAL;
306 1.1 riastrad else if (posixly_correct)
307 1.1 riastrad /* POSIX sez to leave them alone. */
308 1.1 riastrad error = 0;
309 1.1 riastrad else if ((fdvp == tdvp) &&
310 1.1 riastrad (fcnp->cn_namelen == tcnp->cn_namelen) &&
311 1.1 riastrad (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr,
312 1.1 riastrad fcnp->cn_namelen) == 0))
313 1.1 riastrad /* Renaming an entry over itself does nothing. */
314 1.1 riastrad error = 0;
315 1.1 riastrad else
316 1.1 riastrad /* XXX Can't use VOP_REMOVE because of locking. */
317 1.1 riastrad error = genfs_rename_remove(ops, mp, cred,
318 1.6 thorpej fdvp, fcnp, fde, fvp, &tvp_new_nlink);
319 1.1 riastrad goto out;
320 1.1 riastrad }
321 1.1 riastrad KASSERT(fvp != tvp);
322 1.1 riastrad KASSERT((fdvp != tdvp) ||
323 1.1 riastrad (fcnp->cn_namelen != tcnp->cn_namelen) ||
324 1.1 riastrad (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen)
325 1.1 riastrad != 0));
326 1.1 riastrad
327 1.1 riastrad /*
328 1.1 riastrad * If the target exists, refuse to rename a directory over a
329 1.1 riastrad * non-directory or vice versa, or to clobber a non-empty
330 1.1 riastrad * directory.
331 1.1 riastrad */
332 1.1 riastrad if (tvp != NULL) {
333 1.1 riastrad if (fvp->v_type == VDIR && tvp->v_type == VDIR)
334 1.1 riastrad error =
335 1.1 riastrad (ops->gro_directory_empty_p(mp, cred, tvp, tdvp)?
336 1.1 riastrad 0 : ENOTEMPTY);
337 1.1 riastrad else if (fvp->v_type == VDIR && tvp->v_type != VDIR)
338 1.1 riastrad error = ENOTDIR;
339 1.1 riastrad else if (fvp->v_type != VDIR && tvp->v_type == VDIR)
340 1.1 riastrad error = EISDIR;
341 1.1 riastrad else
342 1.1 riastrad error = 0;
343 1.1 riastrad if (error)
344 1.1 riastrad goto out;
345 1.1 riastrad KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
346 1.1 riastrad }
347 1.1 riastrad
348 1.1 riastrad /*
349 1.1 riastrad * Authorize the rename.
350 1.1 riastrad */
351 1.1 riastrad error = ops->gro_rename_check_possible(mp, fdvp, fvp, tdvp, tvp);
352 1.1 riastrad if (error)
353 1.1 riastrad goto out;
354 1.1 riastrad error = ops->gro_rename_check_permitted(mp, cred, fdvp, fvp, tdvp, tvp);
355 1.1 riastrad error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, fvp, fdvp,
356 1.1 riastrad error);
357 1.1 riastrad error = kauth_authorize_vnode(cred, KAUTH_VNODE_RENAME, tvp, tdvp,
358 1.1 riastrad error);
359 1.1 riastrad if (error)
360 1.1 riastrad goto out;
361 1.1 riastrad
362 1.1 riastrad /*
363 1.1 riastrad * Everything is hunky-dory. Shuffle the directory entries.
364 1.1 riastrad */
365 1.1 riastrad error = ops->gro_rename(mp, cred,
366 1.1 riastrad fdvp, fcnp, fde, fvp,
367 1.6 thorpej tdvp, tcnp, tde, tvp,
368 1.6 thorpej &tvp_new_nlink);
369 1.1 riastrad if (error)
370 1.1 riastrad goto out;
371 1.1 riastrad
372 1.1 riastrad /* Success! */
373 1.1 riastrad
374 1.6 thorpej out: if (error == 0) {
375 1.6 thorpej genfs_rename_knote(fdvp, fvp, tdvp, tvp, tvp_new_nlink);
376 1.6 thorpej }
377 1.6 thorpej genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
378 1.1 riastrad return error;
379 1.1 riastrad }
380 1.1 riastrad
381 1.1 riastrad /*
382 1.1 riastrad * genfs_rename_knote: Note events about the various vnodes in a
383 1.1 riastrad * rename. To be called by gro_rename on success. The only pair of
384 1.6 thorpej * vnodes that may be identical is {fdvp, tdvp}. tvp_new_nlink is
385 1.6 thorpej * the resulting link count of tvp.
386 1.1 riastrad */
387 1.1 riastrad void
388 1.1 riastrad genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
389 1.6 thorpej struct vnode *tdvp, struct vnode *tvp, nlink_t tvp_new_nlink)
390 1.1 riastrad {
391 1.1 riastrad long fdvp_events, tdvp_events;
392 1.1 riastrad bool directory_p, reparent_p, replaced_p;
393 1.1 riastrad
394 1.1 riastrad KASSERT(fdvp != NULL);
395 1.1 riastrad KASSERT(fvp != NULL);
396 1.1 riastrad KASSERT(tdvp != NULL);
397 1.1 riastrad KASSERT(fdvp != fvp);
398 1.1 riastrad KASSERT(fdvp != tvp);
399 1.1 riastrad KASSERT(tdvp != fvp);
400 1.1 riastrad KASSERT(tdvp != tvp);
401 1.1 riastrad KASSERT(fvp != tvp);
402 1.1 riastrad KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
403 1.1 riastrad KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
404 1.1 riastrad KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
405 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
406 1.1 riastrad
407 1.1 riastrad directory_p = (fvp->v_type == VDIR);
408 1.1 riastrad reparent_p = (fdvp != tdvp);
409 1.1 riastrad replaced_p = (tvp != NULL);
410 1.1 riastrad
411 1.1 riastrad KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
412 1.1 riastrad
413 1.1 riastrad fdvp_events = NOTE_WRITE;
414 1.1 riastrad if (directory_p && reparent_p)
415 1.1 riastrad fdvp_events |= NOTE_LINK;
416 1.1 riastrad VN_KNOTE(fdvp, fdvp_events);
417 1.1 riastrad
418 1.1 riastrad VN_KNOTE(fvp, NOTE_RENAME);
419 1.1 riastrad
420 1.1 riastrad if (reparent_p) {
421 1.1 riastrad tdvp_events = NOTE_WRITE;
422 1.1 riastrad if (!replaced_p) {
423 1.1 riastrad tdvp_events |= NOTE_EXTEND;
424 1.1 riastrad if (directory_p)
425 1.1 riastrad tdvp_events |= NOTE_LINK;
426 1.1 riastrad }
427 1.1 riastrad VN_KNOTE(tdvp, tdvp_events);
428 1.1 riastrad }
429 1.1 riastrad
430 1.1 riastrad if (replaced_p)
431 1.6 thorpej VN_KNOTE(tvp, (tvp_new_nlink == 0 ? NOTE_DELETE : NOTE_LINK));
432 1.1 riastrad }
433 1.1 riastrad
434 1.1 riastrad /*
435 1.1 riastrad * genfs_rename_cache_purge: Purge the name cache. To be called by
436 1.1 riastrad * gro_rename on success. The only pair of vnodes that may be
437 1.1 riastrad * identical is {fdvp, tdvp}.
438 1.1 riastrad */
439 1.1 riastrad void
440 1.1 riastrad genfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp,
441 1.1 riastrad struct vnode *tdvp, struct vnode *tvp)
442 1.1 riastrad {
443 1.1 riastrad
444 1.1 riastrad KASSERT(fdvp != NULL);
445 1.1 riastrad KASSERT(fvp != NULL);
446 1.1 riastrad KASSERT(tdvp != NULL);
447 1.1 riastrad KASSERT(fdvp != fvp);
448 1.1 riastrad KASSERT(fdvp != tvp);
449 1.1 riastrad KASSERT(tdvp != fvp);
450 1.1 riastrad KASSERT(tdvp != tvp);
451 1.1 riastrad KASSERT(fvp != tvp);
452 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
453 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
454 1.1 riastrad
455 1.1 riastrad /*
456 1.1 riastrad * XXX What actually needs to be purged?
457 1.1 riastrad */
458 1.1 riastrad
459 1.1 riastrad cache_purge(fdvp);
460 1.1 riastrad
461 1.1 riastrad if (fvp->v_type == VDIR)
462 1.1 riastrad cache_purge(fvp);
463 1.1 riastrad
464 1.1 riastrad if (tdvp != fdvp)
465 1.1 riastrad cache_purge(tdvp);
466 1.1 riastrad
467 1.1 riastrad if ((tvp != NULL) && (tvp->v_type == VDIR))
468 1.1 riastrad cache_purge(tvp);
469 1.1 riastrad }
470 1.1 riastrad
471 1.1 riastrad /*
472 1.1 riastrad * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup
473 1.1 riastrad * results in *fde_ret and the associated vnode in *fvp_ret; fail if
474 1.1 riastrad * not found. Look up tcnp in tdvp, and store the lookup results in
475 1.1 riastrad * *tde_ret and the associated vnode in *tvp_ret; store null instead if
476 1.1 riastrad * not found. Fail if anything has been mounted on any of the nodes
477 1.1 riastrad * involved.
478 1.1 riastrad *
479 1.1 riastrad * fdvp and tdvp must be referenced.
480 1.1 riastrad *
481 1.1 riastrad * On entry, nothing is locked.
482 1.1 riastrad *
483 1.1 riastrad * On success, everything is locked, and *fvp_ret, and *tvp_ret if
484 1.1 riastrad * nonnull, are referenced. The only pairs of vnodes that may be
485 1.1 riastrad * identical are {fdvp, tdvp} and {fvp, tvp}.
486 1.1 riastrad *
487 1.1 riastrad * On failure, everything remains as was.
488 1.1 riastrad *
489 1.1 riastrad * Locking everything including the source and target nodes is
490 1.1 riastrad * necessary to make sure that, e.g., link count updates are OK. The
491 1.1 riastrad * locking order is, in general, ancestor-first, matching the order you
492 1.1 riastrad * need to use to look up a descendant anyway.
493 1.1 riastrad */
494 1.1 riastrad static int
495 1.1 riastrad genfs_rename_enter(const struct genfs_rename_ops *ops,
496 1.1 riastrad struct mount *mp, kauth_cred_t cred,
497 1.1 riastrad struct vnode *fdvp, struct componentname *fcnp,
498 1.1 riastrad void *fde_ret, struct vnode **fvp_ret,
499 1.1 riastrad struct vnode *tdvp, struct componentname *tcnp,
500 1.1 riastrad void *tde_ret, struct vnode **tvp_ret)
501 1.1 riastrad {
502 1.1 riastrad int error;
503 1.1 riastrad
504 1.1 riastrad KASSERT(mp != NULL);
505 1.1 riastrad KASSERT(fdvp != NULL);
506 1.1 riastrad KASSERT(fcnp != NULL);
507 1.1 riastrad KASSERT(fvp_ret != NULL);
508 1.1 riastrad KASSERT(tdvp != NULL);
509 1.1 riastrad KASSERT(tcnp != NULL);
510 1.1 riastrad KASSERT(tvp_ret != NULL);
511 1.1 riastrad KASSERT(fvp_ret != tvp_ret);
512 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
513 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
514 1.1 riastrad KASSERT(fdvp->v_mount == mp);
515 1.1 riastrad KASSERT(tdvp->v_mount == mp);
516 1.1 riastrad
517 1.1 riastrad if (fdvp == tdvp)
518 1.1 riastrad error = genfs_rename_enter_common(ops, mp, cred, fdvp,
519 1.1 riastrad fcnp, fde_ret, fvp_ret,
520 1.1 riastrad tcnp, tde_ret, tvp_ret);
521 1.1 riastrad else
522 1.1 riastrad error = genfs_rename_enter_separate(ops, mp, cred,
523 1.1 riastrad fdvp, fcnp, fde_ret, fvp_ret,
524 1.1 riastrad tdvp, tcnp, tde_ret, tvp_ret);
525 1.1 riastrad
526 1.1 riastrad if (error)
527 1.1 riastrad return error;
528 1.1 riastrad
529 1.1 riastrad KASSERT(*fvp_ret != NULL);
530 1.1 riastrad KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE);
531 1.1 riastrad KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE));
532 1.1 riastrad KASSERT(*fvp_ret != fdvp);
533 1.1 riastrad KASSERT(*fvp_ret != tdvp);
534 1.1 riastrad KASSERT(*tvp_ret != fdvp);
535 1.1 riastrad KASSERT(*tvp_ret != tdvp);
536 1.1 riastrad return 0;
537 1.1 riastrad }
538 1.1 riastrad
539 1.1 riastrad /*
540 1.1 riastrad * genfs_rename_enter_common: Lock and look up with a common
541 1.1 riastrad * source/target directory.
542 1.1 riastrad */
543 1.1 riastrad static int
544 1.1 riastrad genfs_rename_enter_common(const struct genfs_rename_ops *ops,
545 1.1 riastrad struct mount *mp, kauth_cred_t cred, struct vnode *dvp,
546 1.1 riastrad struct componentname *fcnp,
547 1.1 riastrad void *fde_ret, struct vnode **fvp_ret,
548 1.1 riastrad struct componentname *tcnp,
549 1.1 riastrad void *tde_ret, struct vnode **tvp_ret)
550 1.1 riastrad {
551 1.1 riastrad struct vnode *fvp, *tvp;
552 1.1 riastrad int error;
553 1.1 riastrad
554 1.1 riastrad KASSERT(ops != NULL);
555 1.1 riastrad KASSERT(mp != NULL);
556 1.1 riastrad KASSERT(dvp != NULL);
557 1.1 riastrad KASSERT(fcnp != NULL);
558 1.1 riastrad KASSERT(fvp_ret != NULL);
559 1.1 riastrad KASSERT(tcnp != NULL);
560 1.1 riastrad KASSERT(tvp_ret != NULL);
561 1.1 riastrad KASSERT(dvp->v_type == VDIR);
562 1.1 riastrad KASSERT(dvp->v_mount == mp);
563 1.1 riastrad
564 1.1 riastrad error = ops->gro_lock_directory(mp, dvp);
565 1.1 riastrad if (error)
566 1.1 riastrad goto fail0;
567 1.1 riastrad
568 1.1 riastrad /* Did we lose a race with mount? */
569 1.1 riastrad if (dvp->v_mountedhere != NULL) {
570 1.1 riastrad error = EBUSY;
571 1.1 riastrad goto fail1;
572 1.1 riastrad }
573 1.1 riastrad
574 1.1 riastrad KASSERT(fcnp->cn_nameiop == DELETE);
575 1.1 riastrad error = ops->gro_lookup(mp, dvp, fcnp, fde_ret, &fvp);
576 1.1 riastrad if (error)
577 1.1 riastrad goto fail1;
578 1.1 riastrad
579 1.1 riastrad KASSERT(fvp != NULL);
580 1.1 riastrad
581 1.1 riastrad /* Refuse to rename `.'. */
582 1.1 riastrad if (fvp == dvp) {
583 1.1 riastrad error = EINVAL;
584 1.1 riastrad goto fail2;
585 1.1 riastrad }
586 1.1 riastrad KASSERT(fvp != dvp);
587 1.1 riastrad
588 1.1 riastrad KASSERT(tcnp->cn_nameiop == RENAME);
589 1.1 riastrad error = ops->gro_lookup(mp, dvp, tcnp, tde_ret, &tvp);
590 1.1 riastrad if (error == ENOENT) {
591 1.1 riastrad tvp = NULL;
592 1.1 riastrad } else if (error) {
593 1.1 riastrad goto fail2;
594 1.1 riastrad } else {
595 1.1 riastrad KASSERT(tvp != NULL);
596 1.1 riastrad
597 1.1 riastrad /* Refuse to rename over `.'. */
598 1.1 riastrad if (tvp == dvp) {
599 1.1 riastrad error = EISDIR; /* XXX EINVAL? */
600 1.1 riastrad goto fail2;
601 1.1 riastrad }
602 1.1 riastrad }
603 1.1 riastrad KASSERT(tvp != dvp);
604 1.1 riastrad
605 1.1 riastrad /*
606 1.1 riastrad * We've looked up both nodes. Now lock them and check them.
607 1.1 riastrad */
608 1.1 riastrad
609 1.1 riastrad vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
610 1.1 riastrad KASSERT(fvp->v_mount == mp);
611 1.1 riastrad /* Refuse to rename a mount point. */
612 1.1 riastrad if ((fvp->v_type == VDIR) && (fvp->v_mountedhere != NULL)) {
613 1.1 riastrad error = EBUSY;
614 1.1 riastrad goto fail3;
615 1.1 riastrad }
616 1.1 riastrad
617 1.1 riastrad if ((tvp != NULL) && (tvp != fvp)) {
618 1.1 riastrad vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
619 1.1 riastrad KASSERT(tvp->v_mount == mp);
620 1.1 riastrad /* Refuse to rename over a mount point. */
621 1.1 riastrad if ((tvp->v_type == VDIR) && (tvp->v_mountedhere != NULL)) {
622 1.1 riastrad error = EBUSY;
623 1.1 riastrad goto fail4;
624 1.1 riastrad }
625 1.1 riastrad }
626 1.1 riastrad
627 1.1 riastrad KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
628 1.1 riastrad KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
629 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
630 1.1 riastrad
631 1.1 riastrad *fvp_ret = fvp;
632 1.1 riastrad *tvp_ret = tvp;
633 1.1 riastrad return 0;
634 1.1 riastrad
635 1.1 riastrad fail4: if ((tvp != NULL) && (tvp != fvp))
636 1.1 riastrad VOP_UNLOCK(tvp);
637 1.1 riastrad fail3: VOP_UNLOCK(fvp);
638 1.1 riastrad if (tvp != NULL)
639 1.1 riastrad vrele(tvp);
640 1.1 riastrad fail2: vrele(fvp);
641 1.1 riastrad fail1: VOP_UNLOCK(dvp);
642 1.1 riastrad fail0: return error;
643 1.1 riastrad }
644 1.1 riastrad
645 1.1 riastrad /*
646 1.1 riastrad * genfs_rename_enter_separate: Lock and look up with separate source
647 1.1 riastrad * and target directories.
648 1.1 riastrad */
649 1.1 riastrad static int
650 1.1 riastrad genfs_rename_enter_separate(const struct genfs_rename_ops *ops,
651 1.1 riastrad struct mount *mp, kauth_cred_t cred,
652 1.1 riastrad struct vnode *fdvp, struct componentname *fcnp,
653 1.1 riastrad void *fde_ret, struct vnode **fvp_ret,
654 1.1 riastrad struct vnode *tdvp, struct componentname *tcnp,
655 1.1 riastrad void *tde_ret, struct vnode **tvp_ret)
656 1.1 riastrad {
657 1.1 riastrad struct vnode *intermediate_node;
658 1.1 riastrad struct vnode *fvp, *tvp;
659 1.1 riastrad int error;
660 1.1 riastrad
661 1.1 riastrad KASSERT(ops != NULL);
662 1.1 riastrad KASSERT(mp != NULL);
663 1.1 riastrad KASSERT(fdvp != NULL);
664 1.1 riastrad KASSERT(fcnp != NULL);
665 1.1 riastrad KASSERT(fvp_ret != NULL);
666 1.1 riastrad KASSERT(tdvp != NULL);
667 1.1 riastrad KASSERT(tcnp != NULL);
668 1.1 riastrad KASSERT(tvp_ret != NULL);
669 1.1 riastrad KASSERT(fdvp != tdvp);
670 1.1 riastrad KASSERT(fcnp != tcnp);
671 1.1 riastrad KASSERT(fcnp->cn_nameiop == DELETE);
672 1.1 riastrad KASSERT(tcnp->cn_nameiop == RENAME);
673 1.1 riastrad KASSERT(fvp_ret != tvp_ret);
674 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
675 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
676 1.1 riastrad KASSERT(fdvp->v_mount == mp);
677 1.1 riastrad KASSERT(tdvp->v_mount == mp);
678 1.1 riastrad
679 1.1 riastrad error = ops->gro_genealogy(mp, cred, fdvp, tdvp, &intermediate_node);
680 1.1 riastrad if (error)
681 1.1 riastrad return error;
682 1.1 riastrad
683 1.1 riastrad /*
684 1.1 riastrad * intermediate_node == NULL means fdvp is not an ancestor of tdvp.
685 1.1 riastrad */
686 1.1 riastrad if (intermediate_node == NULL)
687 1.1 riastrad error = genfs_rename_lock(ops, mp, cred,
688 1.1 riastrad ENOTEMPTY, EISDIR, EINVAL,
689 1.1 riastrad tdvp, tcnp, true, tde_ret, &tvp,
690 1.1 riastrad fdvp, fcnp, false, fde_ret, &fvp);
691 1.1 riastrad else
692 1.1 riastrad error = genfs_rename_lock(ops, mp, cred,
693 1.1 riastrad EINVAL, EISDIR, EINVAL,
694 1.1 riastrad fdvp, fcnp, false, fde_ret, &fvp,
695 1.1 riastrad tdvp, tcnp, true, tde_ret, &tvp);
696 1.1 riastrad if (error)
697 1.1 riastrad goto out;
698 1.1 riastrad
699 1.1 riastrad KASSERT(fvp != NULL);
700 1.1 riastrad
701 1.1 riastrad /*
702 1.1 riastrad * Reject rename("foo/bar", "foo/bar/baz/quux/zot").
703 1.1 riastrad */
704 1.1 riastrad if (fvp == intermediate_node) {
705 1.1 riastrad genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
706 1.1 riastrad error = EINVAL;
707 1.1 riastrad goto out;
708 1.1 riastrad }
709 1.1 riastrad
710 1.1 riastrad *fvp_ret = fvp;
711 1.1 riastrad *tvp_ret = tvp;
712 1.1 riastrad error = 0;
713 1.1 riastrad
714 1.1 riastrad out: if (intermediate_node != NULL)
715 1.1 riastrad vrele(intermediate_node);
716 1.1 riastrad return error;
717 1.1 riastrad }
718 1.1 riastrad
719 1.1 riastrad /*
720 1.5 riastrad * genfs_rename_lock: Lookup and lock it all. The lock order is:
721 1.5 riastrad *
722 1.5 riastrad * a_dvp -> a_vp -> b_dvp -> b_vp,
723 1.5 riastrad *
724 1.5 riastrad * except if a_vp is a nondirectory in which case the lock order is:
725 1.5 riastrad *
726 1.5 riastrad * a_dvp -> b_dvp -> b_vp -> a_vp,
727 1.5 riastrad *
728 1.5 riastrad * which can't violate ancestor->descendant because a_vp has no
729 1.5 riastrad * descendants in this case. This edge case is necessary because some
730 1.5 riastrad * file systems can only lookup/lock/unlock, and we can't hold a_vp
731 1.5 riastrad * locked when we lookup/lock/unlock b_vp if they turn out to be the
732 1.5 riastrad * same, and we can't find out that they're the same until after the
733 1.5 riastrad * lookup.
734 1.5 riastrad *
735 1.5 riastrad * b_dvp must not be an ancestor of a_dvp, although a_dvp may be an
736 1.5 riastrad * ancestor of b_dvp.
737 1.5 riastrad *
738 1.5 riastrad * Fail with overlap_error if node a is directory b. Neither
739 1.5 riastrad * componentname may be `.' or `..'.
740 1.1 riastrad *
741 1.1 riastrad * a_dvp and b_dvp must be referenced.
742 1.1 riastrad *
743 1.1 riastrad * On entry, a_dvp and b_dvp are unlocked.
744 1.1 riastrad *
745 1.1 riastrad * On success,
746 1.1 riastrad * . a_dvp and b_dvp are locked,
747 1.1 riastrad * . *a_dirent_ret is filled with a directory entry whose node is
748 1.1 riastrad * locked and referenced,
749 1.1 riastrad * . *b_vp_ret is filled with the corresponding vnode,
750 1.1 riastrad * . *b_dirent_ret is filled either with null or with a directory entry
751 1.1 riastrad * whose node is locked and referenced,
752 1.1 riastrad * . *b_vp is filled either with null or with the corresponding vnode,
753 1.1 riastrad * and
754 1.1 riastrad * . the only pair of vnodes that may be identical is a_vp and b_vp.
755 1.1 riastrad *
756 1.1 riastrad * On failure, a_dvp and b_dvp are left unlocked, and *a_dirent_ret,
757 1.1 riastrad * *a_vp, *b_dirent_ret, and *b_vp are left alone.
758 1.1 riastrad */
759 1.1 riastrad static int
760 1.1 riastrad genfs_rename_lock(const struct genfs_rename_ops *ops,
761 1.1 riastrad struct mount *mp, kauth_cred_t cred,
762 1.1 riastrad int overlap_error, int a_dot_error, int b_dot_error,
763 1.1 riastrad struct vnode *a_dvp, struct componentname *a_cnp, bool a_missing_ok,
764 1.1 riastrad void *a_de_ret, struct vnode **a_vp_ret,
765 1.1 riastrad struct vnode *b_dvp, struct componentname *b_cnp, bool b_missing_ok,
766 1.1 riastrad void *b_de_ret, struct vnode **b_vp_ret)
767 1.1 riastrad {
768 1.1 riastrad struct vnode *a_vp, *b_vp;
769 1.1 riastrad int error;
770 1.1 riastrad
771 1.1 riastrad KASSERT(ops != NULL);
772 1.1 riastrad KASSERT(mp != NULL);
773 1.1 riastrad KASSERT(a_dvp != NULL);
774 1.1 riastrad KASSERT(a_cnp != NULL);
775 1.1 riastrad KASSERT(a_vp_ret != NULL);
776 1.1 riastrad KASSERT(b_dvp != NULL);
777 1.1 riastrad KASSERT(b_cnp != NULL);
778 1.1 riastrad KASSERT(b_vp_ret != NULL);
779 1.1 riastrad KASSERT(a_dvp != b_dvp);
780 1.1 riastrad KASSERT(a_vp_ret != b_vp_ret);
781 1.1 riastrad KASSERT(a_dvp->v_type == VDIR);
782 1.1 riastrad KASSERT(b_dvp->v_type == VDIR);
783 1.1 riastrad KASSERT(a_dvp->v_mount == mp);
784 1.1 riastrad KASSERT(b_dvp->v_mount == mp);
785 1.1 riastrad KASSERT(a_missing_ok != b_missing_ok);
786 1.1 riastrad
787 1.5 riastrad /*
788 1.5 riastrad * 1. Lock a_dvp.
789 1.5 riastrad */
790 1.1 riastrad error = ops->gro_lock_directory(mp, a_dvp);
791 1.1 riastrad if (error)
792 1.1 riastrad goto fail0;
793 1.1 riastrad
794 1.1 riastrad /* Did we lose a race with mount? */
795 1.1 riastrad if (a_dvp->v_mountedhere != NULL) {
796 1.1 riastrad error = EBUSY;
797 1.1 riastrad goto fail1;
798 1.1 riastrad }
799 1.1 riastrad
800 1.5 riastrad /*
801 1.5 riastrad * 2. Lookup a_vp. May lock/unlock a_vp.
802 1.5 riastrad */
803 1.1 riastrad error = ops->gro_lookup(mp, a_dvp, a_cnp, a_de_ret, &a_vp);
804 1.1 riastrad if (error) {
805 1.1 riastrad if (a_missing_ok && (error == ENOENT))
806 1.1 riastrad a_vp = NULL;
807 1.1 riastrad else
808 1.1 riastrad goto fail1;
809 1.1 riastrad } else {
810 1.1 riastrad KASSERT(a_vp != NULL);
811 1.1 riastrad
812 1.1 riastrad /* Refuse to rename (over) `.'. */
813 1.1 riastrad if (a_vp == a_dvp) {
814 1.1 riastrad error = a_dot_error;
815 1.1 riastrad goto fail2;
816 1.1 riastrad }
817 1.1 riastrad
818 1.5 riastrad /* Reject rename("x", "x/y") or rename("x/y", "x"). */
819 1.1 riastrad if (a_vp == b_dvp) {
820 1.1 riastrad error = overlap_error;
821 1.1 riastrad goto fail2;
822 1.1 riastrad }
823 1.1 riastrad }
824 1.1 riastrad
825 1.1 riastrad KASSERT(a_vp != a_dvp);
826 1.1 riastrad KASSERT(a_vp != b_dvp);
827 1.1 riastrad
828 1.5 riastrad /*
829 1.5 riastrad * 3. Lock a_vp, if it is a directory.
830 1.5 riastrad *
831 1.5 riastrad * We already ruled out a_vp == a_dvp (i.e., a_cnp is `.'), so
832 1.5 riastrad * this is not locking against self, and we already ruled out
833 1.5 riastrad * a_vp == b_dvp, so this won't cause subsequent locking of
834 1.5 riastrad * b_dvp to lock against self.
835 1.5 riastrad *
836 1.5 riastrad * If a_vp is a nondirectory, we can't hold it when we lookup
837 1.5 riastrad * b_vp in case (a) the file system can only lookup/lock/unlock
838 1.5 riastrad * and (b) b_vp turns out to be the same file as a_vp due to
839 1.5 riastrad * hard links -- and we can't even detect that case until after
840 1.5 riastrad * we've looked up b_vp. Fortunately, if a_vp is a
841 1.5 riastrad * nondirectory, then it is a leaf, so we can safely lock it
842 1.5 riastrad * last.
843 1.5 riastrad */
844 1.5 riastrad if (a_vp != NULL && a_vp->v_type == VDIR) {
845 1.5 riastrad vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
846 1.5 riastrad KASSERT(a_vp->v_mount == mp);
847 1.5 riastrad /* Refuse to rename (over) a mount point. */
848 1.5 riastrad if (a_vp->v_mountedhere != NULL) {
849 1.5 riastrad error = EBUSY;
850 1.5 riastrad goto fail3;
851 1.5 riastrad }
852 1.5 riastrad }
853 1.5 riastrad
854 1.5 riastrad /*
855 1.5 riastrad * 4. Lock b_dvp.
856 1.5 riastrad */
857 1.1 riastrad error = ops->gro_lock_directory(mp, b_dvp);
858 1.1 riastrad if (error)
859 1.5 riastrad goto fail3;
860 1.1 riastrad
861 1.1 riastrad /* Did we lose a race with mount? */
862 1.1 riastrad if (b_dvp->v_mountedhere != NULL) {
863 1.1 riastrad error = EBUSY;
864 1.5 riastrad goto fail4;
865 1.1 riastrad }
866 1.1 riastrad
867 1.5 riastrad /*
868 1.5 riastrad * 5. Lookup b_vp. May lock/unlock b_vp.
869 1.5 riastrad */
870 1.1 riastrad error = ops->gro_lookup(mp, b_dvp, b_cnp, b_de_ret, &b_vp);
871 1.1 riastrad if (error) {
872 1.1 riastrad if (b_missing_ok && (error == ENOENT))
873 1.1 riastrad b_vp = NULL;
874 1.1 riastrad else
875 1.5 riastrad goto fail4;
876 1.1 riastrad } else {
877 1.1 riastrad KASSERT(b_vp != NULL);
878 1.1 riastrad
879 1.1 riastrad /* Refuse to rename (over) `.'. */
880 1.1 riastrad if (b_vp == b_dvp) {
881 1.1 riastrad error = b_dot_error;
882 1.5 riastrad goto fail5;
883 1.1 riastrad }
884 1.1 riastrad
885 1.5 riastrad /*
886 1.5 riastrad * b_dvp must not be an ancestor of a_dvp, so if we
887 1.5 riastrad * find b_dvp/b_vp=a_dvp/a_vp something is wrong.
888 1.5 riastrad */
889 1.1 riastrad if (b_vp == a_dvp) {
890 1.1 riastrad /*
891 1.1 riastrad * We have a directory hard link before us.
892 1.1 riastrad * XXX What error should this return? EDEADLK?
893 1.1 riastrad * Panic?
894 1.1 riastrad */
895 1.1 riastrad error = EIO;
896 1.5 riastrad goto fail5;
897 1.1 riastrad }
898 1.1 riastrad }
899 1.1 riastrad KASSERT(b_vp != b_dvp);
900 1.1 riastrad KASSERT(b_vp != a_dvp);
901 1.1 riastrad
902 1.1 riastrad /*
903 1.5 riastrad * 6. Lock a_vp, if it is a nondirectory.
904 1.5 riastrad *
905 1.5 riastrad * In this case a_vp is a leaf, so it is either equal to or
906 1.5 riastrad * incommensurate with b_vp, and so we can safely lock it at
907 1.5 riastrad * any point now.
908 1.1 riastrad */
909 1.5 riastrad if (a_vp != NULL && a_vp->v_type != VDIR) {
910 1.1 riastrad vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
911 1.1 riastrad KASSERT(a_vp->v_mount == mp);
912 1.5 riastrad /* (not a directory so can't have anything mounted here) */
913 1.1 riastrad }
914 1.1 riastrad
915 1.5 riastrad /*
916 1.5 riastrad * 7. Lock b_vp, if it is not a_vp.
917 1.5 riastrad *
918 1.5 riastrad * b_vp and a_vp may the same inode if they are hard links to
919 1.5 riastrad * one another.
920 1.5 riastrad */
921 1.1 riastrad if ((b_vp != NULL) && (b_vp != a_vp)) {
922 1.1 riastrad vn_lock(b_vp, LK_EXCLUSIVE | LK_RETRY);
923 1.1 riastrad KASSERT(b_vp->v_mount == mp);
924 1.1 riastrad /* Refuse to rename (over) a mount point. */
925 1.1 riastrad if ((b_vp->v_type == VDIR) && (b_vp->v_mountedhere != NULL)) {
926 1.1 riastrad error = EBUSY;
927 1.1 riastrad goto fail6;
928 1.1 riastrad }
929 1.1 riastrad }
930 1.1 riastrad
931 1.1 riastrad KASSERT(VOP_ISLOCKED(a_dvp) == LK_EXCLUSIVE);
932 1.1 riastrad KASSERT(VOP_ISLOCKED(b_dvp) == LK_EXCLUSIVE);
933 1.1 riastrad KASSERT(a_missing_ok || (a_vp != NULL));
934 1.1 riastrad KASSERT(b_missing_ok || (b_vp != NULL));
935 1.1 riastrad KASSERT((a_vp == NULL) || (VOP_ISLOCKED(a_vp) == LK_EXCLUSIVE));
936 1.1 riastrad KASSERT((b_vp == NULL) || (VOP_ISLOCKED(b_vp) == LK_EXCLUSIVE));
937 1.1 riastrad
938 1.1 riastrad *a_vp_ret = a_vp;
939 1.1 riastrad *b_vp_ret = b_vp;
940 1.1 riastrad return 0;
941 1.1 riastrad
942 1.1 riastrad fail6: if ((b_vp != NULL) && (b_vp != a_vp))
943 1.1 riastrad VOP_UNLOCK(b_vp);
944 1.5 riastrad if (a_vp != NULL && a_vp->v_type != VDIR)
945 1.1 riastrad VOP_UNLOCK(a_vp);
946 1.5 riastrad fail5: if (b_vp != NULL)
947 1.1 riastrad vrele(b_vp);
948 1.5 riastrad fail4: VOP_UNLOCK(b_dvp);
949 1.5 riastrad fail3: if (a_vp != NULL && a_vp->v_type == VDIR)
950 1.5 riastrad VOP_UNLOCK(a_vp);
951 1.1 riastrad fail2: if (a_vp != NULL)
952 1.1 riastrad vrele(a_vp);
953 1.1 riastrad fail1: VOP_UNLOCK(a_dvp);
954 1.1 riastrad fail0: return error;
955 1.1 riastrad }
956 1.1 riastrad
957 1.1 riastrad /*
958 1.1 riastrad * genfs_rename_exit: Unlock everything we locked for rename.
959 1.1 riastrad *
960 1.1 riastrad * fdvp and tdvp must be referenced.
961 1.1 riastrad *
962 1.1 riastrad * On entry, everything is locked, and fvp and tvp referenced.
963 1.1 riastrad *
964 1.1 riastrad * On exit, everything is unlocked, and fvp and tvp are released.
965 1.1 riastrad */
966 1.1 riastrad static void
967 1.1 riastrad genfs_rename_exit(const struct genfs_rename_ops *ops,
968 1.1 riastrad struct mount *mp,
969 1.1 riastrad struct vnode *fdvp, struct vnode *fvp,
970 1.1 riastrad struct vnode *tdvp, struct vnode *tvp)
971 1.1 riastrad {
972 1.1 riastrad
973 1.1 riastrad (void)ops;
974 1.1 riastrad KASSERT(ops != NULL);
975 1.1 riastrad KASSERT(mp != NULL);
976 1.1 riastrad KASSERT(fdvp != NULL);
977 1.1 riastrad KASSERT(fvp != NULL);
978 1.1 riastrad KASSERT(fdvp != fvp);
979 1.1 riastrad KASSERT(fdvp != tvp);
980 1.1 riastrad KASSERT(tdvp != tvp);
981 1.1 riastrad KASSERT(tdvp != fvp);
982 1.1 riastrad KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
983 1.1 riastrad KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
984 1.1 riastrad KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
985 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
986 1.1 riastrad
987 1.1 riastrad if ((tvp != NULL) && (tvp != fvp))
988 1.1 riastrad VOP_UNLOCK(tvp);
989 1.1 riastrad VOP_UNLOCK(fvp);
990 1.1 riastrad if (tvp != NULL)
991 1.1 riastrad vrele(tvp);
992 1.1 riastrad if (tdvp != fdvp)
993 1.1 riastrad VOP_UNLOCK(tdvp);
994 1.1 riastrad vrele(fvp);
995 1.1 riastrad VOP_UNLOCK(fdvp);
996 1.1 riastrad }
997 1.1 riastrad
998 1.1 riastrad /*
999 1.1 riastrad * genfs_rename_remove: Remove the entry for the non-directory vp with
1000 1.1 riastrad * componentname cnp from the directory dvp, using the lookup results
1001 1.6 thorpej * de. It is the responsibility of gro_remove to purge the name cache.
1002 1.1 riastrad *
1003 1.1 riastrad * Everything must be locked and referenced.
1004 1.1 riastrad */
1005 1.1 riastrad static int
1006 1.1 riastrad genfs_rename_remove(const struct genfs_rename_ops *ops,
1007 1.1 riastrad struct mount *mp, kauth_cred_t cred,
1008 1.6 thorpej struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp,
1009 1.6 thorpej nlink_t *tvp_nlinkp)
1010 1.1 riastrad {
1011 1.1 riastrad int error;
1012 1.1 riastrad
1013 1.1 riastrad KASSERT(ops != NULL);
1014 1.1 riastrad KASSERT(mp != NULL);
1015 1.1 riastrad KASSERT(dvp != NULL);
1016 1.1 riastrad KASSERT(cnp != NULL);
1017 1.1 riastrad KASSERT(vp != NULL);
1018 1.1 riastrad KASSERT(dvp != vp);
1019 1.1 riastrad KASSERT(dvp->v_type == VDIR);
1020 1.1 riastrad KASSERT(vp->v_type != VDIR);
1021 1.1 riastrad KASSERT(dvp->v_mount == mp);
1022 1.1 riastrad KASSERT(vp->v_mount == mp);
1023 1.1 riastrad KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
1024 1.1 riastrad KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1025 1.1 riastrad
1026 1.1 riastrad error = ops->gro_remove_check_possible(mp, dvp, vp);
1027 1.1 riastrad if (error)
1028 1.1 riastrad return error;
1029 1.1 riastrad
1030 1.1 riastrad error = ops->gro_remove_check_permitted(mp, cred, dvp, vp);
1031 1.1 riastrad error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, vp, dvp,
1032 1.1 riastrad error);
1033 1.1 riastrad if (error)
1034 1.1 riastrad return error;
1035 1.1 riastrad
1036 1.6 thorpej error = ops->gro_remove(mp, cred, dvp, cnp, de, vp, tvp_nlinkp);
1037 1.1 riastrad if (error)
1038 1.1 riastrad return error;
1039 1.1 riastrad
1040 1.1 riastrad return 0;
1041 1.1 riastrad }
1042 1.1 riastrad
1043 1.1 riastrad static int
1044 1.1 riastrad genfs_ufslike_check_sticky(kauth_cred_t, mode_t, uid_t, struct vnode *, uid_t);
1045 1.1 riastrad
1046 1.1 riastrad /*
1047 1.1 riastrad * genfs_ufslike_rename_check_possible: Check whether a rename is
1048 1.1 riastrad * possible independent of credentials, assuming UFS-like inode flag
1049 1.1 riastrad * semantics. clobber_p is true iff the target node already exists.
1050 1.1 riastrad */
1051 1.1 riastrad int
1052 1.1 riastrad genfs_ufslike_rename_check_possible(
1053 1.1 riastrad unsigned long fdflags, unsigned long fflags,
1054 1.1 riastrad unsigned long tdflags, unsigned long tflags, bool clobber_p,
1055 1.1 riastrad unsigned long immutable, unsigned long append)
1056 1.1 riastrad {
1057 1.1 riastrad
1058 1.1 riastrad if ((fdflags | fflags) & (immutable | append))
1059 1.1 riastrad return EPERM;
1060 1.1 riastrad
1061 1.1 riastrad if (tdflags & (immutable | (clobber_p? append : 0)))
1062 1.1 riastrad return EPERM;
1063 1.1 riastrad
1064 1.1 riastrad if (clobber_p && (tflags & (immutable | append)))
1065 1.1 riastrad return EPERM;
1066 1.1 riastrad
1067 1.1 riastrad return 0;
1068 1.1 riastrad }
1069 1.1 riastrad
1070 1.1 riastrad /*
1071 1.1 riastrad * genfs_ufslike_rename_check_permitted: Check whether a rename is
1072 1.1 riastrad * permitted given our credentials, assuming UFS-like permission and
1073 1.1 riastrad * ownership semantics.
1074 1.1 riastrad *
1075 1.1 riastrad * The only pair of vnodes that may be identical is {fdvp, tdvp}.
1076 1.1 riastrad *
1077 1.1 riastrad * Everything must be locked and referenced.
1078 1.1 riastrad */
1079 1.1 riastrad int
1080 1.1 riastrad genfs_ufslike_rename_check_permitted(kauth_cred_t cred,
1081 1.1 riastrad struct vnode *fdvp, mode_t fdmode, uid_t fduid,
1082 1.1 riastrad struct vnode *fvp, uid_t fuid,
1083 1.1 riastrad struct vnode *tdvp, mode_t tdmode, uid_t tduid,
1084 1.1 riastrad struct vnode *tvp, uid_t tuid)
1085 1.1 riastrad {
1086 1.1 riastrad int error;
1087 1.1 riastrad
1088 1.1 riastrad KASSERT(fdvp != NULL);
1089 1.1 riastrad KASSERT(fvp != NULL);
1090 1.1 riastrad KASSERT(tdvp != NULL);
1091 1.1 riastrad KASSERT(fdvp != fvp);
1092 1.1 riastrad KASSERT(fdvp != tvp);
1093 1.1 riastrad KASSERT(tdvp != fvp);
1094 1.1 riastrad KASSERT(tdvp != tvp);
1095 1.1 riastrad KASSERT(fvp != tvp);
1096 1.1 riastrad KASSERT(fdvp->v_type == VDIR);
1097 1.1 riastrad KASSERT(tdvp->v_type == VDIR);
1098 1.1 riastrad KASSERT(fdvp->v_mount == fvp->v_mount);
1099 1.1 riastrad KASSERT(fdvp->v_mount == tdvp->v_mount);
1100 1.1 riastrad KASSERT((tvp == NULL) || (fdvp->v_mount == tvp->v_mount));
1101 1.1 riastrad KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
1102 1.1 riastrad KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
1103 1.1 riastrad KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
1104 1.1 riastrad KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
1105 1.1 riastrad
1106 1.1 riastrad /*
1107 1.1 riastrad * We need to remove or change an entry in the source directory.
1108 1.1 riastrad */
1109 1.1 riastrad error = VOP_ACCESS(fdvp, VWRITE, cred);
1110 1.1 riastrad if (error)
1111 1.1 riastrad return error;
1112 1.1 riastrad
1113 1.1 riastrad /*
1114 1.1 riastrad * If we are changing directories, then we need to write to the
1115 1.1 riastrad * target directory to add or change an entry. Also, if fvp is
1116 1.1 riastrad * a directory, we need to write to it to change its `..'
1117 1.1 riastrad * entry.
1118 1.1 riastrad */
1119 1.1 riastrad if (fdvp != tdvp) {
1120 1.1 riastrad error = VOP_ACCESS(tdvp, VWRITE, cred);
1121 1.1 riastrad if (error)
1122 1.1 riastrad return error;
1123 1.1 riastrad if (fvp->v_type == VDIR) {
1124 1.1 riastrad error = VOP_ACCESS(fvp, VWRITE, cred);
1125 1.1 riastrad if (error)
1126 1.1 riastrad return error;
1127 1.1 riastrad }
1128 1.1 riastrad }
1129 1.1 riastrad
1130 1.1 riastrad error = genfs_ufslike_check_sticky(cred, fdmode, fduid, fvp, fuid);
1131 1.1 riastrad if (error)
1132 1.1 riastrad return error;
1133 1.1 riastrad
1134 1.1 riastrad error = genfs_ufslike_check_sticky(cred, tdmode, tduid, tvp, tuid);
1135 1.1 riastrad if (error)
1136 1.1 riastrad return error;
1137 1.1 riastrad
1138 1.1 riastrad return 0;
1139 1.1 riastrad }
1140 1.1 riastrad
1141 1.1 riastrad /*
1142 1.1 riastrad * genfs_ufslike_remove_check_possible: Check whether a remove is
1143 1.1 riastrad * possible independent of credentials, assuming UFS-like inode flag
1144 1.1 riastrad * semantics.
1145 1.1 riastrad */
1146 1.1 riastrad int
1147 1.1 riastrad genfs_ufslike_remove_check_possible(unsigned long dflags, unsigned long flags,
1148 1.1 riastrad unsigned long immutable, unsigned long append)
1149 1.1 riastrad {
1150 1.1 riastrad
1151 1.1 riastrad /*
1152 1.1 riastrad * We want to delete the entry. If the directory is immutable,
1153 1.1 riastrad * we can't write to it to delete the entry. If the directory
1154 1.1 riastrad * is append-only, the only change we can make is to add
1155 1.1 riastrad * entries, so we can't delete entries. If the node is
1156 1.1 riastrad * immutable, we can't change the links to it, so we can't
1157 1.1 riastrad * delete the entry. If the node is append-only...well, this
1158 1.1 riastrad * is what UFS does.
1159 1.1 riastrad */
1160 1.1 riastrad if ((dflags | flags) & (immutable | append))
1161 1.1 riastrad return EPERM;
1162 1.1 riastrad
1163 1.1 riastrad return 0;
1164 1.1 riastrad }
1165 1.1 riastrad
1166 1.1 riastrad /*
1167 1.1 riastrad * genfs_ufslike_remove_check_permitted: Check whether a remove is
1168 1.1 riastrad * permitted given our credentials, assuming UFS-like permission and
1169 1.1 riastrad * ownership semantics.
1170 1.1 riastrad *
1171 1.1 riastrad * Everything must be locked and referenced.
1172 1.1 riastrad */
1173 1.1 riastrad int
1174 1.1 riastrad genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
1175 1.1 riastrad struct vnode *dvp, mode_t dmode, uid_t duid,
1176 1.1 riastrad struct vnode *vp, uid_t uid)
1177 1.1 riastrad {
1178 1.1 riastrad int error;
1179 1.1 riastrad
1180 1.1 riastrad KASSERT(dvp != NULL);
1181 1.1 riastrad KASSERT(vp != NULL);
1182 1.1 riastrad KASSERT(dvp != vp);
1183 1.1 riastrad KASSERT(dvp->v_type == VDIR);
1184 1.1 riastrad KASSERT(vp->v_type != VDIR);
1185 1.1 riastrad KASSERT(dvp->v_mount == vp->v_mount);
1186 1.1 riastrad KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
1187 1.1 riastrad KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1188 1.1 riastrad
1189 1.1 riastrad /*
1190 1.1 riastrad * We need to write to the directory to remove from it.
1191 1.1 riastrad */
1192 1.1 riastrad error = VOP_ACCESS(dvp, VWRITE, cred);
1193 1.1 riastrad if (error)
1194 1.1 riastrad return error;
1195 1.1 riastrad
1196 1.1 riastrad error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid);
1197 1.1 riastrad if (error)
1198 1.1 riastrad return error;
1199 1.1 riastrad
1200 1.1 riastrad return 0;
1201 1.1 riastrad }
1202 1.1 riastrad
1203 1.1 riastrad /*
1204 1.1 riastrad * genfs_ufslike_check_sticky: Check whether a party with credentials
1205 1.1 riastrad * cred may change an entry in a sticky directory, assuming UFS-like
1206 1.1 riastrad * permission, ownership, and stickiness semantics: If the directory is
1207 1.1 riastrad * sticky and the entry exists, the user must own either the directory
1208 1.1 riastrad * or the entry's node in order to change the entry.
1209 1.1 riastrad *
1210 1.1 riastrad * Everything must be locked and referenced.
1211 1.1 riastrad */
1212 1.1 riastrad int
1213 1.1 riastrad genfs_ufslike_check_sticky(kauth_cred_t cred, mode_t dmode, uid_t duid,
1214 1.1 riastrad struct vnode *vp, uid_t uid)
1215 1.1 riastrad {
1216 1.1 riastrad
1217 1.1 riastrad if ((dmode & S_ISTXT) && (vp != NULL))
1218 1.4 christos return genfs_can_sticky(vp, cred, duid, uid);
1219 1.1 riastrad
1220 1.1 riastrad return 0;
1221 1.1 riastrad }
1222