150477Speter/* $FreeBSD$ */ 233548Sjkh/* $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $ */ 32893Sdfr 42893Sdfr/*- 533548Sjkh * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 633548Sjkh * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 72893Sdfr * All rights reserved. 82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 92893Sdfr * 102893Sdfr * Redistribution and use in source and binary forms, with or without 112893Sdfr * modification, are permitted provided that the following conditions 122893Sdfr * are met: 132893Sdfr * 1. Redistributions of source code must retain the above copyright 142893Sdfr * notice, this list of conditions and the following disclaimer. 152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright 162893Sdfr * notice, this list of conditions and the following disclaimer in the 172893Sdfr * documentation and/or other materials provided with the distribution. 182893Sdfr * 3. All advertising materials mentioning features or use of this software 192893Sdfr * must display the following acknowledgement: 202893Sdfr * This product includes software developed by TooLs GmbH. 212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products 222893Sdfr * derived from this software without specific prior written permission. 232893Sdfr * 242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 342893Sdfr */ 35139776Simp/*- 362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com) 378876Srgrimes * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 408876Srgrimes * 412893Sdfr * This software is provided "as is". 428876Srgrimes * 432893Sdfr * The author supplies this software to be publicly redistributed on the 442893Sdfr * understanding that the author is not responsible for the correct 452893Sdfr * functioning of this software in any circumstances and is not liable for 462893Sdfr * any damages caused by this software. 478876Srgrimes * 482893Sdfr * October 1992 492893Sdfr */ 502893Sdfr 512893Sdfr#include <sys/param.h> 522893Sdfr#include <sys/systm.h> 53171750Sbde#include <sys/buf.h> 54171750Sbde#include <sys/clock.h> 5541059Speter#include <sys/kernel.h> 56171750Sbde#include <sys/malloc.h> 572893Sdfr#include <sys/mount.h> 582893Sdfr#include <sys/vnode.h> 592893Sdfr 603152Sphk#include <vm/vm.h> 6112662Sdg#include <vm/vm_extern.h> 623152Sphk 6377162Sru#include <fs/msdosfs/bpb.h> 6477162Sru#include <fs/msdosfs/direntry.h> 6577162Sru#include <fs/msdosfs/denode.h> 6677162Sru#include <fs/msdosfs/fat.h> 67171750Sbde#include <fs/msdosfs/msdosfsmount.h> 682893Sdfr 69151897Srwatsonstatic MALLOC_DEFINE(M_MSDOSFSNODE, "msdosfs_node", "MSDOSFS vnode private part"); 7030309Sphk 71144740Sphkstatic int 72144740Sphkde_vncmpf(struct vnode *vp, void *arg) 73144740Sphk{ 74144740Sphk struct denode *de; 75144740Sphk uint64_t *a; 762893Sdfr 77144740Sphk a = arg; 78144740Sphk de = VTODE(vp); 79144740Sphk return (de->de_inode != *a); 80144740Sphk} 81144740Sphk 822893Sdfr/* 838876Srgrimes * If deget() succeeds it returns with the gotten denode locked(). 842893Sdfr * 852893Sdfr * pmp - address of msdosfsmount structure of the filesystem containing 86143667Sphk * the denode of interest. The address of 878876Srgrimes * the msdosfsmount structure are used. 882893Sdfr * dirclust - which cluster bp contains, if dirclust is 0 (root directory) 892893Sdfr * diroffset is relative to the beginning of the root directory, 908876Srgrimes * otherwise it is cluster relative. 918876Srgrimes * diroffset - offset past begin of cluster of denode we want 922893Sdfr * depp - returns the address of the gotten denode. 932893Sdfr */ 942893Sdfrint 9533548Sjkhdeget(pmp, dirclust, diroffset, depp) 962893Sdfr struct msdosfsmount *pmp; /* so we know the maj/min number */ 972893Sdfr u_long dirclust; /* cluster this dir entry came from */ 982893Sdfr u_long diroffset; /* index of entry within the cluster */ 992893Sdfr struct denode **depp; /* returns the addr of the gotten denode */ 1002893Sdfr{ 1012893Sdfr int error; 102144740Sphk uint64_t inode; 1032893Sdfr struct mount *mntp = pmp->pm_mountp; 10433548Sjkh struct direntry *direntptr; 1052893Sdfr struct denode *ldep; 106143570Sphk struct vnode *nvp, *xvp; 1072893Sdfr struct buf *bp; 1082893Sdfr 1092893Sdfr#ifdef MSDOSFS_DEBUG 11033548Sjkh printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n", 11133548Sjkh pmp, dirclust, diroffset, depp); 1122893Sdfr#endif 1132893Sdfr 1142893Sdfr /* 11533548Sjkh * On FAT32 filesystems, root is a (more or less) normal 11633548Sjkh * directory 1172893Sdfr */ 11833548Sjkh if (FAT32(pmp) && dirclust == MSDOSFSROOT) 11933548Sjkh dirclust = pmp->pm_rootdirblk; 1202893Sdfr 1212893Sdfr /* 1222893Sdfr * See if the denode is in the denode cache. Use the location of 1232893Sdfr * the directory entry to compute the hash value. For subdir use 12433548Sjkh * address of "." entry. For root dir (if not FAT32) use cluster 12533548Sjkh * MSDOSFSROOT, offset MSDOSFSROOT_OFS 1268876Srgrimes * 1272893Sdfr * NOTE: The check for de_refcnt > 0 below insures the denode being 1282893Sdfr * examined does not represent an unlinked but still open file. 1292893Sdfr * These files are not to be accessible even when the directory 1302893Sdfr * entry that represented the file happens to be reused while the 1312893Sdfr * deleted file is still open. 1322893Sdfr */ 133149850Sobrien inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset; 134144740Sphk 135144740Sphk error = vfs_hash_get(mntp, inode, LK_EXCLUSIVE, curthread, &nvp, 136144740Sphk de_vncmpf, &inode); 137143570Sphk if (error) 138171759Sbde return (error); 139143570Sphk if (nvp != NULL) { 140143570Sphk *depp = VTODE(nvp); 141144740Sphk KASSERT((*depp)->de_dirclust == dirclust, ("wrong dirclust")); 142144740Sphk KASSERT((*depp)->de_diroffset == diroffset, ("wrong diroffset")); 14333548Sjkh return (0); 1442893Sdfr } 145203826Skib ldep = malloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK | M_ZERO); 1462893Sdfr 1472893Sdfr /* 1482893Sdfr * Directory entry was not in cache, have to create a vnode and 1492893Sdfr * copy it from the passed disk buffer. 1502893Sdfr */ 1512893Sdfr /* getnewvnode() does a VREF() on the vnode */ 152138290Sphk error = getnewvnode("msdosfs", mntp, &msdosfs_vnodeops, &nvp); 1533152Sphk if (error) { 15416312Sdg *depp = NULL; 155184205Sdes free(ldep, M_MSDOSFSNODE); 1562893Sdfr return error; 1572893Sdfr } 1582893Sdfr nvp->v_data = ldep; 1592893Sdfr ldep->de_vnode = nvp; 1602893Sdfr ldep->de_flag = 0; 1612893Sdfr ldep->de_dirclust = dirclust; 1622893Sdfr ldep->de_diroffset = diroffset; 163144740Sphk ldep->de_inode = inode; 164204466Skib lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); 1652893Sdfr fc_purge(ldep, 0); /* init the fat cache for this denode */ 166167497Stegge error = insmntque(nvp, mntp); 167167497Stegge if (error != 0) { 168184205Sdes free(ldep, M_MSDOSFSNODE); 169167497Stegge *depp = NULL; 170167497Stegge return (error); 171167497Stegge } 172175635Sattilio error = vfs_hash_insert(nvp, inode, LK_EXCLUSIVE, curthread, &xvp, 173144740Sphk de_vncmpf, &inode); 174143570Sphk if (error) { 175143570Sphk *depp = NULL; 176143570Sphk return (error); 177143570Sphk } 178143570Sphk if (xvp != NULL) { 179204469Skib *depp = xvp->v_data; 180204469Skib return (0); 181143570Sphk } 1822893Sdfr 18333548Sjkh ldep->de_pmp = pmp; 18433548Sjkh ldep->de_refcnt = 1; 1852893Sdfr /* 1862893Sdfr * Copy the directory entry into the denode area of the vnode. 1872893Sdfr */ 18833548Sjkh if ((dirclust == MSDOSFSROOT 18933548Sjkh || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) 19033548Sjkh && diroffset == MSDOSFSROOT_OFS) { 1912893Sdfr /* 1922893Sdfr * Directory entry for the root directory. There isn't one, 1932893Sdfr * so we manufacture one. We should probably rummage 1942893Sdfr * through the root directory and find a label entry (if it 1952893Sdfr * exists), and then use the time and date from that entry 1962893Sdfr * as the time and date for the root denode. 1972893Sdfr */ 198101308Sjeff nvp->v_vflag |= VV_ROOT; /* should be further down XXX */ 19933548Sjkh 2002893Sdfr ldep->de_Attributes = ATTR_DIRECTORY; 20141275Sdt ldep->de_LowerCase = 0; 20233548Sjkh if (FAT32(pmp)) 20333548Sjkh ldep->de_StartCluster = pmp->pm_rootdirblk; 20433548Sjkh /* de_FileSize will be filled in further down */ 20533548Sjkh else { 20633548Sjkh ldep->de_StartCluster = MSDOSFSROOT; 20756674Snyan ldep->de_FileSize = pmp->pm_rootdirsize * DEV_BSIZE; 20833548Sjkh } 2092893Sdfr /* 210163647Sphk * fill in time and date so that fattime2timespec() doesn't 2112893Sdfr * spit up when called from msdosfs_getattr() with root 2122893Sdfr * denode 2132893Sdfr */ 21433548Sjkh ldep->de_CHun = 0; 21533548Sjkh ldep->de_CTime = 0x0000; /* 00:00:00 */ 21633548Sjkh ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT) 2172893Sdfr | (1 << DD_DAY_SHIFT); 2182893Sdfr /* Jan 1, 1980 */ 21933548Sjkh ldep->de_ADate = ldep->de_CDate; 22033548Sjkh ldep->de_MTime = ldep->de_CTime; 22133548Sjkh ldep->de_MDate = ldep->de_CDate; 2222893Sdfr /* leave the other fields as garbage */ 2232893Sdfr } else { 22433548Sjkh error = readep(pmp, dirclust, diroffset, &bp, &direntptr); 22536123Sbde if (error) { 22636123Sbde /* 22736123Sbde * The denode does not contain anything useful, so 22836123Sbde * it would be wrong to leave it on its hash chain. 22936123Sbde * Arrange for vput() to just forget about it. 23036123Sbde */ 23136123Sbde ldep->de_Name[0] = SLOT_DELETED; 23236123Sbde 23336123Sbde vput(nvp); 23436123Sbde *depp = NULL; 23533548Sjkh return (error); 23636123Sbde } 237213771Srpaulo (void)DE_INTERNALIZE(ldep, direntptr); 23833548Sjkh brelse(bp); 2392893Sdfr } 2402893Sdfr 2412893Sdfr /* 2422893Sdfr * Fill in a few fields of the vnode and finish filling in the 2432893Sdfr * denode. Then return the address of the found denode. 2442893Sdfr */ 2452893Sdfr if (ldep->de_Attributes & ATTR_DIRECTORY) { 2462893Sdfr /* 2472893Sdfr * Since DOS directory entries that describe directories 2482893Sdfr * have 0 in the filesize field, we take this opportunity 2492893Sdfr * to find out the length of the directory and plug it into 2502893Sdfr * the denode structure. 2512893Sdfr */ 2522893Sdfr u_long size; 2532893Sdfr 254101967Strhodes /* 255171759Sbde * XXX it sometimes happens that the "." entry has cluster 256171759Sbde * number 0 when it shouldn't. Use the actual cluster number 257101967Strhodes * instead of what is written in directory entry. 258101967Strhodes */ 259171759Sbde if (diroffset == 0 && ldep->de_StartCluster != dirclust) { 260227817Skib#ifdef MSDOSFS_DEBUG 261171759Sbde printf("deget(): \".\" entry at clust %lu != %lu\n", 262171759Sbde dirclust, ldep->de_StartCluster); 263227817Skib#endif 264101967Strhodes ldep->de_StartCluster = dirclust; 265101967Strhodes } 266101967Strhodes 2672893Sdfr nvp->v_type = VDIR; 26833548Sjkh if (ldep->de_StartCluster != MSDOSFSROOT) { 26933548Sjkh error = pcbmap(ldep, 0xffff, 0, &size, 0); 2702893Sdfr if (error == E2BIG) { 27133548Sjkh ldep->de_FileSize = de_cn2off(pmp, size); 2722893Sdfr error = 0; 273227817Skib } else { 274227817Skib#ifdef MSDOSFS_DEBUG 2752893Sdfr printf("deget(): pcbmap returned %d\n", error); 276227817Skib#endif 277227817Skib } 2782893Sdfr } 2792893Sdfr } else 2802893Sdfr nvp->v_type = VREG; 281134899Sphk ldep->de_modrev = init_va_filerev(); 2822893Sdfr *depp = ldep; 28333548Sjkh return (0); 2842893Sdfr} 2852893Sdfr 2862893Sdfrint 28733548Sjkhdeupdat(dep, waitfor) 2882893Sdfr struct denode *dep; 2892893Sdfr int waitfor; 2902893Sdfr{ 291250193Skib struct direntry dir; 292250193Skib struct timespec ts; 2932893Sdfr struct buf *bp; 2942893Sdfr struct direntry *dirp; 295250193Skib int error; 2962893Sdfr 297250193Skib if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) { 298250193Skib dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS | 299250193Skib DE_MODIFIED); 30033548Sjkh return (0); 301250193Skib } 30234901Sphk getnanotime(&ts); 30333548Sjkh DETIMES(dep, &ts, &ts, &ts); 304250193Skib if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0) 30533548Sjkh return (0); 30633548Sjkh dep->de_flag &= ~DE_MODIFIED; 307254627Sken if (DETOV(dep)->v_vflag & VV_ROOT) 308254627Sken return (EINVAL); 30933548Sjkh if (dep->de_refcnt <= 0) 31033548Sjkh return (0); 3113152Sphk error = readde(dep, &bp, &dirp); 3128876Srgrimes if (error) 31333548Sjkh return (error); 314250193Skib DE_EXTERNALIZE(&dir, dep); 315250193Skib if (bcmp(dirp, &dir, sizeof(dir)) == 0) { 316250193Skib if (waitfor == 0 || (bp->b_flags & B_DELWRI) == 0) { 317250193Skib brelse(bp); 318250193Skib return (0); 319250193Skib } 320250193Skib } else 321250193Skib *dirp = dir; 322250193Skib if ((DETOV(dep)->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) 323250193Skib bp->b_flags |= B_CLUSTEROK; 3242893Sdfr if (waitfor) 325250193Skib error = bwrite(bp); 326250193Skib else if (vm_page_count_severe() || buf_dirty_count_severe()) 327250193Skib bawrite(bp); 328250193Skib else 3292893Sdfr bdwrite(bp); 330250193Skib return (error); 3312893Sdfr} 3322893Sdfr 3332893Sdfr/* 3342893Sdfr * Truncate the file described by dep to the length specified by length. 3352893Sdfr */ 3362893Sdfrint 337234605Straszdetrunc(dep, length, flags, cred) 3382893Sdfr struct denode *dep; 3392893Sdfr u_long length; 3402893Sdfr int flags; 3412893Sdfr struct ucred *cred; 3422893Sdfr{ 3432893Sdfr int error; 3442893Sdfr int allerror; 3452893Sdfr u_long eofentry; 3462893Sdfr u_long chaintofree; 3472893Sdfr daddr_t bn; 3482893Sdfr int boff; 3492893Sdfr int isadir = dep->de_Attributes & ATTR_DIRECTORY; 3502893Sdfr struct buf *bp; 3512893Sdfr struct msdosfsmount *pmp = dep->de_pmp; 3522893Sdfr 3532893Sdfr#ifdef MSDOSFS_DEBUG 35433548Sjkh printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags); 3552893Sdfr#endif 3562893Sdfr 3572893Sdfr /* 3582893Sdfr * Disallow attempts to truncate the root directory since it is of 3592893Sdfr * fixed size. That's just the way dos filesystems are. We use 3602893Sdfr * the VROOT bit in the vnode because checking for the directory 3612893Sdfr * bit and a startcluster of 0 in the denode is not adequate to 3622893Sdfr * recognize the root directory at this point in a file or 3632893Sdfr * directory's life. 3642893Sdfr */ 365101308Sjeff if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) { 366227817Skib#ifdef MSDOSFS_DEBUG 36733548Sjkh printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n", 3682893Sdfr dep->de_dirclust, dep->de_diroffset); 369227817Skib#endif 37033548Sjkh return (EINVAL); 3712893Sdfr } 3722893Sdfr 37313490Sdyson if (dep->de_FileSize < length) { 37413490Sdyson vnode_pager_setsize(DETOV(dep), length); 3752893Sdfr return deextend(dep, length, cred); 37613490Sdyson } 3772893Sdfr 3782893Sdfr /* 3792893Sdfr * If the desired length is 0 then remember the starting cluster of 3802893Sdfr * the file and set the StartCluster field in the directory entry 3812893Sdfr * to 0. If the desired length is not zero, then get the number of 3822893Sdfr * the last cluster in the shortened file. Then get the number of 3832893Sdfr * the first cluster in the part of the file that is to be freed. 3842893Sdfr * Then set the next cluster pointer in the last cluster of the 3852893Sdfr * file to CLUST_EOFE. 3862893Sdfr */ 3872893Sdfr if (length == 0) { 3882893Sdfr chaintofree = dep->de_StartCluster; 3892893Sdfr dep->de_StartCluster = 0; 3902893Sdfr eofentry = ~0; 3912893Sdfr } else { 39233548Sjkh error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, 39333548Sjkh &eofentry, 0); 3943152Sphk if (error) { 3952893Sdfr#ifdef MSDOSFS_DEBUG 3962893Sdfr printf("detrunc(): pcbmap fails %d\n", error); 3972893Sdfr#endif 39833548Sjkh return (error); 3992893Sdfr } 4002893Sdfr } 4012893Sdfr 40233548Sjkh fc_purge(dep, de_clcount(pmp, length)); 4032893Sdfr 4042893Sdfr /* 4052893Sdfr * If the new length is not a multiple of the cluster size then we 4062893Sdfr * must zero the tail end of the new last cluster in case it 4072893Sdfr * becomes part of the file again because of a seek. 4082893Sdfr */ 4092893Sdfr if ((boff = length & pmp->pm_crbomask) != 0) { 4102893Sdfr if (isadir) { 4112893Sdfr bn = cntobn(pmp, eofentry); 4122893Sdfr error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, 4132893Sdfr NOCRED, &bp); 414116917Strhodes if (error) { 415116917Strhodes brelse(bp); 4162893Sdfr#ifdef MSDOSFS_DEBUG 417116917Strhodes printf("detrunc(): bread fails %d\n", error); 4182893Sdfr#endif 419116917Strhodes return (error); 420116917Strhodes } 421116917Strhodes bzero(bp->b_data + boff, pmp->pm_bpcluster - boff); 422116917Strhodes if (flags & IO_SYNC) 423116917Strhodes bwrite(bp); 424116917Strhodes else 425116917Strhodes bdwrite(bp); 4262893Sdfr } 4272893Sdfr } 4282893Sdfr 4292893Sdfr /* 4302893Sdfr * Write out the updated directory entry. Even if the update fails 4312893Sdfr * we free the trailing clusters. 4322893Sdfr */ 4332893Sdfr dep->de_FileSize = length; 43433548Sjkh if (!isadir) 435171759Sbde dep->de_flag |= DE_UPDATE | DE_MODIFIED; 436234605Strasz allerror = vtruncbuf(DETOV(dep), cred, length, pmp->pm_bpcluster); 4372893Sdfr#ifdef MSDOSFS_DEBUG 43840717Speter if (allerror) 43940717Speter printf("detrunc(): vtruncbuf error %d\n", allerror); 44040717Speter#endif 441231998Skib error = deupdat(dep, !DOINGASYNC((DETOV(dep)))); 442171759Sbde if (error != 0 && allerror == 0) 44340717Speter allerror = error; 44440717Speter#ifdef MSDOSFS_DEBUG 44533548Sjkh printf("detrunc(): allerror %d, eofentry %lu\n", 4462893Sdfr allerror, eofentry); 4472893Sdfr#endif 4482893Sdfr 4492893Sdfr /* 4502893Sdfr * If we need to break the cluster chain for the file then do it 4512893Sdfr * now. 4522893Sdfr */ 4532893Sdfr if (eofentry != ~0) { 4542893Sdfr error = fatentry(FAT_GET_AND_SET, pmp, eofentry, 4552893Sdfr &chaintofree, CLUST_EOFE); 4562893Sdfr if (error) { 4572893Sdfr#ifdef MSDOSFS_DEBUG 4582893Sdfr printf("detrunc(): fatentry errors %d\n", error); 4592893Sdfr#endif 46033548Sjkh return (error); 4612893Sdfr } 46233548Sjkh fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1), 4632893Sdfr eofentry); 4642893Sdfr } 4652893Sdfr 4662893Sdfr /* 4672893Sdfr * Now free the clusters removed from the file because of the 4682893Sdfr * truncation. 4692893Sdfr */ 47033548Sjkh if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree)) 4712893Sdfr freeclusterchain(pmp, chaintofree); 4722893Sdfr 47333548Sjkh return (allerror); 4742893Sdfr} 4752893Sdfr 4762893Sdfr/* 4772893Sdfr * Extend the file described by dep to length specified by length. 4782893Sdfr */ 4792893Sdfrint 4802893Sdfrdeextend(dep, length, cred) 4812893Sdfr struct denode *dep; 48233548Sjkh u_long length; 4832893Sdfr struct ucred *cred; 4842893Sdfr{ 4852893Sdfr struct msdosfsmount *pmp = dep->de_pmp; 4862893Sdfr u_long count; 4872893Sdfr int error; 4888876Srgrimes 4892893Sdfr /* 4902893Sdfr * The root of a DOS filesystem cannot be extended. 4912893Sdfr */ 492101308Sjeff if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) 49333548Sjkh return (EINVAL); 4942893Sdfr 4952893Sdfr /* 49633548Sjkh * Directories cannot be extended. 4972893Sdfr */ 49833548Sjkh if (dep->de_Attributes & ATTR_DIRECTORY) 49933548Sjkh return (EISDIR); 5002893Sdfr 5012893Sdfr if (length <= dep->de_FileSize) 5022893Sdfr panic("deextend: file too large"); 5038876Srgrimes 5042893Sdfr /* 5052893Sdfr * Compute the number of clusters to allocate. 5062893Sdfr */ 5072893Sdfr count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize); 5082893Sdfr if (count > 0) { 5092893Sdfr if (count > pmp->pm_freeclustercount) 51033548Sjkh return (ENOSPC); 5113152Sphk error = extendfile(dep, count, NULL, NULL, DE_CLEAR); 5123152Sphk if (error) { 5132893Sdfr /* truncate the added clusters away again */ 514234605Strasz (void) detrunc(dep, dep->de_FileSize, 0, cred); 51533548Sjkh return (error); 5162893Sdfr } 5172893Sdfr } 5182893Sdfr dep->de_FileSize = length; 519171759Sbde dep->de_flag |= DE_UPDATE | DE_MODIFIED; 520231998Skib return (deupdat(dep, !DOINGASYNC(DETOV(dep)))); 5212893Sdfr} 5222893Sdfr 5232893Sdfr/* 5242893Sdfr * Move a denode to its correct hash queue after the file it represents has 5252893Sdfr * been moved to a new directory. 5262893Sdfr */ 52733548Sjkhvoid 52833548Sjkhreinsert(dep) 5292893Sdfr struct denode *dep; 5302893Sdfr{ 531143570Sphk struct vnode *vp; 532143570Sphk 5332893Sdfr /* 5342893Sdfr * Fix up the denode cache. If the denode is for a directory, 5352893Sdfr * there is nothing to do since the hash is based on the starting 5362893Sdfr * cluster of the directory file and that hasn't changed. If for a 5372893Sdfr * file the hash is based on the location of the directory entry, 5382893Sdfr * so we must remove it from the cache and re-enter it with the 5392893Sdfr * hash based on the new location of the directory entry. 5402893Sdfr */ 541144740Sphk#if 0 54233548Sjkh if (dep->de_Attributes & ATTR_DIRECTORY) 54333548Sjkh return; 544144740Sphk#endif 545143570Sphk vp = DETOV(dep); 546149850Sobrien dep->de_inode = (uint64_t)dep->de_pmp->pm_bpcluster * dep->de_dirclust + 547171759Sbde dep->de_diroffset; 548144740Sphk vfs_hash_rehash(vp, dep->de_inode); 5492893Sdfr} 5502893Sdfr 5512893Sdfrint 5522893Sdfrmsdosfs_reclaim(ap) 5532893Sdfr struct vop_reclaim_args /* { 5542893Sdfr struct vnode *a_vp; 5552893Sdfr } */ *ap; 5562893Sdfr{ 5572893Sdfr struct vnode *vp = ap->a_vp; 5582893Sdfr struct denode *dep = VTODE(vp); 5598876Srgrimes 5602893Sdfr#ifdef MSDOSFS_DEBUG 5613498Sphk printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n", 5622893Sdfr dep, dep->de_Name, dep->de_refcnt); 5632893Sdfr#endif 5642893Sdfr 5652893Sdfr /* 566154487Salfred * Destroy the vm object and flush associated pages. 567154487Salfred */ 568154487Salfred vnode_destroy_vobject(vp); 569154487Salfred /* 57033548Sjkh * Remove the denode from its hash chain. 5712893Sdfr */ 572143570Sphk vfs_hash_remove(vp); 5732893Sdfr /* 57433548Sjkh * Purge old data structures associated with the denode. 5752893Sdfr */ 57633548Sjkh#if 0 /* XXX */ 5772893Sdfr dep->de_flag = 0; 57833548Sjkh#endif 579184205Sdes free(dep, M_MSDOSFSNODE); 5802893Sdfr vp->v_data = NULL; 5818876Srgrimes 58233548Sjkh return (0); 5832893Sdfr} 5842893Sdfr 5852893Sdfrint 5862893Sdfrmsdosfs_inactive(ap) 5872893Sdfr struct vop_inactive_args /* { 5882893Sdfr struct vnode *a_vp; 58983366Sjulian struct thread *a_td; 5902893Sdfr } */ *ap; 5912893Sdfr{ 5922893Sdfr struct vnode *vp = ap->a_vp; 5932893Sdfr struct denode *dep = VTODE(vp); 5942893Sdfr int error = 0; 5958876Srgrimes 5962893Sdfr#ifdef MSDOSFS_DEBUG 5973498Sphk printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep, dep->de_Name[0]); 5982893Sdfr#endif 5992893Sdfr 6002893Sdfr /* 60133548Sjkh * Ignore denodes related to stale file handles. 6022893Sdfr */ 603204468Skib if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY) 60423134Sbde goto out; 6052893Sdfr 6062893Sdfr /* 6072893Sdfr * If the file has been deleted and it is on a read/write 6082893Sdfr * filesystem, then truncate the file, and mark the directory slot 6092893Sdfr * as empty. (This may not be necessary for the dos filesystem.) 6102893Sdfr */ 6112893Sdfr#ifdef MSDOSFS_DEBUG 6123498Sphk printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x, MNT_RDONLY %x\n", 6132893Sdfr dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY); 6142893Sdfr#endif 6152893Sdfr if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 616234605Strasz error = detrunc(dep, (u_long) 0, 0, NOCRED); 6172893Sdfr dep->de_flag |= DE_UPDATE; 6182893Sdfr dep->de_Name[0] = SLOT_DELETED; 6192893Sdfr } 62033548Sjkh deupdat(dep, 0); 62133548Sjkh 62223134Sbdeout: 6232893Sdfr /* 62433548Sjkh * If we are done with the denode, reclaim it 62533548Sjkh * so that it can be reused immediately. 6262893Sdfr */ 6272893Sdfr#ifdef MSDOSFS_DEBUG 628103936Sjeff printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", 629103936Sjeff vrefcnt(vp), dep->de_Name[0]); 6302893Sdfr#endif 631204468Skib if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY) 632234607Strasz vrecycle(vp); 63333548Sjkh return (error); 6342893Sdfr} 635