msdosfs_lookup.c revision 144298
150477Speter/* $FreeBSD: head/sys/fs/msdosfs/msdosfs_lookup.c 144298 2005-03-29 13:04:00Z jeff $ */ 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> 532893Sdfr#include <sys/namei.h> 5460041Sphk#include <sys/bio.h> 552893Sdfr#include <sys/buf.h> 562893Sdfr#include <sys/vnode.h> 572893Sdfr#include <sys/mount.h> 582893Sdfr 5977162Sru#include <fs/msdosfs/bpb.h> 60120492Sfjoe#include <fs/msdosfs/msdosfsmount.h> 6177162Sru#include <fs/msdosfs/direntry.h> 6277162Sru#include <fs/msdosfs/denode.h> 6377162Sru#include <fs/msdosfs/fat.h> 642893Sdfr 652893Sdfr/* 662893Sdfr * When we search a directory the blocks containing directory entries are 672893Sdfr * read and examined. The directory entries contain information that would 682893Sdfr * normally be in the inode of a unix filesystem. This means that some of 692893Sdfr * a directory's contents may also be in memory resident denodes (sort of 702893Sdfr * an inode). This can cause problems if we are searching while some other 712893Sdfr * process is modifying a directory. To prevent one process from accessing 722893Sdfr * incompletely modified directory information we depend upon being the 7329286Sphk * sole owner of a directory block. bread/brelse provide this service. 742893Sdfr * This being the case, when a process modifies a directory it must first 752893Sdfr * acquire the disk block that contains the directory entry to be modified. 762893Sdfr * Then update the disk block and the denode, and then write the disk block 772893Sdfr * out to disk. This way disk blocks containing directory entries and in 782893Sdfr * memory denode's will be in synch. 792893Sdfr */ 802893Sdfrint 812893Sdfrmsdosfs_lookup(ap) 8228787Sphk struct vop_cachedlookup_args /* { 832893Sdfr struct vnode *a_dvp; 842893Sdfr struct vnode **a_vpp; 852893Sdfr struct componentname *a_cnp; 862893Sdfr } */ *ap; 872893Sdfr{ 882893Sdfr struct vnode *vdp = ap->a_dvp; 892893Sdfr struct vnode **vpp = ap->a_vpp; 902893Sdfr struct componentname *cnp = ap->a_cnp; 912893Sdfr daddr_t bn; 922893Sdfr int error; 9333548Sjkh int slotcount; 9433548Sjkh int slotoffset = 0; 952893Sdfr int frcn; 962893Sdfr u_long cluster; 9733548Sjkh int blkoff; 982893Sdfr int diroff; 9933548Sjkh int blsize; 1002893Sdfr int isadir; /* ~0 if found direntry is a directory */ 1012893Sdfr u_long scn; /* starting cluster number */ 1022893Sdfr struct vnode *pdp; 1032893Sdfr struct denode *dp; 1042893Sdfr struct denode *tdp; 1052893Sdfr struct msdosfsmount *pmp; 1062893Sdfr struct buf *bp = 0; 1072893Sdfr struct direntry *dep = NULL; 1082893Sdfr u_char dosfilename[12]; 1092893Sdfr int flags = cnp->cn_flags; 1102893Sdfr int nameiop = cnp->cn_nameiop; 11183366Sjulian struct thread *td = cnp->cn_thread; 11233848Smsmith int unlen; 1132893Sdfr 11433548Sjkh int wincnt = 1; 115134942Stjr int chksum = -1, chksum_ok; 11633548Sjkh int olddos = 1; 11733548Sjkh 1182893Sdfr#ifdef MSDOSFS_DEBUG 1192893Sdfr printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); 1202893Sdfr#endif 1212893Sdfr dp = VTODE(vdp); 1222893Sdfr pmp = dp->de_pmp; 1232893Sdfr *vpp = NULL; 1242893Sdfr#ifdef MSDOSFS_DEBUG 12533548Sjkh printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", 12633548Sjkh vdp, dp, dp->de_Attributes); 1272893Sdfr#endif 1282893Sdfr 1292893Sdfr /* 1302893Sdfr * If they are going after the . or .. entry in the root directory, 1312893Sdfr * they won't find it. DOS filesystems don't have them in the root 1322893Sdfr * directory. So, we fake it. deget() is in on this scam too. 1332893Sdfr */ 134101308Sjeff if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && 1352893Sdfr (cnp->cn_namelen == 1 || 1362893Sdfr (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 1372893Sdfr isadir = ATTR_DIRECTORY; 1382893Sdfr scn = MSDOSFSROOT; 1392893Sdfr#ifdef MSDOSFS_DEBUG 1402893Sdfr printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 1412893Sdfr#endif 1422893Sdfr cluster = MSDOSFSROOT; 14333548Sjkh blkoff = MSDOSFSROOT_OFS; 1442893Sdfr goto foundroot; 1452893Sdfr } 1462893Sdfr 14733548Sjkh switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 148120492Sfjoe cnp->cn_namelen, 0, pmp)) { 14933548Sjkh case 0: 15033548Sjkh return (EINVAL); 15133548Sjkh case 1: 15233548Sjkh break; 15333548Sjkh case 2: 15433548Sjkh wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 155120492Sfjoe cnp->cn_namelen, pmp) + 1; 15633548Sjkh break; 15733548Sjkh case 3: 15833548Sjkh olddos = 0; 15933548Sjkh wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 160120492Sfjoe cnp->cn_namelen, pmp) + 1; 16133548Sjkh break; 16233548Sjkh } 16336133Sdt if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) { 16433548Sjkh wincnt = 1; 16536133Sdt olddos = 1; 16636133Sdt } 16733848Smsmith unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen); 16833548Sjkh 1692893Sdfr /* 17033548Sjkh * Suppress search for slots unless creating 17133548Sjkh * file and at end of pathname, in which case 17233548Sjkh * we watch for a place to put the new file in 17333548Sjkh * case it doesn't already exist. 1742893Sdfr */ 17533548Sjkh slotcount = wincnt; 17633548Sjkh if ((nameiop == CREATE || nameiop == RENAME) && 17733548Sjkh (flags & ISLASTCN)) 17833548Sjkh slotcount = 0; 1792893Sdfr 1802893Sdfr#ifdef MSDOSFS_DEBUG 18133548Sjkh printf("msdosfs_lookup(): dos version of filename %s, length %ld\n", 18233548Sjkh dosfilename, cnp->cn_namelen); 1832893Sdfr#endif 1842893Sdfr /* 1852893Sdfr * Search the directory pointed at by vdp for the name pointed at 1862893Sdfr * by cnp->cn_nameptr. 1872893Sdfr */ 1882893Sdfr tdp = NULL; 189120492Sfjoe mbnambuf_init(); 1902893Sdfr /* 1912893Sdfr * The outer loop ranges over the clusters that make up the 1922893Sdfr * directory. Note that the root directory is different from all 1932893Sdfr * other directories. It has a fixed number of blocks that are not 1942893Sdfr * part of the pool of allocatable clusters. So, we treat it a 1952893Sdfr * little differently. The root directory starts at "cluster" 0. 1962893Sdfr */ 19733548Sjkh diroff = 0; 1982893Sdfr for (frcn = 0;; frcn++) { 19933548Sjkh error = pcbmap(dp, frcn, &bn, &cluster, &blsize); 2003152Sphk if (error) { 2012893Sdfr if (error == E2BIG) 2022893Sdfr break; 20333548Sjkh return (error); 2042893Sdfr } 20533548Sjkh error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 20633548Sjkh if (error) { 20733548Sjkh brelse(bp); 20833548Sjkh return (error); 20933548Sjkh } 21033548Sjkh for (blkoff = 0; blkoff < blsize; 21133548Sjkh blkoff += sizeof(struct direntry), 21233548Sjkh diroff += sizeof(struct direntry)) { 21333548Sjkh dep = (struct direntry *)(bp->b_data + blkoff); 2142893Sdfr /* 2152893Sdfr * If the slot is empty and we are still looking 2162893Sdfr * for an empty then remember this one. If the 2172893Sdfr * slot is not empty then check to see if it 2182893Sdfr * matches what we are looking for. If the slot 2192893Sdfr * has never been filled with anything, then the 2202893Sdfr * remainder of the directory has never been used, 2212893Sdfr * so there is no point in searching it. 2222893Sdfr */ 2232893Sdfr if (dep->deName[0] == SLOT_EMPTY || 2242893Sdfr dep->deName[0] == SLOT_DELETED) { 22533548Sjkh /* 22633548Sjkh * Drop memory of previous long matches 22733548Sjkh */ 22833548Sjkh chksum = -1; 229120492Sfjoe mbnambuf_init(); 23033548Sjkh 23133548Sjkh if (slotcount < wincnt) { 23233548Sjkh slotcount++; 23333548Sjkh slotoffset = diroff; 2342893Sdfr } 2352893Sdfr if (dep->deName[0] == SLOT_EMPTY) { 2362893Sdfr brelse(bp); 2372893Sdfr goto notfound; 2382893Sdfr } 2392893Sdfr } else { 2402893Sdfr /* 24133548Sjkh * If there wasn't enough space for our winentries, 24233548Sjkh * forget about the empty space 24333548Sjkh */ 24433548Sjkh if (slotcount < wincnt) 24533548Sjkh slotcount = 0; 24633548Sjkh 24733548Sjkh /* 24833548Sjkh * Check for Win95 long filename entry 24933548Sjkh */ 25033548Sjkh if (dep->deAttributes == ATTR_WIN95) { 25133548Sjkh if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 25233548Sjkh continue; 25333548Sjkh 254120492Sfjoe chksum = win2unixfn((struct winentry *)dep, 25533750Sache chksum, 256120492Sfjoe pmp); 25733548Sjkh continue; 25833548Sjkh } 25933548Sjkh 260120492Sfjoe chksum = winChkName((const u_char *)cnp->cn_nameptr, 261120492Sfjoe unlen, 262120492Sfjoe chksum, 263120492Sfjoe pmp); 264120492Sfjoe if (chksum == -2) { 265120492Sfjoe chksum = -1; 266120492Sfjoe continue; 267120492Sfjoe } 268120492Sfjoe 26933548Sjkh /* 2702893Sdfr * Ignore volume labels (anywhere, not just 2712893Sdfr * the root directory). 2722893Sdfr */ 27333548Sjkh if (dep->deAttributes & ATTR_VOLUME) { 27433548Sjkh chksum = -1; 27533548Sjkh continue; 27633548Sjkh } 27733548Sjkh 27833548Sjkh /* 27933548Sjkh * Check for a checksum or name match 28033548Sjkh */ 281134942Stjr chksum_ok = (chksum == winChksum(dep->deName)); 282134942Stjr if (!chksum_ok 28333548Sjkh && (!olddos || bcmp(dosfilename, dep->deName, 11))) { 28433548Sjkh chksum = -1; 28533548Sjkh continue; 28633548Sjkh } 2872893Sdfr#ifdef MSDOSFS_DEBUG 28833548Sjkh printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", 28933548Sjkh blkoff, diroff); 2902893Sdfr#endif 29133548Sjkh /* 29233548Sjkh * Remember where this directory 29333548Sjkh * entry came from for whoever did 29433548Sjkh * this lookup. 29533548Sjkh */ 29633548Sjkh dp->de_fndoffset = diroff; 297134942Stjr if (chksum_ok && nameiop == RENAME) { 298134942Stjr /* 299134942Stjr * Target had correct long name 300134942Stjr * directory entries, reuse them 301134942Stjr * as needed. 302134942Stjr */ 303134942Stjr dp->de_fndcnt = wincnt - 1; 304134942Stjr } else { 305134942Stjr /* 306134942Stjr * Long name directory entries 307134942Stjr * not present or corrupt, can only 308134942Stjr * reuse dos directory entry. 309134942Stjr */ 310134942Stjr dp->de_fndcnt = 0; 311134942Stjr } 31233548Sjkh 31333548Sjkh goto found; 3142893Sdfr } 31533548Sjkh } /* for (blkoff = 0; .... */ 3162893Sdfr /* 3172893Sdfr * Release the buffer holding the directory cluster just 3182893Sdfr * searched. 3192893Sdfr */ 3202893Sdfr brelse(bp); 32133548Sjkh } /* for (frcn = 0; ; frcn++) */ 32233548Sjkh 32333548Sjkhnotfound: 3242893Sdfr /* 3252893Sdfr * We hold no disk buffers at this point. 3262893Sdfr */ 3272893Sdfr 3282893Sdfr /* 32933548Sjkh * Fixup the slot description to point to the place where 33033548Sjkh * we might put the new DOS direntry (putting the Win95 33133548Sjkh * long name entries before that) 33233548Sjkh */ 33333548Sjkh if (!slotcount) { 33433548Sjkh slotcount = 1; 33533548Sjkh slotoffset = diroff; 33633548Sjkh } 33733548Sjkh if (wincnt > slotcount) 33833548Sjkh slotoffset += sizeof(struct direntry) * (wincnt - slotcount); 33933548Sjkh 34033548Sjkh /* 3412893Sdfr * If we get here we didn't find the entry we were looking for. But 3422893Sdfr * that's ok if we are creating or renaming and are at the end of 3432893Sdfr * the pathname and the directory hasn't been removed. 3442893Sdfr */ 3452893Sdfr#ifdef MSDOSFS_DEBUG 34633548Sjkh printf("msdosfs_lookup(): op %d, refcnt %ld\n", 34733548Sjkh nameiop, dp->de_refcnt); 34833548Sjkh printf(" slotcount %d, slotoffset %d\n", 34933548Sjkh slotcount, slotoffset); 3502893Sdfr#endif 3512893Sdfr if ((nameiop == CREATE || nameiop == RENAME) && 3522893Sdfr (flags & ISLASTCN) && dp->de_refcnt != 0) { 35333548Sjkh /* 35433548Sjkh * Access for write is interpreted as allowing 35533548Sjkh * creation of files in the directory. 35633548Sjkh */ 35783366Sjulian error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 3588386Sbde if (error) 35933548Sjkh return (error); 36033548Sjkh /* 36133548Sjkh * Return an indication of where the new directory 36233548Sjkh * entry should be put. 36333548Sjkh */ 36433548Sjkh dp->de_fndoffset = slotoffset; 36533548Sjkh dp->de_fndcnt = wincnt - 1; 36633548Sjkh 36733548Sjkh /* 36833548Sjkh * We return with the directory locked, so that 36933548Sjkh * the parameters we set up above will still be 37033548Sjkh * valid if we actually decide to do a direnter(). 37133548Sjkh * We return ni_vp == NULL to indicate that the entry 37233548Sjkh * does not currently exist; we leave a pointer to 37333548Sjkh * the (locked) directory inode in ndp->ni_dvp. 37433548Sjkh * The pathname buffer is saved so that the name 37533548Sjkh * can be obtained later. 37633548Sjkh * 37733548Sjkh * NB - if the directory is unlocked, then this 37833548Sjkh * information cannot be used. 37933548Sjkh */ 3802893Sdfr cnp->cn_flags |= SAVENAME; 38133548Sjkh return (EJUSTRETURN); 3822893Sdfr } 3832893Sdfr /* 38433548Sjkh * Insert name into cache (as non-existent) if appropriate. 3852893Sdfr */ 3862893Sdfr if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 3872893Sdfr cache_enter(vdp, *vpp, cnp); 38833548Sjkh return (ENOENT); 3892893Sdfr 39033548Sjkhfound: 3912893Sdfr /* 3922893Sdfr * NOTE: We still have the buffer with matched directory entry at 3932893Sdfr * this point. 3942893Sdfr */ 3952893Sdfr isadir = dep->deAttributes & ATTR_DIRECTORY; 3962893Sdfr scn = getushort(dep->deStartCluster); 39733548Sjkh if (FAT32(pmp)) { 39833548Sjkh scn |= getushort(dep->deHighClust) << 16; 39933548Sjkh if (scn == pmp->pm_rootdirblk) { 40033548Sjkh /* 40133548Sjkh * There should actually be 0 here. 40233548Sjkh * Just ignore the error. 40333548Sjkh */ 40433548Sjkh scn = MSDOSFSROOT; 40533548Sjkh } 40633548Sjkh } 4072893Sdfr 40833548Sjkh if (isadir) { 40933548Sjkh cluster = scn; 41033548Sjkh if (cluster == MSDOSFSROOT) 41133548Sjkh blkoff = MSDOSFSROOT_OFS; 41233548Sjkh else 41333548Sjkh blkoff = 0; 41433548Sjkh } else if (cluster == MSDOSFSROOT) 41533548Sjkh blkoff = diroff; 41633548Sjkh 4172893Sdfr /* 41833548Sjkh * Now release buf to allow deget to read the entry again. 41933548Sjkh * Reserving it here and giving it to deget could result 42033548Sjkh * in a deadlock. 42133548Sjkh */ 42233548Sjkh brelse(bp); 42333548Sjkh bp = 0; 42433548Sjkh 42533548Sjkhfoundroot: 42633548Sjkh /* 4272893Sdfr * If we entered at foundroot, then we are looking for the . or .. 4282893Sdfr * entry of the filesystems root directory. isadir and scn were 42933548Sjkh * setup before jumping here. And, bp is already null. 4302893Sdfr */ 43133548Sjkh if (FAT32(pmp) && scn == MSDOSFSROOT) 43233548Sjkh scn = pmp->pm_rootdirblk; 4332893Sdfr 4342893Sdfr /* 43533548Sjkh * If deleting, and at end of pathname, return 43633548Sjkh * parameters which can be used to remove file. 4372893Sdfr */ 4382893Sdfr if (nameiop == DELETE && (flags & ISLASTCN)) { 43933548Sjkh /* 44033548Sjkh * Don't allow deleting the root. 44133548Sjkh */ 44233548Sjkh if (blkoff == MSDOSFSROOT_OFS) 44333548Sjkh return EROFS; /* really? XXX */ 44433548Sjkh 44533548Sjkh /* 44633548Sjkh * Write access to directory required to delete files. 44733548Sjkh */ 44883366Sjulian error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 44933548Sjkh if (error) 45033548Sjkh return (error); 45133548Sjkh 45233548Sjkh /* 45333548Sjkh * Return pointer to current entry in dp->i_offset. 45433548Sjkh * Save directory inode pointer in ndp->ni_dvp for dirremove(). 45533548Sjkh */ 4562893Sdfr if (dp->de_StartCluster == scn && isadir) { /* "." */ 4572893Sdfr VREF(vdp); 4582893Sdfr *vpp = vdp; 45933548Sjkh return (0); 4602893Sdfr } 46133548Sjkh error = deget(pmp, cluster, blkoff, &tdp); 46233548Sjkh if (error) 46333548Sjkh return (error); 4642893Sdfr *vpp = DETOV(tdp); 46533548Sjkh return (0); 4662893Sdfr } 4672893Sdfr 4682893Sdfr /* 46933548Sjkh * If rewriting (RENAME), return the inode and the 47033548Sjkh * information required to rewrite the present directory 47133548Sjkh * Must get inode of directory entry to verify it's a 47233548Sjkh * regular file, or empty directory. 4732893Sdfr */ 474144298Sjeff if (nameiop == RENAME && (flags & ISLASTCN)) { 47533548Sjkh if (blkoff == MSDOSFSROOT_OFS) 47633548Sjkh return EROFS; /* really? XXX */ 47733548Sjkh 47883366Sjulian error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 47933548Sjkh if (error) 48033548Sjkh return (error); 48133548Sjkh 48233548Sjkh /* 48333548Sjkh * Careful about locking second inode. 48433548Sjkh * This can only occur if the target is ".". 48533548Sjkh */ 48633548Sjkh if (dp->de_StartCluster == scn && isadir) 48733548Sjkh return (EISDIR); 48833548Sjkh 48933548Sjkh if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 49033548Sjkh return (error); 4912893Sdfr *vpp = DETOV(tdp); 4922893Sdfr cnp->cn_flags |= SAVENAME; 49333548Sjkh return (0); 4942893Sdfr } 4952893Sdfr 4962893Sdfr /* 49733548Sjkh * Step through the translation in the name. We do not `vput' the 49833548Sjkh * directory because we may need it again if a symbolic link 49933548Sjkh * is relative to the current directory. Instead we save it 50033548Sjkh * unlocked as "pdp". We must get the target inode before unlocking 50133548Sjkh * the directory to insure that the inode will not be removed 50233548Sjkh * before we get it. We prevent deadlock by always fetching 50333548Sjkh * inodes from the root, moving down the directory tree. Thus 50433548Sjkh * when following backward pointers ".." we must unlock the 50533548Sjkh * parent directory before getting the requested directory. 50633548Sjkh * There is a potential race condition here if both the current 50733548Sjkh * and parent directories are removed before the VFS_VGET for the 50833548Sjkh * inode associated with ".." returns. We hope that this occurs 50933548Sjkh * infrequently since we cannot avoid this race condition without 51033548Sjkh * implementing a sophisticated deadlock detection algorithm. 51133548Sjkh * Note also that this simple deadlock detection scheme will not 51296755Strhodes * work if the filesystem has any hard links other than ".." 51333548Sjkh * that point backwards in the directory structure. 5142893Sdfr */ 5152893Sdfr pdp = vdp; 5162893Sdfr if (flags & ISDOTDOT) { 51783366Sjulian VOP_UNLOCK(pdp, 0, td); 51833548Sjkh error = deget(pmp, cluster, blkoff, &tdp); 5192893Sdfr if (error) { 52083366Sjulian vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); 52133548Sjkh return (error); 5222893Sdfr } 5232893Sdfr *vpp = DETOV(tdp); 52433548Sjkh } else if (dp->de_StartCluster == scn && isadir) { 52533548Sjkh VREF(vdp); /* we want ourself, ie "." */ 5262893Sdfr *vpp = vdp; 5272893Sdfr } else { 52833548Sjkh if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 52933548Sjkh return (error); 5302893Sdfr *vpp = DETOV(tdp); 5312893Sdfr } 5322893Sdfr 5332893Sdfr /* 53433548Sjkh * Insert name into cache if appropriate. 5352893Sdfr */ 5362893Sdfr if (cnp->cn_flags & MAKEENTRY) 5372893Sdfr cache_enter(vdp, *vpp, cnp); 53833548Sjkh return (0); 5392893Sdfr} 5402893Sdfr 5412893Sdfr/* 5422893Sdfr * dep - directory entry to copy into the directory 5432893Sdfr * ddep - directory to add to 5442893Sdfr * depp - return the address of the denode for the created directory entry 5452893Sdfr * if depp != 0 54633548Sjkh * cnp - componentname needed for Win95 long filenames 5472893Sdfr */ 5482893Sdfrint 54933548Sjkhcreatede(dep, ddep, depp, cnp) 5502893Sdfr struct denode *dep; 5512893Sdfr struct denode *ddep; 5522893Sdfr struct denode **depp; 55333548Sjkh struct componentname *cnp; 5542893Sdfr{ 5552893Sdfr int error; 5562893Sdfr u_long dirclust, diroffset; 5572893Sdfr struct direntry *ndep; 5582893Sdfr struct msdosfsmount *pmp = ddep->de_pmp; 5592893Sdfr struct buf *bp; 56033548Sjkh daddr_t bn; 56133548Sjkh int blsize; 5622893Sdfr 5632893Sdfr#ifdef MSDOSFS_DEBUG 56433548Sjkh printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 56533548Sjkh dep, ddep, depp, cnp); 5662893Sdfr#endif 5672893Sdfr 5682893Sdfr /* 5692893Sdfr * If no space left in the directory then allocate another cluster 5702893Sdfr * and chain it onto the end of the file. There is one exception 5712893Sdfr * to this. That is, if the root directory has no more space it 5722893Sdfr * can NOT be expanded. extendfile() checks for and fails attempts 5732893Sdfr * to extend the root directory. We just return an error in that 5742893Sdfr * case. 5752893Sdfr */ 57633548Sjkh if (ddep->de_fndoffset >= ddep->de_FileSize) { 57733548Sjkh diroffset = ddep->de_fndoffset + sizeof(struct direntry) 57833548Sjkh - ddep->de_FileSize; 57933548Sjkh dirclust = de_clcount(pmp, diroffset); 58033548Sjkh error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); 58133548Sjkh if (error) { 58233548Sjkh (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL); 5832893Sdfr return error; 58433548Sjkh } 58533548Sjkh 5862893Sdfr /* 5872893Sdfr * Update the size of the directory 5882893Sdfr */ 58933548Sjkh ddep->de_FileSize += de_cn2off(pmp, dirclust); 5902893Sdfr } 5912893Sdfr 5922893Sdfr /* 59333548Sjkh * We just read in the cluster with space. Copy the new directory 59433548Sjkh * entry in. Then write it to disk. NOTE: DOS directories 59533548Sjkh * do not get smaller as clusters are emptied. 5962893Sdfr */ 59733548Sjkh error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 59833548Sjkh &bn, &dirclust, &blsize); 59933548Sjkh if (error) 6002893Sdfr return error; 60133548Sjkh diroffset = ddep->de_fndoffset; 60233548Sjkh if (dirclust != MSDOSFSROOT) 60333548Sjkh diroffset &= pmp->pm_crbomask; 60433548Sjkh if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { 60533548Sjkh brelse(bp); 60633548Sjkh return error; 6072893Sdfr } 60833548Sjkh ndep = bptoep(pmp, bp, ddep->de_fndoffset); 6092893Sdfr 61033548Sjkh DE_EXTERNALIZE(ndep, dep); 6112893Sdfr 61233548Sjkh /* 61333548Sjkh * Now write the Win95 long name 61433548Sjkh */ 61533548Sjkh if (ddep->de_fndcnt > 0) { 61633548Sjkh u_int8_t chksum = winChksum(ndep->deName); 61733548Sjkh const u_char *un = (const u_char *)cnp->cn_nameptr; 61833548Sjkh int unlen = cnp->cn_namelen; 61933548Sjkh int cnt = 1; 6202893Sdfr 62133548Sjkh while (--ddep->de_fndcnt >= 0) { 62233548Sjkh if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { 62333548Sjkh if ((error = bwrite(bp)) != 0) 62433548Sjkh return error; 6252893Sdfr 62633548Sjkh ddep->de_fndoffset -= sizeof(struct direntry); 62733548Sjkh error = pcbmap(ddep, 62833548Sjkh de_cluster(pmp, 62933548Sjkh ddep->de_fndoffset), 63033548Sjkh &bn, 0, &blsize); 63133548Sjkh if (error) 63233548Sjkh return error; 6332893Sdfr 63433548Sjkh error = bread(pmp->pm_devvp, bn, blsize, 63533548Sjkh NOCRED, &bp); 63633548Sjkh if (error) { 63733548Sjkh brelse(bp); 63833548Sjkh return error; 63933548Sjkh } 64033548Sjkh ndep = bptoep(pmp, bp, ddep->de_fndoffset); 64133548Sjkh } else { 64233548Sjkh ndep--; 64333548Sjkh ddep->de_fndoffset -= sizeof(struct direntry); 64433548Sjkh } 64533747Sache if (!unix2winfn(un, unlen, (struct winentry *)ndep, 646120492Sfjoe cnt++, chksum, pmp)) 64733548Sjkh break; 64833548Sjkh } 64933548Sjkh } 65033548Sjkh 65133548Sjkh if ((error = bwrite(bp)) != 0) 65233548Sjkh return error; 65333548Sjkh 6542893Sdfr /* 65533548Sjkh * If they want us to return with the denode gotten. 6562893Sdfr */ 65733548Sjkh if (depp) { 65833548Sjkh if (dep->de_Attributes & ATTR_DIRECTORY) { 65933548Sjkh dirclust = dep->de_StartCluster; 66033548Sjkh if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 66133548Sjkh dirclust = MSDOSFSROOT; 66233548Sjkh if (dirclust == MSDOSFSROOT) 66333548Sjkh diroffset = MSDOSFSROOT_OFS; 66433548Sjkh else 66533548Sjkh diroffset = 0; 66633548Sjkh } 66733548Sjkh return deget(pmp, dirclust, diroffset, depp); 66833548Sjkh } 6692893Sdfr 67033548Sjkh return 0; 6712893Sdfr} 6722893Sdfr 6732893Sdfr/* 6742893Sdfr * Be sure a directory is empty except for "." and "..". Return 1 if empty, 6752893Sdfr * return 0 if not empty or error. 6762893Sdfr */ 6772893Sdfrint 6782893Sdfrdosdirempty(dep) 6792893Sdfr struct denode *dep; 6802893Sdfr{ 68133548Sjkh int blsize; 6822893Sdfr int error; 6832893Sdfr u_long cn; 6842893Sdfr daddr_t bn; 6852893Sdfr struct buf *bp; 6862893Sdfr struct msdosfsmount *pmp = dep->de_pmp; 6872893Sdfr struct direntry *dentp; 6882893Sdfr 6892893Sdfr /* 6902893Sdfr * Since the filesize field in directory entries for a directory is 6912893Sdfr * zero, we just have to feel our way through the directory until 6922893Sdfr * we hit end of file. 6932893Sdfr */ 6942893Sdfr for (cn = 0;; cn++) { 69533548Sjkh if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 69633548Sjkh if (error == E2BIG) 69733548Sjkh return (1); /* it's empty */ 69833548Sjkh return (0); 69933548Sjkh } 70033548Sjkh error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 70133548Sjkh if (error) { 70233548Sjkh brelse(bp); 70333548Sjkh return (0); 70433548Sjkh } 70533548Sjkh for (dentp = (struct direntry *)bp->b_data; 70633548Sjkh (char *)dentp < bp->b_data + blsize; 70733548Sjkh dentp++) { 70833548Sjkh if (dentp->deName[0] != SLOT_DELETED && 70933548Sjkh (dentp->deAttributes & ATTR_VOLUME) == 0) { 7102893Sdfr /* 7112893Sdfr * In dos directories an entry whose name 7122893Sdfr * starts with SLOT_EMPTY (0) starts the 7132893Sdfr * beginning of the unused part of the 7142893Sdfr * directory, so we can just return that it 7152893Sdfr * is empty. 7162893Sdfr */ 7172893Sdfr if (dentp->deName[0] == SLOT_EMPTY) { 7182893Sdfr brelse(bp); 71933548Sjkh return (1); 7202893Sdfr } 7212893Sdfr /* 7222893Sdfr * Any names other than "." and ".." in a 7232893Sdfr * directory mean it is not empty. 7242893Sdfr */ 7252893Sdfr if (bcmp(dentp->deName, ". ", 11) && 7262893Sdfr bcmp(dentp->deName, ".. ", 11)) { 7272893Sdfr brelse(bp); 7282893Sdfr#ifdef MSDOSFS_DEBUG 72933548Sjkh printf("dosdirempty(): entry found %02x, %02x\n", 73033548Sjkh dentp->deName[0], dentp->deName[1]); 7312893Sdfr#endif 73233548Sjkh return (0); /* not empty */ 7332893Sdfr } 7342893Sdfr } 7352893Sdfr } 7362893Sdfr brelse(bp); 7372893Sdfr } 7382893Sdfr /* NOTREACHED */ 7392893Sdfr} 7402893Sdfr 7412893Sdfr/* 7422893Sdfr * Check to see if the directory described by target is in some 7432893Sdfr * subdirectory of source. This prevents something like the following from 7442893Sdfr * succeeding and leaving a bunch or files and directories orphaned. mv 7452893Sdfr * /a/b/c /a/b/c/d/e/f Where c and f are directories. 7462893Sdfr * 7472893Sdfr * source - the inode for /a/b/c 7482893Sdfr * target - the inode for /a/b/c/d/e/f 7492893Sdfr * 7502893Sdfr * Returns 0 if target is NOT a subdirectory of source. 7512893Sdfr * Otherwise returns a non-zero error number. 7522893Sdfr * The target inode is always unlocked on return. 7532893Sdfr */ 7542893Sdfrint 7552893Sdfrdoscheckpath(source, target) 7562893Sdfr struct denode *source; 7572893Sdfr struct denode *target; 7582893Sdfr{ 7592893Sdfr daddr_t scn; 7602893Sdfr struct msdosfsmount *pmp; 7612893Sdfr struct direntry *ep; 7622893Sdfr struct denode *dep; 7632893Sdfr struct buf *bp = NULL; 7642893Sdfr int error = 0; 7652893Sdfr 7662893Sdfr dep = target; 7672893Sdfr if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 7682893Sdfr (source->de_Attributes & ATTR_DIRECTORY) == 0) { 7692893Sdfr error = ENOTDIR; 7702893Sdfr goto out; 7712893Sdfr } 7722893Sdfr if (dep->de_StartCluster == source->de_StartCluster) { 7732893Sdfr error = EEXIST; 7742893Sdfr goto out; 7752893Sdfr } 7762893Sdfr if (dep->de_StartCluster == MSDOSFSROOT) 7772893Sdfr goto out; 77833548Sjkh pmp = dep->de_pmp; 77933548Sjkh#ifdef DIAGNOSTIC 78033548Sjkh if (pmp != source->de_pmp) 78133548Sjkh panic("doscheckpath: source and target on different filesystems"); 78233548Sjkh#endif 78333548Sjkh if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk) 78433548Sjkh goto out; 78533548Sjkh 7862893Sdfr for (;;) { 7872893Sdfr if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 7882893Sdfr error = ENOTDIR; 78933548Sjkh break; 7902893Sdfr } 7912893Sdfr scn = dep->de_StartCluster; 7922893Sdfr error = bread(pmp->pm_devvp, cntobn(pmp, scn), 79333548Sjkh pmp->pm_bpcluster, NOCRED, &bp); 79433548Sjkh if (error) 7952893Sdfr break; 79633548Sjkh 7972893Sdfr ep = (struct direntry *) bp->b_data + 1; 7982893Sdfr if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 7992893Sdfr bcmp(ep->deName, ".. ", 11) != 0) { 8002893Sdfr error = ENOTDIR; 8012893Sdfr break; 8022893Sdfr } 8032893Sdfr scn = getushort(ep->deStartCluster); 80433548Sjkh if (FAT32(pmp)) 80533548Sjkh scn |= getushort(ep->deHighClust) << 16; 80633548Sjkh 8072893Sdfr if (scn == source->de_StartCluster) { 8082893Sdfr error = EINVAL; 8092893Sdfr break; 8102893Sdfr } 8112893Sdfr if (scn == MSDOSFSROOT) 8122893Sdfr break; 81333548Sjkh if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 81433548Sjkh /* 81533548Sjkh * scn should be 0 in this case, 81633548Sjkh * but we silently ignore the error. 81733548Sjkh */ 81833548Sjkh break; 81933548Sjkh } 82033548Sjkh 8212893Sdfr vput(DETOV(dep)); 8222893Sdfr brelse(bp); 8232893Sdfr bp = NULL; 82433548Sjkh /* NOTE: deget() clears dep on error */ 82533548Sjkh if ((error = deget(pmp, scn, 0, &dep)) != 0) 8262893Sdfr break; 8272893Sdfr } 82833548Sjkhout:; 8292893Sdfr if (bp) 8302893Sdfr brelse(bp); 8312893Sdfr if (error == ENOTDIR) 8322893Sdfr printf("doscheckpath(): .. not a directory?\n"); 8332893Sdfr if (dep != NULL) 8342893Sdfr vput(DETOV(dep)); 83533548Sjkh return (error); 8362893Sdfr} 8372893Sdfr 8382893Sdfr/* 8392893Sdfr * Read in the disk block containing the directory entry (dirclu, dirofs) 8402893Sdfr * and return the address of the buf header, and the address of the 8412893Sdfr * directory entry within the block. 8422893Sdfr */ 8432893Sdfrint 84433548Sjkhreadep(pmp, dirclust, diroffset, bpp, epp) 8452893Sdfr struct msdosfsmount *pmp; 84633548Sjkh u_long dirclust, diroffset; 8472893Sdfr struct buf **bpp; 8482893Sdfr struct direntry **epp; 8492893Sdfr{ 8502893Sdfr int error; 8512893Sdfr daddr_t bn; 85233548Sjkh int blsize; 8532893Sdfr 85433548Sjkh blsize = pmp->pm_bpcluster; 85533548Sjkh if (dirclust == MSDOSFSROOT 85633548Sjkh && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 85733548Sjkh blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 85833548Sjkh bn = detobn(pmp, dirclust, diroffset); 85933548Sjkh if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { 86033548Sjkh brelse(*bpp); 8612893Sdfr *bpp = NULL; 86233548Sjkh return (error); 8632893Sdfr } 8642893Sdfr if (epp) 86533548Sjkh *epp = bptoep(pmp, *bpp, diroffset); 86633548Sjkh return (0); 8672893Sdfr} 8682893Sdfr 8692893Sdfr/* 8702893Sdfr * Read in the disk block containing the directory entry dep came from and 8712893Sdfr * return the address of the buf header, and the address of the directory 8722893Sdfr * entry within the block. 8732893Sdfr */ 8742893Sdfrint 8752893Sdfrreadde(dep, bpp, epp) 8762893Sdfr struct denode *dep; 8772893Sdfr struct buf **bpp; 8782893Sdfr struct direntry **epp; 8792893Sdfr{ 88033548Sjkh 88133548Sjkh return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 88233548Sjkh bpp, epp)); 8832893Sdfr} 88433548Sjkh 88533548Sjkh/* 88633548Sjkh * Remove a directory entry. At this point the file represented by the 88733548Sjkh * directory entry to be removed is still full length until noone has it 88833548Sjkh * open. When the file no longer being used msdosfs_inactive() is called 88933548Sjkh * and will truncate the file to 0 length. When the vnode containing the 89033548Sjkh * denode is needed for some other purpose by VFS it will call 89133548Sjkh * msdosfs_reclaim() which will remove the denode from the denode cache. 89233548Sjkh */ 89333548Sjkhint 89433548Sjkhremovede(pdep, dep) 89533548Sjkh struct denode *pdep; /* directory where the entry is removed */ 89633548Sjkh struct denode *dep; /* file to be removed */ 89733548Sjkh{ 89833548Sjkh int error; 89933548Sjkh struct direntry *ep; 90033548Sjkh struct buf *bp; 90133548Sjkh daddr_t bn; 90233548Sjkh int blsize; 90333548Sjkh struct msdosfsmount *pmp = pdep->de_pmp; 90433548Sjkh u_long offset = pdep->de_fndoffset; 90533548Sjkh 90633548Sjkh#ifdef MSDOSFS_DEBUG 90733548Sjkh printf("removede(): filename %s, dep %p, offset %08lx\n", 90833548Sjkh dep->de_Name, dep, offset); 90933548Sjkh#endif 91033548Sjkh 91133548Sjkh dep->de_refcnt--; 91233548Sjkh offset += sizeof(struct direntry); 91333548Sjkh do { 91433548Sjkh offset -= sizeof(struct direntry); 91533548Sjkh error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 91633548Sjkh if (error) 91733548Sjkh return error; 91833548Sjkh error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 91933548Sjkh if (error) { 92033548Sjkh brelse(bp); 92133548Sjkh return error; 92233548Sjkh } 92333548Sjkh ep = bptoep(pmp, bp, offset); 92433548Sjkh /* 92533548Sjkh * Check whether, if we came here the second time, i.e. 92633548Sjkh * when underflowing into the previous block, the last 92733548Sjkh * entry in this block is a longfilename entry, too. 92833548Sjkh */ 92933548Sjkh if (ep->deAttributes != ATTR_WIN95 93033548Sjkh && offset != pdep->de_fndoffset) { 93133548Sjkh brelse(bp); 93233548Sjkh break; 93333548Sjkh } 93433548Sjkh offset += sizeof(struct direntry); 93533548Sjkh while (1) { 93633548Sjkh /* 93733548Sjkh * We are a bit agressive here in that we delete any Win95 93833548Sjkh * entries preceding this entry, not just the ones we "own". 93933548Sjkh * Since these presumably aren't valid anyway, 94033548Sjkh * there should be no harm. 94133548Sjkh */ 94233548Sjkh offset -= sizeof(struct direntry); 94333548Sjkh ep--->deName[0] = SLOT_DELETED; 94433548Sjkh if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 94533548Sjkh || !(offset & pmp->pm_crbomask) 94633548Sjkh || ep->deAttributes != ATTR_WIN95) 94733548Sjkh break; 94833548Sjkh } 94933548Sjkh if ((error = bwrite(bp)) != 0) 95033548Sjkh return error; 95133548Sjkh } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 95233548Sjkh && !(offset & pmp->pm_crbomask) 95333548Sjkh && offset); 95433548Sjkh return 0; 95533548Sjkh} 95633548Sjkh 95733548Sjkh/* 95833548Sjkh * Create a unique DOS name in dvp 95933548Sjkh */ 96033548Sjkhint 96133548Sjkhuniqdosname(dep, cnp, cp) 96233548Sjkh struct denode *dep; 96333548Sjkh struct componentname *cnp; 96433548Sjkh u_char *cp; 96533548Sjkh{ 96633548Sjkh struct msdosfsmount *pmp = dep->de_pmp; 96733548Sjkh struct direntry *dentp; 96833548Sjkh int gen; 96933548Sjkh int blsize; 97033548Sjkh u_long cn; 97133548Sjkh daddr_t bn; 97233548Sjkh struct buf *bp; 97333548Sjkh int error; 97436133Sdt 97536154Sdt if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 97636133Sdt return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 977120492Sfjoe cnp->cn_namelen, 0, pmp) ? 0 : EINVAL); 97833548Sjkh 97933548Sjkh for (gen = 1;; gen++) { 98033548Sjkh /* 98133548Sjkh * Generate DOS name with generation number 98233548Sjkh */ 98333548Sjkh if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 984120492Sfjoe cnp->cn_namelen, gen, pmp)) 98533548Sjkh return gen == 1 ? EINVAL : EEXIST; 98633548Sjkh 98733548Sjkh /* 98833548Sjkh * Now look for a dir entry with this exact name 98933548Sjkh */ 99033548Sjkh for (cn = error = 0; !error; cn++) { 99133548Sjkh if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 99233548Sjkh if (error == E2BIG) /* EOF reached and not found */ 99333548Sjkh return 0; 99433548Sjkh return error; 99533548Sjkh } 99633548Sjkh error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 99733548Sjkh if (error) { 99833548Sjkh brelse(bp); 99933548Sjkh return error; 100033548Sjkh } 100133548Sjkh for (dentp = (struct direntry *)bp->b_data; 100233548Sjkh (char *)dentp < bp->b_data + blsize; 100333548Sjkh dentp++) { 100433548Sjkh if (dentp->deName[0] == SLOT_EMPTY) { 100533548Sjkh /* 100633548Sjkh * Last used entry and not found 100733548Sjkh */ 100833548Sjkh brelse(bp); 100933548Sjkh return 0; 101033548Sjkh } 101133548Sjkh /* 101233548Sjkh * Ignore volume labels and Win95 entries 101333548Sjkh */ 101433548Sjkh if (dentp->deAttributes & ATTR_VOLUME) 101533548Sjkh continue; 101633548Sjkh if (!bcmp(dentp->deName, cp, 11)) { 101733548Sjkh error = EEXIST; 101833548Sjkh break; 101933548Sjkh } 102033548Sjkh } 102133548Sjkh brelse(bp); 102233548Sjkh } 102333548Sjkh } 102433548Sjkh} 102533548Sjkh 102633548Sjkh/* 102733548Sjkh * Find any Win'95 long filename entry in directory dep 102833548Sjkh */ 102933548Sjkhint 103033548Sjkhfindwin95(dep) 103133548Sjkh struct denode *dep; 103233548Sjkh{ 103333548Sjkh struct msdosfsmount *pmp = dep->de_pmp; 103433548Sjkh struct direntry *dentp; 103542252Sdt int blsize, win95; 103633548Sjkh u_long cn; 103733548Sjkh daddr_t bn; 103833548Sjkh struct buf *bp; 103933548Sjkh 104042252Sdt win95 = 1; 104133548Sjkh /* 104233548Sjkh * Read through the directory looking for Win'95 entries 104333548Sjkh * Note: Error currently handled just as EOF XXX 104433548Sjkh */ 104533548Sjkh for (cn = 0;; cn++) { 104633548Sjkh if (pcbmap(dep, cn, &bn, 0, &blsize)) 104742252Sdt return (win95); 104833548Sjkh if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) { 104933548Sjkh brelse(bp); 105042252Sdt return (win95); 105133548Sjkh } 105233548Sjkh for (dentp = (struct direntry *)bp->b_data; 105333548Sjkh (char *)dentp < bp->b_data + blsize; 105433548Sjkh dentp++) { 105533548Sjkh if (dentp->deName[0] == SLOT_EMPTY) { 105633548Sjkh /* 105733548Sjkh * Last used entry and not found 105833548Sjkh */ 105933548Sjkh brelse(bp); 106042252Sdt return (win95); 106133548Sjkh } 106233548Sjkh if (dentp->deName[0] == SLOT_DELETED) { 106333548Sjkh /* 106433548Sjkh * Ignore deleted files 106533548Sjkh * Note: might be an indication of Win'95 anyway XXX 106633548Sjkh */ 106733548Sjkh continue; 106833548Sjkh } 106933548Sjkh if (dentp->deAttributes == ATTR_WIN95) { 107033548Sjkh brelse(bp); 107133548Sjkh return 1; 107233548Sjkh } 107342252Sdt win95 = 0; 107433548Sjkh } 107533548Sjkh brelse(bp); 107633548Sjkh } 107733548Sjkh} 1078