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