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