xref: /dflybsd-src/usr.sbin/makefs/msdos/msdosfs_denode.c (revision 20f6ddd0df90767e1eba2d12dfa8e1769be7cec7)
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