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