xref: /netbsd-src/sys/fs/msdosfs/msdosfs_lookup.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: msdosfs_lookup.c,v 1.9 2006/05/14 21:31:52 elad Exp $	*/
2 
3 /*-
4  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
6  * All rights reserved.
7  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by TooLs GmbH.
20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 /*
35  * Written by Paul Popelka (paulp@uts.amdahl.com)
36  *
37  * You can do anything you want with this software, just don't say you wrote
38  * it, and don't remove this notice.
39  *
40  * This software is provided "as is".
41  *
42  * The author supplies this software to be publicly redistributed on the
43  * understanding that the author is not responsible for the correct
44  * functioning of this software in any circumstances and is not liable for
45  * any damages caused by this software.
46  *
47  * October 1992
48  */
49 
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.9 2006/05/14 21:31:52 elad Exp $");
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/namei.h>
56 #include <sys/buf.h>
57 #include <sys/vnode.h>
58 #include <sys/mount.h>
59 #include <sys/dirent.h>
60 #include <sys/kauth.h>
61 
62 #include <fs/msdosfs/bpb.h>
63 #include <fs/msdosfs/direntry.h>
64 #include <fs/msdosfs/denode.h>
65 #include <fs/msdosfs/msdosfsmount.h>
66 #include <fs/msdosfs/fat.h>
67 
68 /*
69  * When we search a directory the blocks containing directory entries are
70  * read and examined.  The directory entries contain information that would
71  * normally be in the inode of a unix filesystem.  This means that some of
72  * a directory's contents may also be in memory resident denodes (sort of
73  * an inode).  This can cause problems if we are searching while some other
74  * process is modifying a directory.  To prevent one process from accessing
75  * incompletely modified directory information we depend upon being the
76  * sole owner of a directory block.  bread/brelse provide this service.
77  * This being the case, when a process modifies a directory it must first
78  * acquire the disk block that contains the directory entry to be modified.
79  * Then update the disk block and the denode, and then write the disk block
80  * out to disk.  This way disk blocks containing directory entries and in
81  * memory denode's will be in synch.
82  */
83 int
84 msdosfs_lookup(v)
85 	void *v;
86 {
87 	struct vop_lookup_args /* {
88 		struct vnode *a_dvp;
89 		struct vnode **a_vpp;
90 		struct componentname *a_cnp;
91 	} */ *ap = v;
92 	struct vnode *vdp = ap->a_dvp;
93 	struct vnode **vpp = ap->a_vpp;
94 	struct componentname *cnp = ap->a_cnp;
95 	daddr_t bn;
96 	int error;
97 	int lockparent;
98 	int wantparent;
99 	int slotcount;
100 	int slotoffset = 0;
101 	int frcn;
102 	u_long cluster;
103 	int blkoff;
104 	int diroff;
105 	int blsize;
106 	int isadir;		/* ~0 if found direntry is a directory	 */
107 	u_long scn;		/* starting cluster number		 */
108 	struct vnode *pdp;
109 	struct denode *dp;
110 	struct denode *tdp;
111 	struct msdosfsmount *pmp;
112 	struct buf *bp = 0;
113 	struct direntry *dep;
114 	u_char dosfilename[12];
115 	int flags;
116 	int nameiop = cnp->cn_nameiop;
117 	int wincnt = 1;
118 	int chksum = -1, chksum_ok;
119 	int olddos = 1;
120 
121 	cnp->cn_flags &= ~PDIRUNLOCK; /* XXX why this ?? */
122 	flags = cnp->cn_flags;
123 
124 #ifdef MSDOSFS_DEBUG
125 	printf("msdosfs_lookup(): looking for %.*s\n",
126 		(int)cnp->cn_namelen, cnp->cn_nameptr);
127 #endif
128 	dp = VTODE(vdp);
129 	pmp = dp->de_pmp;
130 	*vpp = NULL;
131 	lockparent = flags & LOCKPARENT;
132 	wantparent = flags & (LOCKPARENT | WANTPARENT);
133 #ifdef MSDOSFS_DEBUG
134 	printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
135 	    vdp, dp, dp->de_Attributes);
136 #endif
137 
138 	/*
139 	 * Check accessiblity of directory.
140 	 */
141 	if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred, cnp->cn_lwp)) != 0)
142 		return (error);
143 
144 	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
145 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
146 		return (EROFS);
147 
148 	/*
149 	 * We now have a segment name to search for, and a directory to search.
150 	 *
151 	 * Before tediously performing a linear scan of the directory,
152 	 * check the name cache to see if the directory/name pair
153 	 * we are looking for is known already.
154 	 */
155 	if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
156 		return (error);
157 
158 	/*
159 	 * If they are going after the . or .. entry in the root directory,
160 	 * they won't find it.  DOS filesystems don't have them in the root
161 	 * directory.  So, we fake it. deget() is in on this scam too.
162 	 */
163 	if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' &&
164 	    (cnp->cn_namelen == 1 ||
165 		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
166 		isadir = ATTR_DIRECTORY;
167 		scn = MSDOSFSROOT;
168 #ifdef MSDOSFS_DEBUG
169 		printf("msdosfs_lookup(): looking for . or .. in root directory\n");
170 #endif
171 		cluster = MSDOSFSROOT;
172 		blkoff = MSDOSFSROOT_OFS;
173 		goto foundroot;
174 	}
175 
176 	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
177 	    cnp->cn_namelen, 0)) {
178 	case 0:
179 		return (EINVAL);
180 	case 1:
181 		break;
182 	case 2:
183 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
184 		    cnp->cn_namelen) + 1;
185 		break;
186 	case 3:
187 		olddos = 0;
188 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
189 		    cnp->cn_namelen) + 1;
190 		break;
191 	}
192 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
193 		wincnt = 1;
194 
195 	/*
196 	 * Suppress search for slots unless creating
197 	 * file and at end of pathname, in which case
198 	 * we watch for a place to put the new file in
199 	 * case it doesn't already exist.
200 	 */
201 	slotcount = wincnt;
202 	if ((nameiop == CREATE || nameiop == RENAME) &&
203 	    (flags & ISLASTCN))
204 		slotcount = 0;
205 
206 #ifdef MSDOSFS_DEBUG
207 	printf("msdosfs_lookup(): dos filename: %s\n", dosfilename);
208 #endif
209 	/*
210 	 * Search the directory pointed at by vdp for the name pointed at
211 	 * by cnp->cn_nameptr.
212 	 */
213 	tdp = NULL;
214 	/*
215 	 * The outer loop ranges over the clusters that make up the
216 	 * directory.  Note that the root directory is different from all
217 	 * other directories.  It has a fixed number of blocks that are not
218 	 * part of the pool of allocatable clusters.  So, we treat it a
219 	 * little differently. The root directory starts at "cluster" 0.
220 	 */
221 	diroff = 0;
222 	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
223 		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
224 			if (error == E2BIG)
225 				break;
226 			return (error);
227 		}
228 		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
229 		if (error) {
230 			brelse(bp);
231 			return (error);
232 		}
233 		for (blkoff = 0; blkoff < blsize;
234 		     blkoff += sizeof(struct direntry),
235 		     diroff += sizeof(struct direntry)) {
236 			dep = (struct direntry *)(bp->b_data + blkoff);
237 			/*
238 			 * If the slot is empty and we are still looking
239 			 * for an empty then remember this one.  If the
240 			 * slot is not empty then check to see if it
241 			 * matches what we are looking for.  If the slot
242 			 * has never been filled with anything, then the
243 			 * remainder of the directory has never been used,
244 			 * so there is no point in searching it.
245 			 */
246 			if (dep->deName[0] == SLOT_EMPTY ||
247 			    dep->deName[0] == SLOT_DELETED) {
248 				/*
249 				 * Drop memory of previous long matches
250 				 */
251 				chksum = -1;
252 
253 				if (slotcount < wincnt) {
254 					slotcount++;
255 					slotoffset = diroff;
256 				}
257 				if (dep->deName[0] == SLOT_EMPTY) {
258 					brelse(bp);
259 					goto notfound;
260 				}
261 			} else {
262 				/*
263 				 * If there wasn't enough space for our
264 				 * winentries, forget about the empty space
265 				 */
266 				if (slotcount < wincnt)
267 					slotcount = 0;
268 
269 				/*
270 				 * Check for Win95 long filename entry
271 				 */
272 				if (dep->deAttributes == ATTR_WIN95) {
273 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
274 						continue;
275 
276 					chksum = winChkName((const u_char *)cnp->cn_nameptr,
277 							    cnp->cn_namelen,
278 							    (struct winentry *)dep,
279 							    chksum);
280 					continue;
281 				}
282 
283 				/*
284 				 * Ignore volume labels (anywhere, not just
285 				 * the root directory).
286 				 */
287 				if (dep->deAttributes & ATTR_VOLUME) {
288 					chksum = -1;
289 					continue;
290 				}
291 
292 				/*
293 				 * Check for a checksum or name match
294 				 */
295 				chksum_ok = (chksum == winChksum(dep->deName));
296 				if (!chksum_ok
297 				    && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
298 					chksum = -1;
299 					continue;
300 				}
301 #ifdef MSDOSFS_DEBUG
302 				printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
303 				    blkoff, diroff);
304 #endif
305 				/*
306 				 * Remember where this directory
307 				 * entry came from for whoever did
308 				 * this lookup.
309 				 */
310 				dp->de_fndoffset = diroff;
311 				if (chksum_ok && nameiop == RENAME) {
312 					/*
313 					 * Target had correct long name
314 					 * directory entries, reuse them
315 					 * as needed.
316 					 */
317 					dp->de_fndcnt = wincnt - 1;
318 				} else {
319 					/*
320 					 * Long name directory entries
321 					 * not present or corrupt, can only
322 					 * reuse dos directory entry.
323 					 */
324 					dp->de_fndcnt = 0;
325 				}
326 
327 				goto found;
328 			}
329 		}	/* for (blkoff = 0; .... */
330 		/*
331 		 * Release the buffer holding the directory cluster just
332 		 * searched.
333 		 */
334 		brelse(bp);
335 	}	/* for (frcn = 0; ; frcn++) */
336 
337 notfound:
338 	/*
339 	 * We hold no disk buffers at this point.
340 	 */
341 
342 	/*
343 	 * If we get here we didn't find the entry we were looking for. But
344 	 * that's ok if we are creating or renaming and are at the end of
345 	 * the pathname and the directory hasn't been removed.
346 	 */
347 #ifdef MSDOSFS_DEBUG
348 	printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n",
349 	    nameiop, dp->de_refcnt, slotcount, slotoffset);
350 #endif
351 	if ((nameiop == CREATE || nameiop == RENAME) &&
352 	    (flags & ISLASTCN) && dp->de_refcnt != 0) {
353 		/*
354 		 * Access for write is interpreted as allowing
355 		 * creation of files in the directory.
356 		 */
357 		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_lwp);
358 		if (error)
359 			return (error);
360 
361 		/*
362 		 * Fixup the slot description to point to the place where
363 		 * we might put the new DOS direntry (putting the Win95
364 		 * long name entries before that)
365 		 */
366 		if (!slotcount) {
367 			slotcount = 1;
368 			slotoffset = diroff;
369 		}
370 		if (wincnt > slotcount) {
371 			slotoffset +=
372 				sizeof(struct direntry) * (wincnt - slotcount);
373 		}
374 
375 		/*
376 		 * Return an indication of where the new directory
377 		 * entry should be put.
378 		 */
379 		dp->de_fndoffset = slotoffset;
380 		dp->de_fndcnt = wincnt - 1;
381 
382 		/*
383 		 * We return with the directory locked, so that
384 		 * the parameters we set up above will still be
385 		 * valid if we actually decide to do a direnter().
386 		 * We return ni_vp == NULL to indicate that the entry
387 		 * does not currently exist; we leave a pointer to
388 		 * the (locked) directory inode in ndp->ni_dvp.
389 		 * The pathname buffer is saved so that the name
390 		 * can be obtained later.
391 		 *
392 		 * NB - if the directory is unlocked, then this
393 		 * information cannot be used.
394 		 */
395 		cnp->cn_flags |= SAVENAME;
396 		if (!lockparent)
397 			VOP_UNLOCK(vdp, 0);
398 		return (EJUSTRETURN);
399 	}
400 
401 #if 0
402 	/*
403 	 * Insert name into cache (as non-existent) if appropriate.
404 	 *
405 	 * XXX Negative caching is broken for msdosfs because the name
406 	 * cache doesn't understand peculiarities such as case insensitivity
407 	 * and 8.3 filenames.  Hence, it may not invalidate all negative
408 	 * entries if a file with this name is later created.
409 	 * e.g. creating a file 'foo' won't invalidate a negative entry
410 	 * for 'FOO'.
411 	 */
412 	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
413 		cache_enter(vdp, *vpp, cnp);
414 #endif
415 
416 	return (ENOENT);
417 
418 found:
419 	/*
420 	 * NOTE:  We still have the buffer with matched directory entry at
421 	 * this point.
422 	 */
423 	isadir = dep->deAttributes & ATTR_DIRECTORY;
424 	scn = getushort(dep->deStartCluster);
425 	if (FAT32(pmp)) {
426 		scn |= getushort(dep->deHighClust) << 16;
427 		if (scn == pmp->pm_rootdirblk) {
428 			/*
429 			 * There should actually be 0 here.
430 			 * Just ignore the error.
431 			 */
432 			scn = MSDOSFSROOT;
433 		}
434 	}
435 
436 	if (isadir) {
437 		cluster = scn;
438 		if (cluster == MSDOSFSROOT)
439 			blkoff = MSDOSFSROOT_OFS;
440 		else
441 			blkoff = 0;
442 	} else if (cluster == MSDOSFSROOT)
443 		blkoff = diroff;
444 
445 	/*
446 	 * Now release buf to allow deget to read the entry again.
447 	 * Reserving it here and giving it to deget could result
448 	 * in a deadlock.
449 	 */
450 	brelse(bp);
451 
452 foundroot:
453 	/*
454 	 * If we entered at foundroot, then we are looking for the . or ..
455 	 * entry of the filesystems root directory.  isadir and scn were
456 	 * setup before jumping here.  And, bp is already null.
457 	 */
458 	if (FAT32(pmp) && scn == MSDOSFSROOT)
459 		scn = pmp->pm_rootdirblk;
460 
461 	/*
462 	 * If deleting, and at end of pathname, return
463 	 * parameters which can be used to remove file.
464 	 * If the wantparent flag isn't set, we return only
465 	 * the directory (in ndp->ni_dvp), otherwise we go
466 	 * on and lock the inode, being careful with ".".
467 	 */
468 	if (nameiop == DELETE && (flags & ISLASTCN)) {
469 		/*
470 		 * Don't allow deleting the root.
471 		 */
472 		if (blkoff == MSDOSFSROOT_OFS)
473 			return EROFS;			/* really? XXX */
474 
475 		/*
476 		 * Write access to directory required to delete files.
477 		 */
478 		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_lwp);
479 		if (error)
480 			return (error);
481 
482 		/*
483 		 * Return pointer to current entry in dp->i_offset.
484 		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
485 		 */
486 		if (dp->de_StartCluster == scn && isadir) {	/* "." */
487 			VREF(vdp);
488 			*vpp = vdp;
489 			return (0);
490 		}
491 		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
492 			return (error);
493 		*vpp = DETOV(tdp);
494 		if (!lockparent) {
495 			VOP_UNLOCK(vdp, 0);
496 			cnp->cn_flags |= PDIRUNLOCK;
497 		}
498 		return (0);
499 	}
500 
501 	/*
502 	 * If rewriting (RENAME), return the inode and the
503 	 * information required to rewrite the present directory
504 	 * Must get inode of directory entry to verify it's a
505 	 * regular file, or empty directory.
506 	 */
507 	if (nameiop == RENAME && wantparent &&
508 	    (flags & ISLASTCN)) {
509 
510 		if (vdp->v_mount->mnt_flag & MNT_RDONLY)
511 			return (EROFS);
512 
513 		if (blkoff == MSDOSFSROOT_OFS)
514 			return EROFS;				/* really? XXX */
515 
516 		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_lwp);
517 		if (error)
518 			return (error);
519 
520 		/*
521 		 * Careful about locking second inode.
522 		 * This can only occur if the target is ".".
523 		 */
524 		if (dp->de_StartCluster == scn && isadir)
525 			return (EISDIR);
526 
527 		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
528 			return (error);
529 		*vpp = DETOV(tdp);
530 		cnp->cn_flags |= SAVENAME;
531 		if (!lockparent) {
532 			VOP_UNLOCK(vdp, 0);
533 			cnp->cn_flags |= PDIRUNLOCK;
534 		}
535 		return (0);
536 	}
537 
538 	/*
539 	 * Step through the translation in the name.  We do not `vput' the
540 	 * directory because we may need it again if a symbolic link
541 	 * is relative to the current directory.  Instead we save it
542 	 * unlocked as "pdp".  We must get the target inode before unlocking
543 	 * the directory to insure that the inode will not be removed
544 	 * before we get it.  We prevent deadlock by always fetching
545 	 * inodes from the root, moving down the directory tree. Thus
546 	 * when following backward pointers ".." we must unlock the
547 	 * parent directory before getting the requested directory.
548 	 * There is a potential race condition here if both the current
549 	 * and parent directories are removed before the VFS_VGET for the
550 	 * inode associated with ".." returns.  We hope that this occurs
551 	 * infrequently since we cannot avoid this race condition without
552 	 * implementing a sophisticated deadlock detection algorithm.
553 	 * Note also that this simple deadlock detection scheme will not
554 	 * work if the file system has any hard links other than ".."
555 	 * that point backwards in the directory structure.
556 	 */
557 	pdp = vdp;
558 	if (flags & ISDOTDOT) {
559 		VOP_UNLOCK(pdp, 0);	/* race to get the inode */
560 		cnp->cn_flags |= PDIRUNLOCK;
561 		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) {
562 			if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
563 				cnp->cn_flags &= ~PDIRUNLOCK;
564 			return (error);
565 		}
566 		if (lockparent && (flags & ISLASTCN)) {
567 			if ((error = vn_lock(pdp, LK_EXCLUSIVE))) {
568 				vput(DETOV(tdp));
569 				return (error);
570 			}
571 			cnp->cn_flags &= ~PDIRUNLOCK;
572 		}
573 		*vpp = DETOV(tdp);
574 	} else if (dp->de_StartCluster == scn && isadir) {
575 		VREF(vdp);	/* we want ourself, ie "." */
576 		*vpp = vdp;
577 	} else {
578 		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
579 			return (error);
580 		if (!lockparent || !(flags & ISLASTCN)) {
581 			VOP_UNLOCK(pdp, 0);
582 			cnp->cn_flags |= PDIRUNLOCK;
583 		}
584 		*vpp = DETOV(tdp);
585 	}
586 
587 	/*
588 	 * Insert name into cache if appropriate.
589 	 */
590 	if (cnp->cn_flags & MAKEENTRY)
591 		cache_enter(vdp, *vpp, cnp);
592 
593 	return (0);
594 }
595 
596 /*
597  * dep  - directory entry to copy into the directory
598  * ddep - directory to add to
599  * depp - return the address of the denode for the created directory entry
600  *	  if depp != 0
601  * cnp  - componentname needed for Win95 long filenames
602  */
603 int
604 createde(dep, ddep, depp, cnp)
605 	struct denode *dep;
606 	struct denode *ddep;
607 	struct denode **depp;
608 	struct componentname *cnp;
609 {
610 	int error, rberror;
611 	u_long dirclust, clusoffset;
612 	u_long fndoffset, havecnt=0, wcnt=1;
613 	struct direntry *ndep;
614 	struct msdosfsmount *pmp = ddep->de_pmp;
615 	struct buf *bp;
616 	daddr_t bn;
617 	int blsize, i;
618 	int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC;
619 
620 #ifdef MSDOSFS_DEBUG
621 	printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
622 	    dep, ddep, depp, cnp);
623 #endif
624 
625 	/*
626 	 * If no space left in the directory then allocate another cluster
627 	 * and chain it onto the end of the file.  There is one exception
628 	 * to this.  That is, if the root directory has no more space it
629 	 * can NOT be expanded.  extendfile() checks for and fails attempts
630 	 * to extend the root directory.  We just return an error in that
631 	 * case.
632 	 */
633 	if (ddep->de_fndoffset >= ddep->de_FileSize) {
634 		u_long needlen = ddep->de_fndoffset + sizeof(struct direntry)
635 		    - ddep->de_FileSize;
636 		dirclust = de_clcount(pmp, needlen);
637 		if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) {
638 			(void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
639 			goto err_norollback;
640 		}
641 
642 		/*
643 		 * Update the size of the directory
644 		 */
645 		ddep->de_FileSize += de_cn2off(pmp, dirclust);
646 	}
647 
648 	/*
649 	 * We just read in the cluster with space.  Copy the new directory
650 	 * entry in.  Then write it to disk. NOTE:  DOS directories
651 	 * do not get smaller as clusters are emptied.
652 	 */
653 	error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
654 		       &bn, &dirclust, &blsize);
655 	if (error)
656 		goto err_norollback;
657 	clusoffset = ddep->de_fndoffset;
658 	if (dirclust != MSDOSFSROOT)
659 		clusoffset &= pmp->pm_crbomask;
660 	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
661 		brelse(bp);
662 		goto err_norollback;
663 	}
664 	ndep = bptoep(pmp, bp, clusoffset);
665 
666 	DE_EXTERNALIZE(ndep, dep);
667 
668 	/*
669 	 * Now write the Win95 long name
670 	 */
671 	if (ddep->de_fndcnt > 0) {
672 		u_int8_t chksum = winChksum(ndep->deName);
673 		const u_char *un = (const u_char *)cnp->cn_nameptr;
674 		int unlen = cnp->cn_namelen;
675 		u_long xhavecnt;
676 
677 		fndoffset = ddep->de_fndoffset;
678 		xhavecnt = ddep->de_fndcnt + 1;
679 
680 		for(; wcnt < xhavecnt; wcnt++) {
681 			if ((fndoffset & pmp->pm_crbomask) == 0) {
682 				/* we should never get here if ddep is root
683 				 * directory */
684 
685 				if (async)
686 					(void) bdwrite(bp);
687 				else if ((error = bwrite(bp)) != 0)
688 					goto rollback;
689 
690 				fndoffset -= sizeof(struct direntry);
691 				error = pcbmap(ddep,
692 					       de_cluster(pmp, fndoffset),
693 					       &bn, 0, &blsize);
694 				if (error)
695 					goto rollback;
696 
697 				error = bread(pmp->pm_devvp, bn, blsize,
698 					      NOCRED, &bp);
699 				if (error) {
700 					brelse(bp);
701 					goto rollback;
702 				}
703 				ndep = bptoep(pmp, bp,
704 						fndoffset & pmp->pm_crbomask);
705 			} else {
706 				ndep--;
707 				fndoffset -= sizeof(struct direntry);
708 			}
709 			if (!unix2winfn(un, unlen, (struct winentry *)ndep,
710 						wcnt, chksum))
711 				break;
712 		}
713 	}
714 
715 	if (async)
716 		bdwrite(bp);
717 	else if ((error = bwrite(bp)) != 0)
718 		goto rollback;
719 
720 	/*
721 	 * If they want us to return with the denode gotten.
722 	 */
723 	if (depp) {
724 		u_long diroffset = clusoffset;
725 		if (dep->de_Attributes & ATTR_DIRECTORY) {
726 			dirclust = dep->de_StartCluster;
727 			if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
728 				dirclust = MSDOSFSROOT;
729 			if (dirclust == MSDOSFSROOT)
730 				diroffset = MSDOSFSROOT_OFS;
731 			else
732 				diroffset = 0;
733 		}
734 		return deget(pmp, dirclust, diroffset, depp);
735 	}
736 
737 	return 0;
738 
739     rollback:
740 	/*
741 	 * Mark all slots modified so far as deleted. Note that we
742 	 * can't just call removede(), since directory is not in
743 	 * consistent state.
744 	 */
745 	fndoffset = ddep->de_fndoffset;
746 	rberror = pcbmap(ddep, de_cluster(pmp, fndoffset),
747 	       &bn, NULL, &blsize);
748 	if (rberror)
749 		goto err_norollback;
750 	if ((rberror = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
751 		brelse(bp);
752 		goto err_norollback;
753 	}
754 	ndep = bptoep(pmp, bp, clusoffset);
755 
756 	havecnt = ddep->de_fndcnt + 1;
757 	for(i=wcnt; i <= havecnt; i++) {
758 		/* mark entry as deleted */
759 		ndep->deName[0] = SLOT_DELETED;
760 
761 		if ((fndoffset & pmp->pm_crbomask) == 0) {
762 			/* we should never get here if ddep is root
763 			 * directory */
764 
765 			if (async)
766 				bdwrite(bp);
767 			else if ((rberror = bwrite(bp)) != 0)
768 				goto err_norollback;
769 
770 			fndoffset -= sizeof(struct direntry);
771 			rberror = pcbmap(ddep,
772 				       de_cluster(pmp, fndoffset),
773 				       &bn, 0, &blsize);
774 			if (rberror)
775 				goto err_norollback;
776 
777 			rberror = bread(pmp->pm_devvp, bn, blsize,
778 				      NOCRED, &bp);
779 			if (rberror) {
780 				brelse(bp);
781 				goto err_norollback;
782 			}
783 			ndep = bptoep(pmp, bp, fndoffset);
784 		} else {
785 			ndep--;
786 			fndoffset -= sizeof(struct direntry);
787 		}
788 	}
789 
790 	/* ignore any further error */
791 	if (async)
792 		(void) bdwrite(bp);
793 	else
794 		(void) bwrite(bp);
795 
796     err_norollback:
797 	return error;
798 }
799 
800 /*
801  * Be sure a directory is empty except for "." and "..". Return 1 if empty,
802  * return 0 if not empty or error.
803  */
804 int
805 dosdirempty(dep)
806 	struct denode *dep;
807 {
808 	int blsize;
809 	int error;
810 	u_long cn;
811 	daddr_t bn;
812 	struct buf *bp;
813 	struct msdosfsmount *pmp = dep->de_pmp;
814 	struct direntry *dentp;
815 
816 	/*
817 	 * Since the filesize field in directory entries for a directory is
818 	 * zero, we just have to feel our way through the directory until
819 	 * we hit end of file.
820 	 */
821 	for (cn = 0;; cn++) {
822 		if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
823 			if (error == E2BIG)
824 				return (1);	/* it's empty */
825 			return (0);
826 		}
827 		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
828 		if (error) {
829 			brelse(bp);
830 			return (0);
831 		}
832 		for (dentp = (struct direntry *)bp->b_data;
833 		     (char *)dentp < bp->b_data + blsize;
834 		     dentp++) {
835 			if (dentp->deName[0] != SLOT_DELETED &&
836 			    (dentp->deAttributes & ATTR_VOLUME) == 0) {
837 				/*
838 				 * In dos directories an entry whose name
839 				 * starts with SLOT_EMPTY (0) starts the
840 				 * beginning of the unused part of the
841 				 * directory, so we can just return that it
842 				 * is empty.
843 				 */
844 				if (dentp->deName[0] == SLOT_EMPTY) {
845 					brelse(bp);
846 					return (1);
847 				}
848 				/*
849 				 * Any names other than "." and ".." in a
850 				 * directory mean it is not empty.
851 				 */
852 				if (memcmp(dentp->deName, ".          ", 11) &&
853 				    memcmp(dentp->deName, "..         ", 11)) {
854 					brelse(bp);
855 #ifdef MSDOSFS_DEBUG
856 					printf("dosdirempty(): found %.11s, %d, %d\n",
857 					    dentp->deName, dentp->deName[0],
858 						dentp->deName[1]);
859 #endif
860 					return (0);	/* not empty */
861 				}
862 			}
863 		}
864 		brelse(bp);
865 	}
866 	/* NOTREACHED */
867 }
868 
869 /*
870  * Check to see if the directory described by target is in some
871  * subdirectory of source.  This prevents something like the following from
872  * succeeding and leaving a bunch or files and directories orphaned. mv
873  * /a/b/c /a/b/c/d/e/f Where c and f are directories.
874  *
875  * source - the inode for /a/b/c
876  * target - the inode for /a/b/c/d/e/f
877  *
878  * Returns 0 if target is NOT a subdirectory of source.
879  * Otherwise returns a non-zero error number.
880  * The target inode is always unlocked on return.
881  */
882 int
883 doscheckpath(source, target)
884 	struct denode *source;
885 	struct denode *target;
886 {
887 	u_long scn;
888 	struct msdosfsmount *pmp;
889 	struct direntry *ep;
890 	struct denode *dep;
891 	struct buf *bp = NULL;
892 	int error = 0;
893 
894 	dep = target;
895 	if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
896 	    (source->de_Attributes & ATTR_DIRECTORY) == 0) {
897 		error = ENOTDIR;
898 		goto out;
899 	}
900 	if (dep->de_StartCluster == source->de_StartCluster) {
901 		error = EEXIST;
902 		goto out;
903 	}
904 	if (dep->de_StartCluster == MSDOSFSROOT)
905 		goto out;
906 	pmp = dep->de_pmp;
907 #ifdef	DIAGNOSTIC
908 	if (pmp != source->de_pmp)
909 		panic("doscheckpath: source and target on different filesystems");
910 #endif
911 	if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
912 		goto out;
913 
914 	for (;;) {
915 		if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
916 			error = ENOTDIR;
917 			break;
918 		}
919 		scn = dep->de_StartCluster;
920 		error = bread(pmp->pm_devvp, cntobn(pmp, scn),
921 			      pmp->pm_bpcluster, NOCRED, &bp);
922 		if (error)
923 			break;
924 
925 		ep = (struct direntry *) bp->b_data + 1;
926 		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
927 		    memcmp(ep->deName, "..         ", 11) != 0) {
928 			error = ENOTDIR;
929 			break;
930 		}
931 		scn = getushort(ep->deStartCluster);
932 		if (FAT32(pmp))
933 			scn |= getushort(ep->deHighClust) << 16;
934 
935 		if (scn == source->de_StartCluster) {
936 			error = EINVAL;
937 			break;
938 		}
939 		if (scn == MSDOSFSROOT)
940 			break;
941 		if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
942 			/*
943 			 * scn should be 0 in this case,
944 			 * but we silently ignore the error.
945 			 */
946 			break;
947 		}
948 
949 		vput(DETOV(dep));
950 		brelse(bp);
951 		bp = NULL;
952 		/* NOTE: deget() clears dep on error */
953 		if ((error = deget(pmp, scn, 0, &dep)) != 0)
954 			break;
955 	}
956 out:
957 	if (bp)
958 		brelse(bp);
959 	if (error == ENOTDIR)
960 		printf("doscheckpath(): .. not a directory?\n");
961 	if (dep != NULL)
962 		vput(DETOV(dep));
963 	return (error);
964 }
965 
966 /*
967  * Read in the disk block containing the directory entry (dirclu, dirofs)
968  * and return the address of the buf header, and the address of the
969  * directory entry within the block.
970  */
971 int
972 readep(pmp, dirclust, diroffset, bpp, epp)
973 	struct msdosfsmount *pmp;
974 	u_long dirclust, diroffset;
975 	struct buf **bpp;
976 	struct direntry **epp;
977 {
978 	int error;
979 	daddr_t bn;
980 	int blsize;
981 
982 	blsize = pmp->pm_bpcluster;
983 	if (dirclust == MSDOSFSROOT
984 	    && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
985 		blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
986 	bn = detobn(pmp, dirclust, diroffset);
987 	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
988 		brelse(*bpp);
989 		*bpp = NULL;
990 		return (error);
991 	}
992 	if (epp)
993 		*epp = bptoep(pmp, *bpp, diroffset);
994 	return (0);
995 }
996 
997 /*
998  * Read in the disk block containing the directory entry dep came from and
999  * return the address of the buf header, and the address of the directory
1000  * entry within the block.
1001  */
1002 int
1003 readde(dep, bpp, epp)
1004 	struct denode *dep;
1005 	struct buf **bpp;
1006 	struct direntry **epp;
1007 {
1008 	return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
1009 			bpp, epp));
1010 }
1011 
1012 /*
1013  * Remove a directory entry. At this point the file represented by the
1014  * directory entry to be removed is still full length until noone has it
1015  * open.  When the file no longer being used msdosfs_inactive() is called
1016  * and will truncate the file to 0 length.  When the vnode containing the
1017  * denode is needed for some other purpose by VFS it will call
1018  * msdosfs_reclaim() which will remove the denode from the denode cache.
1019  */
1020 int
1021 removede(pdep, dep)
1022 	struct denode *pdep;	/* directory where the entry is removed */
1023 	struct denode *dep;	/* file to be removed */
1024 {
1025 	int error;
1026 	struct direntry *ep;
1027 	struct buf *bp;
1028 	daddr_t bn;
1029 	int blsize;
1030 	struct msdosfsmount *pmp = pdep->de_pmp;
1031 	u_long offset = pdep->de_fndoffset;
1032 	int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC;
1033 
1034 #ifdef MSDOSFS_DEBUG
1035 	printf("removede(): filename %s, dep %p, offset %08lx\n",
1036 	    dep->de_Name, dep, offset);
1037 #endif
1038 
1039 	dep->de_refcnt--;
1040 	offset += sizeof(struct direntry);
1041 	do {
1042 		offset -= sizeof(struct direntry);
1043 		error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
1044 		if (error)
1045 			return error;
1046 		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1047 		if (error) {
1048 			brelse(bp);
1049 			return error;
1050 		}
1051 		ep = bptoep(pmp, bp, offset);
1052 		/*
1053 		 * Check whether, if we came here the second time, i.e.
1054 		 * when underflowing into the previous block, the last
1055 		 * entry in this block is a longfilename entry, too.
1056 		 */
1057 		if (ep->deAttributes != ATTR_WIN95
1058 		    && offset != pdep->de_fndoffset) {
1059 			brelse(bp);
1060 			break;
1061 		}
1062 		offset += sizeof(struct direntry);
1063 		while (1) {
1064 			/*
1065 			 * We are a bit agressive here in that we delete any Win95
1066 			 * entries preceding this entry, not just the ones we "own".
1067 			 * Since these presumably aren't valid anyway,
1068 			 * there should be no harm.
1069 			 */
1070 			offset -= sizeof(struct direntry);
1071 			ep--->deName[0] = SLOT_DELETED;
1072 			if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
1073 			    || !(offset & pmp->pm_crbomask)
1074 			    || ep->deAttributes != ATTR_WIN95)
1075 				break;
1076 		}
1077 		if (async)
1078 			bdwrite(bp);
1079 		else if ((error = bwrite(bp)) != 0)
1080 			return error;
1081 	} while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
1082 	    && !(offset & pmp->pm_crbomask)
1083 	    && offset);
1084 	return 0;
1085 }
1086 
1087 /*
1088  * Create a unique DOS name in dvp
1089  */
1090 int
1091 uniqdosname(dep, cnp, cp)
1092 	struct denode *dep;
1093 	struct componentname *cnp;
1094 	u_char *cp;
1095 {
1096 	struct msdosfsmount *pmp = dep->de_pmp;
1097 	struct direntry *dentp;
1098 	int gen;
1099 	int blsize;
1100 	u_long cn;
1101 	daddr_t bn;
1102 	struct buf *bp;
1103 	int error;
1104 
1105 	for (gen = 1;; gen++) {
1106 		/*
1107 		 * Generate DOS name with generation number
1108 		 */
1109 		if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
1110 		    cnp->cn_namelen, gen))
1111 			return gen == 1 ? EINVAL : EEXIST;
1112 
1113 		/*
1114 		 * Now look for a dir entry with this exact name
1115 		 */
1116 		for (cn = error = 0; !error; cn++) {
1117 			if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
1118 				if (error == E2BIG)	/* EOF reached and not found */
1119 					return 0;
1120 				return error;
1121 			}
1122 			error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1123 			if (error) {
1124 				brelse(bp);
1125 				return error;
1126 			}
1127 			for (dentp = (struct direntry *)bp->b_data;
1128 			     (char *)dentp < bp->b_data + blsize;
1129 			     dentp++) {
1130 				if (dentp->deName[0] == SLOT_EMPTY) {
1131 					/*
1132 					 * Last used entry and not found
1133 					 */
1134 					brelse(bp);
1135 					return 0;
1136 				}
1137 				/*
1138 				 * Ignore volume labels and Win95 entries
1139 				 */
1140 				if (dentp->deAttributes & ATTR_VOLUME)
1141 					continue;
1142 				if (!memcmp(dentp->deName, cp, 11)) {
1143 					error = EEXIST;
1144 					break;
1145 				}
1146 			}
1147 			brelse(bp);
1148 		}
1149 	}
1150 }
1151 
1152 /*
1153  * Find any Win'95 long filename entry in directory dep
1154  */
1155 int
1156 findwin95(dep)
1157 	struct denode *dep;
1158 {
1159 	struct msdosfsmount *pmp = dep->de_pmp;
1160 	struct direntry *dentp;
1161 	int blsize;
1162 	u_long cn;
1163 	daddr_t bn;
1164 	struct buf *bp;
1165 
1166 	/*
1167 	 * Read through the directory looking for Win'95 entries
1168 	 * XXX Note: Error currently handled just as EOF
1169 	 */
1170 	for (cn = 0;; cn++) {
1171 		if (pcbmap(dep, cn, &bn, 0, &blsize))
1172 			return 0;
1173 		if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
1174 			brelse(bp);
1175 			return 0;
1176 		}
1177 		for (dentp = (struct direntry *)bp->b_data;
1178 		     (char *)dentp < bp->b_data + blsize;
1179 		     dentp++) {
1180 			if (dentp->deName[0] == SLOT_EMPTY) {
1181 				/*
1182 				 * Last used entry and not found
1183 				 */
1184 				brelse(bp);
1185 				return 0;
1186 			}
1187 			if (dentp->deName[0] == SLOT_DELETED) {
1188 				/*
1189 				 * Ignore deleted files
1190 				 * Note: might be an indication of Win'95
1191 				 * anyway	XXX
1192 				 */
1193 				continue;
1194 			}
1195 			if (dentp->deAttributes == ATTR_WIN95) {
1196 				brelse(bp);
1197 				return 1;
1198 			}
1199 		}
1200 		brelse(bp);
1201 	}
1202 }
1203