150477Speter/* $FreeBSD$ */
233548Sjkh/*	$NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $	*/
32893Sdfr
42893Sdfr/*-
533548Sjkh * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
633548Sjkh * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
72893Sdfr * All rights reserved.
82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
92893Sdfr *
102893Sdfr * Redistribution and use in source and binary forms, with or without
112893Sdfr * modification, are permitted provided that the following conditions
122893Sdfr * are met:
132893Sdfr * 1. Redistributions of source code must retain the above copyright
142893Sdfr *    notice, this list of conditions and the following disclaimer.
152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright
162893Sdfr *    notice, this list of conditions and the following disclaimer in the
172893Sdfr *    documentation and/or other materials provided with the distribution.
182893Sdfr * 3. All advertising materials mentioning features or use of this software
192893Sdfr *    must display the following acknowledgement:
202893Sdfr *	This product includes software developed by TooLs GmbH.
212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products
222893Sdfr *    derived from this software without specific prior written permission.
232893Sdfr *
242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
342893Sdfr */
35139776Simp/*-
362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com)
378876Srgrimes *
382893Sdfr * You can do anything you want with this software, just don't say you wrote
392893Sdfr * it, and don't remove this notice.
408876Srgrimes *
412893Sdfr * This software is provided "as is".
428876Srgrimes *
432893Sdfr * The author supplies this software to be publicly redistributed on the
442893Sdfr * understanding that the author is not responsible for the correct
452893Sdfr * functioning of this software in any circumstances and is not liable for
462893Sdfr * any damages caused by this software.
478876Srgrimes *
482893Sdfr * October 1992
492893Sdfr */
502893Sdfr
512893Sdfr#include <sys/param.h>
5248425Speter#include <sys/systm.h>
53171750Sbde#include <sys/buf.h>
54171750Sbde#include <sys/mount.h>
552893Sdfr#include <sys/namei.h>
562893Sdfr#include <sys/vnode.h>
572893Sdfr
5877162Sru#include <fs/msdosfs/bpb.h>
5977162Sru#include <fs/msdosfs/direntry.h>
6077162Sru#include <fs/msdosfs/denode.h>
6177162Sru#include <fs/msdosfs/fat.h>
62171750Sbde#include <fs/msdosfs/msdosfsmount.h>
632893Sdfr
64204474Skibstatic int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
65204474Skib    struct componentname *cnp, u_int64_t *inum);
66204474Skibstatic int msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
67204474Skib    struct vnode **rvp);
68204474Skib
69204474Skibint
70204474Skibmsdosfs_lookup(struct vop_cachedlookup_args *ap)
71204474Skib{
72204474Skib
73204474Skib	return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
74204474Skib}
75204474Skib
762893Sdfr/*
772893Sdfr * When we search a directory the blocks containing directory entries are
782893Sdfr * read and examined.  The directory entries contain information that would
792893Sdfr * normally be in the inode of a unix filesystem.  This means that some of
802893Sdfr * a directory's contents may also be in memory resident denodes (sort of
812893Sdfr * an inode).  This can cause problems if we are searching while some other
822893Sdfr * process is modifying a directory.  To prevent one process from accessing
832893Sdfr * incompletely modified directory information we depend upon being the
8429286Sphk * sole owner of a directory block.  bread/brelse provide this service.
852893Sdfr * This being the case, when a process modifies a directory it must first
862893Sdfr * acquire the disk block that contains the directory entry to be modified.
872893Sdfr * Then update the disk block and the denode, and then write the disk block
882893Sdfr * out to disk.  This way disk blocks containing directory entries and in
892893Sdfr * memory denode's will be in synch.
902893Sdfr */
91204474Skibstatic int
92204474Skibmsdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
93204474Skib    struct componentname *cnp, u_int64_t *dd_inum)
942893Sdfr{
95172027Sbde	struct mbnambuf nb;
962893Sdfr	daddr_t bn;
972893Sdfr	int error;
9833548Sjkh	int slotcount;
9933548Sjkh	int slotoffset = 0;
1002893Sdfr	int frcn;
1012893Sdfr	u_long cluster;
10233548Sjkh	int blkoff;
1032893Sdfr	int diroff;
10433548Sjkh	int blsize;
1052893Sdfr	int isadir;		/* ~0 if found direntry is a directory	 */
1062893Sdfr	u_long scn;		/* starting cluster number		 */
1072893Sdfr	struct vnode *pdp;
1082893Sdfr	struct denode *dp;
1092893Sdfr	struct denode *tdp;
1102893Sdfr	struct msdosfsmount *pmp;
111238697Skevlo	struct buf *bp = NULL;
1122893Sdfr	struct direntry *dep = NULL;
1132893Sdfr	u_char dosfilename[12];
1142893Sdfr	int flags = cnp->cn_flags;
1152893Sdfr	int nameiop = cnp->cn_nameiop;
11633848Smsmith	int unlen;
117204474Skib	u_int64_t inode1;
1182893Sdfr
11933548Sjkh	int wincnt = 1;
120134942Stjr	int chksum = -1, chksum_ok;
12133548Sjkh	int olddos = 1;
12233548Sjkh
1232893Sdfr#ifdef MSDOSFS_DEBUG
1242893Sdfr	printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
1252893Sdfr#endif
1262893Sdfr	dp = VTODE(vdp);
1272893Sdfr	pmp = dp->de_pmp;
1282893Sdfr#ifdef MSDOSFS_DEBUG
12933548Sjkh	printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
13033548Sjkh	    vdp, dp, dp->de_Attributes);
1312893Sdfr#endif
1322893Sdfr
133204474Skib restart:
134204675Skib	if (vpp != NULL)
135204675Skib		*vpp = NULL;
1362893Sdfr	/*
1372893Sdfr	 * If they are going after the . or .. entry in the root directory,
1382893Sdfr	 * they won't find it.  DOS filesystems don't have them in the root
1392893Sdfr	 * directory.  So, we fake it. deget() is in on this scam too.
1402893Sdfr	 */
141101308Sjeff	if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' &&
1422893Sdfr	    (cnp->cn_namelen == 1 ||
1432893Sdfr		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
1442893Sdfr		isadir = ATTR_DIRECTORY;
1452893Sdfr		scn = MSDOSFSROOT;
1462893Sdfr#ifdef MSDOSFS_DEBUG
1472893Sdfr		printf("msdosfs_lookup(): looking for . or .. in root directory\n");
1482893Sdfr#endif
1492893Sdfr		cluster = MSDOSFSROOT;
15033548Sjkh		blkoff = MSDOSFSROOT_OFS;
1512893Sdfr		goto foundroot;
1522893Sdfr	}
1532893Sdfr
15433548Sjkh	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
155120492Sfjoe	    cnp->cn_namelen, 0, pmp)) {
15633548Sjkh	case 0:
15733548Sjkh		return (EINVAL);
15833548Sjkh	case 1:
15933548Sjkh		break;
16033548Sjkh	case 2:
16133548Sjkh		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
162120492Sfjoe		    cnp->cn_namelen, pmp) + 1;
16333548Sjkh		break;
16433548Sjkh	case 3:
16533548Sjkh		olddos = 0;
16633548Sjkh		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
167120492Sfjoe		    cnp->cn_namelen, pmp) + 1;
16833548Sjkh		break;
16933548Sjkh	}
17036133Sdt	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
17133548Sjkh		wincnt = 1;
17236133Sdt		olddos = 1;
17336133Sdt	}
17433848Smsmith	unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen);
17533548Sjkh
1762893Sdfr	/*
17733548Sjkh	 * Suppress search for slots unless creating
17833548Sjkh	 * file and at end of pathname, in which case
17933548Sjkh	 * we watch for a place to put the new file in
18033548Sjkh	 * case it doesn't already exist.
1812893Sdfr	 */
18233548Sjkh	slotcount = wincnt;
18333548Sjkh	if ((nameiop == CREATE || nameiop == RENAME) &&
18433548Sjkh	    (flags & ISLASTCN))
18533548Sjkh		slotcount = 0;
1862893Sdfr
1872893Sdfr#ifdef MSDOSFS_DEBUG
18833548Sjkh	printf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
18933548Sjkh	    dosfilename, cnp->cn_namelen);
1902893Sdfr#endif
1912893Sdfr	/*
1922893Sdfr	 * Search the directory pointed at by vdp for the name pointed at
1932893Sdfr	 * by cnp->cn_nameptr.
1942893Sdfr	 */
1952893Sdfr	tdp = NULL;
196172027Sbde	mbnambuf_init(&nb);
1972893Sdfr	/*
1982893Sdfr	 * The outer loop ranges over the clusters that make up the
1992893Sdfr	 * directory.  Note that the root directory is different from all
2002893Sdfr	 * other directories.  It has a fixed number of blocks that are not
2012893Sdfr	 * part of the pool of allocatable clusters.  So, we treat it a
2022893Sdfr	 * little differently. The root directory starts at "cluster" 0.
2032893Sdfr	 */
20433548Sjkh	diroff = 0;
2052893Sdfr	for (frcn = 0;; frcn++) {
20633548Sjkh		error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
2073152Sphk		if (error) {
2082893Sdfr			if (error == E2BIG)
2092893Sdfr				break;
21033548Sjkh			return (error);
2112893Sdfr		}
21233548Sjkh		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
21333548Sjkh		if (error) {
21433548Sjkh			brelse(bp);
21533548Sjkh			return (error);
21633548Sjkh		}
21733548Sjkh		for (blkoff = 0; blkoff < blsize;
21833548Sjkh		     blkoff += sizeof(struct direntry),
21933548Sjkh		     diroff += sizeof(struct direntry)) {
22033548Sjkh			dep = (struct direntry *)(bp->b_data + blkoff);
2212893Sdfr			/*
2222893Sdfr			 * If the slot is empty and we are still looking
2232893Sdfr			 * for an empty then remember this one.  If the
2242893Sdfr			 * slot is not empty then check to see if it
2252893Sdfr			 * matches what we are looking for.  If the slot
2262893Sdfr			 * has never been filled with anything, then the
2272893Sdfr			 * remainder of the directory has never been used,
2282893Sdfr			 * so there is no point in searching it.
2292893Sdfr			 */
2302893Sdfr			if (dep->deName[0] == SLOT_EMPTY ||
2312893Sdfr			    dep->deName[0] == SLOT_DELETED) {
23233548Sjkh				/*
23333548Sjkh				 * Drop memory of previous long matches
23433548Sjkh				 */
23533548Sjkh				chksum = -1;
236172027Sbde				mbnambuf_init(&nb);
23733548Sjkh
23833548Sjkh				if (slotcount < wincnt) {
23933548Sjkh					slotcount++;
24033548Sjkh					slotoffset = diroff;
2412893Sdfr				}
2422893Sdfr				if (dep->deName[0] == SLOT_EMPTY) {
2432893Sdfr					brelse(bp);
2442893Sdfr					goto notfound;
2452893Sdfr				}
2462893Sdfr			} else {
2472893Sdfr				/*
24833548Sjkh				 * If there wasn't enough space for our winentries,
24933548Sjkh				 * forget about the empty space
25033548Sjkh				 */
25133548Sjkh				if (slotcount < wincnt)
25233548Sjkh					slotcount = 0;
25333548Sjkh
25433548Sjkh				/*
25533548Sjkh				 * Check for Win95 long filename entry
25633548Sjkh				 */
25733548Sjkh				if (dep->deAttributes == ATTR_WIN95) {
25833548Sjkh					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
25933548Sjkh						continue;
26033548Sjkh
261172027Sbde					chksum = win2unixfn(&nb,
262172027Sbde					    (struct winentry *)dep, chksum,
263172027Sbde					    pmp);
26433548Sjkh					continue;
26533548Sjkh				}
26633548Sjkh
267172027Sbde				chksum = winChkName(&nb,
268172027Sbde				    (const u_char *)cnp->cn_nameptr, unlen,
269172027Sbde				    chksum, pmp);
270120492Sfjoe				if (chksum == -2) {
271120492Sfjoe					chksum = -1;
272120492Sfjoe					continue;
273120492Sfjoe				}
274120492Sfjoe
27533548Sjkh				/*
2762893Sdfr				 * Ignore volume labels (anywhere, not just
2772893Sdfr				 * the root directory).
2782893Sdfr				 */
27933548Sjkh				if (dep->deAttributes & ATTR_VOLUME) {
28033548Sjkh					chksum = -1;
28133548Sjkh					continue;
28233548Sjkh				}
28333548Sjkh
28433548Sjkh				/*
28533548Sjkh				 * Check for a checksum or name match
28633548Sjkh				 */
287203827Skib				chksum_ok = (chksum == winChksum(dep->deName));
288134942Stjr				if (!chksum_ok
28933548Sjkh				    && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
29033548Sjkh					chksum = -1;
29133548Sjkh					continue;
29233548Sjkh				}
2932893Sdfr#ifdef MSDOSFS_DEBUG
29433548Sjkh				printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
29533548Sjkh				    blkoff, diroff);
2962893Sdfr#endif
29733548Sjkh				/*
29833548Sjkh				 * Remember where this directory
29933548Sjkh				 * entry came from for whoever did
30033548Sjkh				 * this lookup.
30133548Sjkh				 */
30233548Sjkh				dp->de_fndoffset = diroff;
303134942Stjr				if (chksum_ok && nameiop == RENAME) {
304134942Stjr					/*
305134942Stjr					 * Target had correct long name
306134942Stjr					 * directory entries, reuse them
307134942Stjr					 * as needed.
308134942Stjr					 */
309134942Stjr					dp->de_fndcnt = wincnt - 1;
310134942Stjr				} else {
311134942Stjr					/*
312134942Stjr					 * Long name directory entries
313134942Stjr					 * not present or corrupt, can only
314134942Stjr					 * reuse dos directory entry.
315134942Stjr					 */
316134942Stjr					dp->de_fndcnt = 0;
317134942Stjr				}
31833548Sjkh
31933548Sjkh				goto found;
3202893Sdfr			}
32133548Sjkh		}	/* for (blkoff = 0; .... */
3222893Sdfr		/*
3232893Sdfr		 * Release the buffer holding the directory cluster just
3242893Sdfr		 * searched.
3252893Sdfr		 */
3262893Sdfr		brelse(bp);
32733548Sjkh	}	/* for (frcn = 0; ; frcn++) */
32833548Sjkh
32933548Sjkhnotfound:
3302893Sdfr	/*
3312893Sdfr	 * We hold no disk buffers at this point.
3322893Sdfr	 */
3332893Sdfr
3342893Sdfr	/*
33533548Sjkh	 * Fixup the slot description to point to the place where
33633548Sjkh	 * we might put the new DOS direntry (putting the Win95
33733548Sjkh	 * long name entries before that)
33833548Sjkh	 */
33933548Sjkh	if (!slotcount) {
34033548Sjkh		slotcount = 1;
34133548Sjkh		slotoffset = diroff;
34233548Sjkh	}
34333548Sjkh	if (wincnt > slotcount)
34433548Sjkh		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
34533548Sjkh
34633548Sjkh	/*
3472893Sdfr	 * If we get here we didn't find the entry we were looking for. But
3482893Sdfr	 * that's ok if we are creating or renaming and are at the end of
3492893Sdfr	 * the pathname and the directory hasn't been removed.
3502893Sdfr	 */
3512893Sdfr#ifdef MSDOSFS_DEBUG
35233548Sjkh	printf("msdosfs_lookup(): op %d, refcnt %ld\n",
35333548Sjkh	    nameiop, dp->de_refcnt);
35433548Sjkh	printf("               slotcount %d, slotoffset %d\n",
35533548Sjkh	       slotcount, slotoffset);
3562893Sdfr#endif
3572893Sdfr	if ((nameiop == CREATE || nameiop == RENAME) &&
3582893Sdfr	    (flags & ISLASTCN) && dp->de_refcnt != 0) {
35933548Sjkh		/*
36033548Sjkh		 * Access for write is interpreted as allowing
36133548Sjkh		 * creation of files in the directory.
36233548Sjkh		 */
36383366Sjulian		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
3648386Sbde		if (error)
36533548Sjkh			return (error);
36633548Sjkh		/*
36733548Sjkh		 * Return an indication of where the new directory
36833548Sjkh		 * entry should be put.
36933548Sjkh		 */
37033548Sjkh		dp->de_fndoffset = slotoffset;
37133548Sjkh		dp->de_fndcnt = wincnt - 1;
37233548Sjkh
37333548Sjkh		/*
37433548Sjkh		 * We return with the directory locked, so that
37533548Sjkh		 * the parameters we set up above will still be
37633548Sjkh		 * valid if we actually decide to do a direnter().
37733548Sjkh		 * We return ni_vp == NULL to indicate that the entry
37833548Sjkh		 * does not currently exist; we leave a pointer to
37933548Sjkh		 * the (locked) directory inode in ndp->ni_dvp.
38033548Sjkh		 * The pathname buffer is saved so that the name
38133548Sjkh		 * can be obtained later.
38233548Sjkh		 *
38333548Sjkh		 * NB - if the directory is unlocked, then this
38433548Sjkh		 * information cannot be used.
38533548Sjkh		 */
3862893Sdfr		cnp->cn_flags |= SAVENAME;
38733548Sjkh		return (EJUSTRETURN);
3882893Sdfr	}
389145174Sdas#if 0
3902893Sdfr	/*
39133548Sjkh	 * Insert name into cache (as non-existent) if appropriate.
392145174Sdas	 *
393145174Sdas	 * XXX Negative caching is broken for msdosfs because the name
394145174Sdas	 * cache doesn't understand peculiarities such as case insensitivity
395145174Sdas	 * and 8.3 filenames.  Hence, it may not invalidate all negative
396145174Sdas	 * entries if a file with this name is later created.
3972893Sdfr	 */
3982893Sdfr	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
3992893Sdfr		cache_enter(vdp, *vpp, cnp);
400145174Sdas#endif
40133548Sjkh	return (ENOENT);
4022893Sdfr
40333548Sjkhfound:
4042893Sdfr	/*
4052893Sdfr	 * NOTE:  We still have the buffer with matched directory entry at
4062893Sdfr	 * this point.
4072893Sdfr	 */
4082893Sdfr	isadir = dep->deAttributes & ATTR_DIRECTORY;
4092893Sdfr	scn = getushort(dep->deStartCluster);
41033548Sjkh	if (FAT32(pmp)) {
41133548Sjkh		scn |= getushort(dep->deHighClust) << 16;
41233548Sjkh		if (scn == pmp->pm_rootdirblk) {
41333548Sjkh			/*
41433548Sjkh			 * There should actually be 0 here.
41533548Sjkh			 * Just ignore the error.
41633548Sjkh			 */
41733548Sjkh			scn = MSDOSFSROOT;
41833548Sjkh		}
41933548Sjkh	}
4202893Sdfr
42133548Sjkh	if (isadir) {
42233548Sjkh		cluster = scn;
42333548Sjkh		if (cluster == MSDOSFSROOT)
42433548Sjkh			blkoff = MSDOSFSROOT_OFS;
42533548Sjkh		else
42633548Sjkh			blkoff = 0;
42733548Sjkh	} else if (cluster == MSDOSFSROOT)
42833548Sjkh		blkoff = diroff;
42933548Sjkh
4302893Sdfr	/*
43133548Sjkh	 * Now release buf to allow deget to read the entry again.
43233548Sjkh	 * Reserving it here and giving it to deget could result
43333548Sjkh	 * in a deadlock.
43433548Sjkh	 */
43533548Sjkh	brelse(bp);
43633548Sjkh	bp = 0;
43733548Sjkh
43833548Sjkhfoundroot:
43933548Sjkh	/*
4402893Sdfr	 * If we entered at foundroot, then we are looking for the . or ..
4412893Sdfr	 * entry of the filesystems root directory.  isadir and scn were
44233548Sjkh	 * setup before jumping here.  And, bp is already null.
4432893Sdfr	 */
44433548Sjkh	if (FAT32(pmp) && scn == MSDOSFSROOT)
44533548Sjkh		scn = pmp->pm_rootdirblk;
4462893Sdfr
447204474Skib	if (dd_inum != NULL) {
448204474Skib		*dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
449204474Skib		return (0);
450204474Skib	}
451204474Skib
4522893Sdfr	/*
45333548Sjkh	 * If deleting, and at end of pathname, return
45433548Sjkh	 * parameters which can be used to remove file.
4552893Sdfr	 */
4562893Sdfr	if (nameiop == DELETE && (flags & ISLASTCN)) {
45733548Sjkh		/*
45833548Sjkh		 * Don't allow deleting the root.
45933548Sjkh		 */
46033548Sjkh		if (blkoff == MSDOSFSROOT_OFS)
461220014Skib			return (EBUSY);
46233548Sjkh
46333548Sjkh		/*
46433548Sjkh		 * Write access to directory required to delete files.
46533548Sjkh		 */
46683366Sjulian		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
46733548Sjkh		if (error)
46833548Sjkh			return (error);
46933548Sjkh
47033548Sjkh		/*
47133548Sjkh		 * Return pointer to current entry in dp->i_offset.
47233548Sjkh		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
47333548Sjkh		 */
4742893Sdfr		if (dp->de_StartCluster == scn && isadir) {	/* "." */
4752893Sdfr			VREF(vdp);
4762893Sdfr			*vpp = vdp;
47733548Sjkh			return (0);
4782893Sdfr		}
47933548Sjkh		error = deget(pmp, cluster, blkoff, &tdp);
48033548Sjkh		if (error)
48133548Sjkh			return (error);
4822893Sdfr		*vpp = DETOV(tdp);
48333548Sjkh		return (0);
4842893Sdfr	}
4852893Sdfr
4862893Sdfr	/*
48733548Sjkh	 * If rewriting (RENAME), return the inode and the
48833548Sjkh	 * information required to rewrite the present directory
48933548Sjkh	 * Must get inode of directory entry to verify it's a
49033548Sjkh	 * regular file, or empty directory.
4912893Sdfr	 */
492144298Sjeff	if (nameiop == RENAME && (flags & ISLASTCN)) {
49333548Sjkh		if (blkoff == MSDOSFSROOT_OFS)
494220014Skib			return (EBUSY);
49533548Sjkh
49683366Sjulian		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
49733548Sjkh		if (error)
49833548Sjkh			return (error);
49933548Sjkh
50033548Sjkh		/*
50133548Sjkh		 * Careful about locking second inode.
50233548Sjkh		 * This can only occur if the target is ".".
50333548Sjkh		 */
50433548Sjkh		if (dp->de_StartCluster == scn && isadir)
50533548Sjkh			return (EISDIR);
50633548Sjkh
50733548Sjkh		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
50833548Sjkh			return (error);
5092893Sdfr		*vpp = DETOV(tdp);
5102893Sdfr		cnp->cn_flags |= SAVENAME;
51133548Sjkh		return (0);
5122893Sdfr	}
5132893Sdfr
5142893Sdfr	/*
51533548Sjkh	 * Step through the translation in the name.  We do not `vput' the
51633548Sjkh	 * directory because we may need it again if a symbolic link
51733548Sjkh	 * is relative to the current directory.  Instead we save it
51833548Sjkh	 * unlocked as "pdp".  We must get the target inode before unlocking
51933548Sjkh	 * the directory to insure that the inode will not be removed
52033548Sjkh	 * before we get it.  We prevent deadlock by always fetching
52133548Sjkh	 * inodes from the root, moving down the directory tree. Thus
52233548Sjkh	 * when following backward pointers ".." we must unlock the
52333548Sjkh	 * parent directory before getting the requested directory.
5242893Sdfr	 */
5252893Sdfr	pdp = vdp;
5262893Sdfr	if (flags & ISDOTDOT) {
527204474Skib		error = msdosfs_deget_dotdot(pdp, cluster, blkoff, vpp);
528204675Skib		if (error) {
529204675Skib			*vpp = NULL;
53033548Sjkh			return (error);
531204675Skib		}
532204474Skib		/*
533204474Skib		 * Recheck that ".." still points to the inode we
534204474Skib		 * looked up before pdp lock was dropped.
535204474Skib		 */
536204474Skib		error = msdosfs_lookup_(pdp, NULL, cnp, &inode1);
537204474Skib		if (error) {
538204474Skib			vput(*vpp);
539204675Skib			*vpp = NULL;
540204474Skib			return (error);
541204474Skib		}
542204474Skib		if (VTODE(*vpp)->de_inode != inode1) {
543204474Skib			vput(*vpp);
544204474Skib			goto restart;
545204474Skib		}
54633548Sjkh	} else if (dp->de_StartCluster == scn && isadir) {
54733548Sjkh		VREF(vdp);	/* we want ourself, ie "." */
5482893Sdfr		*vpp = vdp;
5492893Sdfr	} else {
55033548Sjkh		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
55133548Sjkh			return (error);
5522893Sdfr		*vpp = DETOV(tdp);
5532893Sdfr	}
5542893Sdfr
5552893Sdfr	/*
55633548Sjkh	 * Insert name into cache if appropriate.
5572893Sdfr	 */
5582893Sdfr	if (cnp->cn_flags & MAKEENTRY)
5592893Sdfr		cache_enter(vdp, *vpp, cnp);
56033548Sjkh	return (0);
5612893Sdfr}
5622893Sdfr
563204474Skibstatic int
564204474Skibmsdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
565204474Skib    struct vnode **rvp)
566204474Skib{
567204474Skib	struct mount *mp;
568204474Skib	struct msdosfsmount *pmp;
569204474Skib	struct denode *rdp;
570204474Skib	int ltype, error;
571204474Skib
572204474Skib	mp = vp->v_mount;
573204474Skib	pmp = VFSTOMSDOSFS(mp);
574204474Skib	ltype = VOP_ISLOCKED(vp);
575204474Skib	KASSERT(ltype == LK_EXCLUSIVE || ltype == LK_SHARED,
576204474Skib	    ("msdosfs_deget_dotdot: vp not locked"));
577204474Skib
578204474Skib	error = vfs_busy(mp, MBF_NOWAIT);
579204474Skib	if (error != 0) {
580204474Skib		vfs_ref(mp);
581204474Skib		VOP_UNLOCK(vp, 0);
582204474Skib		error = vfs_busy(mp, 0);
583204474Skib		vn_lock(vp, ltype | LK_RETRY);
584204474Skib		vfs_rel(mp);
585204474Skib		if (error != 0)
586204474Skib			return (ENOENT);
587204474Skib		if (vp->v_iflag & VI_DOOMED) {
588204474Skib			vfs_unbusy(mp);
589204474Skib			return (ENOENT);
590204474Skib		}
591204474Skib	}
592204474Skib	VOP_UNLOCK(vp, 0);
593204474Skib	error = deget(pmp, cluster, blkoff,  &rdp);
594204474Skib	vfs_unbusy(mp);
595204474Skib	if (error == 0)
596204474Skib		*rvp = DETOV(rdp);
597214001Skevlo	if (*rvp != vp)
598214001Skevlo		vn_lock(vp, ltype | LK_RETRY);
599204474Skib	if (vp->v_iflag & VI_DOOMED) {
600214001Skevlo		if (error == 0) {
601214001Skevlo			if (*rvp == vp)
602214001Skevlo				vunref(*rvp);
603214001Skevlo			else
604214001Skevlo				vput(*rvp);
605214001Skevlo		}
606204474Skib		error = ENOENT;
607204474Skib	}
608204474Skib	return (error);
609204474Skib}
610204474Skib
6112893Sdfr/*
6122893Sdfr * dep  - directory entry to copy into the directory
6132893Sdfr * ddep - directory to add to
6142893Sdfr * depp - return the address of the denode for the created directory entry
6152893Sdfr *	  if depp != 0
61633548Sjkh * cnp  - componentname needed for Win95 long filenames
6172893Sdfr */
6182893Sdfrint
61933548Sjkhcreatede(dep, ddep, depp, cnp)
6202893Sdfr	struct denode *dep;
6212893Sdfr	struct denode *ddep;
6222893Sdfr	struct denode **depp;
62333548Sjkh	struct componentname *cnp;
6242893Sdfr{
6252893Sdfr	int error;
6262893Sdfr	u_long dirclust, diroffset;
6272893Sdfr	struct direntry *ndep;
6282893Sdfr	struct msdosfsmount *pmp = ddep->de_pmp;
6292893Sdfr	struct buf *bp;
63033548Sjkh	daddr_t bn;
63133548Sjkh	int blsize;
6322893Sdfr
6332893Sdfr#ifdef MSDOSFS_DEBUG
63433548Sjkh	printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
63533548Sjkh	    dep, ddep, depp, cnp);
6362893Sdfr#endif
6372893Sdfr
6382893Sdfr	/*
6392893Sdfr	 * If no space left in the directory then allocate another cluster
6402893Sdfr	 * and chain it onto the end of the file.  There is one exception
6412893Sdfr	 * to this.  That is, if the root directory has no more space it
6422893Sdfr	 * can NOT be expanded.  extendfile() checks for and fails attempts
6432893Sdfr	 * to extend the root directory.  We just return an error in that
6442893Sdfr	 * case.
6452893Sdfr	 */
64633548Sjkh	if (ddep->de_fndoffset >= ddep->de_FileSize) {
64733548Sjkh		diroffset = ddep->de_fndoffset + sizeof(struct direntry)
64833548Sjkh		    - ddep->de_FileSize;
64933548Sjkh		dirclust = de_clcount(pmp, diroffset);
65033548Sjkh		error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
65133548Sjkh		if (error) {
652234605Strasz			(void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED);
6532893Sdfr			return error;
65433548Sjkh		}
65533548Sjkh
6562893Sdfr		/*
6572893Sdfr		 * Update the size of the directory
6582893Sdfr		 */
65933548Sjkh		ddep->de_FileSize += de_cn2off(pmp, dirclust);
6602893Sdfr	}
6612893Sdfr
6622893Sdfr	/*
66333548Sjkh	 * We just read in the cluster with space.  Copy the new directory
66433548Sjkh	 * entry in.  Then write it to disk. NOTE:  DOS directories
66533548Sjkh	 * do not get smaller as clusters are emptied.
6662893Sdfr	 */
66733548Sjkh	error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
66833548Sjkh		       &bn, &dirclust, &blsize);
66933548Sjkh	if (error)
6702893Sdfr		return error;
67133548Sjkh	diroffset = ddep->de_fndoffset;
67233548Sjkh	if (dirclust != MSDOSFSROOT)
67333548Sjkh		diroffset &= pmp->pm_crbomask;
67433548Sjkh	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
67533548Sjkh		brelse(bp);
67633548Sjkh		return error;
6772893Sdfr	}
67833548Sjkh	ndep = bptoep(pmp, bp, ddep->de_fndoffset);
6792893Sdfr
68033548Sjkh	DE_EXTERNALIZE(ndep, dep);
6812893Sdfr
68233548Sjkh	/*
68333548Sjkh	 * Now write the Win95 long name
68433548Sjkh	 */
68533548Sjkh	if (ddep->de_fndcnt > 0) {
686203827Skib		u_int8_t chksum = winChksum(ndep->deName);
68733548Sjkh		const u_char *un = (const u_char *)cnp->cn_nameptr;
68833548Sjkh		int unlen = cnp->cn_namelen;
68933548Sjkh		int cnt = 1;
6902893Sdfr
69133548Sjkh		while (--ddep->de_fndcnt >= 0) {
69233548Sjkh			if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
693231998Skib				if (DOINGASYNC(DETOV(ddep)))
694172798Sbde					bdwrite(bp);
695172798Sbde				else if ((error = bwrite(bp)) != 0)
69633548Sjkh					return error;
6972893Sdfr
69833548Sjkh				ddep->de_fndoffset -= sizeof(struct direntry);
69933548Sjkh				error = pcbmap(ddep,
70033548Sjkh					       de_cluster(pmp,
70133548Sjkh							  ddep->de_fndoffset),
70233548Sjkh					       &bn, 0, &blsize);
70333548Sjkh				if (error)
70433548Sjkh					return error;
7052893Sdfr
70633548Sjkh				error = bread(pmp->pm_devvp, bn, blsize,
70733548Sjkh					      NOCRED, &bp);
70833548Sjkh				if (error) {
70933548Sjkh					brelse(bp);
71033548Sjkh					return error;
71133548Sjkh				}
71233548Sjkh				ndep = bptoep(pmp, bp, ddep->de_fndoffset);
71333548Sjkh			} else {
71433548Sjkh				ndep--;
71533548Sjkh				ddep->de_fndoffset -= sizeof(struct direntry);
71633548Sjkh			}
71733747Sache			if (!unix2winfn(un, unlen, (struct winentry *)ndep,
718120492Sfjoe					cnt++, chksum, pmp))
71933548Sjkh				break;
72033548Sjkh		}
72133548Sjkh	}
72233548Sjkh
723231998Skib	if (DOINGASYNC(DETOV(ddep)))
724172798Sbde		bdwrite(bp);
725172798Sbde	else if ((error = bwrite(bp)) != 0)
72633548Sjkh		return error;
72733548Sjkh
7282893Sdfr	/*
72933548Sjkh	 * If they want us to return with the denode gotten.
7302893Sdfr	 */
73133548Sjkh	if (depp) {
73233548Sjkh		if (dep->de_Attributes & ATTR_DIRECTORY) {
73333548Sjkh			dirclust = dep->de_StartCluster;
73433548Sjkh			if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
73533548Sjkh				dirclust = MSDOSFSROOT;
73633548Sjkh			if (dirclust == MSDOSFSROOT)
73733548Sjkh				diroffset = MSDOSFSROOT_OFS;
73833548Sjkh			else
73933548Sjkh				diroffset = 0;
74033548Sjkh		}
74133548Sjkh		return deget(pmp, dirclust, diroffset, depp);
74233548Sjkh	}
7432893Sdfr
74433548Sjkh	return 0;
7452893Sdfr}
7462893Sdfr
7472893Sdfr/*
7482893Sdfr * Be sure a directory is empty except for "." and "..". Return 1 if empty,
7492893Sdfr * return 0 if not empty or error.
7502893Sdfr */
7512893Sdfrint
7522893Sdfrdosdirempty(dep)
7532893Sdfr	struct denode *dep;
7542893Sdfr{
75533548Sjkh	int blsize;
7562893Sdfr	int error;
7572893Sdfr	u_long cn;
7582893Sdfr	daddr_t bn;
7592893Sdfr	struct buf *bp;
7602893Sdfr	struct msdosfsmount *pmp = dep->de_pmp;
7612893Sdfr	struct direntry *dentp;
7622893Sdfr
7632893Sdfr	/*
7642893Sdfr	 * Since the filesize field in directory entries for a directory is
7652893Sdfr	 * zero, we just have to feel our way through the directory until
7662893Sdfr	 * we hit end of file.
7672893Sdfr	 */
7682893Sdfr	for (cn = 0;; cn++) {
76933548Sjkh		if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
77033548Sjkh			if (error == E2BIG)
77133548Sjkh				return (1);	/* it's empty */
77233548Sjkh			return (0);
77333548Sjkh		}
77433548Sjkh		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
77533548Sjkh		if (error) {
77633548Sjkh			brelse(bp);
77733548Sjkh			return (0);
77833548Sjkh		}
77933548Sjkh		for (dentp = (struct direntry *)bp->b_data;
78033548Sjkh		     (char *)dentp < bp->b_data + blsize;
78133548Sjkh		     dentp++) {
78233548Sjkh			if (dentp->deName[0] != SLOT_DELETED &&
78333548Sjkh			    (dentp->deAttributes & ATTR_VOLUME) == 0) {
7842893Sdfr				/*
7852893Sdfr				 * In dos directories an entry whose name
7862893Sdfr				 * starts with SLOT_EMPTY (0) starts the
7872893Sdfr				 * beginning of the unused part of the
7882893Sdfr				 * directory, so we can just return that it
7892893Sdfr				 * is empty.
7902893Sdfr				 */
7912893Sdfr				if (dentp->deName[0] == SLOT_EMPTY) {
7922893Sdfr					brelse(bp);
79333548Sjkh					return (1);
7942893Sdfr				}
7952893Sdfr				/*
7962893Sdfr				 * Any names other than "." and ".." in a
7972893Sdfr				 * directory mean it is not empty.
7982893Sdfr				 */
7992893Sdfr				if (bcmp(dentp->deName, ".          ", 11) &&
8002893Sdfr				    bcmp(dentp->deName, "..         ", 11)) {
8012893Sdfr					brelse(bp);
8022893Sdfr#ifdef MSDOSFS_DEBUG
80333548Sjkh					printf("dosdirempty(): entry found %02x, %02x\n",
80433548Sjkh					    dentp->deName[0], dentp->deName[1]);
8052893Sdfr#endif
80633548Sjkh					return (0);	/* not empty */
8072893Sdfr				}
8082893Sdfr			}
8092893Sdfr		}
8102893Sdfr		brelse(bp);
8112893Sdfr	}
8122893Sdfr	/* NOTREACHED */
8132893Sdfr}
8142893Sdfr
8152893Sdfr/*
8162893Sdfr * Check to see if the directory described by target is in some
8172893Sdfr * subdirectory of source.  This prevents something like the following from
8182893Sdfr * succeeding and leaving a bunch or files and directories orphaned. mv
8192893Sdfr * /a/b/c /a/b/c/d/e/f Where c and f are directories.
8202893Sdfr *
8212893Sdfr * source - the inode for /a/b/c
8222893Sdfr * target - the inode for /a/b/c/d/e/f
8232893Sdfr *
8242893Sdfr * Returns 0 if target is NOT a subdirectory of source.
8252893Sdfr * Otherwise returns a non-zero error number.
8262893Sdfr * The target inode is always unlocked on return.
8272893Sdfr */
8282893Sdfrint
8292893Sdfrdoscheckpath(source, target)
8302893Sdfr	struct denode *source;
8312893Sdfr	struct denode *target;
8322893Sdfr{
8332893Sdfr	daddr_t scn;
8342893Sdfr	struct msdosfsmount *pmp;
8352893Sdfr	struct direntry *ep;
8362893Sdfr	struct denode *dep;
8372893Sdfr	struct buf *bp = NULL;
8382893Sdfr	int error = 0;
8392893Sdfr
8402893Sdfr	dep = target;
8412893Sdfr	if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
8422893Sdfr	    (source->de_Attributes & ATTR_DIRECTORY) == 0) {
8432893Sdfr		error = ENOTDIR;
8442893Sdfr		goto out;
8452893Sdfr	}
8462893Sdfr	if (dep->de_StartCluster == source->de_StartCluster) {
8472893Sdfr		error = EEXIST;
8482893Sdfr		goto out;
8492893Sdfr	}
8502893Sdfr	if (dep->de_StartCluster == MSDOSFSROOT)
8512893Sdfr		goto out;
85233548Sjkh	pmp = dep->de_pmp;
85333548Sjkh#ifdef	DIAGNOSTIC
85433548Sjkh	if (pmp != source->de_pmp)
85533548Sjkh		panic("doscheckpath: source and target on different filesystems");
85633548Sjkh#endif
85733548Sjkh	if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
85833548Sjkh		goto out;
85933548Sjkh
8602893Sdfr	for (;;) {
8612893Sdfr		if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
8622893Sdfr			error = ENOTDIR;
86333548Sjkh			break;
8642893Sdfr		}
8652893Sdfr		scn = dep->de_StartCluster;
8662893Sdfr		error = bread(pmp->pm_devvp, cntobn(pmp, scn),
86733548Sjkh			      pmp->pm_bpcluster, NOCRED, &bp);
86833548Sjkh		if (error)
8692893Sdfr			break;
87033548Sjkh
8712893Sdfr		ep = (struct direntry *) bp->b_data + 1;
8722893Sdfr		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
8732893Sdfr		    bcmp(ep->deName, "..         ", 11) != 0) {
8742893Sdfr			error = ENOTDIR;
8752893Sdfr			break;
8762893Sdfr		}
8772893Sdfr		scn = getushort(ep->deStartCluster);
87833548Sjkh		if (FAT32(pmp))
87933548Sjkh			scn |= getushort(ep->deHighClust) << 16;
88033548Sjkh
8812893Sdfr		if (scn == source->de_StartCluster) {
8822893Sdfr			error = EINVAL;
8832893Sdfr			break;
8842893Sdfr		}
8852893Sdfr		if (scn == MSDOSFSROOT)
8862893Sdfr			break;
88733548Sjkh		if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
88833548Sjkh			/*
88933548Sjkh			 * scn should be 0 in this case,
89033548Sjkh			 * but we silently ignore the error.
89133548Sjkh			 */
89233548Sjkh			break;
89333548Sjkh		}
89433548Sjkh
8952893Sdfr		vput(DETOV(dep));
8962893Sdfr		brelse(bp);
8972893Sdfr		bp = NULL;
89833548Sjkh		/* NOTE: deget() clears dep on error */
89933548Sjkh		if ((error = deget(pmp, scn, 0, &dep)) != 0)
9002893Sdfr			break;
9012893Sdfr	}
90233548Sjkhout:;
9032893Sdfr	if (bp)
9042893Sdfr		brelse(bp);
905227817Skib#ifdef MSDOSFS_DEBUG
9062893Sdfr	if (error == ENOTDIR)
9072893Sdfr		printf("doscheckpath(): .. not a directory?\n");
908227817Skib#endif
9092893Sdfr	if (dep != NULL)
9102893Sdfr		vput(DETOV(dep));
91133548Sjkh	return (error);
9122893Sdfr}
9132893Sdfr
9142893Sdfr/*
9152893Sdfr * Read in the disk block containing the directory entry (dirclu, dirofs)
9162893Sdfr * and return the address of the buf header, and the address of the
9172893Sdfr * directory entry within the block.
9182893Sdfr */
9192893Sdfrint
92033548Sjkhreadep(pmp, dirclust, diroffset, bpp, epp)
9212893Sdfr	struct msdosfsmount *pmp;
92233548Sjkh	u_long dirclust, diroffset;
9232893Sdfr	struct buf **bpp;
9242893Sdfr	struct direntry **epp;
9252893Sdfr{
9262893Sdfr	int error;
9272893Sdfr	daddr_t bn;
92833548Sjkh	int blsize;
9292893Sdfr
93033548Sjkh	blsize = pmp->pm_bpcluster;
93133548Sjkh	if (dirclust == MSDOSFSROOT
93233548Sjkh	    && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
93333548Sjkh		blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
93433548Sjkh	bn = detobn(pmp, dirclust, diroffset);
93533548Sjkh	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
93633548Sjkh		brelse(*bpp);
9372893Sdfr		*bpp = NULL;
93833548Sjkh		return (error);
9392893Sdfr	}
9402893Sdfr	if (epp)
94133548Sjkh		*epp = bptoep(pmp, *bpp, diroffset);
94233548Sjkh	return (0);
9432893Sdfr}
9442893Sdfr
9452893Sdfr/*
9462893Sdfr * Read in the disk block containing the directory entry dep came from and
9472893Sdfr * return the address of the buf header, and the address of the directory
9482893Sdfr * entry within the block.
9492893Sdfr */
9502893Sdfrint
9512893Sdfrreadde(dep, bpp, epp)
9522893Sdfr	struct denode *dep;
9532893Sdfr	struct buf **bpp;
9542893Sdfr	struct direntry **epp;
9552893Sdfr{
95633548Sjkh
95733548Sjkh	return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
95833548Sjkh	    bpp, epp));
9592893Sdfr}
96033548Sjkh
96133548Sjkh/*
96233548Sjkh * Remove a directory entry. At this point the file represented by the
96333548Sjkh * directory entry to be removed is still full length until noone has it
96433548Sjkh * open.  When the file no longer being used msdosfs_inactive() is called
96533548Sjkh * and will truncate the file to 0 length.  When the vnode containing the
96633548Sjkh * denode is needed for some other purpose by VFS it will call
96733548Sjkh * msdosfs_reclaim() which will remove the denode from the denode cache.
96833548Sjkh */
96933548Sjkhint
97033548Sjkhremovede(pdep, dep)
97133548Sjkh	struct denode *pdep;	/* directory where the entry is removed */
97233548Sjkh	struct denode *dep;	/* file to be removed */
97333548Sjkh{
97433548Sjkh	int error;
97533548Sjkh	struct direntry *ep;
97633548Sjkh	struct buf *bp;
97733548Sjkh	daddr_t bn;
97833548Sjkh	int blsize;
97933548Sjkh	struct msdosfsmount *pmp = pdep->de_pmp;
98033548Sjkh	u_long offset = pdep->de_fndoffset;
98133548Sjkh
98233548Sjkh#ifdef MSDOSFS_DEBUG
98333548Sjkh	printf("removede(): filename %s, dep %p, offset %08lx\n",
98433548Sjkh	    dep->de_Name, dep, offset);
98533548Sjkh#endif
98633548Sjkh
98733548Sjkh	dep->de_refcnt--;
98833548Sjkh	offset += sizeof(struct direntry);
98933548Sjkh	do {
99033548Sjkh		offset -= sizeof(struct direntry);
99133548Sjkh		error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
99233548Sjkh		if (error)
99333548Sjkh			return error;
99433548Sjkh		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
99533548Sjkh		if (error) {
99633548Sjkh			brelse(bp);
99733548Sjkh			return error;
99833548Sjkh		}
99933548Sjkh		ep = bptoep(pmp, bp, offset);
100033548Sjkh		/*
100133548Sjkh		 * Check whether, if we came here the second time, i.e.
100233548Sjkh		 * when underflowing into the previous block, the last
100333548Sjkh		 * entry in this block is a longfilename entry, too.
100433548Sjkh		 */
100533548Sjkh		if (ep->deAttributes != ATTR_WIN95
100633548Sjkh		    && offset != pdep->de_fndoffset) {
100733548Sjkh			brelse(bp);
100833548Sjkh			break;
100933548Sjkh		}
101033548Sjkh		offset += sizeof(struct direntry);
101133548Sjkh		while (1) {
101233548Sjkh			/*
101333548Sjkh			 * We are a bit agressive here in that we delete any Win95
101433548Sjkh			 * entries preceding this entry, not just the ones we "own".
101533548Sjkh			 * Since these presumably aren't valid anyway,
101633548Sjkh			 * there should be no harm.
101733548Sjkh			 */
101833548Sjkh			offset -= sizeof(struct direntry);
101933548Sjkh			ep--->deName[0] = SLOT_DELETED;
102033548Sjkh			if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
102133548Sjkh			    || !(offset & pmp->pm_crbomask)
102233548Sjkh			    || ep->deAttributes != ATTR_WIN95)
102333548Sjkh				break;
102433548Sjkh		}
1025231998Skib		if (DOINGASYNC(DETOV(pdep)))
1026172798Sbde			bdwrite(bp);
1027172798Sbde		else if ((error = bwrite(bp)) != 0)
102833548Sjkh			return error;
102933548Sjkh	} while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
103033548Sjkh	    && !(offset & pmp->pm_crbomask)
103133548Sjkh	    && offset);
103233548Sjkh	return 0;
103333548Sjkh}
103433548Sjkh
103533548Sjkh/*
103633548Sjkh * Create a unique DOS name in dvp
103733548Sjkh */
103833548Sjkhint
103933548Sjkhuniqdosname(dep, cnp, cp)
104033548Sjkh	struct denode *dep;
104133548Sjkh	struct componentname *cnp;
104233548Sjkh	u_char *cp;
104333548Sjkh{
104433548Sjkh	struct msdosfsmount *pmp = dep->de_pmp;
104533548Sjkh	struct direntry *dentp;
104633548Sjkh	int gen;
104733548Sjkh	int blsize;
104833548Sjkh	u_long cn;
104933548Sjkh	daddr_t bn;
105033548Sjkh	struct buf *bp;
105133548Sjkh	int error;
105236133Sdt
105336154Sdt	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
105436133Sdt		return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
1055120492Sfjoe		    cnp->cn_namelen, 0, pmp) ? 0 : EINVAL);
105633548Sjkh
105733548Sjkh	for (gen = 1;; gen++) {
105833548Sjkh		/*
105933548Sjkh		 * Generate DOS name with generation number
106033548Sjkh		 */
106133548Sjkh		if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
1062120492Sfjoe		    cnp->cn_namelen, gen, pmp))
106333548Sjkh			return gen == 1 ? EINVAL : EEXIST;
106433548Sjkh
106533548Sjkh		/*
106633548Sjkh		 * Now look for a dir entry with this exact name
106733548Sjkh		 */
106833548Sjkh		for (cn = error = 0; !error; cn++) {
106933548Sjkh			if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
107033548Sjkh				if (error == E2BIG)	/* EOF reached and not found */
107133548Sjkh					return 0;
107233548Sjkh				return error;
107333548Sjkh			}
107433548Sjkh			error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
107533548Sjkh			if (error) {
107633548Sjkh				brelse(bp);
107733548Sjkh				return error;
107833548Sjkh			}
107933548Sjkh			for (dentp = (struct direntry *)bp->b_data;
108033548Sjkh			     (char *)dentp < bp->b_data + blsize;
108133548Sjkh			     dentp++) {
108233548Sjkh				if (dentp->deName[0] == SLOT_EMPTY) {
108333548Sjkh					/*
108433548Sjkh					 * Last used entry and not found
108533548Sjkh					 */
108633548Sjkh					brelse(bp);
108733548Sjkh					return 0;
108833548Sjkh				}
108933548Sjkh				/*
109033548Sjkh				 * Ignore volume labels and Win95 entries
109133548Sjkh				 */
109233548Sjkh				if (dentp->deAttributes & ATTR_VOLUME)
109333548Sjkh					continue;
109433548Sjkh				if (!bcmp(dentp->deName, cp, 11)) {
109533548Sjkh					error = EEXIST;
109633548Sjkh					break;
109733548Sjkh				}
109833548Sjkh			}
109933548Sjkh			brelse(bp);
110033548Sjkh		}
110133548Sjkh	}
110233548Sjkh}
110333548Sjkh
110433548Sjkh/*
110533548Sjkh * Find any Win'95 long filename entry in directory dep
110633548Sjkh */
110733548Sjkhint
110833548Sjkhfindwin95(dep)
110933548Sjkh	struct denode *dep;
111033548Sjkh{
111133548Sjkh	struct msdosfsmount *pmp = dep->de_pmp;
111233548Sjkh	struct direntry *dentp;
111342252Sdt	int blsize, win95;
111433548Sjkh	u_long cn;
111533548Sjkh	daddr_t bn;
111633548Sjkh	struct buf *bp;
111733548Sjkh
111842252Sdt	win95 = 1;
111933548Sjkh	/*
112033548Sjkh	 * Read through the directory looking for Win'95 entries
112133548Sjkh	 * Note: Error currently handled just as EOF			XXX
112233548Sjkh	 */
112333548Sjkh	for (cn = 0;; cn++) {
112433548Sjkh		if (pcbmap(dep, cn, &bn, 0, &blsize))
112542252Sdt			return (win95);
112633548Sjkh		if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
112733548Sjkh			brelse(bp);
112842252Sdt			return (win95);
112933548Sjkh		}
113033548Sjkh		for (dentp = (struct direntry *)bp->b_data;
113133548Sjkh		     (char *)dentp < bp->b_data + blsize;
113233548Sjkh		     dentp++) {
113333548Sjkh			if (dentp->deName[0] == SLOT_EMPTY) {
113433548Sjkh				/*
113533548Sjkh				 * Last used entry and not found
113633548Sjkh				 */
113733548Sjkh				brelse(bp);
113842252Sdt				return (win95);
113933548Sjkh			}
114033548Sjkh			if (dentp->deName[0] == SLOT_DELETED) {
114133548Sjkh				/*
114233548Sjkh				 * Ignore deleted files
114333548Sjkh				 * Note: might be an indication of Win'95 anyway	XXX
114433548Sjkh				 */
114533548Sjkh				continue;
114633548Sjkh			}
114733548Sjkh			if (dentp->deAttributes == ATTR_WIN95) {
114833548Sjkh				brelse(bp);
114933548Sjkh				return 1;
115033548Sjkh			}
115142252Sdt			win95 = 0;
115233548Sjkh		}
115333548Sjkh		brelse(bp);
115433548Sjkh	}
115533548Sjkh}
1156