1c3aac50fSPeter Wemm /* $FreeBSD$ */ 2952a6212SJordan K. Hubbard /* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ 327a0bc89SDoug Rabson 427a0bc89SDoug Rabson /*- 5952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 6952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 727a0bc89SDoug Rabson * All rights reserved. 827a0bc89SDoug Rabson * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 927a0bc89SDoug Rabson * 1027a0bc89SDoug Rabson * Redistribution and use in source and binary forms, with or without 1127a0bc89SDoug Rabson * modification, are permitted provided that the following conditions 1227a0bc89SDoug Rabson * are met: 1327a0bc89SDoug Rabson * 1. Redistributions of source code must retain the above copyright 1427a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer. 1527a0bc89SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1627a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1727a0bc89SDoug Rabson * documentation and/or other materials provided with the distribution. 1827a0bc89SDoug Rabson * 3. All advertising materials mentioning features or use of this software 1927a0bc89SDoug Rabson * must display the following acknowledgement: 2027a0bc89SDoug Rabson * This product includes software developed by TooLs GmbH. 2127a0bc89SDoug Rabson * 4. The name of TooLs GmbH may not be used to endorse or promote products 2227a0bc89SDoug Rabson * derived from this software without specific prior written permission. 2327a0bc89SDoug Rabson * 2427a0bc89SDoug Rabson * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2527a0bc89SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2627a0bc89SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2727a0bc89SDoug Rabson * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2827a0bc89SDoug Rabson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2927a0bc89SDoug Rabson * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3027a0bc89SDoug Rabson * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3127a0bc89SDoug Rabson * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3227a0bc89SDoug Rabson * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3327a0bc89SDoug Rabson * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3427a0bc89SDoug Rabson */ 35d167cf6fSWarner Losh /*- 3627a0bc89SDoug Rabson * Written by Paul Popelka (paulp@uts.amdahl.com) 3727a0bc89SDoug Rabson * 3827a0bc89SDoug Rabson * You can do anything you want with this software, just don't say you wrote 3927a0bc89SDoug Rabson * it, and don't remove this notice. 4027a0bc89SDoug Rabson * 4127a0bc89SDoug Rabson * This software is provided "as is". 4227a0bc89SDoug Rabson * 4327a0bc89SDoug Rabson * The author supplies this software to be publicly redistributed on the 4427a0bc89SDoug Rabson * understanding that the author is not responsible for the correct 4527a0bc89SDoug Rabson * functioning of this software in any circumstances and is not liable for 4627a0bc89SDoug Rabson * any damages caused by this software. 4727a0bc89SDoug Rabson * 4827a0bc89SDoug Rabson * October 1992 4927a0bc89SDoug Rabson */ 5027a0bc89SDoug Rabson 5127a0bc89SDoug Rabson #include <sys/param.h> 52919d1ea2SPeter Wemm #include <sys/systm.h> 5327a0bc89SDoug Rabson #include <sys/buf.h> 5427a0bc89SDoug Rabson #include <sys/mount.h> 55a878a31cSBruce Evans #include <sys/namei.h> 56a878a31cSBruce Evans #include <sys/vnode.h> 5727a0bc89SDoug Rabson 581166fb51SRuslan Ermilov #include <fs/msdosfs/bpb.h> 591166fb51SRuslan Ermilov #include <fs/msdosfs/direntry.h> 601166fb51SRuslan Ermilov #include <fs/msdosfs/denode.h> 611166fb51SRuslan Ermilov #include <fs/msdosfs/fat.h> 62a878a31cSBruce Evans #include <fs/msdosfs/msdosfsmount.h> 6327a0bc89SDoug Rabson 64db811dd7SKonstantin Belousov static int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp, 65db811dd7SKonstantin Belousov struct componentname *cnp, u_int64_t *inum); 66db811dd7SKonstantin Belousov 67db811dd7SKonstantin Belousov int 68db811dd7SKonstantin Belousov msdosfs_lookup(struct vop_cachedlookup_args *ap) 69db811dd7SKonstantin Belousov { 70db811dd7SKonstantin Belousov 71db811dd7SKonstantin Belousov return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); 72db811dd7SKonstantin Belousov } 73db811dd7SKonstantin Belousov 74*a6945216SKonstantin Belousov struct deget_dotdot { 75*a6945216SKonstantin Belousov u_long cluster; 76*a6945216SKonstantin Belousov int blkoff; 77*a6945216SKonstantin Belousov }; 78*a6945216SKonstantin Belousov 79*a6945216SKonstantin Belousov static int 80*a6945216SKonstantin Belousov msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags, 81*a6945216SKonstantin Belousov struct vnode **rvp) 82*a6945216SKonstantin Belousov { 83*a6945216SKonstantin Belousov struct deget_dotdot *dd_arg; 84*a6945216SKonstantin Belousov struct denode *rdp; 85*a6945216SKonstantin Belousov struct msdosfsmount *pmp; 86*a6945216SKonstantin Belousov int error; 87*a6945216SKonstantin Belousov 88*a6945216SKonstantin Belousov pmp = VFSTOMSDOSFS(mp); 89*a6945216SKonstantin Belousov dd_arg = arg; 90*a6945216SKonstantin Belousov error = deget(pmp, dd_arg->cluster, dd_arg->blkoff, &rdp); 91*a6945216SKonstantin Belousov if (error == 0) 92*a6945216SKonstantin Belousov *rvp = DETOV(rdp); 93*a6945216SKonstantin Belousov return (error); 94*a6945216SKonstantin Belousov } 95*a6945216SKonstantin Belousov 9627a0bc89SDoug Rabson /* 9727a0bc89SDoug Rabson * When we search a directory the blocks containing directory entries are 9827a0bc89SDoug Rabson * read and examined. The directory entries contain information that would 9927a0bc89SDoug Rabson * normally be in the inode of a unix filesystem. This means that some of 10027a0bc89SDoug Rabson * a directory's contents may also be in memory resident denodes (sort of 10127a0bc89SDoug Rabson * an inode). This can cause problems if we are searching while some other 10227a0bc89SDoug Rabson * process is modifying a directory. To prevent one process from accessing 10327a0bc89SDoug Rabson * incompletely modified directory information we depend upon being the 104b84d2921SPoul-Henning Kamp * sole owner of a directory block. bread/brelse provide this service. 10527a0bc89SDoug Rabson * This being the case, when a process modifies a directory it must first 10627a0bc89SDoug Rabson * acquire the disk block that contains the directory entry to be modified. 10727a0bc89SDoug Rabson * Then update the disk block and the denode, and then write the disk block 10827a0bc89SDoug Rabson * out to disk. This way disk blocks containing directory entries and in 10927a0bc89SDoug Rabson * memory denode's will be in synch. 11027a0bc89SDoug Rabson */ 111db811dd7SKonstantin Belousov static int 112db811dd7SKonstantin Belousov msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp, 113db811dd7SKonstantin Belousov struct componentname *cnp, u_int64_t *dd_inum) 11427a0bc89SDoug Rabson { 115c2819440SBruce Evans struct mbnambuf nb; 11627a0bc89SDoug Rabson daddr_t bn; 11727a0bc89SDoug Rabson int error; 118952a6212SJordan K. Hubbard int slotcount; 119952a6212SJordan K. Hubbard int slotoffset = 0; 12027a0bc89SDoug Rabson int frcn; 12127a0bc89SDoug Rabson u_long cluster; 122952a6212SJordan K. Hubbard int blkoff; 12327a0bc89SDoug Rabson int diroff; 124952a6212SJordan K. Hubbard int blsize; 12527a0bc89SDoug Rabson int isadir; /* ~0 if found direntry is a directory */ 12627a0bc89SDoug Rabson u_long scn; /* starting cluster number */ 12727a0bc89SDoug Rabson struct vnode *pdp; 12827a0bc89SDoug Rabson struct denode *dp; 12927a0bc89SDoug Rabson struct denode *tdp; 13027a0bc89SDoug Rabson struct msdosfsmount *pmp; 131f7a3729cSKevin Lo struct buf *bp = NULL; 13227a0bc89SDoug Rabson struct direntry *dep = NULL; 133*a6945216SKonstantin Belousov struct deget_dotdot dd_arg; 13427a0bc89SDoug Rabson u_char dosfilename[12]; 13527a0bc89SDoug Rabson int flags = cnp->cn_flags; 13627a0bc89SDoug Rabson int nameiop = cnp->cn_nameiop; 13769a36f24SMike Smith int unlen; 138db811dd7SKonstantin Belousov u_int64_t inode1; 13927a0bc89SDoug Rabson 140952a6212SJordan K. Hubbard int wincnt = 1; 1416a5bf04aSTim J. Robbins int chksum = -1, chksum_ok; 142952a6212SJordan K. Hubbard int olddos = 1; 143952a6212SJordan K. Hubbard 14427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 14527a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); 14627a0bc89SDoug Rabson #endif 14727a0bc89SDoug Rabson dp = VTODE(vdp); 14827a0bc89SDoug Rabson pmp = dp->de_pmp; 14927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 150952a6212SJordan K. Hubbard printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", 15127a0bc89SDoug Rabson vdp, dp, dp->de_Attributes); 15227a0bc89SDoug Rabson #endif 15327a0bc89SDoug Rabson 154db811dd7SKonstantin Belousov restart: 15584caee6bSKonstantin Belousov if (vpp != NULL) 15684caee6bSKonstantin Belousov *vpp = NULL; 15727a0bc89SDoug Rabson /* 15827a0bc89SDoug Rabson * If they are going after the . or .. entry in the root directory, 15927a0bc89SDoug Rabson * they won't find it. DOS filesystems don't have them in the root 16027a0bc89SDoug Rabson * directory. So, we fake it. deget() is in on this scam too. 16127a0bc89SDoug Rabson */ 162e6e370a7SJeff Roberson if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && 16327a0bc89SDoug Rabson (cnp->cn_namelen == 1 || 16427a0bc89SDoug Rabson (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 16527a0bc89SDoug Rabson isadir = ATTR_DIRECTORY; 16627a0bc89SDoug Rabson scn = MSDOSFSROOT; 16727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 16827a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 16927a0bc89SDoug Rabson #endif 17027a0bc89SDoug Rabson cluster = MSDOSFSROOT; 171952a6212SJordan K. Hubbard blkoff = MSDOSFSROOT_OFS; 17227a0bc89SDoug Rabson goto foundroot; 17327a0bc89SDoug Rabson } 17427a0bc89SDoug Rabson 175952a6212SJordan K. Hubbard switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 176c4f02a89SMax Khon cnp->cn_namelen, 0, pmp)) { 177952a6212SJordan K. Hubbard case 0: 178952a6212SJordan K. Hubbard return (EINVAL); 179952a6212SJordan K. Hubbard case 1: 180952a6212SJordan K. Hubbard break; 181952a6212SJordan K. Hubbard case 2: 182952a6212SJordan K. Hubbard wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 183c4f02a89SMax Khon cnp->cn_namelen, pmp) + 1; 184952a6212SJordan K. Hubbard break; 185952a6212SJordan K. Hubbard case 3: 186952a6212SJordan K. Hubbard olddos = 0; 187952a6212SJordan K. Hubbard wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 188c4f02a89SMax Khon cnp->cn_namelen, pmp) + 1; 189952a6212SJordan K. Hubbard break; 19027a0bc89SDoug Rabson } 191011cdb57SDmitrij Tejblum if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) { 192952a6212SJordan K. Hubbard wincnt = 1; 193011cdb57SDmitrij Tejblum olddos = 1; 194011cdb57SDmitrij Tejblum } 19569a36f24SMike Smith unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen); 19627a0bc89SDoug Rabson 197952a6212SJordan K. Hubbard /* 198952a6212SJordan K. Hubbard * Suppress search for slots unless creating 199952a6212SJordan K. Hubbard * file and at end of pathname, in which case 200952a6212SJordan K. Hubbard * we watch for a place to put the new file in 201952a6212SJordan K. Hubbard * case it doesn't already exist. 202952a6212SJordan K. Hubbard */ 203952a6212SJordan K. Hubbard slotcount = wincnt; 204952a6212SJordan K. Hubbard if ((nameiop == CREATE || nameiop == RENAME) && 205952a6212SJordan K. Hubbard (flags & ISLASTCN)) 206952a6212SJordan K. Hubbard slotcount = 0; 207952a6212SJordan K. Hubbard 20827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 209952a6212SJordan K. Hubbard printf("msdosfs_lookup(): dos version of filename %s, length %ld\n", 21027a0bc89SDoug Rabson dosfilename, cnp->cn_namelen); 21127a0bc89SDoug Rabson #endif 21227a0bc89SDoug Rabson /* 21327a0bc89SDoug Rabson * Search the directory pointed at by vdp for the name pointed at 21427a0bc89SDoug Rabson * by cnp->cn_nameptr. 21527a0bc89SDoug Rabson */ 21627a0bc89SDoug Rabson tdp = NULL; 217c2819440SBruce Evans mbnambuf_init(&nb); 21827a0bc89SDoug Rabson /* 21927a0bc89SDoug Rabson * The outer loop ranges over the clusters that make up the 22027a0bc89SDoug Rabson * directory. Note that the root directory is different from all 22127a0bc89SDoug Rabson * other directories. It has a fixed number of blocks that are not 22227a0bc89SDoug Rabson * part of the pool of allocatable clusters. So, we treat it a 22327a0bc89SDoug Rabson * little differently. The root directory starts at "cluster" 0. 22427a0bc89SDoug Rabson */ 225952a6212SJordan K. Hubbard diroff = 0; 22627a0bc89SDoug Rabson for (frcn = 0;; frcn++) { 227952a6212SJordan K. Hubbard error = pcbmap(dp, frcn, &bn, &cluster, &blsize); 228c3c6d51eSPoul-Henning Kamp if (error) { 22927a0bc89SDoug Rabson if (error == E2BIG) 23027a0bc89SDoug Rabson break; 231952a6212SJordan K. Hubbard return (error); 23227a0bc89SDoug Rabson } 233952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 234952a6212SJordan K. Hubbard if (error) { 235952a6212SJordan K. Hubbard brelse(bp); 236952a6212SJordan K. Hubbard return (error); 237952a6212SJordan K. Hubbard } 238952a6212SJordan K. Hubbard for (blkoff = 0; blkoff < blsize; 239952a6212SJordan K. Hubbard blkoff += sizeof(struct direntry), 240952a6212SJordan K. Hubbard diroff += sizeof(struct direntry)) { 241952a6212SJordan K. Hubbard dep = (struct direntry *)(bp->b_data + blkoff); 24227a0bc89SDoug Rabson /* 24327a0bc89SDoug Rabson * If the slot is empty and we are still looking 24427a0bc89SDoug Rabson * for an empty then remember this one. If the 24527a0bc89SDoug Rabson * slot is not empty then check to see if it 24627a0bc89SDoug Rabson * matches what we are looking for. If the slot 24727a0bc89SDoug Rabson * has never been filled with anything, then the 24827a0bc89SDoug Rabson * remainder of the directory has never been used, 24927a0bc89SDoug Rabson * so there is no point in searching it. 25027a0bc89SDoug Rabson */ 25127a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY || 25227a0bc89SDoug Rabson dep->deName[0] == SLOT_DELETED) { 253952a6212SJordan K. Hubbard /* 254952a6212SJordan K. Hubbard * Drop memory of previous long matches 255952a6212SJordan K. Hubbard */ 256952a6212SJordan K. Hubbard chksum = -1; 257c2819440SBruce Evans mbnambuf_init(&nb); 258952a6212SJordan K. Hubbard 259952a6212SJordan K. Hubbard if (slotcount < wincnt) { 260952a6212SJordan K. Hubbard slotcount++; 26127a0bc89SDoug Rabson slotoffset = diroff; 26227a0bc89SDoug Rabson } 26327a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY) { 26427a0bc89SDoug Rabson brelse(bp); 26527a0bc89SDoug Rabson goto notfound; 26627a0bc89SDoug Rabson } 26727a0bc89SDoug Rabson } else { 26827a0bc89SDoug Rabson /* 269952a6212SJordan K. Hubbard * If there wasn't enough space for our winentries, 270952a6212SJordan K. Hubbard * forget about the empty space 271952a6212SJordan K. Hubbard */ 272952a6212SJordan K. Hubbard if (slotcount < wincnt) 273952a6212SJordan K. Hubbard slotcount = 0; 274952a6212SJordan K. Hubbard 275952a6212SJordan K. Hubbard /* 276952a6212SJordan K. Hubbard * Check for Win95 long filename entry 277952a6212SJordan K. Hubbard */ 278952a6212SJordan K. Hubbard if (dep->deAttributes == ATTR_WIN95) { 279952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 280952a6212SJordan K. Hubbard continue; 281952a6212SJordan K. Hubbard 282c2819440SBruce Evans chksum = win2unixfn(&nb, 283c2819440SBruce Evans (struct winentry *)dep, chksum, 284c4f02a89SMax Khon pmp); 285c4f02a89SMax Khon continue; 286c4f02a89SMax Khon } 287c4f02a89SMax Khon 288c2819440SBruce Evans chksum = winChkName(&nb, 289c2819440SBruce Evans (const u_char *)cnp->cn_nameptr, unlen, 290c2819440SBruce Evans chksum, pmp); 291c4f02a89SMax Khon if (chksum == -2) { 292c4f02a89SMax Khon chksum = -1; 293952a6212SJordan K. Hubbard continue; 294952a6212SJordan K. Hubbard } 295952a6212SJordan K. Hubbard 296952a6212SJordan K. Hubbard /* 29727a0bc89SDoug Rabson * Ignore volume labels (anywhere, not just 29827a0bc89SDoug Rabson * the root directory). 29927a0bc89SDoug Rabson */ 300952a6212SJordan K. Hubbard if (dep->deAttributes & ATTR_VOLUME) { 301952a6212SJordan K. Hubbard chksum = -1; 302952a6212SJordan K. Hubbard continue; 303952a6212SJordan K. Hubbard } 304952a6212SJordan K. Hubbard 305952a6212SJordan K. Hubbard /* 306952a6212SJordan K. Hubbard * Check for a checksum or name match 307952a6212SJordan K. Hubbard */ 30848d1bcf8SKonstantin Belousov chksum_ok = (chksum == winChksum(dep->deName)); 3096a5bf04aSTim J. Robbins if (!chksum_ok 310952a6212SJordan K. Hubbard && (!olddos || bcmp(dosfilename, dep->deName, 11))) { 311952a6212SJordan K. Hubbard chksum = -1; 312952a6212SJordan K. Hubbard continue; 313952a6212SJordan K. Hubbard } 31427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 315952a6212SJordan K. Hubbard printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", 316952a6212SJordan K. Hubbard blkoff, diroff); 31727a0bc89SDoug Rabson #endif 31827a0bc89SDoug Rabson /* 31927a0bc89SDoug Rabson * Remember where this directory 32027a0bc89SDoug Rabson * entry came from for whoever did 321952a6212SJordan K. Hubbard * this lookup. 32227a0bc89SDoug Rabson */ 32327a0bc89SDoug Rabson dp->de_fndoffset = diroff; 3246a5bf04aSTim J. Robbins if (chksum_ok && nameiop == RENAME) { 3256a5bf04aSTim J. Robbins /* 3266a5bf04aSTim J. Robbins * Target had correct long name 3276a5bf04aSTim J. Robbins * directory entries, reuse them 3286a5bf04aSTim J. Robbins * as needed. 3296a5bf04aSTim J. Robbins */ 330191e6fd0SDmitrij Tejblum dp->de_fndcnt = wincnt - 1; 3316a5bf04aSTim J. Robbins } else { 3326a5bf04aSTim J. Robbins /* 3336a5bf04aSTim J. Robbins * Long name directory entries 3346a5bf04aSTim J. Robbins * not present or corrupt, can only 3356a5bf04aSTim J. Robbins * reuse dos directory entry. 3366a5bf04aSTim J. Robbins */ 3376a5bf04aSTim J. Robbins dp->de_fndcnt = 0; 3386a5bf04aSTim J. Robbins } 339952a6212SJordan K. Hubbard 34027a0bc89SDoug Rabson goto found; 34127a0bc89SDoug Rabson } 342952a6212SJordan K. Hubbard } /* for (blkoff = 0; .... */ 34327a0bc89SDoug Rabson /* 34427a0bc89SDoug Rabson * Release the buffer holding the directory cluster just 34527a0bc89SDoug Rabson * searched. 34627a0bc89SDoug Rabson */ 34727a0bc89SDoug Rabson brelse(bp); 34827a0bc89SDoug Rabson } /* for (frcn = 0; ; frcn++) */ 349952a6212SJordan K. Hubbard 350952a6212SJordan K. Hubbard notfound: 35127a0bc89SDoug Rabson /* 35227a0bc89SDoug Rabson * We hold no disk buffers at this point. 35327a0bc89SDoug Rabson */ 35427a0bc89SDoug Rabson 35527a0bc89SDoug Rabson /* 356952a6212SJordan K. Hubbard * Fixup the slot description to point to the place where 357952a6212SJordan K. Hubbard * we might put the new DOS direntry (putting the Win95 358952a6212SJordan K. Hubbard * long name entries before that) 359952a6212SJordan K. Hubbard */ 360952a6212SJordan K. Hubbard if (!slotcount) { 361952a6212SJordan K. Hubbard slotcount = 1; 362952a6212SJordan K. Hubbard slotoffset = diroff; 363952a6212SJordan K. Hubbard } 364952a6212SJordan K. Hubbard if (wincnt > slotcount) 365952a6212SJordan K. Hubbard slotoffset += sizeof(struct direntry) * (wincnt - slotcount); 366952a6212SJordan K. Hubbard 367952a6212SJordan K. Hubbard /* 36827a0bc89SDoug Rabson * If we get here we didn't find the entry we were looking for. But 36927a0bc89SDoug Rabson * that's ok if we are creating or renaming and are at the end of 37027a0bc89SDoug Rabson * the pathname and the directory hasn't been removed. 37127a0bc89SDoug Rabson */ 37227a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 373952a6212SJordan K. Hubbard printf("msdosfs_lookup(): op %d, refcnt %ld\n", 374952a6212SJordan K. Hubbard nameiop, dp->de_refcnt); 375952a6212SJordan K. Hubbard printf(" slotcount %d, slotoffset %d\n", 376952a6212SJordan K. Hubbard slotcount, slotoffset); 37727a0bc89SDoug Rabson #endif 37827a0bc89SDoug Rabson if ((nameiop == CREATE || nameiop == RENAME) && 37927a0bc89SDoug Rabson (flags & ISLASTCN) && dp->de_refcnt != 0) { 380952a6212SJordan K. Hubbard /* 381952a6212SJordan K. Hubbard * Access for write is interpreted as allowing 382952a6212SJordan K. Hubbard * creation of files in the directory. 383952a6212SJordan K. Hubbard */ 384b40ce416SJulian Elischer error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 385d8762fa6SBruce Evans if (error) 386952a6212SJordan K. Hubbard return (error); 387952a6212SJordan K. Hubbard /* 388952a6212SJordan K. Hubbard * Return an indication of where the new directory 389952a6212SJordan K. Hubbard * entry should be put. 390952a6212SJordan K. Hubbard */ 39127a0bc89SDoug Rabson dp->de_fndoffset = slotoffset; 392952a6212SJordan K. Hubbard dp->de_fndcnt = wincnt - 1; 393952a6212SJordan K. Hubbard 394952a6212SJordan K. Hubbard /* 395952a6212SJordan K. Hubbard * We return with the directory locked, so that 396952a6212SJordan K. Hubbard * the parameters we set up above will still be 397952a6212SJordan K. Hubbard * valid if we actually decide to do a direnter(). 398952a6212SJordan K. Hubbard * We return ni_vp == NULL to indicate that the entry 399952a6212SJordan K. Hubbard * does not currently exist; we leave a pointer to 400952a6212SJordan K. Hubbard * the (locked) directory inode in ndp->ni_dvp. 401952a6212SJordan K. Hubbard * The pathname buffer is saved so that the name 402952a6212SJordan K. Hubbard * can be obtained later. 403952a6212SJordan K. Hubbard * 404952a6212SJordan K. Hubbard * NB - if the directory is unlocked, then this 405952a6212SJordan K. Hubbard * information cannot be used. 406952a6212SJordan K. Hubbard */ 40727a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 408952a6212SJordan K. Hubbard return (EJUSTRETURN); 40927a0bc89SDoug Rabson } 41023e8fcafSDavid Schultz #if 0 41127a0bc89SDoug Rabson /* 412952a6212SJordan K. Hubbard * Insert name into cache (as non-existent) if appropriate. 41323e8fcafSDavid Schultz * 41423e8fcafSDavid Schultz * XXX Negative caching is broken for msdosfs because the name 41523e8fcafSDavid Schultz * cache doesn't understand peculiarities such as case insensitivity 41623e8fcafSDavid Schultz * and 8.3 filenames. Hence, it may not invalidate all negative 41723e8fcafSDavid Schultz * entries if a file with this name is later created. 41827a0bc89SDoug Rabson */ 41927a0bc89SDoug Rabson if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 42027a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 42123e8fcafSDavid Schultz #endif 422952a6212SJordan K. Hubbard return (ENOENT); 42327a0bc89SDoug Rabson 424952a6212SJordan K. Hubbard found: 42527a0bc89SDoug Rabson /* 42627a0bc89SDoug Rabson * NOTE: We still have the buffer with matched directory entry at 42727a0bc89SDoug Rabson * this point. 42827a0bc89SDoug Rabson */ 42927a0bc89SDoug Rabson isadir = dep->deAttributes & ATTR_DIRECTORY; 43027a0bc89SDoug Rabson scn = getushort(dep->deStartCluster); 431952a6212SJordan K. Hubbard if (FAT32(pmp)) { 432952a6212SJordan K. Hubbard scn |= getushort(dep->deHighClust) << 16; 433952a6212SJordan K. Hubbard if (scn == pmp->pm_rootdirblk) { 434952a6212SJordan K. Hubbard /* 435952a6212SJordan K. Hubbard * There should actually be 0 here. 436952a6212SJordan K. Hubbard * Just ignore the error. 437952a6212SJordan K. Hubbard */ 438952a6212SJordan K. Hubbard scn = MSDOSFSROOT; 439952a6212SJordan K. Hubbard } 440952a6212SJordan K. Hubbard } 44127a0bc89SDoug Rabson 442952a6212SJordan K. Hubbard if (isadir) { 443952a6212SJordan K. Hubbard cluster = scn; 444952a6212SJordan K. Hubbard if (cluster == MSDOSFSROOT) 445952a6212SJordan K. Hubbard blkoff = MSDOSFSROOT_OFS; 446952a6212SJordan K. Hubbard else 447952a6212SJordan K. Hubbard blkoff = 0; 448952a6212SJordan K. Hubbard } else if (cluster == MSDOSFSROOT) 449952a6212SJordan K. Hubbard blkoff = diroff; 450952a6212SJordan K. Hubbard 451952a6212SJordan K. Hubbard /* 452952a6212SJordan K. Hubbard * Now release buf to allow deget to read the entry again. 453952a6212SJordan K. Hubbard * Reserving it here and giving it to deget could result 454952a6212SJordan K. Hubbard * in a deadlock. 455952a6212SJordan K. Hubbard */ 456952a6212SJordan K. Hubbard brelse(bp); 457952a6212SJordan K. Hubbard bp = 0; 458952a6212SJordan K. Hubbard 459952a6212SJordan K. Hubbard foundroot: 46027a0bc89SDoug Rabson /* 46127a0bc89SDoug Rabson * If we entered at foundroot, then we are looking for the . or .. 46227a0bc89SDoug Rabson * entry of the filesystems root directory. isadir and scn were 463952a6212SJordan K. Hubbard * setup before jumping here. And, bp is already null. 46427a0bc89SDoug Rabson */ 465952a6212SJordan K. Hubbard if (FAT32(pmp) && scn == MSDOSFSROOT) 466952a6212SJordan K. Hubbard scn = pmp->pm_rootdirblk; 46727a0bc89SDoug Rabson 468db811dd7SKonstantin Belousov if (dd_inum != NULL) { 469db811dd7SKonstantin Belousov *dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff; 470db811dd7SKonstantin Belousov return (0); 471db811dd7SKonstantin Belousov } 472db811dd7SKonstantin Belousov 47327a0bc89SDoug Rabson /* 474952a6212SJordan K. Hubbard * If deleting, and at end of pathname, return 475952a6212SJordan K. Hubbard * parameters which can be used to remove file. 47627a0bc89SDoug Rabson */ 47727a0bc89SDoug Rabson if (nameiop == DELETE && (flags & ISLASTCN)) { 478952a6212SJordan K. Hubbard /* 479952a6212SJordan K. Hubbard * Don't allow deleting the root. 480952a6212SJordan K. Hubbard */ 481952a6212SJordan K. Hubbard if (blkoff == MSDOSFSROOT_OFS) 4829ba671deSKonstantin Belousov return (EBUSY); 483952a6212SJordan K. Hubbard 484952a6212SJordan K. Hubbard /* 485952a6212SJordan K. Hubbard * Write access to directory required to delete files. 486952a6212SJordan K. Hubbard */ 487b40ce416SJulian Elischer error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 488952a6212SJordan K. Hubbard if (error) 489952a6212SJordan K. Hubbard return (error); 490952a6212SJordan K. Hubbard 491952a6212SJordan K. Hubbard /* 492952a6212SJordan K. Hubbard * Return pointer to current entry in dp->i_offset. 493952a6212SJordan K. Hubbard * Save directory inode pointer in ndp->ni_dvp for dirremove(). 494952a6212SJordan K. Hubbard */ 49527a0bc89SDoug Rabson if (dp->de_StartCluster == scn && isadir) { /* "." */ 49627a0bc89SDoug Rabson VREF(vdp); 49727a0bc89SDoug Rabson *vpp = vdp; 498952a6212SJordan K. Hubbard return (0); 49927a0bc89SDoug Rabson } 500952a6212SJordan K. Hubbard error = deget(pmp, cluster, blkoff, &tdp); 501952a6212SJordan K. Hubbard if (error) 502952a6212SJordan K. Hubbard return (error); 50327a0bc89SDoug Rabson *vpp = DETOV(tdp); 504952a6212SJordan K. Hubbard return (0); 50527a0bc89SDoug Rabson } 50627a0bc89SDoug Rabson 50727a0bc89SDoug Rabson /* 508952a6212SJordan K. Hubbard * If rewriting (RENAME), return the inode and the 509952a6212SJordan K. Hubbard * information required to rewrite the present directory 510952a6212SJordan K. Hubbard * Must get inode of directory entry to verify it's a 511952a6212SJordan K. Hubbard * regular file, or empty directory. 51227a0bc89SDoug Rabson */ 513fcc9c112SJeff Roberson if (nameiop == RENAME && (flags & ISLASTCN)) { 514952a6212SJordan K. Hubbard if (blkoff == MSDOSFSROOT_OFS) 5159ba671deSKonstantin Belousov return (EBUSY); 516952a6212SJordan K. Hubbard 517b40ce416SJulian Elischer error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread); 518952a6212SJordan K. Hubbard if (error) 519952a6212SJordan K. Hubbard return (error); 520952a6212SJordan K. Hubbard 521952a6212SJordan K. Hubbard /* 522952a6212SJordan K. Hubbard * Careful about locking second inode. 523952a6212SJordan K. Hubbard * This can only occur if the target is ".". 524952a6212SJordan K. Hubbard */ 525952a6212SJordan K. Hubbard if (dp->de_StartCluster == scn && isadir) 526952a6212SJordan K. Hubbard return (EISDIR); 527952a6212SJordan K. Hubbard 528952a6212SJordan K. Hubbard if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 529952a6212SJordan K. Hubbard return (error); 53027a0bc89SDoug Rabson *vpp = DETOV(tdp); 53127a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 532952a6212SJordan K. Hubbard return (0); 53327a0bc89SDoug Rabson } 53427a0bc89SDoug Rabson 53527a0bc89SDoug Rabson /* 536952a6212SJordan K. Hubbard * Step through the translation in the name. We do not `vput' the 537952a6212SJordan K. Hubbard * directory because we may need it again if a symbolic link 538952a6212SJordan K. Hubbard * is relative to the current directory. Instead we save it 539952a6212SJordan K. Hubbard * unlocked as "pdp". We must get the target inode before unlocking 540952a6212SJordan K. Hubbard * the directory to insure that the inode will not be removed 541952a6212SJordan K. Hubbard * before we get it. We prevent deadlock by always fetching 542952a6212SJordan K. Hubbard * inodes from the root, moving down the directory tree. Thus 543952a6212SJordan K. Hubbard * when following backward pointers ".." we must unlock the 544952a6212SJordan K. Hubbard * parent directory before getting the requested directory. 54527a0bc89SDoug Rabson */ 54627a0bc89SDoug Rabson pdp = vdp; 54727a0bc89SDoug Rabson if (flags & ISDOTDOT) { 548*a6945216SKonstantin Belousov dd_arg.cluster = cluster; 549*a6945216SKonstantin Belousov dd_arg.blkoff = blkoff; 550*a6945216SKonstantin Belousov error = vn_vget_ino_gen(vdp, msdosfs_deget_dotdot, 551*a6945216SKonstantin Belousov &dd_arg, cnp->cn_lkflags, vpp); 552*a6945216SKonstantin Belousov if (error != 0) { 55384caee6bSKonstantin Belousov *vpp = NULL; 554952a6212SJordan K. Hubbard return (error); 55584caee6bSKonstantin Belousov } 556db811dd7SKonstantin Belousov /* 557db811dd7SKonstantin Belousov * Recheck that ".." still points to the inode we 558db811dd7SKonstantin Belousov * looked up before pdp lock was dropped. 559db811dd7SKonstantin Belousov */ 560db811dd7SKonstantin Belousov error = msdosfs_lookup_(pdp, NULL, cnp, &inode1); 561db811dd7SKonstantin Belousov if (error) { 562db811dd7SKonstantin Belousov vput(*vpp); 56384caee6bSKonstantin Belousov *vpp = NULL; 564db811dd7SKonstantin Belousov return (error); 565db811dd7SKonstantin Belousov } 566db811dd7SKonstantin Belousov if (VTODE(*vpp)->de_inode != inode1) { 567db811dd7SKonstantin Belousov vput(*vpp); 568db811dd7SKonstantin Belousov goto restart; 569db811dd7SKonstantin Belousov } 570952a6212SJordan K. Hubbard } else if (dp->de_StartCluster == scn && isadir) { 571952a6212SJordan K. Hubbard VREF(vdp); /* we want ourself, ie "." */ 57227a0bc89SDoug Rabson *vpp = vdp; 57327a0bc89SDoug Rabson } else { 574952a6212SJordan K. Hubbard if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 575952a6212SJordan K. Hubbard return (error); 57627a0bc89SDoug Rabson *vpp = DETOV(tdp); 57727a0bc89SDoug Rabson } 57827a0bc89SDoug Rabson 57927a0bc89SDoug Rabson /* 580952a6212SJordan K. Hubbard * Insert name into cache if appropriate. 58127a0bc89SDoug Rabson */ 58227a0bc89SDoug Rabson if (cnp->cn_flags & MAKEENTRY) 58327a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 584952a6212SJordan K. Hubbard return (0); 58527a0bc89SDoug Rabson } 58627a0bc89SDoug Rabson 58727a0bc89SDoug Rabson /* 58827a0bc89SDoug Rabson * dep - directory entry to copy into the directory 58927a0bc89SDoug Rabson * ddep - directory to add to 59027a0bc89SDoug Rabson * depp - return the address of the denode for the created directory entry 59127a0bc89SDoug Rabson * if depp != 0 592952a6212SJordan K. Hubbard * cnp - componentname needed for Win95 long filenames 59327a0bc89SDoug Rabson */ 59427a0bc89SDoug Rabson int 595952a6212SJordan K. Hubbard createde(dep, ddep, depp, cnp) 59627a0bc89SDoug Rabson struct denode *dep; 59727a0bc89SDoug Rabson struct denode *ddep; 59827a0bc89SDoug Rabson struct denode **depp; 599952a6212SJordan K. Hubbard struct componentname *cnp; 60027a0bc89SDoug Rabson { 60127a0bc89SDoug Rabson int error; 60227a0bc89SDoug Rabson u_long dirclust, diroffset; 60327a0bc89SDoug Rabson struct direntry *ndep; 60427a0bc89SDoug Rabson struct msdosfsmount *pmp = ddep->de_pmp; 60527a0bc89SDoug Rabson struct buf *bp; 606952a6212SJordan K. Hubbard daddr_t bn; 607952a6212SJordan K. Hubbard int blsize; 60827a0bc89SDoug Rabson 60927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 610952a6212SJordan K. Hubbard printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 611952a6212SJordan K. Hubbard dep, ddep, depp, cnp); 61227a0bc89SDoug Rabson #endif 61327a0bc89SDoug Rabson 61427a0bc89SDoug Rabson /* 61527a0bc89SDoug Rabson * If no space left in the directory then allocate another cluster 61627a0bc89SDoug Rabson * and chain it onto the end of the file. There is one exception 61727a0bc89SDoug Rabson * to this. That is, if the root directory has no more space it 61827a0bc89SDoug Rabson * can NOT be expanded. extendfile() checks for and fails attempts 61927a0bc89SDoug Rabson * to extend the root directory. We just return an error in that 62027a0bc89SDoug Rabson * case. 62127a0bc89SDoug Rabson */ 622952a6212SJordan K. Hubbard if (ddep->de_fndoffset >= ddep->de_FileSize) { 623952a6212SJordan K. Hubbard diroffset = ddep->de_fndoffset + sizeof(struct direntry) 624952a6212SJordan K. Hubbard - ddep->de_FileSize; 625952a6212SJordan K. Hubbard dirclust = de_clcount(pmp, diroffset); 626952a6212SJordan K. Hubbard error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); 627952a6212SJordan K. Hubbard if (error) { 628c52fd858SEdward Tomasz Napierala (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); 62927a0bc89SDoug Rabson return error; 630952a6212SJordan K. Hubbard } 631952a6212SJordan K. Hubbard 63227a0bc89SDoug Rabson /* 63327a0bc89SDoug Rabson * Update the size of the directory 63427a0bc89SDoug Rabson */ 635952a6212SJordan K. Hubbard ddep->de_FileSize += de_cn2off(pmp, dirclust); 636952a6212SJordan K. Hubbard } 637952a6212SJordan K. Hubbard 63827a0bc89SDoug Rabson /* 639952a6212SJordan K. Hubbard * We just read in the cluster with space. Copy the new directory 64027a0bc89SDoug Rabson * entry in. Then write it to disk. NOTE: DOS directories 64127a0bc89SDoug Rabson * do not get smaller as clusters are emptied. 64227a0bc89SDoug Rabson */ 643952a6212SJordan K. Hubbard error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 644952a6212SJordan K. Hubbard &bn, &dirclust, &blsize); 64527a0bc89SDoug Rabson if (error) 64627a0bc89SDoug Rabson return error; 647952a6212SJordan K. Hubbard diroffset = ddep->de_fndoffset; 648952a6212SJordan K. Hubbard if (dirclust != MSDOSFSROOT) 649952a6212SJordan K. Hubbard diroffset &= pmp->pm_crbomask; 650952a6212SJordan K. Hubbard if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { 651952a6212SJordan K. Hubbard brelse(bp); 652952a6212SJordan K. Hubbard return error; 65327a0bc89SDoug Rabson } 654952a6212SJordan K. Hubbard ndep = bptoep(pmp, bp, ddep->de_fndoffset); 655952a6212SJordan K. Hubbard 65627a0bc89SDoug Rabson DE_EXTERNALIZE(ndep, dep); 65727a0bc89SDoug Rabson 65827a0bc89SDoug Rabson /* 659952a6212SJordan K. Hubbard * Now write the Win95 long name 660952a6212SJordan K. Hubbard */ 661952a6212SJordan K. Hubbard if (ddep->de_fndcnt > 0) { 66248d1bcf8SKonstantin Belousov u_int8_t chksum = winChksum(ndep->deName); 663952a6212SJordan K. Hubbard const u_char *un = (const u_char *)cnp->cn_nameptr; 664952a6212SJordan K. Hubbard int unlen = cnp->cn_namelen; 665952a6212SJordan K. Hubbard int cnt = 1; 666952a6212SJordan K. Hubbard 667952a6212SJordan K. Hubbard while (--ddep->de_fndcnt >= 0) { 668952a6212SJordan K. Hubbard if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { 6692aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(ddep))) 670cb65c1eeSBruce Evans bdwrite(bp); 671cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 672952a6212SJordan K. Hubbard return error; 673952a6212SJordan K. Hubbard 674952a6212SJordan K. Hubbard ddep->de_fndoffset -= sizeof(struct direntry); 675952a6212SJordan K. Hubbard error = pcbmap(ddep, 676952a6212SJordan K. Hubbard de_cluster(pmp, 677952a6212SJordan K. Hubbard ddep->de_fndoffset), 678952a6212SJordan K. Hubbard &bn, 0, &blsize); 679952a6212SJordan K. Hubbard if (error) 680952a6212SJordan K. Hubbard return error; 681952a6212SJordan K. Hubbard 682952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, 683952a6212SJordan K. Hubbard NOCRED, &bp); 684952a6212SJordan K. Hubbard if (error) { 685952a6212SJordan K. Hubbard brelse(bp); 686952a6212SJordan K. Hubbard return error; 687952a6212SJordan K. Hubbard } 688952a6212SJordan K. Hubbard ndep = bptoep(pmp, bp, ddep->de_fndoffset); 689952a6212SJordan K. Hubbard } else { 690952a6212SJordan K. Hubbard ndep--; 691952a6212SJordan K. Hubbard ddep->de_fndoffset -= sizeof(struct direntry); 692952a6212SJordan K. Hubbard } 69313df76f2SAndrey A. Chernov if (!unix2winfn(un, unlen, (struct winentry *)ndep, 694c4f02a89SMax Khon cnt++, chksum, pmp)) 695952a6212SJordan K. Hubbard break; 696952a6212SJordan K. Hubbard } 697952a6212SJordan K. Hubbard } 698952a6212SJordan K. Hubbard 6992aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(ddep))) 700cb65c1eeSBruce Evans bdwrite(bp); 701cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 702952a6212SJordan K. Hubbard return error; 703952a6212SJordan K. Hubbard 704952a6212SJordan K. Hubbard /* 70527a0bc89SDoug Rabson * If they want us to return with the denode gotten. 70627a0bc89SDoug Rabson */ 70727a0bc89SDoug Rabson if (depp) { 708952a6212SJordan K. Hubbard if (dep->de_Attributes & ATTR_DIRECTORY) { 709952a6212SJordan K. Hubbard dirclust = dep->de_StartCluster; 710952a6212SJordan K. Hubbard if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 711952a6212SJordan K. Hubbard dirclust = MSDOSFSROOT; 712952a6212SJordan K. Hubbard if (dirclust == MSDOSFSROOT) 713952a6212SJordan K. Hubbard diroffset = MSDOSFSROOT_OFS; 714952a6212SJordan K. Hubbard else 715952a6212SJordan K. Hubbard diroffset = 0; 71627a0bc89SDoug Rabson } 717952a6212SJordan K. Hubbard return deget(pmp, dirclust, diroffset, depp); 71827a0bc89SDoug Rabson } 719952a6212SJordan K. Hubbard 72027a0bc89SDoug Rabson return 0; 72127a0bc89SDoug Rabson } 72227a0bc89SDoug Rabson 72327a0bc89SDoug Rabson /* 72427a0bc89SDoug Rabson * Be sure a directory is empty except for "." and "..". Return 1 if empty, 72527a0bc89SDoug Rabson * return 0 if not empty or error. 72627a0bc89SDoug Rabson */ 72727a0bc89SDoug Rabson int 72827a0bc89SDoug Rabson dosdirempty(dep) 72927a0bc89SDoug Rabson struct denode *dep; 73027a0bc89SDoug Rabson { 731952a6212SJordan K. Hubbard int blsize; 73227a0bc89SDoug Rabson int error; 73327a0bc89SDoug Rabson u_long cn; 73427a0bc89SDoug Rabson daddr_t bn; 73527a0bc89SDoug Rabson struct buf *bp; 73627a0bc89SDoug Rabson struct msdosfsmount *pmp = dep->de_pmp; 73727a0bc89SDoug Rabson struct direntry *dentp; 73827a0bc89SDoug Rabson 73927a0bc89SDoug Rabson /* 74027a0bc89SDoug Rabson * Since the filesize field in directory entries for a directory is 74127a0bc89SDoug Rabson * zero, we just have to feel our way through the directory until 74227a0bc89SDoug Rabson * we hit end of file. 74327a0bc89SDoug Rabson */ 74427a0bc89SDoug Rabson for (cn = 0;; cn++) { 745952a6212SJordan K. Hubbard if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 74627a0bc89SDoug Rabson if (error == E2BIG) 747952a6212SJordan K. Hubbard return (1); /* it's empty */ 748952a6212SJordan K. Hubbard return (0); 749952a6212SJordan K. Hubbard } 750952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 751952a6212SJordan K. Hubbard if (error) { 752952a6212SJordan K. Hubbard brelse(bp); 753952a6212SJordan K. Hubbard return (0); 754952a6212SJordan K. Hubbard } 755952a6212SJordan K. Hubbard for (dentp = (struct direntry *)bp->b_data; 756952a6212SJordan K. Hubbard (char *)dentp < bp->b_data + blsize; 757952a6212SJordan K. Hubbard dentp++) { 758952a6212SJordan K. Hubbard if (dentp->deName[0] != SLOT_DELETED && 759952a6212SJordan K. Hubbard (dentp->deAttributes & ATTR_VOLUME) == 0) { 76027a0bc89SDoug Rabson /* 76127a0bc89SDoug Rabson * In dos directories an entry whose name 76227a0bc89SDoug Rabson * starts with SLOT_EMPTY (0) starts the 76327a0bc89SDoug Rabson * beginning of the unused part of the 76427a0bc89SDoug Rabson * directory, so we can just return that it 76527a0bc89SDoug Rabson * is empty. 76627a0bc89SDoug Rabson */ 76727a0bc89SDoug Rabson if (dentp->deName[0] == SLOT_EMPTY) { 76827a0bc89SDoug Rabson brelse(bp); 769952a6212SJordan K. Hubbard return (1); 77027a0bc89SDoug Rabson } 77127a0bc89SDoug Rabson /* 77227a0bc89SDoug Rabson * Any names other than "." and ".." in a 77327a0bc89SDoug Rabson * directory mean it is not empty. 77427a0bc89SDoug Rabson */ 77527a0bc89SDoug Rabson if (bcmp(dentp->deName, ". ", 11) && 77627a0bc89SDoug Rabson bcmp(dentp->deName, ".. ", 11)) { 77727a0bc89SDoug Rabson brelse(bp); 77827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 779952a6212SJordan K. Hubbard printf("dosdirempty(): entry found %02x, %02x\n", 780952a6212SJordan K. Hubbard dentp->deName[0], dentp->deName[1]); 78127a0bc89SDoug Rabson #endif 782952a6212SJordan K. Hubbard return (0); /* not empty */ 78327a0bc89SDoug Rabson } 78427a0bc89SDoug Rabson } 78527a0bc89SDoug Rabson } 78627a0bc89SDoug Rabson brelse(bp); 78727a0bc89SDoug Rabson } 78827a0bc89SDoug Rabson /* NOTREACHED */ 78927a0bc89SDoug Rabson } 79027a0bc89SDoug Rabson 79127a0bc89SDoug Rabson /* 79227a0bc89SDoug Rabson * Check to see if the directory described by target is in some 79327a0bc89SDoug Rabson * subdirectory of source. This prevents something like the following from 79427a0bc89SDoug Rabson * succeeding and leaving a bunch or files and directories orphaned. mv 79527a0bc89SDoug Rabson * /a/b/c /a/b/c/d/e/f Where c and f are directories. 79627a0bc89SDoug Rabson * 79727a0bc89SDoug Rabson * source - the inode for /a/b/c 79827a0bc89SDoug Rabson * target - the inode for /a/b/c/d/e/f 79927a0bc89SDoug Rabson * 80027a0bc89SDoug Rabson * Returns 0 if target is NOT a subdirectory of source. 80127a0bc89SDoug Rabson * Otherwise returns a non-zero error number. 80227a0bc89SDoug Rabson * The target inode is always unlocked on return. 80327a0bc89SDoug Rabson */ 80427a0bc89SDoug Rabson int 80527a0bc89SDoug Rabson doscheckpath(source, target) 80627a0bc89SDoug Rabson struct denode *source; 80727a0bc89SDoug Rabson struct denode *target; 80827a0bc89SDoug Rabson { 80927a0bc89SDoug Rabson daddr_t scn; 81027a0bc89SDoug Rabson struct msdosfsmount *pmp; 81127a0bc89SDoug Rabson struct direntry *ep; 81227a0bc89SDoug Rabson struct denode *dep; 81327a0bc89SDoug Rabson struct buf *bp = NULL; 81427a0bc89SDoug Rabson int error = 0; 81527a0bc89SDoug Rabson 81627a0bc89SDoug Rabson dep = target; 81727a0bc89SDoug Rabson if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 81827a0bc89SDoug Rabson (source->de_Attributes & ATTR_DIRECTORY) == 0) { 81927a0bc89SDoug Rabson error = ENOTDIR; 82027a0bc89SDoug Rabson goto out; 82127a0bc89SDoug Rabson } 82227a0bc89SDoug Rabson if (dep->de_StartCluster == source->de_StartCluster) { 82327a0bc89SDoug Rabson error = EEXIST; 82427a0bc89SDoug Rabson goto out; 82527a0bc89SDoug Rabson } 82627a0bc89SDoug Rabson if (dep->de_StartCluster == MSDOSFSROOT) 82727a0bc89SDoug Rabson goto out; 828952a6212SJordan K. Hubbard pmp = dep->de_pmp; 829952a6212SJordan K. Hubbard #ifdef DIAGNOSTIC 830952a6212SJordan K. Hubbard if (pmp != source->de_pmp) 831952a6212SJordan K. Hubbard panic("doscheckpath: source and target on different filesystems"); 832952a6212SJordan K. Hubbard #endif 833952a6212SJordan K. Hubbard if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk) 834952a6212SJordan K. Hubbard goto out; 835952a6212SJordan K. Hubbard 83627a0bc89SDoug Rabson for (;;) { 83727a0bc89SDoug Rabson if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 83827a0bc89SDoug Rabson error = ENOTDIR; 839952a6212SJordan K. Hubbard break; 84027a0bc89SDoug Rabson } 84127a0bc89SDoug Rabson scn = dep->de_StartCluster; 84227a0bc89SDoug Rabson error = bread(pmp->pm_devvp, cntobn(pmp, scn), 84327a0bc89SDoug Rabson pmp->pm_bpcluster, NOCRED, &bp); 844952a6212SJordan K. Hubbard if (error) 84527a0bc89SDoug Rabson break; 846952a6212SJordan K. Hubbard 84727a0bc89SDoug Rabson ep = (struct direntry *) bp->b_data + 1; 84827a0bc89SDoug Rabson if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 84927a0bc89SDoug Rabson bcmp(ep->deName, ".. ", 11) != 0) { 85027a0bc89SDoug Rabson error = ENOTDIR; 85127a0bc89SDoug Rabson break; 85227a0bc89SDoug Rabson } 85327a0bc89SDoug Rabson scn = getushort(ep->deStartCluster); 854952a6212SJordan K. Hubbard if (FAT32(pmp)) 855952a6212SJordan K. Hubbard scn |= getushort(ep->deHighClust) << 16; 856952a6212SJordan K. Hubbard 85727a0bc89SDoug Rabson if (scn == source->de_StartCluster) { 85827a0bc89SDoug Rabson error = EINVAL; 85927a0bc89SDoug Rabson break; 86027a0bc89SDoug Rabson } 86127a0bc89SDoug Rabson if (scn == MSDOSFSROOT) 86227a0bc89SDoug Rabson break; 863952a6212SJordan K. Hubbard if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 864952a6212SJordan K. Hubbard /* 865952a6212SJordan K. Hubbard * scn should be 0 in this case, 866952a6212SJordan K. Hubbard * but we silently ignore the error. 867952a6212SJordan K. Hubbard */ 868952a6212SJordan K. Hubbard break; 869952a6212SJordan K. Hubbard } 870952a6212SJordan K. Hubbard 87127a0bc89SDoug Rabson vput(DETOV(dep)); 87227a0bc89SDoug Rabson brelse(bp); 87327a0bc89SDoug Rabson bp = NULL; 874952a6212SJordan K. Hubbard /* NOTE: deget() clears dep on error */ 875952a6212SJordan K. Hubbard if ((error = deget(pmp, scn, 0, &dep)) != 0) 87627a0bc89SDoug Rabson break; 87727a0bc89SDoug Rabson } 87827a0bc89SDoug Rabson out:; 87927a0bc89SDoug Rabson if (bp) 88027a0bc89SDoug Rabson brelse(bp); 88154cf9198SKonstantin Belousov #ifdef MSDOSFS_DEBUG 88227a0bc89SDoug Rabson if (error == ENOTDIR) 88327a0bc89SDoug Rabson printf("doscheckpath(): .. not a directory?\n"); 88454cf9198SKonstantin Belousov #endif 88527a0bc89SDoug Rabson if (dep != NULL) 88627a0bc89SDoug Rabson vput(DETOV(dep)); 887952a6212SJordan K. Hubbard return (error); 88827a0bc89SDoug Rabson } 88927a0bc89SDoug Rabson 89027a0bc89SDoug Rabson /* 89127a0bc89SDoug Rabson * Read in the disk block containing the directory entry (dirclu, dirofs) 89227a0bc89SDoug Rabson * and return the address of the buf header, and the address of the 89327a0bc89SDoug Rabson * directory entry within the block. 89427a0bc89SDoug Rabson */ 89527a0bc89SDoug Rabson int 896952a6212SJordan K. Hubbard readep(pmp, dirclust, diroffset, bpp, epp) 89727a0bc89SDoug Rabson struct msdosfsmount *pmp; 898952a6212SJordan K. Hubbard u_long dirclust, diroffset; 89927a0bc89SDoug Rabson struct buf **bpp; 90027a0bc89SDoug Rabson struct direntry **epp; 90127a0bc89SDoug Rabson { 90227a0bc89SDoug Rabson int error; 90327a0bc89SDoug Rabson daddr_t bn; 904952a6212SJordan K. Hubbard int blsize; 90527a0bc89SDoug Rabson 906952a6212SJordan K. Hubbard blsize = pmp->pm_bpcluster; 907952a6212SJordan K. Hubbard if (dirclust == MSDOSFSROOT 908952a6212SJordan K. Hubbard && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 909952a6212SJordan K. Hubbard blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 910952a6212SJordan K. Hubbard bn = detobn(pmp, dirclust, diroffset); 911952a6212SJordan K. Hubbard if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { 912952a6212SJordan K. Hubbard brelse(*bpp); 91327a0bc89SDoug Rabson *bpp = NULL; 914952a6212SJordan K. Hubbard return (error); 91527a0bc89SDoug Rabson } 91627a0bc89SDoug Rabson if (epp) 917952a6212SJordan K. Hubbard *epp = bptoep(pmp, *bpp, diroffset); 918952a6212SJordan K. Hubbard return (0); 91927a0bc89SDoug Rabson } 92027a0bc89SDoug Rabson 92127a0bc89SDoug Rabson /* 92227a0bc89SDoug Rabson * Read in the disk block containing the directory entry dep came from and 92327a0bc89SDoug Rabson * return the address of the buf header, and the address of the directory 92427a0bc89SDoug Rabson * entry within the block. 92527a0bc89SDoug Rabson */ 92627a0bc89SDoug Rabson int 92727a0bc89SDoug Rabson readde(dep, bpp, epp) 92827a0bc89SDoug Rabson struct denode *dep; 92927a0bc89SDoug Rabson struct buf **bpp; 93027a0bc89SDoug Rabson struct direntry **epp; 93127a0bc89SDoug Rabson { 932952a6212SJordan K. Hubbard 933952a6212SJordan K. Hubbard return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 934952a6212SJordan K. Hubbard bpp, epp)); 935952a6212SJordan K. Hubbard } 936952a6212SJordan K. Hubbard 937952a6212SJordan K. Hubbard /* 938952a6212SJordan K. Hubbard * Remove a directory entry. At this point the file represented by the 939952a6212SJordan K. Hubbard * directory entry to be removed is still full length until noone has it 940952a6212SJordan K. Hubbard * open. When the file no longer being used msdosfs_inactive() is called 941952a6212SJordan K. Hubbard * and will truncate the file to 0 length. When the vnode containing the 942952a6212SJordan K. Hubbard * denode is needed for some other purpose by VFS it will call 943952a6212SJordan K. Hubbard * msdosfs_reclaim() which will remove the denode from the denode cache. 944952a6212SJordan K. Hubbard */ 945952a6212SJordan K. Hubbard int 946952a6212SJordan K. Hubbard removede(pdep, dep) 947952a6212SJordan K. Hubbard struct denode *pdep; /* directory where the entry is removed */ 948952a6212SJordan K. Hubbard struct denode *dep; /* file to be removed */ 949952a6212SJordan K. Hubbard { 950952a6212SJordan K. Hubbard int error; 951952a6212SJordan K. Hubbard struct direntry *ep; 952952a6212SJordan K. Hubbard struct buf *bp; 953952a6212SJordan K. Hubbard daddr_t bn; 954952a6212SJordan K. Hubbard int blsize; 955952a6212SJordan K. Hubbard struct msdosfsmount *pmp = pdep->de_pmp; 956952a6212SJordan K. Hubbard u_long offset = pdep->de_fndoffset; 957952a6212SJordan K. Hubbard 958952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 959952a6212SJordan K. Hubbard printf("removede(): filename %s, dep %p, offset %08lx\n", 960952a6212SJordan K. Hubbard dep->de_Name, dep, offset); 961952a6212SJordan K. Hubbard #endif 962952a6212SJordan K. Hubbard 963952a6212SJordan K. Hubbard dep->de_refcnt--; 964952a6212SJordan K. Hubbard offset += sizeof(struct direntry); 965952a6212SJordan K. Hubbard do { 966952a6212SJordan K. Hubbard offset -= sizeof(struct direntry); 967952a6212SJordan K. Hubbard error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 968952a6212SJordan K. Hubbard if (error) 969952a6212SJordan K. Hubbard return error; 970952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 971952a6212SJordan K. Hubbard if (error) { 972952a6212SJordan K. Hubbard brelse(bp); 973952a6212SJordan K. Hubbard return error; 974952a6212SJordan K. Hubbard } 975952a6212SJordan K. Hubbard ep = bptoep(pmp, bp, offset); 976952a6212SJordan K. Hubbard /* 977952a6212SJordan K. Hubbard * Check whether, if we came here the second time, i.e. 978952a6212SJordan K. Hubbard * when underflowing into the previous block, the last 979952a6212SJordan K. Hubbard * entry in this block is a longfilename entry, too. 980952a6212SJordan K. Hubbard */ 981952a6212SJordan K. Hubbard if (ep->deAttributes != ATTR_WIN95 982952a6212SJordan K. Hubbard && offset != pdep->de_fndoffset) { 983952a6212SJordan K. Hubbard brelse(bp); 984952a6212SJordan K. Hubbard break; 985952a6212SJordan K. Hubbard } 986952a6212SJordan K. Hubbard offset += sizeof(struct direntry); 987952a6212SJordan K. Hubbard while (1) { 988952a6212SJordan K. Hubbard /* 989952a6212SJordan K. Hubbard * We are a bit agressive here in that we delete any Win95 990952a6212SJordan K. Hubbard * entries preceding this entry, not just the ones we "own". 991952a6212SJordan K. Hubbard * Since these presumably aren't valid anyway, 992952a6212SJordan K. Hubbard * there should be no harm. 993952a6212SJordan K. Hubbard */ 994952a6212SJordan K. Hubbard offset -= sizeof(struct direntry); 995952a6212SJordan K. Hubbard ep--->deName[0] = SLOT_DELETED; 996952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 997952a6212SJordan K. Hubbard || !(offset & pmp->pm_crbomask) 998952a6212SJordan K. Hubbard || ep->deAttributes != ATTR_WIN95) 999952a6212SJordan K. Hubbard break; 1000952a6212SJordan K. Hubbard } 10012aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(pdep))) 1002cb65c1eeSBruce Evans bdwrite(bp); 1003cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 1004952a6212SJordan K. Hubbard return error; 1005952a6212SJordan K. Hubbard } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1006952a6212SJordan K. Hubbard && !(offset & pmp->pm_crbomask) 1007952a6212SJordan K. Hubbard && offset); 1008952a6212SJordan K. Hubbard return 0; 1009952a6212SJordan K. Hubbard } 1010952a6212SJordan K. Hubbard 1011952a6212SJordan K. Hubbard /* 1012952a6212SJordan K. Hubbard * Create a unique DOS name in dvp 1013952a6212SJordan K. Hubbard */ 1014952a6212SJordan K. Hubbard int 1015952a6212SJordan K. Hubbard uniqdosname(dep, cnp, cp) 1016952a6212SJordan K. Hubbard struct denode *dep; 1017952a6212SJordan K. Hubbard struct componentname *cnp; 1018952a6212SJordan K. Hubbard u_char *cp; 1019952a6212SJordan K. Hubbard { 1020952a6212SJordan K. Hubbard struct msdosfsmount *pmp = dep->de_pmp; 1021952a6212SJordan K. Hubbard struct direntry *dentp; 1022952a6212SJordan K. Hubbard int gen; 1023952a6212SJordan K. Hubbard int blsize; 1024952a6212SJordan K. Hubbard u_long cn; 1025952a6212SJordan K. Hubbard daddr_t bn; 1026952a6212SJordan K. Hubbard struct buf *bp; 1027952a6212SJordan K. Hubbard int error; 1028952a6212SJordan K. Hubbard 1029af9f1d50SDmitrij Tejblum if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 1030011cdb57SDmitrij Tejblum return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1031c4f02a89SMax Khon cnp->cn_namelen, 0, pmp) ? 0 : EINVAL); 1032011cdb57SDmitrij Tejblum 1033952a6212SJordan K. Hubbard for (gen = 1;; gen++) { 1034952a6212SJordan K. Hubbard /* 1035952a6212SJordan K. Hubbard * Generate DOS name with generation number 1036952a6212SJordan K. Hubbard */ 1037952a6212SJordan K. Hubbard if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1038c4f02a89SMax Khon cnp->cn_namelen, gen, pmp)) 1039952a6212SJordan K. Hubbard return gen == 1 ? EINVAL : EEXIST; 1040952a6212SJordan K. Hubbard 1041952a6212SJordan K. Hubbard /* 1042952a6212SJordan K. Hubbard * Now look for a dir entry with this exact name 1043952a6212SJordan K. Hubbard */ 1044952a6212SJordan K. Hubbard for (cn = error = 0; !error; cn++) { 1045952a6212SJordan K. Hubbard if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 1046952a6212SJordan K. Hubbard if (error == E2BIG) /* EOF reached and not found */ 1047952a6212SJordan K. Hubbard return 0; 1048952a6212SJordan K. Hubbard return error; 1049952a6212SJordan K. Hubbard } 1050952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 1051952a6212SJordan K. Hubbard if (error) { 1052952a6212SJordan K. Hubbard brelse(bp); 1053952a6212SJordan K. Hubbard return error; 1054952a6212SJordan K. Hubbard } 1055952a6212SJordan K. Hubbard for (dentp = (struct direntry *)bp->b_data; 1056952a6212SJordan K. Hubbard (char *)dentp < bp->b_data + blsize; 1057952a6212SJordan K. Hubbard dentp++) { 1058952a6212SJordan K. Hubbard if (dentp->deName[0] == SLOT_EMPTY) { 1059952a6212SJordan K. Hubbard /* 1060952a6212SJordan K. Hubbard * Last used entry and not found 1061952a6212SJordan K. Hubbard */ 1062952a6212SJordan K. Hubbard brelse(bp); 1063952a6212SJordan K. Hubbard return 0; 1064952a6212SJordan K. Hubbard } 1065952a6212SJordan K. Hubbard /* 1066952a6212SJordan K. Hubbard * Ignore volume labels and Win95 entries 1067952a6212SJordan K. Hubbard */ 1068952a6212SJordan K. Hubbard if (dentp->deAttributes & ATTR_VOLUME) 1069952a6212SJordan K. Hubbard continue; 1070952a6212SJordan K. Hubbard if (!bcmp(dentp->deName, cp, 11)) { 1071952a6212SJordan K. Hubbard error = EEXIST; 1072952a6212SJordan K. Hubbard break; 1073952a6212SJordan K. Hubbard } 1074952a6212SJordan K. Hubbard } 1075952a6212SJordan K. Hubbard brelse(bp); 1076952a6212SJordan K. Hubbard } 1077952a6212SJordan K. Hubbard } 1078952a6212SJordan K. Hubbard } 1079952a6212SJordan K. Hubbard 1080952a6212SJordan K. Hubbard /* 1081952a6212SJordan K. Hubbard * Find any Win'95 long filename entry in directory dep 1082952a6212SJordan K. Hubbard */ 1083952a6212SJordan K. Hubbard int 1084952a6212SJordan K. Hubbard findwin95(dep) 1085952a6212SJordan K. Hubbard struct denode *dep; 1086952a6212SJordan K. Hubbard { 1087952a6212SJordan K. Hubbard struct msdosfsmount *pmp = dep->de_pmp; 1088952a6212SJordan K. Hubbard struct direntry *dentp; 108957081f7bSDmitrij Tejblum int blsize, win95; 1090952a6212SJordan K. Hubbard u_long cn; 1091952a6212SJordan K. Hubbard daddr_t bn; 1092952a6212SJordan K. Hubbard struct buf *bp; 1093952a6212SJordan K. Hubbard 109457081f7bSDmitrij Tejblum win95 = 1; 1095952a6212SJordan K. Hubbard /* 1096952a6212SJordan K. Hubbard * Read through the directory looking for Win'95 entries 1097952a6212SJordan K. Hubbard * Note: Error currently handled just as EOF XXX 1098952a6212SJordan K. Hubbard */ 1099952a6212SJordan K. Hubbard for (cn = 0;; cn++) { 1100952a6212SJordan K. Hubbard if (pcbmap(dep, cn, &bn, 0, &blsize)) 110157081f7bSDmitrij Tejblum return (win95); 1102952a6212SJordan K. Hubbard if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) { 1103952a6212SJordan K. Hubbard brelse(bp); 110457081f7bSDmitrij Tejblum return (win95); 1105952a6212SJordan K. Hubbard } 1106952a6212SJordan K. Hubbard for (dentp = (struct direntry *)bp->b_data; 1107952a6212SJordan K. Hubbard (char *)dentp < bp->b_data + blsize; 1108952a6212SJordan K. Hubbard dentp++) { 1109952a6212SJordan K. Hubbard if (dentp->deName[0] == SLOT_EMPTY) { 1110952a6212SJordan K. Hubbard /* 1111952a6212SJordan K. Hubbard * Last used entry and not found 1112952a6212SJordan K. Hubbard */ 1113952a6212SJordan K. Hubbard brelse(bp); 111457081f7bSDmitrij Tejblum return (win95); 1115952a6212SJordan K. Hubbard } 1116952a6212SJordan K. Hubbard if (dentp->deName[0] == SLOT_DELETED) { 1117952a6212SJordan K. Hubbard /* 1118952a6212SJordan K. Hubbard * Ignore deleted files 1119952a6212SJordan K. Hubbard * Note: might be an indication of Win'95 anyway XXX 1120952a6212SJordan K. Hubbard */ 1121952a6212SJordan K. Hubbard continue; 1122952a6212SJordan K. Hubbard } 1123952a6212SJordan K. Hubbard if (dentp->deAttributes == ATTR_WIN95) { 1124952a6212SJordan K. Hubbard brelse(bp); 1125952a6212SJordan K. Hubbard return 1; 1126952a6212SJordan K. Hubbard } 112757081f7bSDmitrij Tejblum win95 = 0; 1128952a6212SJordan K. Hubbard } 1129952a6212SJordan K. Hubbard brelse(bp); 1130952a6212SJordan K. Hubbard } 113127a0bc89SDoug Rabson } 1132