1/*
2 * Copyright (c) 2000-2008,2010-2011,2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* $FreeBSD: src/sys/msdosfs/msdosfs_denode.c,v 1.48 2000/05/05 09:58:34 phk Exp $ */
24/*	$NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $	*/
25
26/*-
27 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
28 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
29 * All rights reserved.
30 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 *    must display the following acknowledgement:
42 *	This product includes software developed by TooLs GmbH.
43 * 4. The name of TooLs GmbH may not be used to endorse or promote products
44 *    derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57/*
58 * Written by Paul Popelka (paulp@uts.amdahl.com)
59 *
60 * You can do anything you want with this software, just don't say you wrote
61 * it, and don't remove this notice.
62 *
63 * This software is provided "as is".
64 *
65 * The author supplies this software to be publicly redistributed on the
66 * understanding that the author is not responsible for the correct
67 * functioning of this software in any circumstances and is not liable for
68 * any damages caused by this software.
69 *
70 * October 1992
71 */
72
73#include <sys/param.h>
74#include <sys/systm.h>
75#include <sys/kernel.h>
76#include <sys/mount.h>
77#include <sys/malloc.h>
78#include <sys/proc.h>
79#include <sys/buf.h>
80#include <sys/vnode.h>
81#include <sys/ubc.h>
82#include <sys/namei.h>
83#include <mach/boolean.h>
84#include <libkern/OSMalloc.h>
85
86#include "bpb.h"
87#include "msdosfsmount.h"
88#include "direntry.h"
89#include "denode.h"
90#include "fat.h"
91#include "msdosfs_kdebug.h"
92
93#ifndef DEBUG
94#define DEBUG 0
95#endif
96
97OSMallocTag  msdosfs_node_tag = NULL;
98static lck_mtx_t *msdosfs_hash_lock = NULL;
99
100static struct denode **dehashtbl = NULL;
101static unsigned long dehash;			/* size of hash table - 1 */
102#define	DEHASH(dev, dcl, doff)	(dehashtbl[(minor(dev) + (dcl) + (doff)) & dehash])
103
104union _qcvt {
105	quad_t qcvt;
106	int32_t val[2];
107};
108#define SETHIGH(q, h) { \
109	union _qcvt tmp; \
110	tmp.qcvt = (q); \
111	tmp.val[_QUAD_HIGHWORD] = (h); \
112	(q) = tmp.qcvt; \
113}
114#define SETLOW(q, l) { \
115	union _qcvt tmp; \
116	tmp.qcvt = (q); \
117	tmp.val[_QUAD_LOWWORD] = (l); \
118	(q) = tmp.qcvt; \
119}
120
121struct denode *msdosfs_hash_get(dev_t dev, uint32_t dirclust, uint32_t diroff);
122void msdosfs_hash_insert(struct denode *dep);
123void msdosfs_hash_remove(struct denode *dep);
124
125void msdosfs_hash_init(void)
126{
127	msdosfs_hash_lock = lck_mtx_alloc_init(msdosfs_lck_grp, msdosfs_lck_attr);
128    msdosfs_node_tag = OSMalloc_Tagalloc("msdosfs denode", OSMT_DEFAULT);
129    dehashtbl = hashinit(desiredvnodes, M_TEMP, &dehash);
130}
131
132void msdosfs_hash_uninit(void)
133{
134	if (dehashtbl)
135		FREE(dehashtbl, M_TEMP);
136	if (msdosfs_node_tag)
137		OSMalloc_Tagfree(msdosfs_node_tag);
138	if (msdosfs_hash_lock)
139		lck_mtx_free(msdosfs_hash_lock, msdosfs_lck_grp);
140}
141
142/*
143 * Look for a given denode in the denode hash.  If found,
144 * return with a use_count reference on the vnode.
145 *
146 * Assumes the msdosfs_hash_lock has already been acquired.
147 */
148struct denode *msdosfs_hash_get(dev_t dev, uint32_t dirclust, uint32_t diroff)
149{
150	int error;
151	struct denode *dep;
152	vnode_t vp;
153	u_int32_t vid;
154	struct denode *found = 0;	/* Only used if DEBUG is non-zero */
155
156loop:
157	for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next)
158	{
159		if (dirclust == dep->de_dirclust
160		    && diroff == dep->de_diroffset
161		    && dev == dep->de_dev
162		    && dep->de_refcnt != 0)
163		{
164			if (ISSET(dep->de_flag, DE_INIT))
165			{
166				/*
167				 * Denode is being initialized. Wait for it to complete.
168				 * We unlock the hash lock while sleeping to avoid deadlock.
169				 */
170				SET(dep->de_flag, DE_WAITINIT);
171				msleep(dep, msdosfs_hash_lock, PINOD, "msdosfs_hash_get", 0);
172				goto loop;
173			}
174
175			/* If the vnode has been deleted, ignore it */
176			if (dep->de_refcnt <= 0)
177			{
178				if (DEBUG)
179					printf("msdosfs_hash_get: found deleted object\n");
180				msdosfs_hash_remove(dep);
181				goto loop;
182			}
183
184			/*
185			 * Make sure the vnode isn't being terminated.  NOTE: we have to
186			 * drop the hash lock to avoid deadlock with other threads that
187			 * may be trying to terminate this vnode.
188			 */
189			vp = DETOV(dep);
190			vid = vnode_vid(vp);
191			lck_mtx_unlock(msdosfs_hash_lock);
192			error = vnode_getwithvid(vp, vid);
193			lck_mtx_lock(msdosfs_hash_lock);
194			if (error)
195				goto loop;
196
197			if (DEBUG)
198			{
199				if (found)
200					panic("msdosfs_hash_get: multiple denodes");
201				found = dep;
202				continue;
203			}
204			return dep;
205		}
206	}
207	if (DEBUG)
208		return found;
209
210	return NULL;
211}
212
213/*
214 * Insert a given denode in the denode hash.
215 *
216 * Assumes the msdosfs_hash_lock has already been acquired.  Assumes the
217 * denode is not currently in the hash.
218 */
219void msdosfs_hash_insert(struct denode *dep)
220{
221	struct denode **depp, *deq;
222
223	if (DEBUG)
224	{
225		struct denode *found;
226		found = msdosfs_hash_get(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
227		if (found)
228			panic("msdosfs_hash_insert: denode already in hash? found=%p", found);
229	}
230
231	depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
232	deq = *depp;
233	if (deq)
234		deq->de_prev = &dep->de_next;
235	dep->de_next = deq;
236	dep->de_prev = depp;
237	*depp = dep;
238}
239
240/*
241 * Remove a given denode in the denode hash.
242 *
243 * Assumes the msdosfs_hash_lock has already been acquired.
244 */
245void msdosfs_hash_remove(struct denode *dep)
246{
247	struct denode *deq;
248
249	deq = dep->de_next;
250	if (deq)
251		deq->de_prev = dep->de_prev;
252	*dep->de_prev = deq;
253}
254
255/*
256 * If msdosfs_deget() succeeds it returns with an io_count reference on the denode's
257 * corresponding vnode.  If not returning that vnode to VFS, then be sure
258 * to vnode_put it!
259 *
260 * pmp	     - address of msdosfsmount structure of the filesystem containing
261 *	       the denode of interest.  The pm_dev field and the address of
262 *	       the msdosfsmount structure are used.
263 * dirclust  - which cluster bp contains, if dirclust is 0 (root directory)
264 *	       diroffset is relative to the beginning of the root directory,
265 *	       otherwise it is cluster relative.
266 * diroffset - offset from start of parent directory to the directory entry we want
267 * dvp		 - parent directory
268 * cnp		 - name used to look up the denode
269 * depp	     - returns the address of the gotten denode.
270 */
271int msdosfs_deget(
272	struct msdosfsmount *pmp,	/* so we know the maj/min number */
273	uint32_t dirclust,			/* cluster this dir entry came from */
274	uint32_t diroffset,			/* index of entry within the cluster */
275	vnode_t dvp,				/* parent directory */
276	struct componentname *cnp,	/* name used to find this node */
277	struct denode **depp,		/* returns the addr of the gotten denode */
278	vfs_context_t context)
279{
280	int error;
281	dev_t dev = pmp->pm_dev;
282	struct mount *mntp = pmp->pm_mountp;
283	struct denode *dep;
284	struct dosdirentry *direntptr;
285	struct buf *bp = NULL;
286	struct timeval tv;
287	struct vnode_fsparam vfsp;
288	enum vtype vtype;
289
290	/*
291	 * On FAT32 filesystems, root is a (more or less) normal
292	 * directory
293	 */
294	if (FAT32(pmp) && dirclust == MSDOSFSROOT)
295		dirclust = pmp->pm_rootdirblk;
296
297	/*
298	 * Lock the hash so that we can't race against another msdosfs_deget(),
299	 * VNOP_RECLAIM, etc.
300	 */
301	lck_mtx_lock(msdosfs_hash_lock);
302
303	/*
304	 * See if the denode is already in our hash.  If so,
305	 * just return it.
306	 */
307	dep = msdosfs_hash_get(dev, dirclust, diroffset);
308	if (dep != NULL) {
309		*depp = dep;
310		if (dvp && cnp && (cnp->cn_flags & MAKEENTRY) && (dep->de_flag & DE_ROOT) == 0)
311			cache_enter(dvp, DETOV(dep), cnp);
312		if (dep->de_parent == NULL && dvp != NULLVP && (dep->de_flag & DE_ROOT) == 0)
313		{
314			if (DEBUG) printf("msdosfs_deget: fixing de_parent\n");
315			dep->de_parent = VTODE(dvp);
316		}
317		lck_mtx_unlock(msdosfs_hash_lock);
318		return 0;
319	}
320
321	/*
322	 * There was nothing in the hash.  Before we block on I/O,
323	 * we need to insert a matching denode marked as being
324	 * initialized.  Any other msdosfs_deget() will block until we're
325	 * finished here, and either find the fully initialized
326	 * denode, or none at all.
327	 */
328	dep = OSMalloc(sizeof(struct denode), msdosfs_node_tag);
329	if (dep == NULL) {
330		*depp = NULL;
331		lck_mtx_unlock(msdosfs_hash_lock);
332		return ENOMEM;
333	}
334	bzero(dep, sizeof *dep);
335	dep->de_lock = lck_mtx_alloc_init(msdosfs_lck_grp, msdosfs_lck_attr);
336	dep->de_cluster_lock = lck_mtx_alloc_init(msdosfs_lck_grp, msdosfs_lck_attr);
337	dep->de_pmp = pmp;
338	dep->de_devvp = pmp->pm_devvp;
339	dep->de_dev = dev;
340	dep->de_dirclust = dirclust;
341	dep->de_diroffset = diroffset;
342	dep->de_refcnt = 1;
343	SET(dep->de_flag, DE_INIT);
344	msdosfs_hash_insert(dep);
345	lck_mtx_unlock(msdosfs_hash_lock);
346
347	vfsp.vnfs_markroot = 0;	/* Assume not the root */
348
349	/*
350	 * Copy the directory entry into the denode
351	 */
352	if ((dirclust == MSDOSFSROOT
353	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
354	    && diroffset == MSDOSFSROOT_OFS) {
355		/*
356		 * Directory entry for the root directory. There isn't one,
357		 * so we manufacture one. We should probably rummage
358		 * through the root directory and find a label entry (if it
359		 * exists), and then use the time and date from that entry
360		 * as the time and date for the root denode.
361		 */
362		vfsp.vnfs_markroot = 1;
363		SET(dep->de_flag, DE_ROOT);
364
365		bcopy("           ", dep->de_Name, 11);
366		dep->de_Attributes = ATTR_DIRECTORY;
367		dep->de_LowerCase = 0;
368		if (FAT32(pmp))
369			dep->de_StartCluster = pmp->pm_rootdirblk;
370			/* de_FileSize will be filled in further down */
371		else {
372			dep->de_StartCluster = MSDOSFSROOT;
373			dep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BlockSize;
374		}
375		/*
376		 * fill in time and date so that msdosfs_dos2unixtime() doesn't
377		 * spit up when called from msdosfs_vnop_getattr() with root
378		 * denode
379		 */
380		dep->de_CHun = 0;
381		dep->de_CTime = 0x0000;	/* 00:00:00	 */
382		dep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
383		    | (1 << DD_DAY_SHIFT);
384		/* Jan 1, 1980	 */
385		dep->de_ADate = dep->de_CDate;
386		dep->de_MTime = dep->de_CTime;
387		dep->de_MDate = dep->de_CDate;
388		/* leave the other fields as garbage */
389
390		/*
391		 * If there is a volume label entry, then grab the times from it instead.
392		 */
393		if (pmp->pm_label_cluster != CLUST_EOFE) {
394			error = msdosfs_readep(pmp, pmp->pm_label_cluster, pmp->pm_label_offset,
395					&bp, &direntptr, context);
396			if (!error) {
397				dep->de_CHun = direntptr->deCHundredth;
398				dep->de_CTime = getuint16(direntptr->deCTime);
399				dep->de_CDate = getuint16(direntptr->deCDate);
400				dep->de_ADate = getuint16(direntptr->deADate);
401				dep->de_MTime = getuint16(direntptr->deMTime);
402				dep->de_MDate = getuint16(direntptr->deMDate);
403				buf_brelse(bp);
404				bp = NULL;
405			}
406		}
407	} else {
408		/* Not the root directory */
409
410		/* Get the non-date values from the given directory entry */
411		error = msdosfs_readep(pmp, dirclust, diroffset, &bp, &direntptr, context);
412		if (error) goto fail;
413		bcopy(direntptr->deName, dep->de_Name, 11);
414		dep->de_Attributes = direntptr->deAttributes;
415		dep->de_LowerCase = direntptr->deLowerCase;
416		dep->de_StartCluster = getuint16(direntptr->deStartCluster);
417		if (FAT32(pmp))
418			dep->de_StartCluster |= getuint16(direntptr->deHighClust) << 16;
419		dep->de_FileSize = getuint32(direntptr->deFileSize);
420
421		/* For directories, the dates/times come from its "." entry */
422		if (direntptr->deAttributes & ATTR_DIRECTORY)
423		{
424			buf_brelse(bp);
425			bp = NULL;
426			if (DEBUG)
427			{
428				if (dep->de_StartCluster < CLUST_FIRST || dep->de_StartCluster > pmp->pm_maxcluster)
429					panic("msdosfs_deget: directory de_StartCluster=%u", dep->de_StartCluster);
430			}
431			error = msdosfs_readep(pmp, dep->de_StartCluster, 0, &bp, &direntptr, context);
432			if (error) goto fail;
433		}
434
435		/* Copy the dates and times */
436		dep->de_CHun = direntptr->deCHundredth;
437		dep->de_CTime = getuint16(direntptr->deCTime);
438		dep->de_CDate = getuint16(direntptr->deCDate);
439		dep->de_ADate = getuint16(direntptr->deADate);
440		dep->de_MTime = getuint16(direntptr->deMTime);
441		dep->de_MDate = getuint16(direntptr->deMDate);
442
443		buf_brelse(bp);
444		bp = NULL;
445	}
446
447	/*
448	 * Determine initial values for vnode fields, and finish
449	 * populating the denode.
450	 */
451	if (dep->de_Attributes & ATTR_DIRECTORY) {
452		/*
453		 * Since DOS directory entries that describe directories
454		 * have 0 in the filesize field, we take this opportunity
455		 * to find out the length of the directory and plug it into
456		 * the denode structure.
457		 */
458		uint32_t size;
459
460		vtype = VDIR;
461		if (dep->de_StartCluster != MSDOSFSROOT) {
462			error = msdosfs_pcbmap(dep, 0xFFFFFFFF, 1, NULL, &size, &dep->de_LastCluster);
463			if (error == E2BIG) {
464				dep->de_FileSize = de_cn2off(pmp, size);
465				error = 0;
466			}
467			if (error)
468				goto fail;
469		}
470	} else {
471		/*
472		 * We found a regular file.  See if it is really a symlink.
473		 */
474		vtype = msdosfs_check_link(dep, context);
475	}
476	getmicrouptime(&tv);
477	SETHIGH(dep->de_modrev, (int32_t)tv.tv_sec);
478	SETLOW(dep->de_modrev, tv.tv_usec * 4294);
479
480	/* Remember the parent denode */
481	dep->de_parent = (dvp != NULLVP) ? VTODE(dvp) : NULL;
482
483	/*
484	 * Create the vnode
485	 */
486	vfsp.vnfs_mp = mntp;
487	vfsp.vnfs_vtype = vtype;
488	vfsp.vnfs_str = "msdosfs";
489	vfsp.vnfs_dvp = dvp;
490	vfsp.vnfs_fsnode = dep;
491	vfsp.vnfs_cnp = cnp;
492	vfsp.vnfs_vops = msdosfs_vnodeop_p;
493	vfsp.vnfs_rdev = 0;		/* msdosfs doesn't support block devices */
494	vfsp.vnfs_filesize = dep->de_FileSize;
495	if (dvp && cnp && (cnp->cn_flags & MAKEENTRY))
496		vfsp.vnfs_flags = 0;
497	else
498		vfsp.vnfs_flags = VNFS_NOCACHE;
499	/* vfsp.vnfs_markroot was set or cleared above */
500	vfsp.vnfs_marksystem = 0;	/* msdosfs has no "system" vnodes */
501
502	error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &dep->de_vnode);
503	if (error)
504		goto fail;
505
506	/*
507	 * Take an "fs"  reference on the new vnode on
508	 * behalf of the denode.
509	 */
510	vnode_addfsref(dep->de_vnode);
511
512	/*
513	 * Return it.  We're done.
514	 */
515	*depp = dep;
516
517	CLR(dep->de_flag, DE_INIT);
518	if (ISSET(dep->de_flag, DE_WAITINIT))
519		wakeup(dep);
520
521	return 0;
522
523fail:
524	if (bp)
525		buf_brelse(bp);
526
527	lck_mtx_lock(msdosfs_hash_lock);
528	msdosfs_hash_remove(dep);
529	lck_mtx_unlock(msdosfs_hash_lock);
530
531	if (ISSET(dep->de_flag, DE_WAITINIT))
532		wakeup(dep);
533
534	OSFree(dep, sizeof *dep, msdosfs_node_tag);
535
536	return error;
537}
538
539int msdosfs_deupdat(struct denode *dep, int waitfor, vfs_context_t context)
540{
541#pragma unused (waitfor)
542    int error = 0;
543    int isRoot = 0;
544    int isDir = 0;
545    uint32_t dirclust, diroffset;
546    struct buf *bp;
547    struct dosdirentry *dirp;
548    struct timespec ts;
549    struct msdosfsmount *pmp = dep->de_pmp;
550
551    if (vnode_vfsisrdonly(DETOV(dep)))
552	return (0);
553    getnanotime(&ts);
554    DETIMES(dep, &ts, &ts, &ts);
555    if ((dep->de_flag & DE_MODIFIED) == 0)
556	return 0;
557
558    isRoot = dep->de_flag & DE_ROOT;
559    isDir = dep->de_Attributes & ATTR_DIRECTORY;
560
561    if (isRoot && pmp->pm_label_cluster == CLUST_EOFE)
562	return 0;				/* There is no volume label entry to update. */
563    if (dep->de_refcnt <= 0)
564	return 0;				/* Object was deleted from the namespace. */
565
566    /*
567     * Update the fields, like times, which go in the directory entry.
568     *
569     * Windows never updates the times in a directory's directory entry.
570     * Since we wish to update them persistently, we use the times from
571     * the "." entry in the directory.  Since the root doesn't have a "."
572     * entry, we use the times in the volume label entry (if there is one).
573     */
574    if (dep->de_flag & DE_MODIFIED)
575    {
576	dep->de_flag &= ~DE_MODIFIED;
577
578	/*
579	 * Read in the directory entry to be updated.
580	 * For files, this is just the file's directory entry (in its parent).
581	 * For directories, this is the "." entry inside the directory.
582	 * For the root, this is the volume label's directory entry.
583	 */
584	if (isDir)
585	{
586	    if (isRoot)
587	    {
588		dirclust = pmp->pm_label_cluster;
589		diroffset = pmp->pm_label_offset;
590	    }
591	    else
592	    {
593		dirclust = dep->de_StartCluster;
594		diroffset = 0;
595	    }
596	}
597	else
598	{
599	    dirclust = dep->de_dirclust;
600	    diroffset = dep->de_diroffset;
601	}
602	error = msdosfs_readep(pmp, dirclust, diroffset, &bp, &dirp, context);
603	if (error) return (error);
604
605	if (isRoot)
606	    DE_EXTERNALIZE_ROOT(dirp, dep);
607	else
608	{
609	    if (DEBUG)
610	    {
611		if ((dirp->deAttributes ^ dep->de_Attributes) & ATTR_DIRECTORY)
612		    panic("deupdate: attributes are wrong");
613		if (!isDir && bcmp(dirp->deName, dep->de_Name, SHORT_NAME_LEN))
614		{
615		    panic("msdosfs_deupdat: file name is wrong");
616		}
617	    }
618	    DE_EXTERNALIZE(dirp, dep);
619	}
620
621	error = buf_bdwrite(bp);
622	bp = NULL;
623    }
624
625    /*
626     * We need to be able to update the de_Attributes for a directory (in the
627     * directory's own entry, not the "." or volume label entry) so that we can
628     * change its hidden bit.  For files, we've already updated the de_Attributes
629     * above.
630     */
631    if (error == 0 && (dep->de_flag & DE_ATTR_MOD))
632    {
633	dep->de_flag &= ~DE_ATTR_MOD;
634
635	if (isDir && !isRoot)
636	{
637	    error = msdosfs_readep(pmp, dep->de_dirclust, dep->de_diroffset, &bp, &dirp, context);
638	    if (error) return error;
639	    dirp->deAttributes = dep->de_Attributes;
640	    error = buf_bdwrite(bp);
641	    bp = NULL;
642	}
643    }
644    return error;
645}
646
647/*
648 * Truncate the file described by dep to the length specified by length.
649 *
650 * NOTE: This function takes care of updating dep->de_FileSize and calling
651 * ubc_setsize with new length.
652 */
653int msdosfs_detrunc(struct denode *dep, uint32_t length, int flags, vfs_context_t context)
654{
655    int error;
656    int allerror;
657    int cluster_locked = 0;
658    uint32_t eofentry;
659    uint32_t chaintofree;
660    int isadir = dep->de_Attributes & ATTR_DIRECTORY;
661    struct msdosfsmount *pmp = dep->de_pmp;
662    vnode_t vp = DETOV(dep);
663
664    /*
665     * Disallow attempts to truncate the root directory since it is of
666     * fixed size.  That's just the way dos filesystems are.  We use
667     * the VROOT bit in the vnode because checking for the directory
668     * bit and a startcluster of 0 in the denode is not adequate to
669     * recognize the root directory at this point in a file or
670     * directory's life.
671     */
672    if (vnode_isvroot(vp) && !FAT32(pmp)) {
673        printf("msdosfs_detrunc(): can't truncate root directory, clust %d, offset %d\n",
674               dep->de_dirclust, dep->de_diroffset);
675        return (EINVAL);
676    }
677
678    if (dep->de_FileSize < length) {
679        return msdosfs_deextend(dep, length, flags, context);
680    }
681
682    lck_mtx_lock(dep->de_cluster_lock);
683    cluster_locked = 1;
684
685    /*
686     * If the desired length is 0 then remember the starting cluster of
687     * the file and set the StartCluster field in the directory entry
688     * to 0.  If the desired length is not zero, then get the number of
689     * the last cluster in the shortened file.  Then get the number of
690     * the first cluster in the part of the file that is to be freed.
691     * Then set the next cluster pointer in the last cluster of the
692     * file to CLUST_EOFE.
693     */
694    if (length == 0) {
695        chaintofree = dep->de_StartCluster;
696        dep->de_StartCluster = 0;
697        dep->de_LastCluster = 0;
698	dep->de_cluster_count = 0;
699    } else {
700	uint32_t length_clusters;
701
702	length_clusters = de_clcount(pmp, length);
703
704	/*
705	 * Determine the new last cluster of the file.
706	 *
707	 * Note: this has a side effect of updating the cluster extent cache
708	 * to be the extent containing the new end of file.  We must do this
709	 * before updating the cluster extent cache; if not, msdosfs_pcbmap_internal
710	 * could update the cluster extent cache (if the previously cached
711	 * extent didn't contain the new last cluster), leaving it inconsistent
712	 * once we actually truncate the extra clusters.
713	 */
714	lck_mtx_lock(dep->de_pmp->pm_fat_lock);
715	error = msdosfs_pcbmap_internal(dep, length_clusters - 1, 1, NULL,
716		   &eofentry, NULL);
717	lck_mtx_unlock(dep->de_pmp->pm_fat_lock);
718
719	if (error)
720	{
721	    allerror = error;
722	    goto exit;
723	}
724
725	/*
726	 * Update the cluster extent cache.  We have to be careful that we
727	 * don't call msdosfs_pcbmap_internal until after the cluster chain has actually
728	 * been truncated.  (Otherwise our cluster extent cache would be
729	 * inconsistent with the actual cluster chain on disk.)
730	 *
731	 * We could also move this code below, after the msdosfs_fatentry() call that
732	 * truncates the chain.
733	 */
734	if (length_clusters >= dep->de_cluster_logical)
735	{
736	    /*
737	     * New length is in or after the currently cached extent.
738	     * If within the cached extent, then truncate it.
739	     */
740	    if (length_clusters < (dep->de_cluster_logical + dep->de_cluster_count))
741		    dep->de_cluster_count = length_clusters - dep->de_cluster_logical;
742	}
743	else
744	{
745	    /*
746	     * The new length is before the currently cached extent,
747	     * so completely invalidate the cached extent (none of it
748	     * exists any more).
749	     */
750	    dep->de_cluster_count = 0;
751	}
752    }
753
754    allerror = buf_invalidateblks(vp, ((length > 0) ? BUF_WRITE_DATA : 0), 0, 0);
755
756    dep->de_FileSize = length;
757
758    /*
759     * Write out the updated directory entry.  Even if the update fails
760     * we free the trailing clusters.
761     */
762    if (!isadir)
763        dep->de_flag |= DE_UPDATE|DE_MODIFIED;
764
765    error = msdosfs_deupdat(dep, 1, context);
766    if (error && (allerror == 0))
767        allerror = error;
768
769    /*
770     * If we need to break the cluster chain for the file then do it
771     * now.
772     */
773    if (length != 0) {
774        error = msdosfs_fatentry(FAT_GET_AND_SET, pmp, eofentry,
775                         &chaintofree, CLUST_EOFE);
776        if (error)
777	{
778	    dep->de_cluster_count = 0;
779	    allerror = error;
780	    goto exit;
781	}
782
783	dep->de_LastCluster = eofentry;
784    }
785
786    /*
787     * Now free the clusters removed from the file because of the
788     * truncation.
789     */
790    if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
791        msdosfs_freeclusterchain(pmp, chaintofree);
792
793    /*
794     * If "length" is not a multiple of the page size, ubc_setsize will
795     * cause the page containing offset "length" to be flushed.  This will
796     * call VNOP_BLOCKMAP, which will need the de_cluster_lock.  Since
797     * we're done manipulating the cached cluster extent, release the
798     * de_cluster_lock now.
799     */
800    lck_mtx_unlock(dep->de_cluster_lock);
801    cluster_locked = 0;
802
803    ubc_setsize(vp, (off_t)length); /* XXX check errors */
804
805exit:
806    if (cluster_locked)
807	lck_mtx_unlock(dep->de_cluster_lock);
808
809    return (allerror);
810}
811
812/*
813 * Extend the file described by dep to length specified by length.
814 * We must be able to allocate all of the new space, else fail this request.
815 */
816int msdosfs_deextend(struct denode *dep, uint32_t length, int flags, vfs_context_t context)
817{
818    struct msdosfsmount *pmp = dep->de_pmp;
819    uint32_t count;
820    int error;
821
822    /*
823     * The root of a DOS filesystem cannot be extended.
824     */
825    if (vnode_isvroot(DETOV(dep)) && !FAT32(pmp))
826        return (EINVAL);
827
828    /*
829     * Directories cannot be extended.
830     */
831    if (dep->de_Attributes & ATTR_DIRECTORY)
832        return (EISDIR);
833
834    if (length <= dep->de_FileSize)
835        panic("msdosfs_deextend: file too large");
836
837    /*
838     * Compute the number of clusters to allocate.
839     */
840    count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
841    if (count > 0) {
842        if (count > pmp->pm_freeclustercount)
843            return (ENOSPC);
844        error = msdosfs_extendfile(dep, count, NULL);
845        if (error) {
846            /* truncate the added clusters away again */
847            (void) msdosfs_detrunc(dep, dep->de_FileSize, 0, context);
848            return (error);
849        }
850    }
851
852    /* Zero fill the newly allocated bytes, except if IO_NOZEROFILL was given. */
853    if (!(flags & IO_NOZEROFILL)) {
854        error = cluster_write(DETOV(dep), (struct uio *) 0,
855                              (off_t)dep->de_FileSize, (off_t)(length),
856                              (off_t)dep->de_FileSize, (off_t)0,
857                              (flags | IO_HEADZEROFILL));
858        if (error)
859            return (error);
860    }
861
862    ubc_setsize(DETOV(dep), (off_t)length); /* XXX check errors */
863
864    dep->de_FileSize = length;
865
866    dep->de_flag |= DE_UPDATE|DE_MODIFIED;
867    return (msdosfs_deupdat(dep, 1, context));
868}
869
870/*
871 * Move a denode to its correct hash queue after the file it represents has
872 * been moved to a new directory.
873 *
874 * Assumes the msdosfs_hash_lock has NOT been acquired.
875 */
876void msdosfs_hash_reinsert(struct denode *dep)
877{
878	/*
879	 * Fix up the denode cache.  The hash is based on the location of the
880	 * directory entry, so we must remove it from the cache and re-enter it
881	 * with the hash based on the new location of the directory entry.
882	 */
883	lck_mtx_lock(msdosfs_hash_lock);
884	msdosfs_hash_remove(dep);
885	msdosfs_hash_insert(dep);
886	lck_mtx_unlock(msdosfs_hash_lock);
887}
888
889int msdosfs_vnop_reclaim(struct vnop_reclaim_args *ap)
890/* {
891		vnode_t a_vp;
892		vfs_context_t a_context;
893	} */
894{
895	vnode_t vp = ap->a_vp;
896	struct denode *dep = VTODE(vp);
897
898    KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RECLAIM|DBG_FUNC_START, dep, 0, 0, 0, 0);
899	/*
900	 * Skip everything if there was no denode.  This can happen
901	 * If the vnode was temporarily created in msdosfs_check_link.
902	 */
903	if (dep == NULL)
904		goto done;
905
906	/*
907	 * Remove the denode from its hash chain.
908	 */
909	lck_mtx_lock(msdosfs_hash_lock);
910	msdosfs_hash_remove(dep);
911	lck_mtx_unlock(msdosfs_hash_lock);
912
913	/*
914	 * Purge old data structures associated with the denode.
915	 */
916	cache_purge(vp);
917
918	lck_mtx_free(dep->de_cluster_lock, msdosfs_lck_grp);
919	lck_mtx_free(dep->de_lock, msdosfs_lck_grp);
920	OSFree(dep, sizeof(struct denode), msdosfs_node_tag);
921	vnode_clearfsnode(vp);
922	vnode_removefsref(vp);
923
924done:
925    KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RECLAIM|DBG_FUNC_END, 0, 0, 0, 0, 0);
926	return 0;
927}
928
929int msdosfs_vnop_inactive(struct vnop_inactive_args *ap)
930/* {
931		vnode_t a_vp;
932		vfs_context_t a_context;
933	} */
934{
935	vnode_t vp = ap->a_vp;
936	vfs_context_t context = ap->a_context;
937	struct denode *dep = VTODE(vp);
938	int error = 0;
939	int needs_flush = 0;
940
941    KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_INACTIVE|DBG_FUNC_START, dep, 0, 0, 0, 0);
942
943	/*
944	 * Skip everything if there was no denode.  This can happen
945	 * If the vnode was temporarily created in msdosfs_check_link.
946	 */
947	if (dep == NULL)
948		goto done;
949
950	lck_mtx_lock(dep->de_lock);
951
952	/*
953	 * Ignore denodes related to stale file handles.
954	 */
955	if (dep->de_Name[0] == SLOT_DELETED)
956		goto out;
957
958	/*
959	 * If the file has been deleted and it is on a read/write
960	 * filesystem, then truncate the file, and mark the directory slot
961	 * as empty.  (This may not be necessary for the dos filesystem.)
962	 */
963	if (dep->de_refcnt <= 0 && ( !vnode_vfsisrdonly(vp))) {
964		error = msdosfs_detrunc(dep, (uint32_t) 0, 0, context);
965		needs_flush = 1;
966		dep->de_flag |= DE_UPDATE;
967		dep->de_Name[0] = SLOT_DELETED;
968		vnode_recycle(vp);
969	}
970	msdosfs_deupdat(dep, 1, context);
971
972out:
973	if (needs_flush)
974		msdosfs_meta_flush(dep->de_pmp, FALSE);
975
976	/*
977	 * We used to do a vnode_recycle(vp) here if the file/dir had
978	 * been deleted.  That's good for reducing the pressure for vnodes,
979	 * but bad for delayed writes (including async mounts) because VFS
980	 * calls VNOP_FSYNC(..., MNT_WAIT,...) on the vnode during vclean(),
981	 * which causes us to synchronously write all of the volume's metadata.
982	 * And that means that mass deletions become totally synchronous.
983	 */
984
985	lck_mtx_unlock(dep->de_lock);
986
987done:
988    KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_INACTIVE|DBG_FUNC_END, error, 0, 0, 0, 0);
989	return (error);
990}
991
992
993/*
994 * msdosfs_defileid -- Return the file ID (inode number) for a given denode.  This routine
995 * is used by msdosfs_vnop_getattr and msdosfs_vnop_readdir to ensure a consistent file
996 * ID space.
997 *
998 * In older versions, the file ID was based on the location of the directory entry
999 * on disk (essentially the byte offset of the entry divided by the size of an entry).
1000 * The file ID of a directory was the ID of the "." entry (which is the first entry
1001 * in the directory).  The file ID of the root of a FAT12 or FAT16 volume (whose root
1002 * directory is not in an allocated cluster) is 1.
1003 *
1004 * We now use the starting cluster number of the file or directory, or 1 for the root
1005 * of a FAT12 or FAT16 volume.  Note that empty files have no starting cluster number,
1006 * and their file ID is a constant that is out of range for any FAT volume (since
1007 * FAT32 really only uses 28 bits for cluster number).  Directories (other than the root)
1008 * always contain at least one cluster for their "." and ".." entries.
1009 */
1010uint32_t msdosfs_defileid(struct denode *dep)
1011{
1012    uint32_t fileid;
1013
1014    fileid = dep->de_StartCluster;
1015
1016    if ((dep->de_Attributes & ATTR_DIRECTORY) && (dep->de_StartCluster == MSDOSFSROOT))
1017        fileid = FILENO_ROOT;		/* root of FAT12 or FAT16 */
1018
1019    if (fileid == 0)			/* empty? */
1020        fileid = FILENO_EMPTY;		/* use an out-of-range cluster number */
1021
1022    return fileid;
1023}
1024