1*20f6ddd0STomohiro Kusumi /* $NetBSD: msdosfs_denode.c,v 1.7 2015/03/29 05:52:59 agc Exp $ */ 2*20f6ddd0STomohiro Kusumi 3*20f6ddd0STomohiro Kusumi /*- 4*20f6ddd0STomohiro Kusumi * SPDX-License-Identifier: BSD-4-Clause 5*20f6ddd0STomohiro Kusumi * 6*20f6ddd0STomohiro Kusumi * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 7*20f6ddd0STomohiro Kusumi * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 8*20f6ddd0STomohiro Kusumi * All rights reserved. 9*20f6ddd0STomohiro Kusumi * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 10*20f6ddd0STomohiro Kusumi * 11*20f6ddd0STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 12*20f6ddd0STomohiro Kusumi * modification, are permitted provided that the following conditions 13*20f6ddd0STomohiro Kusumi * are met: 14*20f6ddd0STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 15*20f6ddd0STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 16*20f6ddd0STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 17*20f6ddd0STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the 18*20f6ddd0STomohiro Kusumi * documentation and/or other materials provided with the distribution. 19*20f6ddd0STomohiro Kusumi * 3. All advertising materials mentioning features or use of this software 20*20f6ddd0STomohiro Kusumi * must display the following acknowledgement: 21*20f6ddd0STomohiro Kusumi * This product includes software developed by TooLs GmbH. 22*20f6ddd0STomohiro Kusumi * 4. The name of TooLs GmbH may not be used to endorse or promote products 23*20f6ddd0STomohiro Kusumi * derived from this software without specific prior written permission. 24*20f6ddd0STomohiro Kusumi * 25*20f6ddd0STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 26*20f6ddd0STomohiro Kusumi * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27*20f6ddd0STomohiro Kusumi * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28*20f6ddd0STomohiro Kusumi * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29*20f6ddd0STomohiro Kusumi * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30*20f6ddd0STomohiro Kusumi * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31*20f6ddd0STomohiro Kusumi * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32*20f6ddd0STomohiro Kusumi * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33*20f6ddd0STomohiro Kusumi * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34*20f6ddd0STomohiro Kusumi * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35*20f6ddd0STomohiro Kusumi */ 36*20f6ddd0STomohiro Kusumi /*- 37*20f6ddd0STomohiro Kusumi * Written by Paul Popelka (paulp@uts.amdahl.com) 38*20f6ddd0STomohiro Kusumi * 39*20f6ddd0STomohiro Kusumi * You can do anything you want with this software, just don't say you wrote 40*20f6ddd0STomohiro Kusumi * it, and don't remove this notice. 41*20f6ddd0STomohiro Kusumi * 42*20f6ddd0STomohiro Kusumi * This software is provided "as is". 43*20f6ddd0STomohiro Kusumi * 44*20f6ddd0STomohiro Kusumi * The author supplies this software to be publicly redistributed on the 45*20f6ddd0STomohiro Kusumi * understanding that the author is not responsible for the correct 46*20f6ddd0STomohiro Kusumi * functioning of this software in any circumstances and is not liable for 47*20f6ddd0STomohiro Kusumi * any damages caused by this software. 48*20f6ddd0STomohiro Kusumi * 49*20f6ddd0STomohiro Kusumi * October 1992 50*20f6ddd0STomohiro Kusumi */ 51*20f6ddd0STomohiro Kusumi 52*20f6ddd0STomohiro Kusumi #include <sys/cdefs.h> 53*20f6ddd0STomohiro Kusumi __FBSDID("$FreeBSD$"); 54*20f6ddd0STomohiro Kusumi 55*20f6ddd0STomohiro Kusumi #include <sys/param.h> 56*20f6ddd0STomohiro Kusumi #include <sys/errno.h> 57*20f6ddd0STomohiro Kusumi 58*20f6ddd0STomohiro Kusumi #include <stdbool.h> 59*20f6ddd0STomohiro Kusumi #include <stdio.h> 60*20f6ddd0STomohiro Kusumi #include <string.h> 61*20f6ddd0STomohiro Kusumi #include <stdlib.h> 62*20f6ddd0STomohiro Kusumi #include <util.h> 63*20f6ddd0STomohiro Kusumi 64*20f6ddd0STomohiro Kusumi #include <vfs/msdosfs/bpb.h> 65*20f6ddd0STomohiro Kusumi #include "msdos/denode.h" 66*20f6ddd0STomohiro Kusumi #include <vfs/msdosfs/fat.h> 67*20f6ddd0STomohiro Kusumi #include <vfs/msdosfs/msdosfsmount.h> 68*20f6ddd0STomohiro Kusumi 69*20f6ddd0STomohiro Kusumi #include "makefs.h" 70*20f6ddd0STomohiro Kusumi #include "msdos.h" 71*20f6ddd0STomohiro Kusumi 72*20f6ddd0STomohiro Kusumi 73*20f6ddd0STomohiro Kusumi /* 74*20f6ddd0STomohiro Kusumi * If deget() succeeds it returns with the gotten denode locked(). 75*20f6ddd0STomohiro Kusumi * 76*20f6ddd0STomohiro Kusumi * pmp - address of msdosfsmount structure of the filesystem containing 77*20f6ddd0STomohiro Kusumi * the denode of interest. The pm_dev field and the address of 78*20f6ddd0STomohiro Kusumi * the msdosfsmount structure are used. 79*20f6ddd0STomohiro Kusumi * dirclust - which cluster bp contains, if dirclust is 0 (root directory) 80*20f6ddd0STomohiro Kusumi * diroffset is relative to the beginning of the root directory, 81*20f6ddd0STomohiro Kusumi * otherwise it is cluster relative. 82*20f6ddd0STomohiro Kusumi * diroffset - offset past begin of cluster of denode we want 83*20f6ddd0STomohiro Kusumi * depp - returns the address of the gotten denode. 84*20f6ddd0STomohiro Kusumi */ 85*20f6ddd0STomohiro Kusumi int 86*20f6ddd0STomohiro Kusumi deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, 87*20f6ddd0STomohiro Kusumi struct denode **depp) 88*20f6ddd0STomohiro Kusumi { 89*20f6ddd0STomohiro Kusumi int error; 90*20f6ddd0STomohiro Kusumi uint64_t inode; 91*20f6ddd0STomohiro Kusumi struct direntry *direntptr; 92*20f6ddd0STomohiro Kusumi struct denode *ldep; 93*20f6ddd0STomohiro Kusumi struct m_buf *bp; 94*20f6ddd0STomohiro Kusumi 95*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n", 96*20f6ddd0STomohiro Kusumi pmp, dirclust, diroffset, depp)); 97*20f6ddd0STomohiro Kusumi 98*20f6ddd0STomohiro Kusumi /* 99*20f6ddd0STomohiro Kusumi * On FAT32 filesystems, root is a (more or less) normal 100*20f6ddd0STomohiro Kusumi * directory 101*20f6ddd0STomohiro Kusumi */ 102*20f6ddd0STomohiro Kusumi if (FAT32(pmp) && dirclust == MSDOSFSROOT) 103*20f6ddd0STomohiro Kusumi dirclust = pmp->pm_rootdirblk; 104*20f6ddd0STomohiro Kusumi 105*20f6ddd0STomohiro Kusumi inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset; 106*20f6ddd0STomohiro Kusumi 107*20f6ddd0STomohiro Kusumi ldep = ecalloc(1, sizeof(*ldep)); 108*20f6ddd0STomohiro Kusumi ldep->de_vnode = NULL; 109*20f6ddd0STomohiro Kusumi ldep->de_flag = 0; 110*20f6ddd0STomohiro Kusumi ldep->de_dirclust = dirclust; 111*20f6ddd0STomohiro Kusumi ldep->de_diroffset = diroffset; 112*20f6ddd0STomohiro Kusumi /* XXX unused + non existent in DragonFly */ 113*20f6ddd0STomohiro Kusumi //ldep->de_inode = inode; 114*20f6ddd0STomohiro Kusumi ldep->de_pmp = pmp; 115*20f6ddd0STomohiro Kusumi ldep->de_refcnt = 1; 116*20f6ddd0STomohiro Kusumi fc_purge(ldep, 0); /* init the FAT cache for this denode */ 117*20f6ddd0STomohiro Kusumi /* 118*20f6ddd0STomohiro Kusumi * Copy the directory entry into the denode area of the vnode. 119*20f6ddd0STomohiro Kusumi */ 120*20f6ddd0STomohiro Kusumi if ((dirclust == MSDOSFSROOT 121*20f6ddd0STomohiro Kusumi || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) 122*20f6ddd0STomohiro Kusumi && diroffset == MSDOSFSROOT_OFS) { 123*20f6ddd0STomohiro Kusumi /* 124*20f6ddd0STomohiro Kusumi * Directory entry for the root directory. There isn't one, 125*20f6ddd0STomohiro Kusumi * so we manufacture one. We should probably rummage 126*20f6ddd0STomohiro Kusumi * through the root directory and find a label entry (if it 127*20f6ddd0STomohiro Kusumi * exists), and then use the time and date from that entry 128*20f6ddd0STomohiro Kusumi * as the time and date for the root denode. 129*20f6ddd0STomohiro Kusumi */ 130*20f6ddd0STomohiro Kusumi ldep->de_vnode = (struct vnode *)-1; 131*20f6ddd0STomohiro Kusumi 132*20f6ddd0STomohiro Kusumi ldep->de_Attributes = ATTR_DIRECTORY; 133*20f6ddd0STomohiro Kusumi ldep->de_LowerCase = 0; 134*20f6ddd0STomohiro Kusumi if (FAT32(pmp)) 135*20f6ddd0STomohiro Kusumi ldep->de_StartCluster = pmp->pm_rootdirblk; 136*20f6ddd0STomohiro Kusumi /* de_FileSize will be filled in further down */ 137*20f6ddd0STomohiro Kusumi else { 138*20f6ddd0STomohiro Kusumi ldep->de_StartCluster = MSDOSFSROOT; 139*20f6ddd0STomohiro Kusumi ldep->de_FileSize = pmp->pm_rootdirsize * DEV_BSIZE; 140*20f6ddd0STomohiro Kusumi } 141*20f6ddd0STomohiro Kusumi /* 142*20f6ddd0STomohiro Kusumi * fill in time and date so that dos2unixtime() doesn't 143*20f6ddd0STomohiro Kusumi * spit up when called from msdosfs_getattr() with root 144*20f6ddd0STomohiro Kusumi * denode 145*20f6ddd0STomohiro Kusumi */ 146*20f6ddd0STomohiro Kusumi ldep->de_CHun = 0; 147*20f6ddd0STomohiro Kusumi ldep->de_CTime = 0x0000; /* 00:00:00 */ 148*20f6ddd0STomohiro Kusumi ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT) 149*20f6ddd0STomohiro Kusumi | (1 << DD_DAY_SHIFT); 150*20f6ddd0STomohiro Kusumi /* Jan 1, 1980 */ 151*20f6ddd0STomohiro Kusumi ldep->de_ADate = ldep->de_CDate; 152*20f6ddd0STomohiro Kusumi ldep->de_MTime = ldep->de_CTime; 153*20f6ddd0STomohiro Kusumi ldep->de_MDate = ldep->de_CDate; 154*20f6ddd0STomohiro Kusumi /* leave the other fields as garbage */ 155*20f6ddd0STomohiro Kusumi } else { 156*20f6ddd0STomohiro Kusumi error = m_readep(pmp, dirclust, diroffset, &bp, &direntptr); 157*20f6ddd0STomohiro Kusumi if (error) { 158*20f6ddd0STomohiro Kusumi ldep->de_Name[0] = SLOT_DELETED; 159*20f6ddd0STomohiro Kusumi 160*20f6ddd0STomohiro Kusumi *depp = NULL; 161*20f6ddd0STomohiro Kusumi return (error); 162*20f6ddd0STomohiro Kusumi } 163*20f6ddd0STomohiro Kusumi (void)DE_INTERNALIZE(ldep, direntptr); 164*20f6ddd0STomohiro Kusumi brelse(bp); 165*20f6ddd0STomohiro Kusumi } 166*20f6ddd0STomohiro Kusumi 167*20f6ddd0STomohiro Kusumi /* 168*20f6ddd0STomohiro Kusumi * Fill in a few fields of the vnode and finish filling in the 169*20f6ddd0STomohiro Kusumi * denode. Then return the address of the found denode. 170*20f6ddd0STomohiro Kusumi */ 171*20f6ddd0STomohiro Kusumi if (ldep->de_Attributes & ATTR_DIRECTORY) { 172*20f6ddd0STomohiro Kusumi /* 173*20f6ddd0STomohiro Kusumi * Since DOS directory entries that describe directories 174*20f6ddd0STomohiro Kusumi * have 0 in the filesize field, we take this opportunity 175*20f6ddd0STomohiro Kusumi * to find out the length of the directory and plug it into 176*20f6ddd0STomohiro Kusumi * the denode structure. 177*20f6ddd0STomohiro Kusumi */ 178*20f6ddd0STomohiro Kusumi u_long size; 179*20f6ddd0STomohiro Kusumi 180*20f6ddd0STomohiro Kusumi /* 181*20f6ddd0STomohiro Kusumi * XXX it sometimes happens that the "." entry has cluster 182*20f6ddd0STomohiro Kusumi * number 0 when it shouldn't. Use the actual cluster number 183*20f6ddd0STomohiro Kusumi * instead of what is written in directory entry. 184*20f6ddd0STomohiro Kusumi */ 185*20f6ddd0STomohiro Kusumi if (diroffset == 0 && ldep->de_StartCluster != dirclust) { 186*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("deget(): \".\" entry at clust %lu != %lu\n", 187*20f6ddd0STomohiro Kusumi dirclust, ldep->de_StartCluster)); 188*20f6ddd0STomohiro Kusumi 189*20f6ddd0STomohiro Kusumi ldep->de_StartCluster = dirclust; 190*20f6ddd0STomohiro Kusumi } 191*20f6ddd0STomohiro Kusumi 192*20f6ddd0STomohiro Kusumi if (ldep->de_StartCluster != MSDOSFSROOT) { 193*20f6ddd0STomohiro Kusumi error = pcbmap(ldep, 0xffff, 0, &size, 0); 194*20f6ddd0STomohiro Kusumi if (error == E2BIG) { 195*20f6ddd0STomohiro Kusumi ldep->de_FileSize = de_cn2off(pmp, size); 196*20f6ddd0STomohiro Kusumi error = 0; 197*20f6ddd0STomohiro Kusumi } else { 198*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("deget(): pcbmap returned %d\n", 199*20f6ddd0STomohiro Kusumi error)); 200*20f6ddd0STomohiro Kusumi } 201*20f6ddd0STomohiro Kusumi } 202*20f6ddd0STomohiro Kusumi } 203*20f6ddd0STomohiro Kusumi *depp = ldep; 204*20f6ddd0STomohiro Kusumi return (0); 205*20f6ddd0STomohiro Kusumi } 206*20f6ddd0STomohiro Kusumi 207*20f6ddd0STomohiro Kusumi /* 208*20f6ddd0STomohiro Kusumi * Truncate the file described by dep to the length specified by length. 209*20f6ddd0STomohiro Kusumi */ 210*20f6ddd0STomohiro Kusumi int 211*20f6ddd0STomohiro Kusumi detrunc(struct denode *dep, u_long length, int flags) 212*20f6ddd0STomohiro Kusumi { 213*20f6ddd0STomohiro Kusumi int error; 214*20f6ddd0STomohiro Kusumi int allerror; 215*20f6ddd0STomohiro Kusumi u_long eofentry; 216*20f6ddd0STomohiro Kusumi u_long chaintofree; 217*20f6ddd0STomohiro Kusumi daddr_t bn; 218*20f6ddd0STomohiro Kusumi int boff; 219*20f6ddd0STomohiro Kusumi int isadir = dep->de_Attributes & ATTR_DIRECTORY; 220*20f6ddd0STomohiro Kusumi struct m_buf *bp; 221*20f6ddd0STomohiro Kusumi struct msdosfsmount *pmp = dep->de_pmp; 222*20f6ddd0STomohiro Kusumi 223*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): file %s, length %lu, flags %x\n", 224*20f6ddd0STomohiro Kusumi dep->de_Name, length, flags)); 225*20f6ddd0STomohiro Kusumi 226*20f6ddd0STomohiro Kusumi /* 227*20f6ddd0STomohiro Kusumi * Disallow attempts to truncate the root directory since it is of 228*20f6ddd0STomohiro Kusumi * fixed size. That's just the way dos filesystems are. We use 229*20f6ddd0STomohiro Kusumi * the VROOT bit in the vnode because checking for the directory 230*20f6ddd0STomohiro Kusumi * bit and a startcluster of 0 in the denode is not adequate to 231*20f6ddd0STomohiro Kusumi * recognize the root directory at this point in a file or 232*20f6ddd0STomohiro Kusumi * directory's life. 233*20f6ddd0STomohiro Kusumi */ 234*20f6ddd0STomohiro Kusumi if (dep->de_vnode != NULL && !FAT32(pmp)) { 235*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): can't truncate root directory, " 236*20f6ddd0STomohiro Kusumi "clust %ld, offset %ld\n", 237*20f6ddd0STomohiro Kusumi dep->de_dirclust, dep->de_diroffset)); 238*20f6ddd0STomohiro Kusumi 239*20f6ddd0STomohiro Kusumi return (EINVAL); 240*20f6ddd0STomohiro Kusumi } 241*20f6ddd0STomohiro Kusumi 242*20f6ddd0STomohiro Kusumi if (dep->de_FileSize < length) 243*20f6ddd0STomohiro Kusumi return deextend(dep, length); 244*20f6ddd0STomohiro Kusumi 245*20f6ddd0STomohiro Kusumi /* 246*20f6ddd0STomohiro Kusumi * If the desired length is 0 then remember the starting cluster of 247*20f6ddd0STomohiro Kusumi * the file and set the StartCluster field in the directory entry 248*20f6ddd0STomohiro Kusumi * to 0. If the desired length is not zero, then get the number of 249*20f6ddd0STomohiro Kusumi * the last cluster in the shortened file. Then get the number of 250*20f6ddd0STomohiro Kusumi * the first cluster in the part of the file that is to be freed. 251*20f6ddd0STomohiro Kusumi * Then set the next cluster pointer in the last cluster of the 252*20f6ddd0STomohiro Kusumi * file to CLUST_EOFE. 253*20f6ddd0STomohiro Kusumi */ 254*20f6ddd0STomohiro Kusumi if (length == 0) { 255*20f6ddd0STomohiro Kusumi chaintofree = dep->de_StartCluster; 256*20f6ddd0STomohiro Kusumi dep->de_StartCluster = 0; 257*20f6ddd0STomohiro Kusumi eofentry = ~0; 258*20f6ddd0STomohiro Kusumi } else { 259*20f6ddd0STomohiro Kusumi error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, 260*20f6ddd0STomohiro Kusumi &eofentry, 0); 261*20f6ddd0STomohiro Kusumi if (error) { 262*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): pcbmap fails %d\n", 263*20f6ddd0STomohiro Kusumi error)); 264*20f6ddd0STomohiro Kusumi return (error); 265*20f6ddd0STomohiro Kusumi } 266*20f6ddd0STomohiro Kusumi } 267*20f6ddd0STomohiro Kusumi 268*20f6ddd0STomohiro Kusumi fc_purge(dep, de_clcount(pmp, length)); 269*20f6ddd0STomohiro Kusumi 270*20f6ddd0STomohiro Kusumi /* 271*20f6ddd0STomohiro Kusumi * If the new length is not a multiple of the cluster size then we 272*20f6ddd0STomohiro Kusumi * must zero the tail end of the new last cluster in case it 273*20f6ddd0STomohiro Kusumi * becomes part of the file again because of a seek. 274*20f6ddd0STomohiro Kusumi */ 275*20f6ddd0STomohiro Kusumi if ((boff = length & pmp->pm_crbomask) != 0) { 276*20f6ddd0STomohiro Kusumi if (isadir) { 277*20f6ddd0STomohiro Kusumi bn = cntobn(pmp, eofentry); 278*20f6ddd0STomohiro Kusumi error = bread((void *)pmp->pm_devvp, bn, 279*20f6ddd0STomohiro Kusumi pmp->pm_bpcluster, 0, &bp); 280*20f6ddd0STomohiro Kusumi if (error) { 281*20f6ddd0STomohiro Kusumi brelse(bp); 282*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): bread fails %d\n", 283*20f6ddd0STomohiro Kusumi error)); 284*20f6ddd0STomohiro Kusumi 285*20f6ddd0STomohiro Kusumi return (error); 286*20f6ddd0STomohiro Kusumi } 287*20f6ddd0STomohiro Kusumi memset(bp->b_data + boff, 0, pmp->pm_bpcluster - boff); 288*20f6ddd0STomohiro Kusumi bwrite(bp); 289*20f6ddd0STomohiro Kusumi } 290*20f6ddd0STomohiro Kusumi } 291*20f6ddd0STomohiro Kusumi 292*20f6ddd0STomohiro Kusumi /* 293*20f6ddd0STomohiro Kusumi * Write out the updated directory entry. Even if the update fails 294*20f6ddd0STomohiro Kusumi * we free the trailing clusters. 295*20f6ddd0STomohiro Kusumi */ 296*20f6ddd0STomohiro Kusumi dep->de_FileSize = length; 297*20f6ddd0STomohiro Kusumi if (!isadir) 298*20f6ddd0STomohiro Kusumi dep->de_flag |= DE_UPDATE|DE_MODIFIED; 299*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): allerror %d, eofentry %lu\n", 300*20f6ddd0STomohiro Kusumi allerror, eofentry)); 301*20f6ddd0STomohiro Kusumi 302*20f6ddd0STomohiro Kusumi /* 303*20f6ddd0STomohiro Kusumi * If we need to break the cluster chain for the file then do it 304*20f6ddd0STomohiro Kusumi * now. 305*20f6ddd0STomohiro Kusumi */ 306*20f6ddd0STomohiro Kusumi if (eofentry != ~0) { 307*20f6ddd0STomohiro Kusumi error = fatentry(FAT_GET_AND_SET, pmp, eofentry, 308*20f6ddd0STomohiro Kusumi &chaintofree, CLUST_EOFE); 309*20f6ddd0STomohiro Kusumi if (error) { 310*20f6ddd0STomohiro Kusumi MSDOSFS_DPRINTF(("detrunc(): fatentry errors %d\n", 311*20f6ddd0STomohiro Kusumi error)); 312*20f6ddd0STomohiro Kusumi return (error); 313*20f6ddd0STomohiro Kusumi } 314*20f6ddd0STomohiro Kusumi fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1), 315*20f6ddd0STomohiro Kusumi eofentry); 316*20f6ddd0STomohiro Kusumi } 317*20f6ddd0STomohiro Kusumi 318*20f6ddd0STomohiro Kusumi /* 319*20f6ddd0STomohiro Kusumi * Now free the clusters removed from the file because of the 320*20f6ddd0STomohiro Kusumi * truncation. 321*20f6ddd0STomohiro Kusumi */ 322*20f6ddd0STomohiro Kusumi if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree)) 323*20f6ddd0STomohiro Kusumi freeclusterchain(pmp, chaintofree); 324*20f6ddd0STomohiro Kusumi 325*20f6ddd0STomohiro Kusumi return (allerror); 326*20f6ddd0STomohiro Kusumi } 327*20f6ddd0STomohiro Kusumi 328*20f6ddd0STomohiro Kusumi /* 329*20f6ddd0STomohiro Kusumi * Extend the file described by dep to length specified by length. 330*20f6ddd0STomohiro Kusumi */ 331*20f6ddd0STomohiro Kusumi int 332*20f6ddd0STomohiro Kusumi deextend(struct denode *dep, u_long length) 333*20f6ddd0STomohiro Kusumi { 334*20f6ddd0STomohiro Kusumi struct msdosfsmount *pmp = dep->de_pmp; 335*20f6ddd0STomohiro Kusumi u_long count; 336*20f6ddd0STomohiro Kusumi int error; 337*20f6ddd0STomohiro Kusumi 338*20f6ddd0STomohiro Kusumi /* 339*20f6ddd0STomohiro Kusumi * The root of a DOS filesystem cannot be extended. 340*20f6ddd0STomohiro Kusumi */ 341*20f6ddd0STomohiro Kusumi if (dep->de_vnode != NULL && !FAT32(pmp)) 342*20f6ddd0STomohiro Kusumi return (EINVAL); 343*20f6ddd0STomohiro Kusumi 344*20f6ddd0STomohiro Kusumi /* 345*20f6ddd0STomohiro Kusumi * Directories cannot be extended. 346*20f6ddd0STomohiro Kusumi */ 347*20f6ddd0STomohiro Kusumi if (dep->de_Attributes & ATTR_DIRECTORY) 348*20f6ddd0STomohiro Kusumi return (EISDIR); 349*20f6ddd0STomohiro Kusumi 350*20f6ddd0STomohiro Kusumi if (length <= dep->de_FileSize) 351*20f6ddd0STomohiro Kusumi return (E2BIG); 352*20f6ddd0STomohiro Kusumi 353*20f6ddd0STomohiro Kusumi /* 354*20f6ddd0STomohiro Kusumi * Compute the number of clusters to allocate. 355*20f6ddd0STomohiro Kusumi */ 356*20f6ddd0STomohiro Kusumi count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize); 357*20f6ddd0STomohiro Kusumi if (count > 0) { 358*20f6ddd0STomohiro Kusumi if (count > pmp->pm_freeclustercount) 359*20f6ddd0STomohiro Kusumi return (ENOSPC); 360*20f6ddd0STomohiro Kusumi error = m_extendfile(dep, count, NULL, NULL, DE_CLEAR); 361*20f6ddd0STomohiro Kusumi if (error) { 362*20f6ddd0STomohiro Kusumi /* truncate the added clusters away again */ 363*20f6ddd0STomohiro Kusumi (void) detrunc(dep, dep->de_FileSize, 0); 364*20f6ddd0STomohiro Kusumi return (error); 365*20f6ddd0STomohiro Kusumi } 366*20f6ddd0STomohiro Kusumi } 367*20f6ddd0STomohiro Kusumi 368*20f6ddd0STomohiro Kusumi /* 369*20f6ddd0STomohiro Kusumi * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a 370*20f6ddd0STomohiro Kusumi * memset(); we set the write size so ubc won't read in file data that 371*20f6ddd0STomohiro Kusumi * is zero'd later. 372*20f6ddd0STomohiro Kusumi */ 373*20f6ddd0STomohiro Kusumi dep->de_FileSize = length; 374*20f6ddd0STomohiro Kusumi dep->de_flag |= DE_UPDATE | DE_MODIFIED; 375*20f6ddd0STomohiro Kusumi return 0; 376*20f6ddd0STomohiro Kusumi } 377