1*0a6a1f1dSLionel Sambuc /* $NetBSD: msdosfs_denode.c,v 1.7 2015/03/29 05:52:59 agc Exp $ */
29f988b79SJean-Baptiste Boric
39f988b79SJean-Baptiste Boric /*-
49f988b79SJean-Baptiste Boric * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
59f988b79SJean-Baptiste Boric * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
69f988b79SJean-Baptiste Boric * All rights reserved.
79f988b79SJean-Baptiste Boric * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
89f988b79SJean-Baptiste Boric *
99f988b79SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
109f988b79SJean-Baptiste Boric * modification, are permitted provided that the following conditions
119f988b79SJean-Baptiste Boric * are met:
129f988b79SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
139f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
149f988b79SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
159f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in the
169f988b79SJean-Baptiste Boric * documentation and/or other materials provided with the distribution.
179f988b79SJean-Baptiste Boric * 3. All advertising materials mentioning features or use of this software
189f988b79SJean-Baptiste Boric * must display the following acknowledgement:
199f988b79SJean-Baptiste Boric * This product includes software developed by TooLs GmbH.
209f988b79SJean-Baptiste Boric * 4. The name of TooLs GmbH may not be used to endorse or promote products
219f988b79SJean-Baptiste Boric * derived from this software without specific prior written permission.
229f988b79SJean-Baptiste Boric *
239f988b79SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
249f988b79SJean-Baptiste Boric * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
259f988b79SJean-Baptiste Boric * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
269f988b79SJean-Baptiste Boric * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
279f988b79SJean-Baptiste Boric * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
289f988b79SJean-Baptiste Boric * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
299f988b79SJean-Baptiste Boric * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
309f988b79SJean-Baptiste Boric * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
319f988b79SJean-Baptiste Boric * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
329f988b79SJean-Baptiste Boric * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
339f988b79SJean-Baptiste Boric */
349f988b79SJean-Baptiste Boric /*
359f988b79SJean-Baptiste Boric * Written by Paul Popelka (paulp@uts.amdahl.com)
369f988b79SJean-Baptiste Boric *
379f988b79SJean-Baptiste Boric * You can do anything you want with this software, just don't say you wrote
389f988b79SJean-Baptiste Boric * it, and don't remove this notice.
399f988b79SJean-Baptiste Boric *
409f988b79SJean-Baptiste Boric * This software is provided "as is".
419f988b79SJean-Baptiste Boric *
429f988b79SJean-Baptiste Boric * The author supplies this software to be publicly redistributed on the
439f988b79SJean-Baptiste Boric * understanding that the author is not responsible for the correct
449f988b79SJean-Baptiste Boric * functioning of this software in any circumstances and is not liable for
459f988b79SJean-Baptiste Boric * any damages caused by this software.
469f988b79SJean-Baptiste Boric *
479f988b79SJean-Baptiste Boric * October 1992
489f988b79SJean-Baptiste Boric */
499f988b79SJean-Baptiste Boric
509f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
519f988b79SJean-Baptiste Boric #include "nbtool_config.h"
529f988b79SJean-Baptiste Boric #endif
539f988b79SJean-Baptiste Boric
549f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
55*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.7 2015/03/29 05:52:59 agc Exp $");
569f988b79SJean-Baptiste Boric
579f988b79SJean-Baptiste Boric #include <sys/param.h>
589f988b79SJean-Baptiste Boric
599f988b79SJean-Baptiste Boric #include <ffs/buf.h>
609f988b79SJean-Baptiste Boric
619f988b79SJean-Baptiste Boric #include <fs/msdosfs/bpb.h>
629f988b79SJean-Baptiste Boric #include <fs/msdosfs/msdosfsmount.h>
639f988b79SJean-Baptiste Boric #include <fs/msdosfs/direntry.h>
649f988b79SJean-Baptiste Boric #include <fs/msdosfs/denode.h>
659f988b79SJean-Baptiste Boric #include <fs/msdosfs/fat.h>
669f988b79SJean-Baptiste Boric
679f988b79SJean-Baptiste Boric #include <util.h>
689f988b79SJean-Baptiste Boric
699f988b79SJean-Baptiste Boric /*
709f988b79SJean-Baptiste Boric * If deget() succeeds it returns with the gotten denode locked().
719f988b79SJean-Baptiste Boric *
729f988b79SJean-Baptiste Boric * pmp - address of msdosfsmount structure of the filesystem containing
739f988b79SJean-Baptiste Boric * the denode of interest. The pm_dev field and the address of
749f988b79SJean-Baptiste Boric * the msdosfsmount structure are used.
759f988b79SJean-Baptiste Boric * dirclust - which cluster bp contains, if dirclust is 0 (root directory)
769f988b79SJean-Baptiste Boric * diroffset is relative to the beginning of the root directory,
779f988b79SJean-Baptiste Boric * otherwise it is cluster relative.
789f988b79SJean-Baptiste Boric * diroffset - offset past begin of cluster of denode we want
799f988b79SJean-Baptiste Boric * depp - returns the address of the gotten denode.
809f988b79SJean-Baptiste Boric */
819f988b79SJean-Baptiste Boric int
deget(struct msdosfsmount * pmp,u_long dirclust,u_long diroffset,struct denode ** depp)829f988b79SJean-Baptiste Boric deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
839f988b79SJean-Baptiste Boric struct denode **depp)
849f988b79SJean-Baptiste Boric /* pmp: so we know the maj/min number */
859f988b79SJean-Baptiste Boric /* dirclust: cluster this dir entry came from */
869f988b79SJean-Baptiste Boric /* diroffset: index of entry within the cluster */
879f988b79SJean-Baptiste Boric /* depp: returns the addr of the gotten denode */
889f988b79SJean-Baptiste Boric {
899f988b79SJean-Baptiste Boric int error;
909f988b79SJean-Baptiste Boric struct direntry *direntptr;
919f988b79SJean-Baptiste Boric struct denode *ldep;
929f988b79SJean-Baptiste Boric struct buf *bp;
939f988b79SJean-Baptiste Boric
949f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
959f988b79SJean-Baptiste Boric printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
969f988b79SJean-Baptiste Boric pmp, dirclust, diroffset, depp);
979f988b79SJean-Baptiste Boric #endif
989f988b79SJean-Baptiste Boric
999f988b79SJean-Baptiste Boric /*
1009f988b79SJean-Baptiste Boric * On FAT32 filesystems, root is a (more or less) normal
1019f988b79SJean-Baptiste Boric * directory
1029f988b79SJean-Baptiste Boric */
1039f988b79SJean-Baptiste Boric if (FAT32(pmp) && dirclust == MSDOSFSROOT)
1049f988b79SJean-Baptiste Boric dirclust = pmp->pm_rootdirblk;
1059f988b79SJean-Baptiste Boric
1069f988b79SJean-Baptiste Boric ldep = ecalloc(1, sizeof(*ldep));
1079f988b79SJean-Baptiste Boric ldep->de_vnode = NULL;
1089f988b79SJean-Baptiste Boric ldep->de_flag = 0;
1099f988b79SJean-Baptiste Boric ldep->de_devvp = 0;
1109f988b79SJean-Baptiste Boric ldep->de_lockf = 0;
1119f988b79SJean-Baptiste Boric ldep->de_dev = pmp->pm_dev;
1129f988b79SJean-Baptiste Boric ldep->de_dirclust = dirclust;
1139f988b79SJean-Baptiste Boric ldep->de_diroffset = diroffset;
1149f988b79SJean-Baptiste Boric ldep->de_pmp = pmp;
1159f988b79SJean-Baptiste Boric ldep->de_devvp = pmp->pm_devvp;
1169f988b79SJean-Baptiste Boric ldep->de_refcnt = 1;
1179f988b79SJean-Baptiste Boric fc_purge(ldep, 0);
1189f988b79SJean-Baptiste Boric /*
1199f988b79SJean-Baptiste Boric * Copy the directory entry into the denode area of the vnode.
1209f988b79SJean-Baptiste Boric */
1219f988b79SJean-Baptiste Boric if ((dirclust == MSDOSFSROOT
1229f988b79SJean-Baptiste Boric || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
1239f988b79SJean-Baptiste Boric && diroffset == MSDOSFSROOT_OFS) {
1249f988b79SJean-Baptiste Boric /*
1259f988b79SJean-Baptiste Boric * Directory entry for the root directory. There isn't one,
1269f988b79SJean-Baptiste Boric * so we manufacture one. We should probably rummage
1279f988b79SJean-Baptiste Boric * through the root directory and find a label entry (if it
1289f988b79SJean-Baptiste Boric * exists), and then use the time and date from that entry
1299f988b79SJean-Baptiste Boric * as the time and date for the root denode.
1309f988b79SJean-Baptiste Boric */
1319f988b79SJean-Baptiste Boric ldep->de_vnode = (struct vnode *)-1;
1329f988b79SJean-Baptiste Boric
1339f988b79SJean-Baptiste Boric ldep->de_Attributes = ATTR_DIRECTORY;
1349f988b79SJean-Baptiste Boric if (FAT32(pmp))
1359f988b79SJean-Baptiste Boric ldep->de_StartCluster = pmp->pm_rootdirblk;
1369f988b79SJean-Baptiste Boric /* de_FileSize will be filled in further down */
1379f988b79SJean-Baptiste Boric else {
1389f988b79SJean-Baptiste Boric ldep->de_StartCluster = MSDOSFSROOT;
1399f988b79SJean-Baptiste Boric ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
1409f988b79SJean-Baptiste Boric }
1419f988b79SJean-Baptiste Boric /*
1429f988b79SJean-Baptiste Boric * fill in time and date so that dos2unixtime() doesn't
1439f988b79SJean-Baptiste Boric * spit up when called from msdosfs_getattr() with root
1449f988b79SJean-Baptiste Boric * denode
1459f988b79SJean-Baptiste Boric */
1469f988b79SJean-Baptiste Boric ldep->de_CHun = 0;
1479f988b79SJean-Baptiste Boric ldep->de_CTime = 0x0000; /* 00:00:00 */
1489f988b79SJean-Baptiste Boric ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
1499f988b79SJean-Baptiste Boric | (1 << DD_DAY_SHIFT);
1509f988b79SJean-Baptiste Boric /* Jan 1, 1980 */
1519f988b79SJean-Baptiste Boric ldep->de_ADate = ldep->de_CDate;
1529f988b79SJean-Baptiste Boric ldep->de_MTime = ldep->de_CTime;
1539f988b79SJean-Baptiste Boric ldep->de_MDate = ldep->de_CDate;
1549f988b79SJean-Baptiste Boric /* leave the other fields as garbage */
1559f988b79SJean-Baptiste Boric } else {
1569f988b79SJean-Baptiste Boric error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
1579f988b79SJean-Baptiste Boric if (error) {
1589f988b79SJean-Baptiste Boric ldep->de_devvp = NULL;
1599f988b79SJean-Baptiste Boric ldep->de_Name[0] = SLOT_DELETED;
1609f988b79SJean-Baptiste Boric return (error);
1619f988b79SJean-Baptiste Boric }
1629f988b79SJean-Baptiste Boric DE_INTERNALIZE(ldep, direntptr);
1639f988b79SJean-Baptiste Boric brelse(bp, 0);
1649f988b79SJean-Baptiste Boric }
1659f988b79SJean-Baptiste Boric
1669f988b79SJean-Baptiste Boric /*
1679f988b79SJean-Baptiste Boric * Fill in a few fields of the vnode and finish filling in the
1689f988b79SJean-Baptiste Boric * denode. Then return the address of the found denode.
1699f988b79SJean-Baptiste Boric */
1709f988b79SJean-Baptiste Boric if (ldep->de_Attributes & ATTR_DIRECTORY) {
1719f988b79SJean-Baptiste Boric /*
1729f988b79SJean-Baptiste Boric * Since DOS directory entries that describe directories
1739f988b79SJean-Baptiste Boric * have 0 in the filesize field, we take this opportunity
1749f988b79SJean-Baptiste Boric * to find out the length of the directory and plug it into
1759f988b79SJean-Baptiste Boric * the denode structure.
1769f988b79SJean-Baptiste Boric */
1779f988b79SJean-Baptiste Boric u_long size;
1789f988b79SJean-Baptiste Boric
1799f988b79SJean-Baptiste Boric if (ldep->de_StartCluster != MSDOSFSROOT) {
1809f988b79SJean-Baptiste Boric error = pcbmap(ldep, CLUST_END, 0, &size, 0);
1819f988b79SJean-Baptiste Boric if (error == E2BIG) {
1829f988b79SJean-Baptiste Boric ldep->de_FileSize = de_cn2off(pmp, size);
1839f988b79SJean-Baptiste Boric error = 0;
1849f988b79SJean-Baptiste Boric } else
1859f988b79SJean-Baptiste Boric printf("deget(): pcbmap returned %d\n", error);
1869f988b79SJean-Baptiste Boric }
1879f988b79SJean-Baptiste Boric }
1889f988b79SJean-Baptiste Boric *depp = ldep;
1899f988b79SJean-Baptiste Boric return (0);
1909f988b79SJean-Baptiste Boric }
1919f988b79SJean-Baptiste Boric
1929f988b79SJean-Baptiste Boric /*
1939f988b79SJean-Baptiste Boric * Truncate the file described by dep to the length specified by length.
1949f988b79SJean-Baptiste Boric */
1959f988b79SJean-Baptiste Boric int
detrunc(struct denode * dep,u_long length,int flags,struct kauth_cred * cred)1969f988b79SJean-Baptiste Boric detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred)
1979f988b79SJean-Baptiste Boric {
1989f988b79SJean-Baptiste Boric int error;
1999f988b79SJean-Baptiste Boric int allerror = 0;
2009f988b79SJean-Baptiste Boric u_long eofentry;
2019f988b79SJean-Baptiste Boric u_long chaintofree = 0;
2029f988b79SJean-Baptiste Boric daddr_t bn, lastblock;
2039f988b79SJean-Baptiste Boric int boff;
2049f988b79SJean-Baptiste Boric int isadir = dep->de_Attributes & ATTR_DIRECTORY;
2059f988b79SJean-Baptiste Boric struct buf *bp;
2069f988b79SJean-Baptiste Boric struct msdosfsmount *pmp = dep->de_pmp;
2079f988b79SJean-Baptiste Boric
2089f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
2099f988b79SJean-Baptiste Boric printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
2109f988b79SJean-Baptiste Boric #endif
2119f988b79SJean-Baptiste Boric
2129f988b79SJean-Baptiste Boric /*
2139f988b79SJean-Baptiste Boric * Disallow attempts to truncate the root directory since it is of
2149f988b79SJean-Baptiste Boric * fixed size. That's just the way dos filesystems are. We use
2159f988b79SJean-Baptiste Boric * the VROOT bit in the vnode because checking for the directory
2169f988b79SJean-Baptiste Boric * bit and a startcluster of 0 in the denode is not adequate to
2179f988b79SJean-Baptiste Boric * recognize the root directory at this point in a file or
2189f988b79SJean-Baptiste Boric * directory's life.
2199f988b79SJean-Baptiste Boric */
2209f988b79SJean-Baptiste Boric if (dep->de_vnode != NULL && !FAT32(pmp)) {
2219f988b79SJean-Baptiste Boric printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
2229f988b79SJean-Baptiste Boric dep->de_dirclust, dep->de_diroffset);
2239f988b79SJean-Baptiste Boric return (EINVAL);
2249f988b79SJean-Baptiste Boric }
2259f988b79SJean-Baptiste Boric
2269f988b79SJean-Baptiste Boric if (dep->de_FileSize < length)
2279f988b79SJean-Baptiste Boric return (deextend(dep, length, cred));
2289f988b79SJean-Baptiste Boric lastblock = de_clcount(pmp, length) - 1;
2299f988b79SJean-Baptiste Boric
2309f988b79SJean-Baptiste Boric /*
2319f988b79SJean-Baptiste Boric * If the desired length is 0 then remember the starting cluster of
2329f988b79SJean-Baptiste Boric * the file and set the StartCluster field in the directory entry
2339f988b79SJean-Baptiste Boric * to 0. If the desired length is not zero, then get the number of
2349f988b79SJean-Baptiste Boric * the last cluster in the shortened file. Then get the number of
2359f988b79SJean-Baptiste Boric * the first cluster in the part of the file that is to be freed.
2369f988b79SJean-Baptiste Boric * Then set the next cluster pointer in the last cluster of the
2379f988b79SJean-Baptiste Boric * file to CLUST_EOFE.
2389f988b79SJean-Baptiste Boric */
2399f988b79SJean-Baptiste Boric if (length == 0) {
2409f988b79SJean-Baptiste Boric chaintofree = dep->de_StartCluster;
2419f988b79SJean-Baptiste Boric dep->de_StartCluster = 0;
2429f988b79SJean-Baptiste Boric eofentry = ~0;
2439f988b79SJean-Baptiste Boric } else {
2449f988b79SJean-Baptiste Boric error = pcbmap(dep, lastblock, 0, &eofentry, 0);
2459f988b79SJean-Baptiste Boric if (error) {
2469f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
2479f988b79SJean-Baptiste Boric printf("detrunc(): pcbmap fails %d\n", error);
2489f988b79SJean-Baptiste Boric #endif
2499f988b79SJean-Baptiste Boric return (error);
2509f988b79SJean-Baptiste Boric }
2519f988b79SJean-Baptiste Boric }
2529f988b79SJean-Baptiste Boric
2539f988b79SJean-Baptiste Boric /*
2549f988b79SJean-Baptiste Boric * If the new length is not a multiple of the cluster size then we
2559f988b79SJean-Baptiste Boric * must zero the tail end of the new last cluster in case it
2569f988b79SJean-Baptiste Boric * becomes part of the file again because of a seek.
2579f988b79SJean-Baptiste Boric */
2589f988b79SJean-Baptiste Boric if ((boff = length & pmp->pm_crbomask) != 0) {
2599f988b79SJean-Baptiste Boric if (isadir) {
2609f988b79SJean-Baptiste Boric bn = cntobn(pmp, eofentry);
2619f988b79SJean-Baptiste Boric error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
262*0a6a1f1dSLionel Sambuc pmp->pm_bpcluster, B_MODIFY, &bp);
2639f988b79SJean-Baptiste Boric if (error) {
2649f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
2659f988b79SJean-Baptiste Boric printf("detrunc(): bread fails %d\n", error);
2669f988b79SJean-Baptiste Boric #endif
2679f988b79SJean-Baptiste Boric return (error);
2689f988b79SJean-Baptiste Boric }
2699f988b79SJean-Baptiste Boric memset((char *)bp->b_data + boff, 0,
2709f988b79SJean-Baptiste Boric pmp->pm_bpcluster - boff);
2719f988b79SJean-Baptiste Boric if (flags & IO_SYNC)
2729f988b79SJean-Baptiste Boric bwrite(bp);
2739f988b79SJean-Baptiste Boric else
2749f988b79SJean-Baptiste Boric bdwrite(bp);
2759f988b79SJean-Baptiste Boric }
2769f988b79SJean-Baptiste Boric }
2779f988b79SJean-Baptiste Boric
2789f988b79SJean-Baptiste Boric /*
2799f988b79SJean-Baptiste Boric * Write out the updated directory entry. Even if the update fails
2809f988b79SJean-Baptiste Boric * we free the trailing clusters.
2819f988b79SJean-Baptiste Boric */
2829f988b79SJean-Baptiste Boric dep->de_FileSize = length;
2839f988b79SJean-Baptiste Boric if (!isadir)
2849f988b79SJean-Baptiste Boric dep->de_flag |= DE_UPDATE|DE_MODIFIED;
2859f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
2869f988b79SJean-Baptiste Boric printf("detrunc(): allerror %d, eofentry %lu\n",
2879f988b79SJean-Baptiste Boric allerror, eofentry);
2889f988b79SJean-Baptiste Boric #endif
2899f988b79SJean-Baptiste Boric
2909f988b79SJean-Baptiste Boric /*
2919f988b79SJean-Baptiste Boric * If we need to break the cluster chain for the file then do it
2929f988b79SJean-Baptiste Boric * now.
2939f988b79SJean-Baptiste Boric */
2949f988b79SJean-Baptiste Boric if (eofentry != (u_long)~0) {
2959f988b79SJean-Baptiste Boric error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
2969f988b79SJean-Baptiste Boric &chaintofree, CLUST_EOFE);
2979f988b79SJean-Baptiste Boric if (error) {
2989f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
2999f988b79SJean-Baptiste Boric printf("detrunc(): fatentry errors %d\n", error);
3009f988b79SJean-Baptiste Boric #endif
3019f988b79SJean-Baptiste Boric return (error);
3029f988b79SJean-Baptiste Boric }
3039f988b79SJean-Baptiste Boric }
3049f988b79SJean-Baptiste Boric
3059f988b79SJean-Baptiste Boric /*
3069f988b79SJean-Baptiste Boric * Now free the clusters removed from the file because of the
3079f988b79SJean-Baptiste Boric * truncation.
3089f988b79SJean-Baptiste Boric */
3099f988b79SJean-Baptiste Boric if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask))
3109f988b79SJean-Baptiste Boric freeclusterchain(pmp, chaintofree);
3119f988b79SJean-Baptiste Boric
3129f988b79SJean-Baptiste Boric return (allerror);
3139f988b79SJean-Baptiste Boric }
3149f988b79SJean-Baptiste Boric
3159f988b79SJean-Baptiste Boric /*
3169f988b79SJean-Baptiste Boric * Extend the file described by dep to length specified by length.
3179f988b79SJean-Baptiste Boric */
3189f988b79SJean-Baptiste Boric int
deextend(struct denode * dep,u_long length,struct kauth_cred * cred)3199f988b79SJean-Baptiste Boric deextend(struct denode *dep, u_long length, struct kauth_cred *cred)
3209f988b79SJean-Baptiste Boric {
3219f988b79SJean-Baptiste Boric struct msdosfsmount *pmp = dep->de_pmp;
3229f988b79SJean-Baptiste Boric u_long count;
3239f988b79SJean-Baptiste Boric int error;
3249f988b79SJean-Baptiste Boric
3259f988b79SJean-Baptiste Boric /*
3269f988b79SJean-Baptiste Boric * The root of a DOS filesystem cannot be extended.
3279f988b79SJean-Baptiste Boric */
3289f988b79SJean-Baptiste Boric if (dep->de_vnode != NULL && !FAT32(pmp))
3299f988b79SJean-Baptiste Boric return EINVAL;
3309f988b79SJean-Baptiste Boric
3319f988b79SJean-Baptiste Boric /*
3329f988b79SJean-Baptiste Boric * Directories cannot be extended.
3339f988b79SJean-Baptiste Boric */
3349f988b79SJean-Baptiste Boric if (dep->de_Attributes & ATTR_DIRECTORY)
3359f988b79SJean-Baptiste Boric return EISDIR;
3369f988b79SJean-Baptiste Boric
3379f988b79SJean-Baptiste Boric if (length <= dep->de_FileSize)
3389f988b79SJean-Baptiste Boric return E2BIG;
3399f988b79SJean-Baptiste Boric
3409f988b79SJean-Baptiste Boric /*
3419f988b79SJean-Baptiste Boric * Compute the number of clusters to allocate.
3429f988b79SJean-Baptiste Boric */
3439f988b79SJean-Baptiste Boric count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
3449f988b79SJean-Baptiste Boric if (count > 0) {
3459f988b79SJean-Baptiste Boric if (count > pmp->pm_freeclustercount)
3469f988b79SJean-Baptiste Boric return (ENOSPC);
3479f988b79SJean-Baptiste Boric error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
3489f988b79SJean-Baptiste Boric if (error) {
3499f988b79SJean-Baptiste Boric /* truncate the added clusters away again */
3509f988b79SJean-Baptiste Boric (void) detrunc(dep, dep->de_FileSize, 0, cred);
3519f988b79SJean-Baptiste Boric return (error);
3529f988b79SJean-Baptiste Boric }
3539f988b79SJean-Baptiste Boric }
3549f988b79SJean-Baptiste Boric
3559f988b79SJean-Baptiste Boric /*
3569f988b79SJean-Baptiste Boric * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a
3579f988b79SJean-Baptiste Boric * memset(); we set the write size so ubc won't read in file data that
3589f988b79SJean-Baptiste Boric * is zero'd later.
3599f988b79SJean-Baptiste Boric */
3609f988b79SJean-Baptiste Boric dep->de_FileSize = length;
3619f988b79SJean-Baptiste Boric dep->de_flag |= DE_UPDATE|DE_MODIFIED;
3629f988b79SJean-Baptiste Boric return 0;
3639f988b79SJean-Baptiste Boric }
364