msdosfs_rename.c revision 1.1 1 1.1 hannken /* $NetBSD: msdosfs_rename.c,v 1.1 2021/10/23 07:41:37 hannken Exp $ */
2 1.1 hannken
3 1.1 hannken /*-
4 1.1 hannken * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5 1.1 hannken * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
6 1.1 hannken * All rights reserved.
7 1.1 hannken * Original code by Paul Popelka (paulp (at) uts.amdahl.com) (see below).
8 1.1 hannken *
9 1.1 hannken * Redistribution and use in source and binary forms, with or without
10 1.1 hannken * modification, are permitted provided that the following conditions
11 1.1 hannken * are met:
12 1.1 hannken * 1. Redistributions of source code must retain the above copyright
13 1.1 hannken * notice, this list of conditions and the following disclaimer.
14 1.1 hannken * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 hannken * notice, this list of conditions and the following disclaimer in the
16 1.1 hannken * documentation and/or other materials provided with the distribution.
17 1.1 hannken * 3. All advertising materials mentioning features or use of this software
18 1.1 hannken * must display the following acknowledgement:
19 1.1 hannken * This product includes software developed by TooLs GmbH.
20 1.1 hannken * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 1.1 hannken * derived from this software without specific prior written permission.
22 1.1 hannken *
23 1.1 hannken * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 1.1 hannken * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 1.1 hannken * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.1 hannken * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 1.1 hannken * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 1.1 hannken * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 1.1 hannken * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 1.1 hannken * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 1.1 hannken * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 1.1 hannken * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 1.1 hannken */
34 1.1 hannken /*
35 1.1 hannken * Written by Paul Popelka (paulp (at) uts.amdahl.com)
36 1.1 hannken *
37 1.1 hannken * You can do anything you want with this software, just don't say you wrote
38 1.1 hannken * it, and don't remove this notice.
39 1.1 hannken *
40 1.1 hannken * This software is provided "as is".
41 1.1 hannken *
42 1.1 hannken * The author supplies this software to be publicly redistributed on the
43 1.1 hannken * understanding that the author is not responsible for the correct
44 1.1 hannken * functioning of this software in any circumstances and is not liable for
45 1.1 hannken * any damages caused by this software.
46 1.1 hannken *
47 1.1 hannken * October 1992
48 1.1 hannken */
49 1.1 hannken
50 1.1 hannken #include <sys/param.h>
51 1.1 hannken #include <sys/systm.h>
52 1.1 hannken #include <sys/namei.h>
53 1.1 hannken #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
54 1.1 hannken #include <sys/kernel.h>
55 1.1 hannken #include <sys/file.h> /* define FWRITE ... */
56 1.1 hannken #include <sys/stat.h>
57 1.1 hannken #include <sys/buf.h>
58 1.1 hannken #include <sys/proc.h>
59 1.1 hannken #include <sys/mount.h>
60 1.1 hannken #include <sys/vnode.h>
61 1.1 hannken #include <sys/signalvar.h>
62 1.1 hannken #include <sys/malloc.h>
63 1.1 hannken #include <sys/dirent.h>
64 1.1 hannken #include <sys/lockf.h>
65 1.1 hannken #include <sys/kauth.h>
66 1.1 hannken
67 1.1 hannken #include <miscfs/genfs/genfs.h>
68 1.1 hannken #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
69 1.1 hannken
70 1.1 hannken #include <uvm/uvm_extern.h>
71 1.1 hannken
72 1.1 hannken #include <fs/msdosfs/bpb.h>
73 1.1 hannken #include <fs/msdosfs/direntry.h>
74 1.1 hannken #include <fs/msdosfs/denode.h>
75 1.1 hannken #include <fs/msdosfs/msdosfsmount.h>
76 1.1 hannken #include <fs/msdosfs/fat.h>
77 1.1 hannken
78 1.1 hannken int
79 1.1 hannken msdosfs_rename(void *v)
80 1.1 hannken {
81 1.1 hannken struct vop_rename_args /* {
82 1.1 hannken struct vnode *a_fdvp;
83 1.1 hannken struct vnode *a_fvp;
84 1.1 hannken struct componentname *a_fcnp;
85 1.1 hannken struct vnode *a_tdvp;
86 1.1 hannken struct vnode *a_tvp;
87 1.1 hannken struct componentname *a_tcnp;
88 1.1 hannken } */ *ap = v;
89 1.1 hannken struct vnode *tvp = ap->a_tvp;
90 1.1 hannken struct vnode *tdvp = ap->a_tdvp;
91 1.1 hannken struct vnode *fvp = ap->a_fvp;
92 1.1 hannken struct vnode *fdvp = ap->a_fdvp;
93 1.1 hannken struct componentname *tcnp = ap->a_tcnp;
94 1.1 hannken struct componentname *fcnp = ap->a_fcnp;
95 1.1 hannken struct denode *ip, *xp, *dp, *zp;
96 1.1 hannken u_char toname[12], oldname[12];
97 1.1 hannken u_long from_diroffset, to_diroffset;
98 1.1 hannken u_char to_count;
99 1.1 hannken int doingdirectory = 0, newparent = 0;
100 1.1 hannken int error;
101 1.1 hannken u_long cn;
102 1.1 hannken daddr_t bn;
103 1.1 hannken struct msdosfsmount *pmp;
104 1.1 hannken struct direntry *dotdotp;
105 1.1 hannken struct buf *bp;
106 1.1 hannken
107 1.1 hannken pmp = VFSTOMSDOSFS(fdvp->v_mount);
108 1.1 hannken
109 1.1 hannken /*
110 1.1 hannken * Check for cross-device rename.
111 1.1 hannken */
112 1.1 hannken if ((fvp->v_mount != tdvp->v_mount) ||
113 1.1 hannken (tvp && (fvp->v_mount != tvp->v_mount))) {
114 1.1 hannken error = EXDEV;
115 1.1 hannken abortit:
116 1.1 hannken VOP_ABORTOP(tdvp, tcnp);
117 1.1 hannken if (tdvp == tvp)
118 1.1 hannken vrele(tdvp);
119 1.1 hannken else
120 1.1 hannken vput(tdvp);
121 1.1 hannken if (tvp)
122 1.1 hannken vput(tvp);
123 1.1 hannken VOP_ABORTOP(fdvp, fcnp);
124 1.1 hannken vrele(fdvp);
125 1.1 hannken vrele(fvp);
126 1.1 hannken return (error);
127 1.1 hannken }
128 1.1 hannken
129 1.1 hannken /*
130 1.1 hannken * If source and dest are the same, do nothing.
131 1.1 hannken */
132 1.1 hannken if (tvp == fvp) {
133 1.1 hannken error = 0;
134 1.1 hannken goto abortit;
135 1.1 hannken }
136 1.1 hannken
137 1.1 hannken /*
138 1.1 hannken * XXX: This can deadlock since we hold tdvp/tvp locked.
139 1.1 hannken * But I'm not going to fix it now.
140 1.1 hannken */
141 1.1 hannken if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
142 1.1 hannken goto abortit;
143 1.1 hannken dp = VTODE(fdvp);
144 1.1 hannken ip = VTODE(fvp);
145 1.1 hannken
146 1.1 hannken /*
147 1.1 hannken * Be sure we are not renaming ".", "..", or an alias of ".". This
148 1.1 hannken * leads to a crippled directory tree. It's pretty tough to do a
149 1.1 hannken * "ls" or "pwd" with the "." directory entry missing, and "cd .."
150 1.1 hannken * doesn't work if the ".." entry is missing.
151 1.1 hannken */
152 1.1 hannken if (ip->de_Attributes & ATTR_DIRECTORY) {
153 1.1 hannken /*
154 1.1 hannken * Avoid ".", "..", and aliases of "." for obvious reasons.
155 1.1 hannken */
156 1.1 hannken if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
157 1.1 hannken dp == ip ||
158 1.1 hannken (fcnp->cn_flags & ISDOTDOT) ||
159 1.1 hannken (tcnp->cn_flags & ISDOTDOT) ||
160 1.1 hannken (ip->de_flag & DE_RENAME)) {
161 1.1 hannken VOP_UNLOCK(fvp);
162 1.1 hannken error = EINVAL;
163 1.1 hannken goto abortit;
164 1.1 hannken }
165 1.1 hannken ip->de_flag |= DE_RENAME;
166 1.1 hannken doingdirectory++;
167 1.1 hannken }
168 1.1 hannken VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
169 1.1 hannken
170 1.1 hannken /*
171 1.1 hannken * When the target exists, both the directory
172 1.1 hannken * and target vnodes are returned locked.
173 1.1 hannken */
174 1.1 hannken dp = VTODE(tdvp);
175 1.1 hannken xp = tvp ? VTODE(tvp) : NULL;
176 1.1 hannken /*
177 1.1 hannken * Remember direntry place to use for destination
178 1.1 hannken */
179 1.1 hannken to_diroffset = dp->de_crap.mlr_fndoffset;
180 1.1 hannken to_count = dp->de_crap.mlr_fndcnt;
181 1.1 hannken
182 1.1 hannken /*
183 1.1 hannken * If ".." must be changed (ie the directory gets a new
184 1.1 hannken * parent) then the source directory must not be in the
185 1.1 hannken * directory hierarchy above the target, as this would
186 1.1 hannken * orphan everything below the source directory. Also
187 1.1 hannken * the user must have write permission in the source so
188 1.1 hannken * as to be able to change "..". We must repeat the call
189 1.1 hannken * to namei, as the parent directory is unlocked by the
190 1.1 hannken * call to doscheckpath().
191 1.1 hannken */
192 1.1 hannken error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
193 1.1 hannken VOP_UNLOCK(fvp);
194 1.1 hannken if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
195 1.1 hannken newparent = 1;
196 1.1 hannken
197 1.1 hannken if (doingdirectory && newparent) {
198 1.1 hannken if (error) /* write access check above */
199 1.1 hannken goto tdvpbad;
200 1.1 hannken if (xp != NULL)
201 1.1 hannken vput(tvp);
202 1.1 hannken tvp = NULL;
203 1.1 hannken /*
204 1.1 hannken * doscheckpath() vput()'s tdvp (dp == VTODE(tdvp)),
205 1.1 hannken * so we have to get an extra ref to it first, and
206 1.1 hannken * because it's been unlocked we need to do a relookup
207 1.1 hannken * afterwards in case tvp has changed.
208 1.1 hannken */
209 1.1 hannken vref(tdvp);
210 1.1 hannken if ((error = doscheckpath(ip, dp)) != 0)
211 1.1 hannken goto bad;
212 1.1 hannken vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
213 1.1 hannken if ((error = relookup(tdvp, &tvp, tcnp, 0)) != 0) {
214 1.1 hannken VOP_UNLOCK(tdvp);
215 1.1 hannken goto bad;
216 1.1 hannken }
217 1.1 hannken dp = VTODE(tdvp);
218 1.1 hannken xp = tvp ? VTODE(tvp) : NULL;
219 1.1 hannken }
220 1.1 hannken
221 1.1 hannken if (xp != NULL) {
222 1.1 hannken /*
223 1.1 hannken * Target must be empty if a directory and have no links
224 1.1 hannken * to it. Also, ensure source and target are compatible
225 1.1 hannken * (both directories, or both not directories).
226 1.1 hannken */
227 1.1 hannken if (xp->de_Attributes & ATTR_DIRECTORY) {
228 1.1 hannken if (!dosdirempty(xp)) {
229 1.1 hannken error = ENOTEMPTY;
230 1.1 hannken goto tdvpbad;
231 1.1 hannken }
232 1.1 hannken if (!doingdirectory) {
233 1.1 hannken error = ENOTDIR;
234 1.1 hannken goto tdvpbad;
235 1.1 hannken }
236 1.1 hannken } else if (doingdirectory) {
237 1.1 hannken error = EISDIR;
238 1.1 hannken goto tdvpbad;
239 1.1 hannken }
240 1.1 hannken if ((error = removede(dp, xp, &dp->de_crap)) != 0)
241 1.1 hannken goto tdvpbad;
242 1.1 hannken VN_KNOTE(tdvp, NOTE_WRITE);
243 1.1 hannken VN_KNOTE(tvp, NOTE_DELETE);
244 1.1 hannken cache_purge(tvp);
245 1.1 hannken vput(tvp);
246 1.1 hannken tvp = NULL;
247 1.1 hannken xp = NULL;
248 1.1 hannken }
249 1.1 hannken
250 1.1 hannken /*
251 1.1 hannken * Convert the filename in tcnp into a dos filename. We copy this
252 1.1 hannken * into the denode and directory entry for the destination
253 1.1 hannken * file/directory.
254 1.1 hannken */
255 1.1 hannken if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) {
256 1.1 hannken goto abortit;
257 1.1 hannken }
258 1.1 hannken
259 1.1 hannken /*
260 1.1 hannken * Since from wasn't locked at various places above,
261 1.1 hannken * have to do a relookup here.
262 1.1 hannken */
263 1.1 hannken fcnp->cn_flags &= ~MODMASK;
264 1.1 hannken fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
265 1.1 hannken VOP_UNLOCK(tdvp);
266 1.1 hannken vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
267 1.1 hannken if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
268 1.1 hannken VOP_UNLOCK(fdvp);
269 1.1 hannken vrele(ap->a_fvp);
270 1.1 hannken vrele(tdvp);
271 1.1 hannken return (error);
272 1.1 hannken }
273 1.1 hannken if (fvp == NULL) {
274 1.1 hannken /*
275 1.1 hannken * From name has disappeared.
276 1.1 hannken */
277 1.1 hannken if (doingdirectory)
278 1.1 hannken panic("rename: lost dir entry");
279 1.1 hannken vput(fdvp);
280 1.1 hannken vrele(ap->a_fvp);
281 1.1 hannken vrele(tdvp);
282 1.1 hannken return 0;
283 1.1 hannken }
284 1.1 hannken VOP_UNLOCK(fdvp);
285 1.1 hannken xp = VTODE(fvp);
286 1.1 hannken zp = VTODE(fdvp);
287 1.1 hannken from_diroffset = zp->de_crap.mlr_fndoffset;
288 1.1 hannken
289 1.1 hannken /*
290 1.1 hannken * Ensure that the directory entry still exists and has not
291 1.1 hannken * changed till now. If the source is a file the entry may
292 1.1 hannken * have been unlinked or renamed. In either case there is
293 1.1 hannken * no further work to be done. If the source is a directory
294 1.1 hannken * then it cannot have been rmdir'ed or renamed; this is
295 1.1 hannken * prohibited by the DE_RENAME flag.
296 1.1 hannken */
297 1.1 hannken if (xp != ip) {
298 1.1 hannken if (doingdirectory)
299 1.1 hannken panic("rename: lost dir entry");
300 1.1 hannken vrele(ap->a_fvp);
301 1.1 hannken xp = NULL;
302 1.1 hannken } else {
303 1.1 hannken vrele(fvp);
304 1.1 hannken xp = NULL;
305 1.1 hannken
306 1.1 hannken /*
307 1.1 hannken * First write a new entry in the destination
308 1.1 hannken * directory and mark the entry in the source directory
309 1.1 hannken * as deleted. Then move the denode to the correct hash
310 1.1 hannken * chain for its new location in the filesystem. And, if
311 1.1 hannken * we moved a directory, then update its .. entry to point
312 1.1 hannken * to the new parent directory.
313 1.1 hannken */
314 1.1 hannken memcpy(oldname, ip->de_Name, 11);
315 1.1 hannken memcpy(ip->de_Name, toname, 11); /* update denode */
316 1.1 hannken dp->de_crap.mlr_fndoffset = to_diroffset;
317 1.1 hannken dp->de_crap.mlr_fndcnt = to_count;
318 1.1 hannken error = createde(ip, dp, &dp->de_crap, (struct denode **)0,
319 1.1 hannken tcnp);
320 1.1 hannken if (error) {
321 1.1 hannken memcpy(ip->de_Name, oldname, 11);
322 1.1 hannken VOP_UNLOCK(fvp);
323 1.1 hannken goto bad;
324 1.1 hannken }
325 1.1 hannken ip->de_refcnt++;
326 1.1 hannken zp->de_crap.mlr_fndoffset = from_diroffset;
327 1.1 hannken if ((error = removede(zp, ip, &zp->de_crap)) != 0) {
328 1.1 hannken /* XXX should really panic here, fs is corrupt */
329 1.1 hannken VOP_UNLOCK(fvp);
330 1.1 hannken goto bad;
331 1.1 hannken }
332 1.1 hannken cache_purge(fvp);
333 1.1 hannken if (!doingdirectory) {
334 1.1 hannken struct denode_key old_key = ip->de_key;
335 1.1 hannken struct denode_key new_key = ip->de_key;
336 1.1 hannken
337 1.1 hannken error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
338 1.1 hannken &new_key.dk_dirclust, 0);
339 1.1 hannken if (error) {
340 1.1 hannken /* XXX should really panic here, fs is corrupt */
341 1.1 hannken VOP_UNLOCK(fvp);
342 1.1 hannken goto bad;
343 1.1 hannken }
344 1.1 hannken new_key.dk_diroffset = to_diroffset;
345 1.1 hannken if (new_key.dk_dirclust != MSDOSFSROOT)
346 1.1 hannken new_key.dk_diroffset &= pmp->pm_crbomask;
347 1.1 hannken vcache_rekey_enter(pmp->pm_mountp, fvp, &old_key,
348 1.1 hannken sizeof(old_key), &new_key, sizeof(new_key));
349 1.1 hannken ip->de_key = new_key;
350 1.1 hannken vcache_rekey_exit(pmp->pm_mountp, fvp, &old_key,
351 1.1 hannken sizeof(old_key), &ip->de_key, sizeof(ip->de_key));
352 1.1 hannken }
353 1.1 hannken }
354 1.1 hannken
355 1.1 hannken /*
356 1.1 hannken * If we moved a directory to a new parent directory, then we must
357 1.1 hannken * fixup the ".." entry in the moved directory.
358 1.1 hannken */
359 1.1 hannken if (doingdirectory && newparent) {
360 1.1 hannken cn = ip->de_StartCluster;
361 1.1 hannken if (cn == MSDOSFSROOT) {
362 1.1 hannken /* this should never happen */
363 1.1 hannken panic("msdosfs_rename: updating .. in root directory?");
364 1.1 hannken } else
365 1.1 hannken bn = cntobn(pmp, cn);
366 1.1 hannken error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
367 1.1 hannken pmp->pm_bpcluster, B_MODIFY, &bp);
368 1.1 hannken if (error) {
369 1.1 hannken /* XXX should really panic here, fs is corrupt */
370 1.1 hannken VOP_UNLOCK(fvp);
371 1.1 hannken goto bad;
372 1.1 hannken }
373 1.1 hannken dotdotp = (struct direntry *)bp->b_data + 1;
374 1.1 hannken putushort(dotdotp->deStartCluster, dp->de_StartCluster);
375 1.1 hannken if (FAT32(pmp)) {
376 1.1 hannken putushort(dotdotp->deHighClust,
377 1.1 hannken dp->de_StartCluster >> 16);
378 1.1 hannken } else {
379 1.1 hannken putushort(dotdotp->deHighClust, 0);
380 1.1 hannken }
381 1.1 hannken if ((error = bwrite(bp)) != 0) {
382 1.1 hannken /* XXX should really panic here, fs is corrupt */
383 1.1 hannken VOP_UNLOCK(fvp);
384 1.1 hannken goto bad;
385 1.1 hannken }
386 1.1 hannken }
387 1.1 hannken
388 1.1 hannken VN_KNOTE(fvp, NOTE_RENAME);
389 1.1 hannken VOP_UNLOCK(fvp);
390 1.1 hannken bad:
391 1.1 hannken if (tvp)
392 1.1 hannken vput(tvp);
393 1.1 hannken vrele(tdvp);
394 1.1 hannken ip->de_flag &= ~DE_RENAME;
395 1.1 hannken vrele(fdvp);
396 1.1 hannken vrele(fvp);
397 1.1 hannken return (error);
398 1.1 hannken
399 1.1 hannken /* XXX: uuuh */
400 1.1 hannken tdvpbad:
401 1.1 hannken VOP_UNLOCK(tdvp);
402 1.1 hannken goto bad;
403 1.1 hannken }
404 1.1 hannken
405 1.1 hannken /*
406 1.1 hannken * Check to see if the directory described by target is in some
407 1.1 hannken * subdirectory of source. This prevents something like the following from
408 1.1 hannken * succeeding and leaving a bunch or files and directories orphaned. mv
409 1.1 hannken * /a/b/c /a/b/c/d/e/f Where c and f are directories.
410 1.1 hannken *
411 1.1 hannken * source - the inode for /a/b/c
412 1.1 hannken * target - the inode for /a/b/c/d/e/f
413 1.1 hannken *
414 1.1 hannken * Returns 0 if target is NOT a subdirectory of source.
415 1.1 hannken * Otherwise returns a non-zero error number.
416 1.1 hannken * The target inode is always unlocked on return.
417 1.1 hannken */
418 1.1 hannken int
419 1.1 hannken doscheckpath(struct denode *source, struct denode *target)
420 1.1 hannken {
421 1.1 hannken u_long scn;
422 1.1 hannken struct msdosfsmount *pmp;
423 1.1 hannken struct direntry *ep;
424 1.1 hannken struct denode *dep;
425 1.1 hannken struct buf *bp = NULL;
426 1.1 hannken int error = 0;
427 1.1 hannken
428 1.1 hannken dep = target;
429 1.1 hannken if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
430 1.1 hannken (source->de_Attributes & ATTR_DIRECTORY) == 0) {
431 1.1 hannken error = ENOTDIR;
432 1.1 hannken goto out;
433 1.1 hannken }
434 1.1 hannken if (dep->de_StartCluster == source->de_StartCluster) {
435 1.1 hannken error = EEXIST;
436 1.1 hannken goto out;
437 1.1 hannken }
438 1.1 hannken if (dep->de_StartCluster == MSDOSFSROOT)
439 1.1 hannken goto out;
440 1.1 hannken pmp = dep->de_pmp;
441 1.1 hannken #ifdef DIAGNOSTIC
442 1.1 hannken if (pmp != source->de_pmp)
443 1.1 hannken panic("doscheckpath: source and target on different filesystems");
444 1.1 hannken #endif
445 1.1 hannken if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
446 1.1 hannken goto out;
447 1.1 hannken
448 1.1 hannken for (;;) {
449 1.1 hannken if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
450 1.1 hannken error = ENOTDIR;
451 1.1 hannken break;
452 1.1 hannken }
453 1.1 hannken scn = dep->de_StartCluster;
454 1.1 hannken error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)),
455 1.1 hannken pmp->pm_bpcluster, 0, &bp);
456 1.1 hannken if (error)
457 1.1 hannken break;
458 1.1 hannken
459 1.1 hannken ep = (struct direntry *) bp->b_data + 1;
460 1.1 hannken if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
461 1.1 hannken memcmp(ep->deName, ".. ", 11) != 0) {
462 1.1 hannken error = ENOTDIR;
463 1.1 hannken break;
464 1.1 hannken }
465 1.1 hannken scn = getushort(ep->deStartCluster);
466 1.1 hannken if (FAT32(pmp))
467 1.1 hannken scn |= getushort(ep->deHighClust) << 16;
468 1.1 hannken
469 1.1 hannken if (scn == source->de_StartCluster) {
470 1.1 hannken error = EINVAL;
471 1.1 hannken break;
472 1.1 hannken }
473 1.1 hannken if (scn == MSDOSFSROOT)
474 1.1 hannken break;
475 1.1 hannken if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
476 1.1 hannken /*
477 1.1 hannken * scn should be 0 in this case,
478 1.1 hannken * but we silently ignore the error.
479 1.1 hannken */
480 1.1 hannken break;
481 1.1 hannken }
482 1.1 hannken
483 1.1 hannken vput(DETOV(dep));
484 1.1 hannken brelse(bp, 0);
485 1.1 hannken bp = NULL;
486 1.1 hannken #ifdef MAKEFS
487 1.1 hannken /* NOTE: deget() clears dep on error */
488 1.1 hannken if ((error = deget(pmp, scn, 0, &dep)) != 0)
489 1.1 hannken break;
490 1.1 hannken #else
491 1.1 hannken struct vnode *vp;
492 1.1 hannken
493 1.1 hannken dep = NULL;
494 1.1 hannken error = deget(pmp, scn, 0, &vp);
495 1.1 hannken if (error)
496 1.1 hannken break;
497 1.1 hannken error = vn_lock(vp, LK_EXCLUSIVE);
498 1.1 hannken if (error) {
499 1.1 hannken vrele(vp);
500 1.1 hannken break;
501 1.1 hannken }
502 1.1 hannken dep = VTODE(vp);
503 1.1 hannken #endif
504 1.1 hannken }
505 1.1 hannken out:
506 1.1 hannken if (bp)
507 1.1 hannken brelse(bp, 0);
508 1.1 hannken if (error == ENOTDIR)
509 1.1 hannken printf("doscheckpath(): .. not a directory?\n");
510 1.1 hannken if (dep != NULL)
511 1.1 hannken vput(DETOV(dep));
512 1.1 hannken return (error);
513 1.1 hannken }
514