1b84d2921SPoul-Henning Kamp /* $Id: msdosfs_lookup.c,v 1.13 1997/09/02 20:06:17 bde Exp $ */ 227a0bc89SDoug Rabson /* $NetBSD: msdosfs_lookup.c,v 1.14 1994/08/21 18:44:07 ws Exp $ */ 327a0bc89SDoug Rabson 427a0bc89SDoug Rabson /*- 527a0bc89SDoug Rabson * Copyright (C) 1994 Wolfgang Solfrank. 627a0bc89SDoug Rabson * Copyright (C) 1994 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 */ 3527a0bc89SDoug Rabson /* 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> 5227a0bc89SDoug Rabson #include <sys/namei.h> 5327a0bc89SDoug Rabson #include <sys/buf.h> 5427a0bc89SDoug Rabson #include <sys/vnode.h> 5527a0bc89SDoug Rabson #include <sys/mount.h> 56c3c6d51eSPoul-Henning Kamp #include <sys/systm.h> 5727a0bc89SDoug Rabson 5827a0bc89SDoug Rabson #include <msdosfs/bpb.h> 5927a0bc89SDoug Rabson #include <msdosfs/direntry.h> 6027a0bc89SDoug Rabson #include <msdosfs/denode.h> 6127a0bc89SDoug Rabson #include <msdosfs/msdosfsmount.h> 6227a0bc89SDoug Rabson #include <msdosfs/fat.h> 6327a0bc89SDoug Rabson 6458c27bcfSBruce Evans static int markdeleted __P((struct msdosfsmount *pmp, u_long dirclust, 6558c27bcfSBruce Evans u_long diroffset)); 6658c27bcfSBruce Evans 6727a0bc89SDoug Rabson /* 6827a0bc89SDoug Rabson * When we search a directory the blocks containing directory entries are 6927a0bc89SDoug Rabson * read and examined. The directory entries contain information that would 7027a0bc89SDoug Rabson * normally be in the inode of a unix filesystem. This means that some of 7127a0bc89SDoug Rabson * a directory's contents may also be in memory resident denodes (sort of 7227a0bc89SDoug Rabson * an inode). This can cause problems if we are searching while some other 7327a0bc89SDoug Rabson * process is modifying a directory. To prevent one process from accessing 7427a0bc89SDoug Rabson * incompletely modified directory information we depend upon being the 75b84d2921SPoul-Henning Kamp * sole owner of a directory block. bread/brelse provide this service. 7627a0bc89SDoug Rabson * This being the case, when a process modifies a directory it must first 7727a0bc89SDoug Rabson * acquire the disk block that contains the directory entry to be modified. 7827a0bc89SDoug Rabson * Then update the disk block and the denode, and then write the disk block 7927a0bc89SDoug Rabson * out to disk. This way disk blocks containing directory entries and in 8027a0bc89SDoug Rabson * memory denode's will be in synch. 8127a0bc89SDoug Rabson */ 8227a0bc89SDoug Rabson int 8327a0bc89SDoug Rabson msdosfs_lookup(ap) 840fa2443fSPoul-Henning Kamp struct vop_cachedlookup_args /* { 8527a0bc89SDoug Rabson struct vnode *a_dvp; 8627a0bc89SDoug Rabson struct vnode **a_vpp; 8727a0bc89SDoug Rabson struct componentname *a_cnp; 8827a0bc89SDoug Rabson } */ *ap; 8927a0bc89SDoug Rabson { 9027a0bc89SDoug Rabson struct vnode *vdp = ap->a_dvp; 9127a0bc89SDoug Rabson struct vnode **vpp = ap->a_vpp; 9227a0bc89SDoug Rabson struct componentname *cnp = ap->a_cnp; 9327a0bc89SDoug Rabson daddr_t bn; 9427a0bc89SDoug Rabson int error; 9527a0bc89SDoug Rabson int lockparent; 9627a0bc89SDoug Rabson int wantparent; 9727a0bc89SDoug Rabson int slotstatus; 9827a0bc89SDoug Rabson 9927a0bc89SDoug Rabson #define NONE 0 10027a0bc89SDoug Rabson #define FOUND 1 10127a0bc89SDoug Rabson int slotoffset = -1; 10227a0bc89SDoug Rabson int slotcluster = -1; 10327a0bc89SDoug Rabson int frcn; 10427a0bc89SDoug Rabson u_long cluster; 10527a0bc89SDoug Rabson int rootreloff; 10627a0bc89SDoug Rabson int diroff; 10727a0bc89SDoug Rabson int isadir; /* ~0 if found direntry is a directory */ 10827a0bc89SDoug Rabson u_long scn; /* starting cluster number */ 10927a0bc89SDoug Rabson struct vnode *pdp; 11027a0bc89SDoug Rabson struct denode *dp; 11127a0bc89SDoug Rabson struct denode *tdp; 11227a0bc89SDoug Rabson struct msdosfsmount *pmp; 11327a0bc89SDoug Rabson struct buf *bp = 0; 11427a0bc89SDoug Rabson struct direntry *dep = NULL; 115d8762fa6SBruce Evans struct ucred *cred = cnp->cn_cred; 11627a0bc89SDoug Rabson u_char dosfilename[12]; 11727a0bc89SDoug Rabson int flags = cnp->cn_flags; 11827a0bc89SDoug Rabson int nameiop = cnp->cn_nameiop; 119af3f60d5SBruce Evans struct proc *p = cnp->cn_proc; 12027a0bc89SDoug Rabson 12127a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 12227a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); 12327a0bc89SDoug Rabson #endif 12427a0bc89SDoug Rabson dp = VTODE(vdp); 12527a0bc89SDoug Rabson pmp = dp->de_pmp; 12627a0bc89SDoug Rabson *vpp = NULL; 12727a0bc89SDoug Rabson lockparent = flags & LOCKPARENT; 12827a0bc89SDoug Rabson wantparent = flags & (LOCKPARENT | WANTPARENT); 12927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 13027a0bc89SDoug Rabson printf("msdosfs_lookup(): vdp %08x, dp %08x, Attr %02x\n", 13127a0bc89SDoug Rabson vdp, dp, dp->de_Attributes); 13227a0bc89SDoug Rabson #endif 13327a0bc89SDoug Rabson 13427a0bc89SDoug Rabson /* 13527a0bc89SDoug Rabson * If they are going after the . or .. entry in the root directory, 13627a0bc89SDoug Rabson * they won't find it. DOS filesystems don't have them in the root 13727a0bc89SDoug Rabson * directory. So, we fake it. deget() is in on this scam too. 13827a0bc89SDoug Rabson */ 13927a0bc89SDoug Rabson if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' && 14027a0bc89SDoug Rabson (cnp->cn_namelen == 1 || 14127a0bc89SDoug Rabson (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 14227a0bc89SDoug Rabson isadir = ATTR_DIRECTORY; 14327a0bc89SDoug Rabson scn = MSDOSFSROOT; 14427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 14527a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 14627a0bc89SDoug Rabson #endif 14727a0bc89SDoug Rabson cluster = MSDOSFSROOT; 14827a0bc89SDoug Rabson diroff = MSDOSFSROOT_OFS; 14927a0bc89SDoug Rabson goto foundroot; 15027a0bc89SDoug Rabson } 15127a0bc89SDoug Rabson 15227a0bc89SDoug Rabson /* 15327a0bc89SDoug Rabson * Don't search for free slots unless we are creating a filename 15427a0bc89SDoug Rabson * and we are at the end of the pathname. 15527a0bc89SDoug Rabson */ 15627a0bc89SDoug Rabson slotstatus = FOUND; 15727a0bc89SDoug Rabson if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { 15827a0bc89SDoug Rabson slotstatus = NONE; 15927a0bc89SDoug Rabson slotoffset = -1; 16027a0bc89SDoug Rabson } 16127a0bc89SDoug Rabson 16227a0bc89SDoug Rabson unix2dosfn((u_char *) cnp->cn_nameptr, dosfilename, cnp->cn_namelen); 16327a0bc89SDoug Rabson dosfilename[11] = 0; 16427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 16527a0bc89SDoug Rabson printf("msdosfs_lookup(): dos version of filename %s, length %d\n", 16627a0bc89SDoug Rabson dosfilename, cnp->cn_namelen); 16727a0bc89SDoug Rabson #endif 16827a0bc89SDoug Rabson /* 16927a0bc89SDoug Rabson * Search the directory pointed at by vdp for the name pointed at 17027a0bc89SDoug Rabson * by cnp->cn_nameptr. 17127a0bc89SDoug Rabson */ 17227a0bc89SDoug Rabson tdp = NULL; 17327a0bc89SDoug Rabson /* 17427a0bc89SDoug Rabson * The outer loop ranges over the clusters that make up the 17527a0bc89SDoug Rabson * directory. Note that the root directory is different from all 17627a0bc89SDoug Rabson * other directories. It has a fixed number of blocks that are not 17727a0bc89SDoug Rabson * part of the pool of allocatable clusters. So, we treat it a 17827a0bc89SDoug Rabson * little differently. The root directory starts at "cluster" 0. 17927a0bc89SDoug Rabson */ 18027a0bc89SDoug Rabson rootreloff = 0; 18127a0bc89SDoug Rabson for (frcn = 0;; frcn++) { 182c3c6d51eSPoul-Henning Kamp error = pcbmap(dp, frcn, &bn, &cluster); 183c3c6d51eSPoul-Henning Kamp if (error) { 18427a0bc89SDoug Rabson if (error == E2BIG) 18527a0bc89SDoug Rabson break; 18627a0bc89SDoug Rabson return error; 18727a0bc89SDoug Rabson } 188c3c6d51eSPoul-Henning Kamp error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,NOCRED,&bp); 189c3c6d51eSPoul-Henning Kamp if (error) 19027a0bc89SDoug Rabson return error; 19127a0bc89SDoug Rabson for (diroff = 0; diroff < pmp->pm_depclust; diroff++) { 19227a0bc89SDoug Rabson dep = (struct direntry *) bp->b_data + diroff; 19327a0bc89SDoug Rabson 19427a0bc89SDoug Rabson /* 19527a0bc89SDoug Rabson * If the slot is empty and we are still looking 19627a0bc89SDoug Rabson * for an empty then remember this one. If the 19727a0bc89SDoug Rabson * slot is not empty then check to see if it 19827a0bc89SDoug Rabson * matches what we are looking for. If the slot 19927a0bc89SDoug Rabson * has never been filled with anything, then the 20027a0bc89SDoug Rabson * remainder of the directory has never been used, 20127a0bc89SDoug Rabson * so there is no point in searching it. 20227a0bc89SDoug Rabson */ 20327a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY || 20427a0bc89SDoug Rabson dep->deName[0] == SLOT_DELETED) { 20527a0bc89SDoug Rabson if (slotstatus != FOUND) { 20627a0bc89SDoug Rabson slotstatus = FOUND; 20727a0bc89SDoug Rabson if (cluster == MSDOSFSROOT) 20827a0bc89SDoug Rabson slotoffset = rootreloff; 20927a0bc89SDoug Rabson else 21027a0bc89SDoug Rabson slotoffset = diroff; 21127a0bc89SDoug Rabson slotcluster = cluster; 21227a0bc89SDoug Rabson } 21327a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY) { 21427a0bc89SDoug Rabson brelse(bp); 21527a0bc89SDoug Rabson goto notfound; 21627a0bc89SDoug Rabson } 21727a0bc89SDoug Rabson } else { 21827a0bc89SDoug Rabson /* 21927a0bc89SDoug Rabson * Ignore volume labels (anywhere, not just 22027a0bc89SDoug Rabson * the root directory). 22127a0bc89SDoug Rabson */ 22227a0bc89SDoug Rabson if ((dep->deAttributes & ATTR_VOLUME) == 0 && 22327a0bc89SDoug Rabson bcmp(dosfilename, dep->deName, 11) == 0) { 22427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 22527a0bc89SDoug Rabson printf("msdosfs_lookup(): match diroff %d, rootreloff %d\n", 22627a0bc89SDoug Rabson diroff, rootreloff); 22727a0bc89SDoug Rabson #endif 22827a0bc89SDoug Rabson /* 22927a0bc89SDoug Rabson * Remember where this directory 23027a0bc89SDoug Rabson * entry came from for whoever did 23127a0bc89SDoug Rabson * this lookup. If this is the root 23227a0bc89SDoug Rabson * directory we are interested in 23327a0bc89SDoug Rabson * the offset relative to the 23427a0bc89SDoug Rabson * beginning of the directory (not 23527a0bc89SDoug Rabson * the beginning of the cluster). 23627a0bc89SDoug Rabson */ 23727a0bc89SDoug Rabson if (cluster == MSDOSFSROOT) 23827a0bc89SDoug Rabson diroff = rootreloff; 23927a0bc89SDoug Rabson dp->de_fndoffset = diroff; 24027a0bc89SDoug Rabson dp->de_fndclust = cluster; 24127a0bc89SDoug Rabson goto found; 24227a0bc89SDoug Rabson } 24327a0bc89SDoug Rabson } 24427a0bc89SDoug Rabson rootreloff++; 24527a0bc89SDoug Rabson } /* for (diroff = 0; .... */ 24627a0bc89SDoug Rabson /* 24727a0bc89SDoug Rabson * Release the buffer holding the directory cluster just 24827a0bc89SDoug Rabson * searched. 24927a0bc89SDoug Rabson */ 25027a0bc89SDoug Rabson brelse(bp); 25127a0bc89SDoug Rabson } /* for (frcn = 0; ; frcn++) */ 25227a0bc89SDoug Rabson notfound:; 25327a0bc89SDoug Rabson /* 25427a0bc89SDoug Rabson * We hold no disk buffers at this point. 25527a0bc89SDoug Rabson */ 25627a0bc89SDoug Rabson 25727a0bc89SDoug Rabson /* 25827a0bc89SDoug Rabson * If we get here we didn't find the entry we were looking for. But 25927a0bc89SDoug Rabson * that's ok if we are creating or renaming and are at the end of 26027a0bc89SDoug Rabson * the pathname and the directory hasn't been removed. 26127a0bc89SDoug Rabson */ 26227a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 26327a0bc89SDoug Rabson printf("msdosfs_lookup(): op %d, refcnt %d, slotstatus %d\n", 26427a0bc89SDoug Rabson nameiop, dp->de_refcnt, slotstatus); 26527a0bc89SDoug Rabson printf(" slotoffset %d, slotcluster %d\n", 26627a0bc89SDoug Rabson slotoffset, slotcluster); 26727a0bc89SDoug Rabson #endif 26827a0bc89SDoug Rabson if ((nameiop == CREATE || nameiop == RENAME) && 26927a0bc89SDoug Rabson (flags & ISLASTCN) && dp->de_refcnt != 0) { 270d8762fa6SBruce Evans error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); 271d8762fa6SBruce Evans if (error) 272d8762fa6SBruce Evans return error; 27327a0bc89SDoug Rabson if (slotstatus == NONE) { 27427a0bc89SDoug Rabson dp->de_fndoffset = (u_long)-1; 27527a0bc89SDoug Rabson dp->de_fndclust = (u_long)-1; 27627a0bc89SDoug Rabson } else { 27727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 27827a0bc89SDoug Rabson printf("msdosfs_lookup(): saving empty slot location\n"); 27927a0bc89SDoug Rabson #endif 28027a0bc89SDoug Rabson dp->de_fndoffset = slotoffset; 28127a0bc89SDoug Rabson dp->de_fndclust = slotcluster; 28227a0bc89SDoug Rabson } 28327a0bc89SDoug Rabson /* dp->de_flag |= DE_UPDATE; never update dos directories */ 28427a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 28527a0bc89SDoug Rabson if (!lockparent)/* leave searched dir locked? */ 286af3f60d5SBruce Evans VOP_UNLOCK(vdp, 0, p); 28727a0bc89SDoug Rabson return EJUSTRETURN; 28827a0bc89SDoug Rabson } 28927a0bc89SDoug Rabson /* 29027a0bc89SDoug Rabson * Insert name in cache as non-existant if not trying to create it. 29127a0bc89SDoug Rabson */ 29227a0bc89SDoug Rabson if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 29327a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 29427a0bc89SDoug Rabson return ENOENT; 29527a0bc89SDoug Rabson 29627a0bc89SDoug Rabson found: ; 29727a0bc89SDoug Rabson /* 29827a0bc89SDoug Rabson * NOTE: We still have the buffer with matched directory entry at 29927a0bc89SDoug Rabson * this point. 30027a0bc89SDoug Rabson */ 30127a0bc89SDoug Rabson isadir = dep->deAttributes & ATTR_DIRECTORY; 30227a0bc89SDoug Rabson scn = getushort(dep->deStartCluster); 30327a0bc89SDoug Rabson 30427a0bc89SDoug Rabson foundroot:; 30527a0bc89SDoug Rabson /* 30627a0bc89SDoug Rabson * If we entered at foundroot, then we are looking for the . or .. 30727a0bc89SDoug Rabson * entry of the filesystems root directory. isadir and scn were 30827a0bc89SDoug Rabson * setup before jumping here. And, bp is null. There is no buf 30927a0bc89SDoug Rabson * header. 31027a0bc89SDoug Rabson */ 31127a0bc89SDoug Rabson 31227a0bc89SDoug Rabson /* 31327a0bc89SDoug Rabson * If deleting and at the end of the path, then if we matched on 31427a0bc89SDoug Rabson * "." then don't deget() we would probably panic(). Otherwise 31527a0bc89SDoug Rabson * deget() the directory entry. 31627a0bc89SDoug Rabson */ 31727a0bc89SDoug Rabson if (nameiop == DELETE && (flags & ISLASTCN)) { 318d8762fa6SBruce Evans error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); 319d8762fa6SBruce Evans if (error) { 320d8762fa6SBruce Evans if (bp) 321d8762fa6SBruce Evans brelse(bp); 322d8762fa6SBruce Evans return error; 323d8762fa6SBruce Evans } 32427a0bc89SDoug Rabson if (dp->de_StartCluster == scn && isadir) { /* "." */ 32527a0bc89SDoug Rabson VREF(vdp); 32627a0bc89SDoug Rabson *vpp = vdp; 32727a0bc89SDoug Rabson if (bp) 32827a0bc89SDoug Rabson brelse(bp); 32927a0bc89SDoug Rabson return 0; 33027a0bc89SDoug Rabson } 33127a0bc89SDoug Rabson error = deget(pmp, cluster, diroff, dep, &tdp); 33227a0bc89SDoug Rabson if (error) { 33327a0bc89SDoug Rabson if (bp) 33427a0bc89SDoug Rabson brelse(bp); 33527a0bc89SDoug Rabson return error; 33627a0bc89SDoug Rabson } 33727a0bc89SDoug Rabson *vpp = DETOV(tdp); 33827a0bc89SDoug Rabson if (!lockparent) 339af3f60d5SBruce Evans VOP_UNLOCK(vdp, 0, p); 34027a0bc89SDoug Rabson if (bp) 34127a0bc89SDoug Rabson brelse(bp); 34227a0bc89SDoug Rabson return 0; 34327a0bc89SDoug Rabson } 34427a0bc89SDoug Rabson 34527a0bc89SDoug Rabson /* 34627a0bc89SDoug Rabson * If renaming. 34727a0bc89SDoug Rabson */ 34827a0bc89SDoug Rabson if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 349d8762fa6SBruce Evans error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); 350d8762fa6SBruce Evans if (error) { 351d8762fa6SBruce Evans if (bp) 352d8762fa6SBruce Evans brelse(bp); 353d8762fa6SBruce Evans return error; 354d8762fa6SBruce Evans } 35527a0bc89SDoug Rabson if (dp->de_StartCluster == scn && isadir) { 35627a0bc89SDoug Rabson if (bp) 35727a0bc89SDoug Rabson brelse(bp); 35827a0bc89SDoug Rabson return EISDIR; 35927a0bc89SDoug Rabson } 36027a0bc89SDoug Rabson error = deget(pmp, cluster, diroff, dep, &tdp); 36127a0bc89SDoug Rabson if (error) { 36227a0bc89SDoug Rabson if (bp) 36327a0bc89SDoug Rabson brelse(bp); 36427a0bc89SDoug Rabson return error; 36527a0bc89SDoug Rabson } 36627a0bc89SDoug Rabson *vpp = DETOV(tdp); 36727a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 36827a0bc89SDoug Rabson if (!lockparent) 369af3f60d5SBruce Evans VOP_UNLOCK(vdp, 0, p); 37027a0bc89SDoug Rabson if (bp) 37127a0bc89SDoug Rabson brelse(bp); 37227a0bc89SDoug Rabson return 0; 37327a0bc89SDoug Rabson } 37427a0bc89SDoug Rabson 37527a0bc89SDoug Rabson /* 37627a0bc89SDoug Rabson * ? 37727a0bc89SDoug Rabson */ 37827a0bc89SDoug Rabson pdp = vdp; 37927a0bc89SDoug Rabson if (flags & ISDOTDOT) { 380af3f60d5SBruce Evans VOP_UNLOCK(pdp, 0, p); 38127a0bc89SDoug Rabson error = deget(pmp, cluster, diroff, dep, &tdp); 38227a0bc89SDoug Rabson if (error) { 383af3f60d5SBruce Evans vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); 38427a0bc89SDoug Rabson if (bp) 38527a0bc89SDoug Rabson brelse(bp); 38627a0bc89SDoug Rabson return error; 38727a0bc89SDoug Rabson } 38827a0bc89SDoug Rabson if (lockparent && (flags & ISLASTCN) 389af3f60d5SBruce Evans && (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { 39027a0bc89SDoug Rabson vput(DETOV(tdp)); 39127a0bc89SDoug Rabson return error; 39227a0bc89SDoug Rabson } 39327a0bc89SDoug Rabson *vpp = DETOV(tdp); 39427a0bc89SDoug Rabson } else if (dp->de_StartCluster == scn && isadir) { /* "." */ 39527a0bc89SDoug Rabson VREF(vdp); 39627a0bc89SDoug Rabson *vpp = vdp; 39727a0bc89SDoug Rabson } else { 39827a0bc89SDoug Rabson error = deget(pmp, cluster, diroff, dep, &tdp); 39927a0bc89SDoug Rabson if (error) { 40027a0bc89SDoug Rabson if (bp) 40127a0bc89SDoug Rabson brelse(bp); 40227a0bc89SDoug Rabson return error; 40327a0bc89SDoug Rabson } 40427a0bc89SDoug Rabson if (!lockparent || !(flags & ISLASTCN)) 405af3f60d5SBruce Evans VOP_UNLOCK(pdp, 0, p); 40627a0bc89SDoug Rabson *vpp = DETOV(tdp); 40727a0bc89SDoug Rabson } 40827a0bc89SDoug Rabson if (bp) 40927a0bc89SDoug Rabson brelse(bp); 41027a0bc89SDoug Rabson 41127a0bc89SDoug Rabson /* 41227a0bc89SDoug Rabson * Insert name in cache if wanted. 41327a0bc89SDoug Rabson */ 41427a0bc89SDoug Rabson if (cnp->cn_flags & MAKEENTRY) 41527a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 41627a0bc89SDoug Rabson return 0; 41727a0bc89SDoug Rabson } 41827a0bc89SDoug Rabson 41927a0bc89SDoug Rabson /* 42027a0bc89SDoug Rabson * dep - directory entry to copy into the directory 42127a0bc89SDoug Rabson * ddep - directory to add to 42227a0bc89SDoug Rabson * depp - return the address of the denode for the created directory entry 42327a0bc89SDoug Rabson * if depp != 0 42427a0bc89SDoug Rabson */ 42527a0bc89SDoug Rabson int 42627a0bc89SDoug Rabson createde(dep, ddep, depp) 42727a0bc89SDoug Rabson struct denode *dep; 42827a0bc89SDoug Rabson struct denode *ddep; 42927a0bc89SDoug Rabson struct denode **depp; 43027a0bc89SDoug Rabson { 43127a0bc89SDoug Rabson int error; 43227a0bc89SDoug Rabson u_long dirclust, diroffset; 43327a0bc89SDoug Rabson struct direntry *ndep; 43427a0bc89SDoug Rabson struct msdosfsmount *pmp = ddep->de_pmp; 43527a0bc89SDoug Rabson struct buf *bp; 43627a0bc89SDoug Rabson 43727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 43827a0bc89SDoug Rabson printf("createde(dep %08x, ddep %08x, depp %08x)\n", dep, ddep, depp); 43927a0bc89SDoug Rabson #endif 44027a0bc89SDoug Rabson 44127a0bc89SDoug Rabson /* 44227a0bc89SDoug Rabson * If no space left in the directory then allocate another cluster 44327a0bc89SDoug Rabson * and chain it onto the end of the file. There is one exception 44427a0bc89SDoug Rabson * to this. That is, if the root directory has no more space it 44527a0bc89SDoug Rabson * can NOT be expanded. extendfile() checks for and fails attempts 44627a0bc89SDoug Rabson * to extend the root directory. We just return an error in that 44727a0bc89SDoug Rabson * case. 44827a0bc89SDoug Rabson */ 44927a0bc89SDoug Rabson if (ddep->de_fndclust == (u_long)-1) { 450c3c6d51eSPoul-Henning Kamp error = extendfile(ddep, 1, &bp, &dirclust, DE_CLEAR); 451c3c6d51eSPoul-Henning Kamp if (error) 45227a0bc89SDoug Rabson return error; 45327a0bc89SDoug Rabson ndep = (struct direntry *) bp->b_data; 45427a0bc89SDoug Rabson /* 45527a0bc89SDoug Rabson * Let caller know where we put the directory entry. 45627a0bc89SDoug Rabson */ 45727a0bc89SDoug Rabson ddep->de_fndclust = dirclust; 45827a0bc89SDoug Rabson ddep->de_fndoffset = diroffset = 0; 45927a0bc89SDoug Rabson /* 46027a0bc89SDoug Rabson * Update the size of the directory 46127a0bc89SDoug Rabson */ 46227a0bc89SDoug Rabson ddep->de_FileSize += pmp->pm_bpcluster; 46327a0bc89SDoug Rabson } else { 46427a0bc89SDoug Rabson /* 46527a0bc89SDoug Rabson * There is space in the existing directory. So, we just 46627a0bc89SDoug Rabson * read in the cluster with space. Copy the new directory 46727a0bc89SDoug Rabson * entry in. Then write it to disk. NOTE: DOS directories 46827a0bc89SDoug Rabson * do not get smaller as clusters are emptied. 46927a0bc89SDoug Rabson */ 47027a0bc89SDoug Rabson dirclust = ddep->de_fndclust; 47127a0bc89SDoug Rabson diroffset = ddep->de_fndoffset; 47227a0bc89SDoug Rabson 47327a0bc89SDoug Rabson error = readep(pmp, dirclust, diroffset, &bp, &ndep); 47427a0bc89SDoug Rabson if (error) 47527a0bc89SDoug Rabson return error; 47627a0bc89SDoug Rabson } 47727a0bc89SDoug Rabson DE_EXTERNALIZE(ndep, dep); 47827a0bc89SDoug Rabson 47927a0bc89SDoug Rabson /* 48027a0bc89SDoug Rabson * If they want us to return with the denode gotten. 48127a0bc89SDoug Rabson */ 48227a0bc89SDoug Rabson if (depp) { 48327a0bc89SDoug Rabson error = deget(pmp, dirclust, diroffset, ndep, depp); 48427a0bc89SDoug Rabson if (error) 48527a0bc89SDoug Rabson return error; 48627a0bc89SDoug Rabson } 487c3c6d51eSPoul-Henning Kamp error = bwrite(bp); 488c3c6d51eSPoul-Henning Kamp if (error) { 48927a0bc89SDoug Rabson vput(DETOV(*depp)); /* free the vnode we got on error */ 49027a0bc89SDoug Rabson return error; 49127a0bc89SDoug Rabson } 49227a0bc89SDoug Rabson return 0; 49327a0bc89SDoug Rabson } 49427a0bc89SDoug Rabson 49527a0bc89SDoug Rabson /* 49627a0bc89SDoug Rabson * Read in a directory entry and mark it as being deleted. 49727a0bc89SDoug Rabson */ 4987fefffeeSPoul-Henning Kamp static int 49927a0bc89SDoug Rabson markdeleted(pmp, dirclust, diroffset) 50027a0bc89SDoug Rabson struct msdosfsmount *pmp; 50127a0bc89SDoug Rabson u_long dirclust; 50227a0bc89SDoug Rabson u_long diroffset; 50327a0bc89SDoug Rabson { 50427a0bc89SDoug Rabson int error; 50527a0bc89SDoug Rabson struct direntry *ep; 50627a0bc89SDoug Rabson struct buf *bp; 50727a0bc89SDoug Rabson 50827a0bc89SDoug Rabson error = readep(pmp, dirclust, diroffset, &bp, &ep); 50927a0bc89SDoug Rabson if (error) 51027a0bc89SDoug Rabson return error; 51127a0bc89SDoug Rabson ep->deName[0] = SLOT_DELETED; 51227a0bc89SDoug Rabson return bwrite(bp); 51327a0bc89SDoug Rabson } 51427a0bc89SDoug Rabson 51527a0bc89SDoug Rabson /* 51627a0bc89SDoug Rabson * Remove a directory entry. At this point the file represented by the 51727a0bc89SDoug Rabson * directory entry to be removed is still full length until no one has it 51827a0bc89SDoug Rabson * open. When the file no longer being used msdosfs_inactive() is called 51927a0bc89SDoug Rabson * and will truncate the file to 0 length. When the vnode containing the 52027a0bc89SDoug Rabson * denode is needed for some other purpose by VFS it will call 52127a0bc89SDoug Rabson * msdosfs_reclaim() which will remove the denode from the denode cache. 52227a0bc89SDoug Rabson */ 52327a0bc89SDoug Rabson int 52427a0bc89SDoug Rabson removede(pdep,dep) 52527a0bc89SDoug Rabson struct denode *pdep; /* directory where the entry is removed */ 52627a0bc89SDoug Rabson struct denode *dep; /* file to be removed */ 52727a0bc89SDoug Rabson { 52827a0bc89SDoug Rabson struct msdosfsmount *pmp = pdep->de_pmp; 52927a0bc89SDoug Rabson int error; 53027a0bc89SDoug Rabson 53127a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 53227a0bc89SDoug Rabson printf("removede(): filename %s\n", dep->de_Name); 53327a0bc89SDoug Rabson printf("removede(): dep %08x, ndpcluster %d, ndpoffset %d\n", 53427a0bc89SDoug Rabson dep, pdep->de_fndclust, pdep->de_fndoffset); 53527a0bc89SDoug Rabson #endif 53627a0bc89SDoug Rabson 53727a0bc89SDoug Rabson /* 53827a0bc89SDoug Rabson * Read the directory block containing the directory entry we are 53927a0bc89SDoug Rabson * to make free. The nameidata structure holds the cluster number 54027a0bc89SDoug Rabson * and directory entry index number of the entry to free. 54127a0bc89SDoug Rabson */ 54227a0bc89SDoug Rabson error = markdeleted(pmp, pdep->de_fndclust, pdep->de_fndoffset); 54327a0bc89SDoug Rabson 54427a0bc89SDoug Rabson if (error == 0) 54527a0bc89SDoug Rabson dep->de_refcnt--; 54627a0bc89SDoug Rabson return error; 54727a0bc89SDoug Rabson } 54827a0bc89SDoug Rabson 54927a0bc89SDoug Rabson /* 55027a0bc89SDoug Rabson * Be sure a directory is empty except for "." and "..". Return 1 if empty, 55127a0bc89SDoug Rabson * return 0 if not empty or error. 55227a0bc89SDoug Rabson */ 55327a0bc89SDoug Rabson int 55427a0bc89SDoug Rabson dosdirempty(dep) 55527a0bc89SDoug Rabson struct denode *dep; 55627a0bc89SDoug Rabson { 55727a0bc89SDoug Rabson int dei; 55827a0bc89SDoug Rabson int error; 55927a0bc89SDoug Rabson u_long cn; 56027a0bc89SDoug Rabson daddr_t bn; 56127a0bc89SDoug Rabson struct buf *bp; 56227a0bc89SDoug Rabson struct msdosfsmount *pmp = dep->de_pmp; 56327a0bc89SDoug Rabson struct direntry *dentp; 56427a0bc89SDoug Rabson 56527a0bc89SDoug Rabson /* 56627a0bc89SDoug Rabson * Since the filesize field in directory entries for a directory is 56727a0bc89SDoug Rabson * zero, we just have to feel our way through the directory until 56827a0bc89SDoug Rabson * we hit end of file. 56927a0bc89SDoug Rabson */ 57027a0bc89SDoug Rabson for (cn = 0;; cn++) { 57127a0bc89SDoug Rabson error = pcbmap(dep, cn, &bn, 0); 57227a0bc89SDoug Rabson if (error == E2BIG) 57327a0bc89SDoug Rabson return 1; /* it's empty */ 57427a0bc89SDoug Rabson error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, 57527a0bc89SDoug Rabson &bp); 57627a0bc89SDoug Rabson if (error) 57727a0bc89SDoug Rabson return error; 57827a0bc89SDoug Rabson dentp = (struct direntry *) bp->b_data; 57927a0bc89SDoug Rabson for (dei = 0; dei < pmp->pm_depclust; dei++) { 58027a0bc89SDoug Rabson if (dentp->deName[0] != SLOT_DELETED) { 58127a0bc89SDoug Rabson /* 58227a0bc89SDoug Rabson * In dos directories an entry whose name 58327a0bc89SDoug Rabson * starts with SLOT_EMPTY (0) starts the 58427a0bc89SDoug Rabson * beginning of the unused part of the 58527a0bc89SDoug Rabson * directory, so we can just return that it 58627a0bc89SDoug Rabson * is empty. 58727a0bc89SDoug Rabson */ 58827a0bc89SDoug Rabson if (dentp->deName[0] == SLOT_EMPTY) { 58927a0bc89SDoug Rabson brelse(bp); 59027a0bc89SDoug Rabson return 1; 59127a0bc89SDoug Rabson } 59227a0bc89SDoug Rabson /* 59327a0bc89SDoug Rabson * Any names other than "." and ".." in a 59427a0bc89SDoug Rabson * directory mean it is not empty. 59527a0bc89SDoug Rabson */ 59627a0bc89SDoug Rabson if (bcmp(dentp->deName, ". ", 11) && 59727a0bc89SDoug Rabson bcmp(dentp->deName, ".. ", 11)) { 59827a0bc89SDoug Rabson brelse(bp); 59927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 60027a0bc89SDoug Rabson printf("dosdirempty(): entry %d found %02x, %02x\n", 60127a0bc89SDoug Rabson dei, dentp->deName[0], dentp->deName[1]); 60227a0bc89SDoug Rabson #endif 60327a0bc89SDoug Rabson return 0; /* not empty */ 60427a0bc89SDoug Rabson } 60527a0bc89SDoug Rabson } 60627a0bc89SDoug Rabson dentp++; 60727a0bc89SDoug Rabson } 60827a0bc89SDoug Rabson brelse(bp); 60927a0bc89SDoug Rabson } 61027a0bc89SDoug Rabson /* NOTREACHED */ 61127a0bc89SDoug Rabson } 61227a0bc89SDoug Rabson 61327a0bc89SDoug Rabson /* 61427a0bc89SDoug Rabson * Check to see if the directory described by target is in some 61527a0bc89SDoug Rabson * subdirectory of source. This prevents something like the following from 61627a0bc89SDoug Rabson * succeeding and leaving a bunch or files and directories orphaned. mv 61727a0bc89SDoug Rabson * /a/b/c /a/b/c/d/e/f Where c and f are directories. 61827a0bc89SDoug Rabson * 61927a0bc89SDoug Rabson * source - the inode for /a/b/c 62027a0bc89SDoug Rabson * target - the inode for /a/b/c/d/e/f 62127a0bc89SDoug Rabson * 62227a0bc89SDoug Rabson * Returns 0 if target is NOT a subdirectory of source. 62327a0bc89SDoug Rabson * Otherwise returns a non-zero error number. 62427a0bc89SDoug Rabson * The target inode is always unlocked on return. 62527a0bc89SDoug Rabson */ 62627a0bc89SDoug Rabson int 62727a0bc89SDoug Rabson doscheckpath(source, target) 62827a0bc89SDoug Rabson struct denode *source; 62927a0bc89SDoug Rabson struct denode *target; 63027a0bc89SDoug Rabson { 63127a0bc89SDoug Rabson daddr_t scn; 63227a0bc89SDoug Rabson struct msdosfsmount *pmp; 63327a0bc89SDoug Rabson struct direntry *ep; 63427a0bc89SDoug Rabson struct denode *dep; 63527a0bc89SDoug Rabson struct buf *bp = NULL; 63627a0bc89SDoug Rabson int error = 0; 63727a0bc89SDoug Rabson 63827a0bc89SDoug Rabson dep = target; 63927a0bc89SDoug Rabson if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 64027a0bc89SDoug Rabson (source->de_Attributes & ATTR_DIRECTORY) == 0) { 64127a0bc89SDoug Rabson error = ENOTDIR; 64227a0bc89SDoug Rabson goto out; 64327a0bc89SDoug Rabson } 64427a0bc89SDoug Rabson if (dep->de_StartCluster == source->de_StartCluster) { 64527a0bc89SDoug Rabson error = EEXIST; 64627a0bc89SDoug Rabson goto out; 64727a0bc89SDoug Rabson } 64827a0bc89SDoug Rabson if (dep->de_StartCluster == MSDOSFSROOT) 64927a0bc89SDoug Rabson goto out; 65027a0bc89SDoug Rabson for (;;) { 65127a0bc89SDoug Rabson if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 65227a0bc89SDoug Rabson error = ENOTDIR; 65327a0bc89SDoug Rabson goto out; 65427a0bc89SDoug Rabson } 65527a0bc89SDoug Rabson pmp = dep->de_pmp; 65627a0bc89SDoug Rabson scn = dep->de_StartCluster; 65727a0bc89SDoug Rabson error = bread(pmp->pm_devvp, cntobn(pmp, scn), 65827a0bc89SDoug Rabson pmp->pm_bpcluster, NOCRED, &bp); 65927a0bc89SDoug Rabson if (error) { 66027a0bc89SDoug Rabson break; 66127a0bc89SDoug Rabson } 66227a0bc89SDoug Rabson ep = (struct direntry *) bp->b_data + 1; 66327a0bc89SDoug Rabson if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 66427a0bc89SDoug Rabson bcmp(ep->deName, ".. ", 11) != 0) { 66527a0bc89SDoug Rabson error = ENOTDIR; 66627a0bc89SDoug Rabson break; 66727a0bc89SDoug Rabson } 66827a0bc89SDoug Rabson scn = getushort(ep->deStartCluster); 66927a0bc89SDoug Rabson if (scn == source->de_StartCluster) { 67027a0bc89SDoug Rabson error = EINVAL; 67127a0bc89SDoug Rabson break; 67227a0bc89SDoug Rabson } 67327a0bc89SDoug Rabson if (scn == MSDOSFSROOT) 67427a0bc89SDoug Rabson break; 67527a0bc89SDoug Rabson vput(DETOV(dep)); 67627a0bc89SDoug Rabson /* NOTE: deget() clears dep on error */ 67727a0bc89SDoug Rabson error = deget(pmp, scn, 0, ep, &dep); 67827a0bc89SDoug Rabson brelse(bp); 67927a0bc89SDoug Rabson bp = NULL; 68027a0bc89SDoug Rabson if (error) 68127a0bc89SDoug Rabson break; 68227a0bc89SDoug Rabson } 68327a0bc89SDoug Rabson out: ; 68427a0bc89SDoug Rabson if (bp) 68527a0bc89SDoug Rabson brelse(bp); 68627a0bc89SDoug Rabson if (error == ENOTDIR) 68727a0bc89SDoug Rabson printf("doscheckpath(): .. not a directory?\n"); 68827a0bc89SDoug Rabson if (dep != NULL) 68927a0bc89SDoug Rabson vput(DETOV(dep)); 69027a0bc89SDoug Rabson return error; 69127a0bc89SDoug Rabson } 69227a0bc89SDoug Rabson 69327a0bc89SDoug Rabson /* 69427a0bc89SDoug Rabson * Read in the disk block containing the directory entry (dirclu, dirofs) 69527a0bc89SDoug Rabson * and return the address of the buf header, and the address of the 69627a0bc89SDoug Rabson * directory entry within the block. 69727a0bc89SDoug Rabson */ 69827a0bc89SDoug Rabson int 69927a0bc89SDoug Rabson readep(pmp, dirclu, dirofs, bpp, epp) 70027a0bc89SDoug Rabson struct msdosfsmount *pmp; 70127a0bc89SDoug Rabson u_long dirclu, dirofs; 70227a0bc89SDoug Rabson struct buf **bpp; 70327a0bc89SDoug Rabson struct direntry **epp; 70427a0bc89SDoug Rabson { 70527a0bc89SDoug Rabson int error; 70627a0bc89SDoug Rabson daddr_t bn; 70727a0bc89SDoug Rabson 70827a0bc89SDoug Rabson bn = detobn(pmp, dirclu, dirofs); 709c3c6d51eSPoul-Henning Kamp error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp); 710c3c6d51eSPoul-Henning Kamp if (error) { 71127a0bc89SDoug Rabson *bpp = NULL; 71227a0bc89SDoug Rabson return error; 71327a0bc89SDoug Rabson } 71427a0bc89SDoug Rabson if (epp) 71527a0bc89SDoug Rabson *epp = bptoep(pmp, *bpp, dirofs); 71627a0bc89SDoug Rabson return 0; 71727a0bc89SDoug Rabson } 71827a0bc89SDoug Rabson 71927a0bc89SDoug Rabson 72027a0bc89SDoug Rabson /* 72127a0bc89SDoug Rabson * Read in the disk block containing the directory entry dep came from and 72227a0bc89SDoug Rabson * return the address of the buf header, and the address of the directory 72327a0bc89SDoug Rabson * entry within the block. 72427a0bc89SDoug Rabson */ 72527a0bc89SDoug Rabson int 72627a0bc89SDoug Rabson readde(dep, bpp, epp) 72727a0bc89SDoug Rabson struct denode *dep; 72827a0bc89SDoug Rabson struct buf **bpp; 72927a0bc89SDoug Rabson struct direntry **epp; 73027a0bc89SDoug Rabson { 73127a0bc89SDoug Rabson return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 73227a0bc89SDoug Rabson bpp, epp); 73327a0bc89SDoug Rabson } 734