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