1/*
2 * Copyright (c) 2000-2011 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_vfsops.c,v 1.63 2000/05/05 09:58:36 phk Exp $ */
24/*	$NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws 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#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/conf.h>
75#include <sys/proc.h>
76#include <sys/kernel.h>
77#include <sys/vnode.h>
78#include <sys/mount.h>
79#include <sys/buf.h>
80#include <sys/fcntl.h>
81#include <sys/malloc.h>
82#include <sys/stat.h> 				/* defines ALLPERMS */
83#include <sys/ubc.h>
84#include <sys/utfconv.h>
85#include <sys/disk.h>
86#include <sys/sysctl.h>
87#include <mach/kmod.h>
88#include <libkern/OSBase.h>
89#include <libkern/OSAtomic.h>
90#include <kern/clock.h>
91#include <kern/thread.h>
92#include <kern/thread_call.h>
93#include <miscfs/specfs/specdev.h>
94#include <IOKit/IOTypes.h>
95#include <libkern/OSMalloc.h>
96#include <libkern/OSKextLib.h>
97#include <libkern/crypto/md5.h>
98#include <TargetConditionals.h>
99
100#include "bpb.h"
101#include "bootsect.h"
102#include "direntry.h"
103#include "denode.h"
104#include "msdosfsmount.h"
105#include "fat.h"
106#include "msdosfs_kdebug.h"
107
108/*
109 * By default, don't try to auto unload the KEXT on embedded systems, since
110 * that isn't currently supported.  You can always explicitly set
111 * MSDOSFS_AUTO_UNLOAD to 0 or 1 to override the default.
112 */
113#ifndef MSDOSFS_AUTO_UNLOAD
114#if TARGET_OS_EMBEDDED
115#define MSDOSFS_AUTO_UNLOAD		0
116#else
117#define MSDOSFS_AUTO_UNLOAD		1
118#endif
119#endif
120
121#define MSDOSFS_DFLTBSIZE       4096
122
123#define rounddown(x,y)	(((x)/(y))*(y))
124
125extern u_int16_t dos2unicode[32];
126
127extern int32_t msdos_secondsWest;	/* In msdosfs_conv.c */
128
129__private_extern__ lck_grp_attr_t *msdosfs_lck_grp_attr = NULL;
130__private_extern__ lck_grp_t *msdosfs_lck_grp = NULL;
131__private_extern__ lck_attr_t *msdosfs_lck_attr = NULL;
132__private_extern__ OSMallocTag msdosfs_malloc_tag = NULL;
133
134#if DEBUG
135SYSCTL_DECL(_vfs_generic);
136SYSCTL_NODE(_vfs_generic, OID_AUTO, msdosfs, CTLFLAG_RW, 0, "msdosfs (FAT) file system");
137SYSCTL_INT(_vfs_generic_msdosfs, OID_AUTO, meta_delay, CTLFLAG_RW, &msdosfs_meta_delay, 0, "max delay before flushing metadata (ms)");
138#endif
139
140int msdosfs_init(struct vfsconf *vfsp);
141int msdosfs_uninit(void);
142int msdosfs_start(struct mount *mp, int flags, vfs_context_t context);
143
144int msdosfs_update_mp(struct mount *mp, struct msdosfs_args *argp);
145int msdosfs_mount(vnode_t devvp, struct mount *mp, vfs_context_t context);
146int msdosfs_vfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t);
147int msdosfs_vfs_root(struct mount *, vnode_t *, vfs_context_t);
148int msdosfs_vfs_statfs(struct mount *, struct vfsstatfs *, vfs_context_t);
149int msdosfs_vfs_getattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context);
150int msdosfs_vfs_setattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context);
151int msdosfs_vfs_sync(struct mount *, int, vfs_context_t);
152int msdosfs_vfs_unmount(struct mount *, int, vfs_context_t);
153
154int msdosfs_scan_root_dir(struct mount *mp, vfs_context_t context);
155int msdosfs_sync_callback(vnode_t vp, void *cargs);
156
157/* The routines are exported for the KEXT glue to link against. */
158int msdosfs_module_start(kmod_info_t *ki, void *data);
159int msdosfs_module_stop (kmod_info_t *ki, void *data);
160
161/*ARGSUSED*/
162int msdosfs_init(struct vfsconf *vfsp)
163{
164#pragma unused (vfsp)
165	msdosfs_lck_grp_attr = lck_grp_attr_alloc_init();
166	msdosfs_lck_grp = lck_grp_alloc_init("msdosfs", msdosfs_lck_grp_attr);
167	msdosfs_lck_attr = lck_attr_alloc_init();
168
169	msdosfs_malloc_tag = OSMalloc_Tagalloc("msdosfs", OSMT_DEFAULT);
170
171	msdosfs_hash_init();
172	return 0;
173}
174
175
176/*
177 * There is no "un-init" VFS operation.  This routine is only called by
178 * the KEXT as it is about to be unloaded.
179 */
180
181int msdosfs_uninit(void)
182{
183	msdosfs_hash_uninit();
184
185	OSMalloc_Tagfree(msdosfs_malloc_tag);
186
187	lck_attr_free(msdosfs_lck_attr);
188	lck_grp_free(msdosfs_lck_grp);
189	lck_grp_attr_free(msdosfs_lck_grp_attr);
190
191	return 0;
192}
193
194
195int msdosfs_update_mp(struct mount *mp, struct msdosfs_args *argp)
196{
197	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
198
199	pmp->pm_gid = argp->gid;
200	pmp->pm_uid = argp->uid;
201	pmp->pm_mask = argp->mask & ALLPERMS;
202	pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
203	if (argp->flags & MSDOSFSMNT_SECONDSWEST)
204		msdos_secondsWest = argp->secondsWest;
205
206	if (argp->flags & MSDOSFSMNT_LABEL)
207		bcopy(argp->label, pmp->pm_label, sizeof(pmp->pm_label));
208
209	return 0;
210}
211
212
213/*
214 * mp - path - addr in user space of mount point (ie /usr or whatever)
215 * data - addr in user space of mount params including the name of the block
216 * special file to treat as a filesystem.
217 */
218int msdosfs_vfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
219{
220	struct msdosfs_args args; /* will hold data from mount request */
221	/* msdosfs specific mount control block */
222	struct msdosfsmount *pmp = NULL;
223	int error, flags;
224
225	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_MOUNT|DBG_FUNC_START, 0, 0, 0, 0, 0);
226#if MSDOSFS_AUTO_UNLOAD
227	OSKextRetainKextWithLoadTag(OSKextGetCurrentLoadTag());
228#endif
229
230	error = copyin(data, &args, sizeof(struct msdosfs_args));
231	if (error)
232		goto error_exit;
233	if (args.magic != MSDOSFS_ARGSMAGIC)
234		args.flags = 0;
235
236	/*
237	 * If updating, check whether changing from read-only to
238	 * read/write; if there is no device name, that's all we do.
239	 */
240	if (vfs_isupdate(mp)) {
241		pmp = VFSTOMSDOSFS(mp);
242		error = 0;
243		if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && vfs_isrdonly(mp)) {
244			/* Downgrading from read/write to read-only */
245			/* � Is vflush() sufficient?  Is there more we should flush out? */
246			flags = WRITECLOSE;
247			if (vfs_isforce(mp))
248				flags |= FORCECLOSE;
249			error = vflush(mp, NULLVP, flags);
250		}
251		if (!error && vfs_isreload(mp))
252			/* not yet implemented */
253			error = ENOTSUP;
254		if (error)
255			goto error_exit;
256		if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && vfs_iswriteupgrade(mp)) {
257			/* � Assuming that VFS has verified we can write to the device */
258
259			pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
260
261			/* Now that the volume is modifiable, mark it dirty */
262			error = msdosfs_markvoldirty(pmp, 1);
263			if (error) {
264				pmp->pm_flags |= MSDOSFSMNT_RONLY;
265				goto error_exit;
266			}
267		}
268	}
269
270	if ( !vfs_isupdate(mp)) {
271		error = msdosfs_mount(devvp, mp, context);
272		if (error)
273			goto error_exit;	/* msdosfs_mount cleaned up already */
274	}
275
276	if (error == 0)
277		error = msdosfs_update_mp(mp, &args);
278
279	if (error == 0)
280		(void) msdosfs_vfs_statfs(mp, vfs_statfs(mp), context);
281
282	if (error)
283		msdosfs_vfs_unmount(mp, MNT_FORCE, context);	/* NOTE: calls OSKextReleaseKextWithLoadTag */
284
285	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_MOUNT|DBG_FUNC_END, error, 0, 0, 0, 0);
286	return error;
287
288error_exit:
289#if MSDOSFS_AUTO_UNLOAD
290	OSKextReleaseKextWithLoadTag(OSKextGetCurrentLoadTag());
291#endif
292	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_MOUNT|DBG_FUNC_END, error, 0, 0, 0, 0);
293	return error;
294}
295
296/*
297 * Create a version 3 UUID from unique data in the SHA1 "name space".
298 * Version 3 UUIDs are derived using MD5 checksum.  Here, the unique
299 * data is the 4-byte volume ID and the number of sectors (normalized
300 * to a 4-byte little endian value).
301 */
302static void msdosfs_generate_volume_uuid(uuid_t result_uuid, uint8_t volumeID[4], uint32_t totalSectors)
303{
304    MD5_CTX c;
305    uint8_t sectorsLittleEndian[4];
306
307    UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
308
309    /*
310     * Normalize totalSectors to a little endian value so that this returns the
311     * same UUID regardless of endianness.
312     */
313    putuint32(sectorsLittleEndian, totalSectors);
314
315    /*
316     * Generate an MD5 hash of our "name space", and our unique bits of data
317     * (the volume ID and total sectors).
318     */
319    MD5Init(&c);
320    MD5Update(&c, kFSUUIDNamespaceSHA1, sizeof(uuid_t));
321    MD5Update(&c, volumeID, 4);
322    MD5Update(&c, sectorsLittleEndian, sizeof(sectorsLittleEndian));
323    MD5Final(result_uuid, &c);
324
325    /* Force the resulting UUID to be a version 3 UUID. */
326    result_uuid[6] = (result_uuid[6] & 0x0F) | 0x30;
327    result_uuid[8] = (result_uuid[8] & 0x3F) | 0x80;
328}
329
330int msdosfs_mount(vnode_t devvp, struct mount *mp, vfs_context_t context)
331{
332	struct msdosfsmount *pmp;
333	struct buf *bp;
334	dev_t dev = vnode_specrdev(devvp);
335	union bootsector *bsp;
336	struct byte_bpb50 *b50;
337	struct byte_bpb710 *b710;
338	uint32_t total_sectors;
339	uint32_t fat_sectors;
340	uint32_t clusters;
341	uint32_t fsinfo = 0;
342	int	error;
343	struct vfsstatfs *vfsstatfs;
344	u_int8_t SecPerClust;
345
346	/*
347	 * Disallow multiple mounts of the same device.
348	 * Disallow mounting of a device that is currently in use
349	 * (except for root, which might share swap device for miniroot).
350	 * Flush out any old buffers remaining from a previous use.
351	 *
352	 *� Obsolete?
353
354	error = vfs_mountedon(devvp);
355	if (error)
356		return (error);
357	if (vcount(devvp) > 1 && devvp != rootvp)
358		return (EBUSY);
359	 */
360
361	error = buf_invalidateblks(devvp, BUF_WRITE_DATA, 0, 0);
362	if (error)
363		return (error);
364
365	vfs_setlocklocal(mp);
366
367	bp  = NULL; /* both used in error_exit */
368	pmp = NULL;
369
370	/*
371	 * Read the boot sector of the filesystem, and then check the
372	 * boot signature.  If not a dos boot sector then error out.
373	 *
374	 * NOTE: 4096 is a maximum sector size in current...
375	 */
376	error = (int)buf_meta_bread(devvp, 0, 4096, vfs_context_ucred(context), &bp);
377	if (error)
378		goto error_exit;
379	buf_markaged(bp);
380	bsp = (union bootsector *)buf_dataptr(bp);
381	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
382	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
383
384
385	/* [2699033]
386	 *
387	 * The first three bytes are an Intel x86 jump instruction.  It should be one
388	 * of the following forms:
389	 *    0xE9 0x?? 0x??
390	 *    0xEB 0x?? 0x90
391	 * where 0x?? means any byte value is OK.
392	 *
393	 * [5016947]
394	 *
395	 * Windows doesn't actually check the third byte if the first byte is 0xEB,
396	 * so we don't either
397	 */
398	if (bsp->bs50.bsJump[0] != 0xE9
399		&& bsp->bs50.bsJump[0] != 0xEB)
400	{
401		error = EINVAL;
402		goto error_exit;
403	}
404
405	MALLOC(pmp, struct msdosfsmount *, sizeof(*pmp), M_TEMP, M_WAITOK);
406	bzero((caddr_t)pmp, sizeof *pmp);
407	pmp->pm_mountp = mp;
408	pmp->pm_fat_lock = lck_mtx_alloc_init(msdosfs_lck_grp, msdosfs_lck_attr);
409	pmp->pm_rename_lock = lck_mtx_alloc_init(msdosfs_lck_grp, msdosfs_lck_attr);
410
411	/*
412	 * Compute several useful quantities from the bpb in the
413	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
414	 * the fields that are different between dos 5 and dos 3.3.
415	 */
416	SecPerClust = b50->bpbSecPerClust;
417	pmp->pm_BytesPerSec = getuint16(b50->bpbBytesPerSec);
418	pmp->pm_bpcluster = (u_int32_t) SecPerClust * (u_int32_t) pmp->pm_BytesPerSec;
419	pmp->pm_ResSectors = getuint16(b50->bpbResSectors);
420	pmp->pm_FATs = b50->bpbFATs;
421	pmp->pm_RootDirEnts = getuint16(b50->bpbRootDirEnts);
422	total_sectors = getuint16(b50->bpbSectors);
423	if (total_sectors == 0)
424		total_sectors = getuint32(b50->bpbHugeSectors);
425	fat_sectors = getuint16(b50->bpbFATsecs);
426	if (fat_sectors == 0)
427		fat_sectors = getuint32(b710->bpbBigFATsecs);
428	pmp->pm_label_cluster = CLUST_EOFE;	/* Assume there is no label in the root */
429
430	/*
431	 * Check a few values (could do some more):
432	 * - logical sector size: power of 2, >= block size
433	 * - sectors per cluster: power of 2, >= 1
434	 * - number of sectors:   >= 1, <= size of partition
435	 * - number of FAT sectors > 0 (too large values handled later)
436	 */
437	if (total_sectors == 0)
438	{
439		printf("msdosfs_mount: invalid total sectors (%u)\n", total_sectors);
440		error = EINVAL;
441		goto error_exit;
442	}
443	if (fat_sectors == 0)
444	{
445		printf("msdosfs_mount: invalid sectors per FAT (%u)\n", fat_sectors);
446		error = EINVAL;
447		goto error_exit;
448	}
449	if (SecPerClust == 0 || (SecPerClust & (SecPerClust - 1)))
450	{
451		printf("msdosfs_mount: invalid sectors per cluster (%u)\n", SecPerClust);
452		error = EINVAL;
453		goto error_exit;
454	}
455	if ((pmp->pm_BytesPerSec < DEV_BSIZE) ||
456		(pmp->pm_BytesPerSec > 4096) ||
457		(pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)))
458	{
459		printf("msdosfs_mount: invalid bytes per sector (%u)\n", pmp->pm_BytesPerSec);
460		error = EINVAL;
461		goto error_exit;
462	}
463
464	/* calculate the ratio of sector size to device block size */
465	error = VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t) &pmp->pm_BlockSize, 0, context);
466	if (error) {
467		error = ENXIO;
468		goto error_exit;
469	}
470	pmp->pm_BlocksPerSec = pmp->pm_BytesPerSec / pmp->pm_BlockSize;
471	pmp->pm_bnshift = ffs(pmp->pm_BlockSize) - 1;
472
473	/* Get the device's physical sector size */
474	error = VNOP_IOCTL(devvp, DKIOCGETPHYSICALBLOCKSIZE, (caddr_t) &pmp->pm_PhysBlockSize, 0, context);
475	if (error)
476		pmp->pm_PhysBlockSize = pmp->pm_BlockSize;
477
478	/*
479	 * For now, assume a FAT12 or FAT16 volume with a dedicated root directory.
480	 * We need these values before we can figure out how many clusters (and
481	 * thus whether the volume is FAT32 or not).  Start by calculating sectors.
482	 */
483	pmp->pm_rootdirblk = (pmp->pm_ResSectors + (pmp->pm_FATs * fat_sectors));
484	pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct dosdirentry) + pmp->pm_BytesPerSec - 1) / pmp->pm_BytesPerSec;
485	pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
486
487	/* Change the root directory values to physical (device) blocks */
488	pmp->pm_rootdirblk *= pmp->pm_BlocksPerSec;
489	pmp->pm_rootdirsize *= pmp->pm_BlocksPerSec;
490
491	if (fat_sectors > total_sectors ||
492		pmp->pm_rootdirblk < fat_sectors ||		/* Catch numeric overflow! */
493		pmp->pm_firstcluster + SecPerClust > total_sectors)
494	{
495		/* We think there isn't room for even a single cluster. */
496		printf("msdosfs_mount: invalid configuration; no room for clusters\n");
497		error = EINVAL;
498		goto error_exit;
499	}
500
501	/*
502	 * Usable clusters are numbered starting at 2, so the maximum usable cluster
503	 * is (number of clusters) + 1.  Convert the pm_firstcluster to device blocks.
504	 */
505	pmp->pm_maxcluster = (total_sectors - pmp->pm_firstcluster) / SecPerClust + 1;
506	pmp->pm_firstcluster *= pmp->pm_BlocksPerSec;
507
508	/*
509	 * Figure out the FAT type based on the number of clusters.
510	 */
511	if (pmp->pm_maxcluster < (CLUST_RSRVD & FAT12_MASK))
512	{
513		pmp->pm_fatmask = FAT12_MASK;
514		pmp->pm_fatmult = 3;
515		pmp->pm_fatdiv = 2;
516	}
517	else if (pmp->pm_maxcluster < (CLUST_RSRVD & FAT16_MASK))
518	{
519		pmp->pm_fatmask = FAT16_MASK;
520		pmp->pm_fatmult = 2;
521		pmp->pm_fatdiv = 1;
522	}
523	else if (pmp->pm_maxcluster < (CLUST_RSRVD & FAT32_MASK))
524	{
525		pmp->pm_fatmask = FAT32_MASK;
526		pmp->pm_fatmult = 4;
527		pmp->pm_fatdiv = 1;
528	}
529	else
530	{
531		printf("msdosfs_mount: number of clusters (0x%x) is too large\n", pmp->pm_maxcluster + 1);
532		error = EINVAL;
533		goto error_exit;
534	}
535
536	/* See if FAT32 has its FAT mirrored or not. */
537	if (FAT32(pmp) && (getuint16(b710->bpbExtFlags) & FATMIRROR))
538	{
539		pmp->pm_curfat = getuint16(b710->bpbExtFlags) & FATNUM;
540	}
541	else
542	{
543		pmp->pm_flags |= MSDOSFS_FATMIRROR;
544	}
545
546	/*
547	 * Sanity check some differences between FAT32 and FAT12/16.
548	 * Also set up FAT32's root directory and FSInfo sector.
549	 */
550	if (FAT32(pmp))
551	{
552		fsinfo = getuint16(b710->bpbFSInfo);
553		pmp->pm_rootdirblk = getuint32(b710->bpbRootClust);
554		if (pmp->pm_rootdirblk < CLUST_FIRST || pmp->pm_rootdirblk > pmp->pm_maxcluster)
555		{
556			printf("msdosfs_mount: FAT32 root starting cluster (%u) out of range (%u..%u)\n",
557				   pmp->pm_rootdirblk, CLUST_FIRST, pmp->pm_maxcluster);
558			error = EINVAL;
559			goto error_exit;
560		}
561		if (pmp->pm_RootDirEnts)
562		{
563			printf("msdosfs_mount: FAT32 has non-zero root directory count\n");
564			error = EINVAL;
565			goto error_exit;
566		}
567		if (getuint16(b710->bpbFSVers) != 0)
568		{
569			printf("msdosfs_mount: FAT32 has non-zero version\n");
570			error = EINVAL;
571			goto error_exit;
572		}
573		if (getuint16(b50->bpbSectors) != 0)
574		{
575			printf("msdosfs_mount: FAT32 has 16-bit total sectors\n");
576			error = EINVAL;
577			goto error_exit;
578		}
579		if (getuint16(b50->bpbFATsecs) != 0)
580		{
581			printf("msdosfs_mount: FAT32 has 16-bit FAT sectors\n");
582			error = EINVAL;
583			goto error_exit;
584		}
585	}
586	else
587	{
588		if (pmp->pm_RootDirEnts == 0)
589		{
590			printf("msdosfs_mount: FAT12/16 has zero-length root directory\n");
591			error = EINVAL;
592			goto error_exit;
593		}
594		if (total_sectors < 0x10000 && getuint16(b50->bpbSectors) == 0)
595		{
596			printf("msdosfs_mount: Warning: FAT12/16 total sectors (%u) fit in 16 bits, but stored in 32 bits\n", total_sectors);
597		}
598		if (getuint16(b50->bpbFATsecs) == 0)
599		{
600			printf("msdosfs_mount: Warning: FAT12/16 has 32-bit FAT sectors\n");
601		}
602	}
603
604	/*
605	 * Compute number of clusters this FAT could hold based on its total size.
606	 * Pin the maximum cluster number to the size of the FAT.
607	 * NOTE: We have to do this AFTER determining the FAT type.  If we did this
608	 * before, we could end up deducing a different FAT type than what's actually
609	 * on disk, and that would be very bad.
610	 */
611	clusters = fat_sectors * pmp->pm_BytesPerSec;	/* Size of FAT in bytes */
612	clusters *= pmp->pm_fatdiv;
613	clusters /= pmp->pm_fatmult;				/* Max number of clusters, rounded down */
614	if (pmp->pm_maxcluster >= clusters) {
615		printf("msdosfs_mount: Warning: number of clusters (%d) exceeds FAT "
616		    "capacity (%d)\n", pmp->pm_maxcluster + 1, clusters);
617		pmp->pm_maxcluster = clusters - 1;
618	}
619
620	/*
621	 * Pin the maximum cluster number based on the number of sectors the device
622	 * is reporting (in case that is smaller than the total sectors field(s)
623	 * in the boot sector).
624	 */
625	uint64_t block_count;
626	error = VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t) &block_count, 0, context);
627	if (error == 0 && block_count < total_sectors)
628	{
629		if (pmp->pm_firstcluster + SecPerClust > block_count)
630		{
631			printf("msdosfs_mount: device sector count (%llu) too small; no room for clusters\n", block_count);
632			error = EINVAL;
633			goto error_exit;
634		}
635
636		uint32_t maxcluster = (uint32_t)((block_count - pmp->pm_firstcluster) / SecPerClust + 1);
637		if (maxcluster < pmp->pm_maxcluster)
638		{
639			printf("msdosfs_mount: device sector count (%llu) is less than volume sector count (%u); limiting maximum cluster to %u (was %u)\n",
640				   block_count, total_sectors, maxcluster, pmp->pm_maxcluster);
641			pmp->pm_maxcluster = maxcluster;
642		}
643		else
644		{
645			printf("msdosfs_mount: device sector count (%llu) is less than volume sector count (%u)\n",
646				   block_count, total_sectors);
647		}
648	}
649
650	/*
651	 * Set up values for accessing the FAT.
652	 */
653	if (FAT12(pmp))
654		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
655	else
656		pmp->pm_fatblocksize = PAGE_SIZE;
657	pmp->pm_fat_bytes = fat_sectors * pmp->pm_BytesPerSec;
658
659	/*
660	 * Compute mask and shift value for isolating cluster relative byte
661	 * offsets and cluster numbers from a file offset.
662	 */
663	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
664	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
665
666	/*
667	 * Compute an "optimal" I/O size based on the largest I/O that both
668	 * UBC and the device can handle.
669	 */
670	{
671		u_int32_t	temp_size;
672		struct vfsioattr ioattr;
673
674		pmp->pm_iosize = ubc_upl_maxbufsize();
675		vfs_ioattr(mp, &ioattr);
676		if (ioattr.io_maxreadcnt < pmp->pm_iosize)
677			pmp->pm_iosize = ioattr.io_maxreadcnt;
678		if (ioattr.io_maxwritecnt < pmp->pm_iosize)
679			pmp->pm_iosize = ioattr.io_maxwritecnt;
680		temp_size = ioattr.io_segreadcnt * ioattr.io_maxsegreadsize;
681		if (temp_size < pmp->pm_iosize)
682			pmp->pm_iosize = temp_size;
683		temp_size = ioattr.io_segwritecnt * ioattr.io_maxsegwritesize;
684		if (temp_size < pmp->pm_iosize)
685			pmp->pm_iosize = temp_size;
686
687		/*
688		 * If the device returned bogus values, like zeroes, pin the optimal
689		 * size to the cluster size.
690		 */
691		if (pmp->pm_iosize < pmp->pm_bpcluster)
692			pmp->pm_iosize = pmp->pm_bpcluster;
693	}
694
695	/* Copy volume label and serial number from boot sector into mount point */
696	{
697		struct extboot *extboot;
698		int i;
699		u_char uc;
700
701		/* Start out assuming no label (empty string) */
702		pmp->pm_label[0] = '\0';
703
704		if (FAT32(pmp)) {
705			extboot = (struct extboot *) bsp->bs710.bsExt;
706		} else {
707			extboot = (struct extboot *) bsp->bs50.bsExt;
708		}
709
710		if (extboot->exBootSignature == EXBOOTSIG) {
711			pmp->pm_flags |= MSDOSFS_HAS_EXT_BOOT;
712
713			/* Copy the volume serial number into the mount point. */
714			bcopy(extboot->exVolumeID, pmp->pm_volume_serial_num, sizeof(pmp->pm_volume_serial_num));
715
716            /*
717             * See if the volume has a non-zero ID; if so, turn it into a UUID.
718             * The field is odd aligned, so don't cast to uint32_t.
719             */
720            if (pmp->pm_volume_serial_num[0] || pmp->pm_volume_serial_num[1] ||
721                pmp->pm_volume_serial_num[2] || pmp->pm_volume_serial_num[3])
722            {
723                pmp->pm_flags |= MSDOSFS_HAS_VOL_UUID;
724                msdosfs_generate_volume_uuid(pmp->pm_uuid, pmp->pm_volume_serial_num, total_sectors);
725            }
726
727			/*
728			 * Copy the label from the boot sector into the mount point.
729			 *
730			 * We don't call msdosfs_dos2unicodefn() because it assumes the last three
731			 * characters are an extension, and it will put a period before the
732			 * extension.
733			 */
734			for (i=0; i<SHORT_NAME_LEN; i++) {
735				uc = extboot->exVolumeLabel[i];
736				if (i==0 && uc == SLOT_E5)
737					uc = 0xE5;
738				pmp->pm_label[i] = (uc < 0x80 || uc > 0x9F ? uc : dos2unicode[uc - 0x80]);
739			}
740
741			/* Remove trailing spaces, add NUL terminator */
742			for (i=10; i>=0 && pmp->pm_label[i]==' '; --i)
743				;
744			pmp->pm_label[i+1] = '\0';
745		}
746	}
747
748	/*
749	 * Release the bootsector buffer.
750	 */
751	buf_brelse(bp);
752	bp = NULL;
753
754	/*
755	 * We always reset the "next allocation" pointer to the start of the volume
756	 * on mount.  FAT12 and FAT16 don't have a way to persistently store it, and
757	 * we need a valid value in all cases.
758	 *
759	 * For FAT32, we ignore the value in the FSInfo sector so that we'll tend
760	 * to put allocations toward the start of the volume.  This is a trade
761	 * off.  The benefits are that reads and writes to sectors near the start
762	 * of the volume are often faster, and some broken devices report more
763	 * sectors than they can actually access.  The cost is large volumes with
764	 * all clusters near the start of the volume already allocated; we'll
765	 * have to read through that part of the FAT once, which we could have
766	 * skipped if we didn't ignore the "next free cluster" in the FSInfo sector.
767	 */
768	pmp->pm_nxtfree = CLUST_FIRST;
769
770	/*
771	 * Check FSInfo.
772	 */
773	if (fsinfo) {
774		struct fsinfo *fp;
775		u_int32_t log_per_phys;
776
777		/* Convert FSInfo logical sector number to device block number */
778		fsinfo *= pmp->pm_BytesPerSec / pmp->pm_BlockSize;
779
780		/*
781		 * %%% We want to read/write an entire physical sector when we access
782		 * %%% the FSInfo sector.  So precompute the starting logical sector
783		 * %%% number, size of the physical sector, and offset of FSInfo from
784		 * %%% the start of the physical sector.
785		 */
786		log_per_phys = pmp->pm_PhysBlockSize / pmp->pm_BlockSize;
787		if ((rounddown(fsinfo,log_per_phys) + log_per_phys) <= pmp->pm_ResSectors) {
788			pmp->pm_fsinfo_sector = rounddown(fsinfo,log_per_phys);
789			pmp->pm_fsinfo_size = pmp->pm_PhysBlockSize;
790			pmp->pm_fsinfo_offset = (fsinfo % log_per_phys) * pmp->pm_BlockSize;
791		} else {
792			pmp->pm_fsinfo_sector = fsinfo;
793			pmp->pm_fsinfo_size = pmp->pm_BlockSize;
794			pmp->pm_fsinfo_offset = 0;
795		}
796
797		/*
798		 * The FSInfo sector occupies pm_BytesPerSec bytes on disk,
799		 * but only 512 of those have meaningful contents.  There's no point
800		 * in reading all pm_BytesPerSec bytes if the device block size is
801		 * smaller.  So just use the device block size here.
802		 */
803		error = buf_meta_bread(devvp, pmp->pm_fsinfo_sector, pmp->pm_fsinfo_size, vfs_context_ucred(context), &bp);
804		if (error)
805			goto error_exit;
806		fp = (struct fsinfo *)(buf_dataptr(bp) + pmp->pm_fsinfo_offset);
807		if (!bcmp(fp->fsisig1, "RRaA", 4)
808		    && !bcmp(fp->fsisig2, "rrAa", 4)
809		    && !bcmp(fp->fsisig3, "\0\0\125\252", 4))
810		{
811			pmp->pm_nxtfree = getuint32(fp->fsinxtfree);
812			pmp->pm_freeclustercount = getuint32(fp->fsinfree);
813		} else {
814			printf("msdosfs_mount: FSInfo has bad signature\n");
815			pmp->pm_fsinfo_size = 0;
816		}
817		buf_brelse(bp);
818		bp = NULL;
819	}
820
821	/*
822	 * Check and validate (or perhaps invalidate?) the fsinfo structure?		XXX
823	 */
824
825	/*
826	 * If they want fat updates to be synchronous then let them suffer
827	 * the performance degradation in exchange for the on disk copy of
828	 * the fat being correct just about all the time.  I suppose this
829	 * would be a good thing to turn on if the kernel is still flakey.
830	 */
831	if (vfs_issynchronous(mp))
832		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
833
834	/*
835	 * msdosfs_fat_init_vol() needs pm_devvp.
836	 */
837	pmp->pm_dev = dev;
838	pmp->pm_devvp = devvp;
839
840	/*
841	 * Set up the per-volume FAT structures, including
842	 * the in-use map.
843	 */
844	error = msdosfs_fat_init_vol(pmp);
845	if (error != 0)
846		goto error_exit;
847
848	/*
849	 * Initialize a timer to automatically sync shortly after writing.
850	 */
851	pmp->pm_sync_timer = thread_call_allocate(msdosfs_meta_sync_callback, pmp);
852	if (pmp->pm_sync_timer == NULL)
853	{
854		error = ENOMEM;
855		goto error_exit;
856	}
857
858	/*
859	 * Set up our private data pointer for use by other routines.
860	 */
861	vfs_setfsprivate(mp, (void *)pmp);
862
863	/*
864	 * Look through the root directory for volume name, and Windows hibernation.
865	 */
866	error = msdosfs_scan_root_dir(mp, context);
867	if (error)
868	{
869		if (error == EIO && vfs_isrdwr(mp))
870		{
871			(void) msdosfs_markvoldirty(pmp, 1);	/* Verify/repair the volume next time. */
872		}
873		goto error_exit;
874	}
875
876	/*
877	 * NOTE: we have to call vfs_isrdonly here, not cache the value from earlier.
878	 * It is possible that msdosfs_scan_root_dir made the mount read-only due to a
879	 * Windows hibernation image.
880	 */
881	if (vfs_isrdonly(mp))
882		pmp->pm_flags |= MSDOSFSMNT_RONLY;
883	else {
884		/* [2753891] Mark the volume dirty while it is mounted read/write */
885		if ((error = msdosfs_markvoldirty(pmp, 1)) != 0)
886			goto error_exit;
887	}
888
889	/*
890	 * Fill in the statvfs fields that are constant (not updated by msdosfs_vfs_statfs)
891	 */
892	vfsstatfs = vfs_statfs(mp);
893	vfsstatfs->f_bsize = pmp->pm_bpcluster;
894	vfsstatfs->f_iosize = pmp->pm_iosize;
895	/* Clusters are numbered from 2..pm_maxcluster, so pm_maxcluster - 2 + 1 of them */
896	vfsstatfs->f_blocks = pmp->pm_maxcluster - 1;
897	vfsstatfs->f_fsid.val[0] = dev;
898	vfsstatfs->f_fsid.val[1] = vfs_typenum(mp);
899
900	vfs_setflags(mp, MNT_IGNORE_OWNERSHIP);
901
902
903	return 0;
904
905error_exit:
906	if (bp)
907		buf_brelse(bp);
908	if (pmp) {
909		if (pmp->pm_sync_timer)
910		{
911		    thread_call_cancel(pmp->pm_sync_timer);
912			thread_call_free(pmp->pm_sync_timer);
913			pmp->pm_sync_timer = NULL;
914		}
915
916		(void) vflush(mp, NULLVP, SKIPSYSTEM|FORCECLOSE);
917
918		msdosfs_fat_uninit_vol(pmp);
919
920		(void) vflush(mp, NULLVP, FORCECLOSE);
921
922		lck_mtx_free(pmp->pm_fat_lock, msdosfs_lck_grp);
923		lck_mtx_free(pmp->pm_rename_lock, msdosfs_lck_grp);
924
925		FREE(pmp, M_TEMP);
926
927		vfs_setfsprivate(mp, (void *)NULL);
928	}
929	return (error);
930}
931
932/*
933 * Make a filesystem operational.
934 * Nothing to do at the moment.
935 */
936/* ARGSUSED */
937int msdosfs_start(struct mount *mp, int flags, vfs_context_t context)
938{
939#pragma unused (mp)
940#pragma unused (flags)
941#pragma unused (context)
942	return (0);
943}
944
945/*
946 * Unmount the filesystem described by mp.
947 */
948int msdosfs_vfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
949{
950	struct msdosfsmount *pmp;
951	int error, flags;
952	int force;
953
954	pmp = VFSTOMSDOSFS(mp);
955
956	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_UNMOUNT|DBG_FUNC_START, pmp, 0, 0, 0, 0);
957
958	flags = SKIPSYSTEM;
959	force = 0;
960	if (mntflags & MNT_FORCE) {
961		flags |= FORCECLOSE;
962		force = 1;
963	}
964
965	/*
966	 * Cancel any pending timers for this volume.  Then wait for any timers
967	 * which have fired, but whose callbacks have not yet completed.
968	 */
969	if (pmp->pm_sync_timer)
970	{
971		struct timespec ts = {0, 100000000};	/* 0.1 seconds */
972
973		/*
974		 * Cancel any timers that have been scheduled, but have not
975		 * fired yet.  NOTE: The kernel considers a timer complete as
976		 * soon as it starts your callback, so the kernel does not
977		 * keep track of the number of callbacks in progress.
978		 */
979		if (thread_call_cancel(pmp->pm_sync_timer))
980			OSDecrementAtomic(&pmp->pm_sync_incomplete);
981		thread_call_free(pmp->pm_sync_timer);
982		pmp->pm_sync_timer = NULL;
983
984		/*
985		 * This waits for all of the callbacks that were entered before
986		 * we did thread_call_cancel above, but have not completed yet.
987		 */
988		while(pmp->pm_sync_incomplete > 0)
989		{
990			msleep(&pmp->pm_sync_incomplete, NULL, PWAIT, "msdosfs_vfs_unmount", &ts);
991		}
992
993		if (pmp->pm_sync_incomplete < 0)
994			panic("msdosfs_vfs_unmount: pm_sync_incomplete underflow!\n");
995	}
996
997	error = vflush(mp, NULLVP, flags);
998	if (error && !force)
999		goto error_exit;
1000
1001	/*
1002	 * [2753891] If the volume was mounted read/write, and no corruption
1003	 * was detected, mark it clean now.
1004	 */
1005	if ((pmp->pm_flags & (MSDOSFSMNT_RONLY | MSDOSFS_CORRUPT)) == 0) {
1006		error = msdosfs_markvoldirty(pmp, 0);
1007		if (error && !force)
1008			goto error_exit;
1009	}
1010
1011	msdosfs_fat_uninit_vol(pmp);
1012	(void) vflush(mp, NULLVP, FORCECLOSE);
1013	VNOP_FSYNC(pmp->pm_devvp, MNT_WAIT, context);
1014
1015	lck_mtx_free(pmp->pm_fat_lock, msdosfs_lck_grp);
1016	lck_mtx_free(pmp->pm_rename_lock, msdosfs_lck_grp);
1017
1018	FREE(pmp, M_TEMP);
1019
1020	vfs_setfsprivate(mp, (void *)NULL);
1021
1022#if MSDOSFS_AUTO_UNLOAD
1023	OSKextReleaseKextWithLoadTag(OSKextGetCurrentLoadTag());
1024#endif
1025
1026	/*
1027	 * If "force" was set, we may get here with error != 0.  Since we have
1028	 * in fact completed the unmount (as best we can), we need to return
1029	 * no error so that VFS can clean up our mount point.
1030	 */
1031	error = 0;
1032
1033error_exit:
1034	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_UNMOUNT|DBG_FUNC_END, error, 0, 0, 0, 0);
1035	return (error);
1036}
1037
1038int msdosfs_vfs_root(struct mount *mp, vnode_t *vpp, vfs_context_t context)
1039{
1040	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1041	struct denode *ndep;
1042	int error;
1043
1044	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_ROOT|DBG_FUNC_START, pmp, 0, 0, 0, 0);
1045
1046	error = msdosfs_deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULLVP, NULL, &ndep, context);
1047	if (error)
1048		return (error);
1049	*vpp = DETOV(ndep);
1050
1051	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_ROOT|DBG_FUNC_END, 0, ndep, 0, 0, 0);
1052	return 0;
1053}
1054
1055
1056int msdosfs_vfs_statfs(struct mount *mp, struct vfsstatfs *sbp, vfs_context_t context)
1057{
1058#pragma unused (context)
1059	struct msdosfsmount *pmp;
1060
1061	pmp = VFSTOMSDOSFS(mp);
1062
1063	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_STATFS|DBG_FUNC_START, pmp, 0, 0, 0, 0);
1064
1065	/*
1066	 * � VFS fills in everything from a cached copy.
1067	 * We only need to fill in fields that can change.
1068	 */
1069	sbp->f_bfree = pmp->pm_freeclustercount;
1070	sbp->f_bavail = pmp->pm_freeclustercount;
1071	sbp->f_bused = sbp->f_blocks - sbp->f_bavail;
1072	sbp->f_files = pmp->pm_RootDirEnts;			/* XXX */
1073	sbp->f_ffree = 0;	/* what to put in here? */
1074	vfs_name(mp, sbp->f_fstypename);
1075
1076	/* Subtypes (flavors) for MSDOS
1077		0 - FAT12
1078		1 - FAT16
1079		2 - FAT32
1080	*/
1081	if (pmp->pm_fatmask == FAT12_MASK) {
1082		 sbp->f_fssubtype = 0;	/* FAT12 */
1083	} else if (pmp->pm_fatmask == FAT16_MASK) {
1084		sbp->f_fssubtype = 1;	/* FAT16 */
1085	} else {
1086		sbp->f_fssubtype = 2;	/* FAT32 */
1087	}
1088
1089	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_STATFS|DBG_FUNC_END, 0, sbp->f_blocks, sbp->f_bfree, sbp->f_fssubtype, 0);
1090	return 0;
1091}
1092
1093
1094int msdosfs_vfs_getattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context)
1095{
1096#pragma unused (context)
1097	struct msdosfsmount *pmp;
1098
1099	pmp = VFSTOMSDOSFS(mp);
1100
1101	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_GETATTR|DBG_FUNC_START, pmp, attr->f_active, 0, 0, 0);
1102
1103	/* FAT doesn't track the object counts */
1104
1105	VFSATTR_RETURN(attr, f_bsize,  pmp->pm_bpcluster);
1106	VFSATTR_RETURN(attr, f_iosize, pmp->pm_iosize);
1107	/* Clusters are numbered from 2..pm_maxcluster, so pm_maxcluster - 2 + 1 of them */
1108	VFSATTR_RETURN(attr, f_blocks, pmp->pm_maxcluster - 1);
1109	VFSATTR_RETURN(attr, f_bfree,  pmp->pm_freeclustercount);
1110	VFSATTR_RETURN(attr, f_bavail, pmp->pm_freeclustercount);
1111	VFSATTR_RETURN(attr, f_bused,  attr->f_blocks - attr->f_bfree);
1112
1113	/* FAT doesn't have a fixed limit on the number of file nodes */
1114
1115	if (VFSATTR_IS_ACTIVE(attr, f_fsid)) {
1116		attr->f_fsid.val[0] = pmp->pm_dev;
1117		attr->f_fsid.val[1] = vfs_typenum(mp);
1118		VFSATTR_SET_SUPPORTED(attr, f_fsid);
1119	}
1120
1121	if (VFSATTR_IS_ACTIVE(attr, f_capabilities)) {
1122		attr->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
1123			VOL_CAP_FMT_SYMBOLICLINKS |
1124			VOL_CAP_FMT_NO_ROOT_TIMES |
1125			VOL_CAP_FMT_CASE_PRESERVING |
1126			VOL_CAP_FMT_FAST_STATFS |
1127			VOL_CAP_FMT_HIDDEN_FILES ;
1128		attr->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] =
1129			VOL_CAP_INT_VOL_RENAME |
1130			VOL_CAP_INT_ADVLOCK |
1131			VOL_CAP_INT_FLOCK ;
1132		attr->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1133		attr->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1134
1135		attr->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
1136			VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1137			VOL_CAP_FMT_SYMBOLICLINKS |
1138			VOL_CAP_FMT_HARDLINKS |
1139			VOL_CAP_FMT_JOURNAL |
1140			VOL_CAP_FMT_JOURNAL_ACTIVE |
1141			VOL_CAP_FMT_NO_ROOT_TIMES |
1142			VOL_CAP_FMT_SPARSE_FILES |
1143			VOL_CAP_FMT_ZERO_RUNS |
1144			VOL_CAP_FMT_CASE_SENSITIVE |
1145			VOL_CAP_FMT_CASE_PRESERVING |
1146			VOL_CAP_FMT_FAST_STATFS |
1147			VOL_CAP_FMT_2TB_FILESIZE |
1148			VOL_CAP_FMT_OPENDENYMODES |
1149			VOL_CAP_FMT_HIDDEN_FILES ;
1150		attr->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
1151			VOL_CAP_INT_SEARCHFS |
1152			VOL_CAP_INT_ATTRLIST |
1153			VOL_CAP_INT_NFSEXPORT |
1154			VOL_CAP_INT_READDIRATTR |
1155			VOL_CAP_INT_EXCHANGEDATA |
1156			VOL_CAP_INT_COPYFILE |
1157			VOL_CAP_INT_ALLOCATE |
1158			VOL_CAP_INT_VOL_RENAME |
1159			VOL_CAP_INT_ADVLOCK |
1160			VOL_CAP_INT_FLOCK |
1161			VOL_CAP_INT_MANLOCK ;
1162		attr->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
1163		attr->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
1164		VFSATTR_SET_SUPPORTED(attr, f_capabilities);
1165	}
1166
1167	if (VFSATTR_IS_ACTIVE(attr, f_attributes)) {
1168		attr->f_attributes.validattr.commonattr =
1169			ATTR_CMN_NAME	|
1170			ATTR_CMN_DEVID	|
1171			ATTR_CMN_FSID	|
1172			ATTR_CMN_OBJTYPE |
1173			ATTR_CMN_OBJTAG	|
1174			ATTR_CMN_OBJID	|
1175			/* ATTR_CMN_OBJPERMANENTID | */
1176			ATTR_CMN_PAROBJID |
1177			/* ATTR_CMN_SCRIPT | */
1178			ATTR_CMN_CRTIME |
1179			ATTR_CMN_MODTIME |
1180			ATTR_CMN_CHGTIME |
1181			ATTR_CMN_ACCTIME |
1182			/* ATTR_CMN_BKUPTIME | */
1183			/* ATTR_CMN_FNDRINFO | */
1184			ATTR_CMN_OWNERID |
1185			ATTR_CMN_GRPID	|
1186			ATTR_CMN_ACCESSMASK |
1187			ATTR_CMN_FLAGS	|
1188			ATTR_CMN_USERACCESS |
1189			/* ATTR_CMN_EXTENDED_SECURITY | */
1190			/* ATTR_CMN_UUID | */
1191			/* ATTR_CMN_GRPUUID | */
1192			0;
1193		attr->f_attributes.validattr.volattr =
1194			ATTR_VOL_FSTYPE	|
1195			/* ATTR_VOL_SIGNATURE */
1196			ATTR_VOL_SIZE	|
1197			ATTR_VOL_SPACEFREE |
1198			ATTR_VOL_SPACEAVAIL |
1199			ATTR_VOL_MINALLOCATION |
1200			ATTR_VOL_ALLOCATIONCLUMP |
1201			ATTR_VOL_IOBLOCKSIZE |
1202			/* ATTR_VOL_OBJCOUNT */
1203			/* ATTR_VOL_FILECOUNT */
1204			/* ATTR_VOL_DIRCOUNT */
1205			/* ATTR_VOL_MAXOBJCOUNT */
1206			ATTR_VOL_MOUNTPOINT |
1207			ATTR_VOL_NAME	|
1208			ATTR_VOL_MOUNTFLAGS |
1209			ATTR_VOL_MOUNTEDDEVICE |
1210			/* ATTR_VOL_ENCODINGSUSED */
1211			ATTR_VOL_CAPABILITIES |
1212			ATTR_VOL_ATTRIBUTES;
1213		attr->f_attributes.validattr.dirattr =
1214			ATTR_DIR_LINKCOUNT |
1215			/* ATTR_DIR_ENTRYCOUNT */
1216			ATTR_DIR_MOUNTSTATUS;
1217		attr->f_attributes.validattr.fileattr =
1218			ATTR_FILE_LINKCOUNT |
1219			ATTR_FILE_TOTALSIZE |
1220			ATTR_FILE_ALLOCSIZE |
1221			/* ATTR_FILE_IOBLOCKSIZE */
1222			ATTR_FILE_DEVTYPE |
1223			/* ATTR_FILE_FORKCOUNT */
1224			/* ATTR_FILE_FORKLIST */
1225			ATTR_FILE_DATALENGTH |
1226			ATTR_FILE_DATAALLOCSIZE |
1227			ATTR_FILE_RSRCLENGTH |
1228			ATTR_FILE_RSRCALLOCSIZE;
1229		attr->f_attributes.validattr.forkattr = 0;
1230		attr->f_attributes.nativeattr.commonattr =
1231			ATTR_CMN_NAME	|
1232			ATTR_CMN_DEVID	|
1233			ATTR_CMN_FSID	|
1234			ATTR_CMN_OBJTYPE |
1235			ATTR_CMN_OBJTAG	|
1236			ATTR_CMN_OBJID	|
1237			/* ATTR_CMN_OBJPERMANENTID | */
1238			ATTR_CMN_PAROBJID |
1239			/* ATTR_CMN_SCRIPT | */
1240			ATTR_CMN_CRTIME |
1241			ATTR_CMN_MODTIME |
1242			/* ATTR_CMN_CHGTIME | */	/* Supported but not native */
1243			ATTR_CMN_ACCTIME |
1244			/* ATTR_CMN_BKUPTIME | */
1245			/* ATTR_CMN_FNDRINFO | */
1246			/* ATTR_CMN_OWNERID | */	/* Supported but not native */
1247			/* ATTR_CMN_GRPID	| */	/* Supported but not native */
1248			/* ATTR_CMN_ACCESSMASK | */	/* Supported but not native */
1249			ATTR_CMN_FLAGS	|
1250			ATTR_CMN_USERACCESS |
1251			/* ATTR_CMN_EXTENDED_SECURITY | */
1252			/* ATTR_CMN_UUID | */
1253			/* ATTR_CMN_GRPUUID | */
1254			0;
1255		attr->f_attributes.nativeattr.volattr =
1256			ATTR_VOL_FSTYPE	|
1257			/* ATTR_VOL_SIGNATURE */
1258			ATTR_VOL_SIZE	|
1259			ATTR_VOL_SPACEFREE |
1260			ATTR_VOL_SPACEAVAIL |
1261			ATTR_VOL_MINALLOCATION |
1262			ATTR_VOL_ALLOCATIONCLUMP |
1263			ATTR_VOL_IOBLOCKSIZE |
1264			/* ATTR_VOL_OBJCOUNT */
1265			/* ATTR_VOL_FILECOUNT */
1266			/* ATTR_VOL_DIRCOUNT */
1267			/* ATTR_VOL_MAXOBJCOUNT */
1268			ATTR_VOL_MOUNTPOINT |
1269			ATTR_VOL_NAME	|
1270			ATTR_VOL_MOUNTFLAGS |
1271			ATTR_VOL_MOUNTEDDEVICE |
1272			/* ATTR_VOL_ENCODINGSUSED */
1273			ATTR_VOL_CAPABILITIES |
1274			ATTR_VOL_ATTRIBUTES;
1275		attr->f_attributes.nativeattr.dirattr = 0;
1276		attr->f_attributes.nativeattr.fileattr =
1277			/* ATTR_FILE_LINKCOUNT | */	/* Supported but not native */
1278			ATTR_FILE_TOTALSIZE |
1279			ATTR_FILE_ALLOCSIZE |
1280			/* ATTR_FILE_IOBLOCKSIZE */
1281			ATTR_FILE_DEVTYPE |
1282			/* ATTR_FILE_FORKCOUNT */
1283			/* ATTR_FILE_FORKLIST */
1284			ATTR_FILE_DATALENGTH |
1285			ATTR_FILE_DATAALLOCSIZE |
1286			ATTR_FILE_RSRCLENGTH |
1287			ATTR_FILE_RSRCALLOCSIZE;
1288		attr->f_attributes.nativeattr.forkattr = 0;
1289		VFSATTR_SET_SUPPORTED(attr, f_attributes);
1290	}
1291
1292	/* FAT doesn't have volume dates */
1293
1294	if (VFSATTR_IS_ACTIVE(attr, f_fssubtype)) {
1295		/* Subtypes (flavors) for MSDOS
1296			0 - FAT12
1297			1 - FAT16
1298			2 - FAT32
1299		*/
1300		if (pmp->pm_fatmask == FAT12_MASK) {
1301			attr->f_fssubtype = 0;	/* FAT12 */
1302		} else if (pmp->pm_fatmask == FAT16_MASK) {
1303			attr->f_fssubtype = 1;	/* FAT16 */
1304		} else {
1305			attr->f_fssubtype = 2;	/* FAT32 */
1306		}
1307		VFSATTR_SET_SUPPORTED(attr, f_fssubtype);
1308	}
1309
1310	/* f_bsize returned above */
1311
1312	if (VFSATTR_IS_ACTIVE(attr, f_vol_name)) {
1313		strlcpy(attr->f_vol_name, (char*)pmp->pm_label, MAXPATHLEN);
1314		VFSATTR_SET_SUPPORTED(attr, f_vol_name);
1315	}
1316
1317    if (VFSATTR_IS_ACTIVE(attr, f_uuid) && (pmp->pm_flags & MSDOSFS_HAS_VOL_UUID))
1318    {
1319        memcpy(attr->f_uuid, pmp->pm_uuid, sizeof(uuid_t));
1320        VFSATTR_SET_SUPPORTED(attr, f_uuid);
1321    }
1322
1323	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_GETATTR|DBG_FUNC_END, pmp, attr->f_supported, 0, 0, 0);
1324	return 0;
1325}
1326
1327
1328int msdosfs_vfs_setattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context)
1329{
1330    int error = 0;
1331	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1332
1333	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_SETATTR|DBG_FUNC_START, pmp, attr->f_active, 0, 0, 0);
1334
1335	if (VFSATTR_IS_ACTIVE(attr, f_vol_name))
1336	{
1337	    struct buf *bp = NULL;
1338	    size_t i;
1339	    size_t len;
1340	    size_t unichars;
1341		u_int16_t c;
1342	    u_int16_t volName[SHORT_NAME_LEN];
1343	    u_char label[SHORT_NAME_LEN];
1344
1345		len = strlen(attr->f_vol_name);
1346        if (len > 63)
1347        	return EINVAL;
1348
1349		/* Convert the UTF-8 to UTF-16 */
1350        error = utf8_decodestr((u_int8_t*)attr->f_vol_name, len, volName,
1351        	&unichars, sizeof(volName), 0, UTF_PRECOMPOSED);
1352        if (error)
1353            return error;
1354        unichars /= 2;	/* Bytes to characters */
1355		if (unichars > SHORT_NAME_LEN)
1356			return EINVAL;
1357
1358        /*
1359         * Convert from UTF-16 to local encoding (like a short name).
1360         * We can't call msdosfs_unicode_to_dos_name here because it
1361		 * assumes a dot between the first 8 and last 3 characters.
1362         *
1363         * The specification doesn't say what syntax limitations exist
1364         * for volume labels.  By experimentation, they appear to be
1365         * upper case only.  I am assuming they are like short names,
1366         * but no period is assumed/required after the 8th character.
1367         */
1368
1369        /* Name is trailing space padded, so init to all spaces. */
1370        for (i=0; i<SHORT_NAME_LEN; ++i)
1371            label[i] = ' ';
1372
1373        for (i=0; i<unichars; ++i) {
1374            c = volName[i];
1375            if (c < 0x100)
1376                c = l2u[c];			/* Convert to lower case */
1377            if (c != ' ')			/* Allow space to pass unchanged */
1378                c = msdosfs_unicode2dos(c);	/* Convert to local encoding */
1379            if (c < 3)
1380                return EINVAL;		/* Illegal char in name */
1381            label[i] = c;
1382        }
1383
1384        /* Copy the UTF-8 to pmp->pm_label */
1385        bcopy(attr->f_vol_name, pmp->pm_label, len);
1386        pmp->pm_label[len] = '\0';
1387
1388        /* Update label in boot sector */
1389        error = (int)buf_meta_bread(pmp->pm_devvp, 0, pmp->pm_BlockSize, vfs_context_ucred(context), &bp);
1390        if (!error) {
1391            if (FAT32(pmp))
1392                bcopy(label, (char*)buf_dataptr(bp)+71, SHORT_NAME_LEN);
1393            else
1394                bcopy(label, (char*)buf_dataptr(bp)+43, SHORT_NAME_LEN);
1395            buf_bdwrite(bp);
1396            bp = NULL;
1397        }
1398        if (bp)
1399            buf_brelse(bp);
1400        bp = NULL;
1401
1402        /*
1403         * Update label in root directory, if any.  For now, don't
1404         * create one if it doesn't exist (in case devices like
1405         * cameras don't understand them).
1406         */
1407        if (pmp->pm_label_cluster != CLUST_EOFE) {
1408        	error = msdosfs_readep(pmp, pmp->pm_label_cluster, pmp->pm_label_offset, &bp, NULL, context);
1409            if (!error) {
1410                bcopy(label, (char *)buf_dataptr(bp) + pmp->pm_label_offset, SHORT_NAME_LEN);
1411                buf_bdwrite(bp);
1412                bp = NULL;
1413            }
1414            if (bp)
1415                buf_brelse(bp);
1416            bp=NULL;
1417        }
1418
1419        if (error == 0)
1420        	VFSATTR_SET_SUPPORTED(attr, f_vol_name);
1421	}
1422
1423	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_SETATTR|DBG_FUNC_END, pmp, attr->f_supported, 0, 0, 0);
1424	return error;
1425}
1426
1427
1428struct msdosfs_sync_cargs {
1429	vfs_context_t context;
1430	int		waitfor;
1431	int		error;
1432};
1433
1434
1435int msdosfs_sync_callback(vnode_t vp, void *cargs)
1436{
1437	struct msdosfs_sync_cargs *args;
1438	struct denode *dep;
1439	int error;
1440
1441	/*
1442	 * msdosfs_check_link creates a temporary vnode whose v_data is
1443	 * NULL.  It normally gets reclaimed very quickly, but it is
1444	 * possible for a sync() to race with that reclaim.  Since that
1445	 * vnode doesn't have a denode to go with it, we can just ignore
1446	 * it for the purposes of syncing.
1447	 */
1448	dep = VTODE(vp);
1449	if (dep == NULL)
1450		return VNODE_RETURNED;
1451
1452	args = (struct msdosfs_sync_cargs *)cargs;
1453
1454	/*
1455	 * If this is a FAT vnode, then don't sync it here.  It will be sync'ed
1456	 * separately in msdosfs_vfs_sync.
1457	 */
1458	if (vnode_issystem(vp))
1459		return VNODE_RETURNED;
1460
1461	lck_mtx_lock(dep->de_lock);
1462
1463	error = msdosfs_fsync_internal(vp, args->waitfor, 0, args->context);
1464	if (error)
1465		args->error = error;
1466
1467	lck_mtx_unlock(dep->de_lock);
1468
1469	return VNODE_RETURNED;
1470}
1471
1472
1473int msdosfs_vfs_sync(mp, waitfor, context)
1474	struct mount *mp;
1475	int waitfor;
1476	vfs_context_t context;
1477{
1478	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1479	int error, allerror = 0;
1480	struct msdosfs_sync_cargs args;
1481
1482	if (pmp->pm_flags & MSDOSFSMNT_RONLY) {
1483		/* For read-only mounts, there's no syncing to do */
1484		return 0;
1485	}
1486
1487	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_SYNC|DBG_FUNC_START, pmp, 0, 0, 0, 0);
1488
1489	/*
1490	 * Flush the FSInfo sector and all copies of the FAT.
1491	 */
1492	error = msdosfs_update_fsinfo(pmp, waitfor, context);
1493	if (error)
1494		allerror = error;
1495
1496	error = VNOP_FSYNC(pmp->pm_fat_active_vp, waitfor, context);
1497	if (error)
1498		allerror = error;
1499	if (pmp->pm_fat_mirror_vp)
1500		error = VNOP_FSYNC(pmp->pm_fat_mirror_vp, waitfor, context);
1501	if (error)
1502		allerror = error;
1503
1504	/*
1505	 * Write back each (modified) denode.
1506	 */
1507	args.context = context;
1508	args.waitfor = waitfor;
1509	args.error = 0;
1510	/*
1511	 * msdosfs_sync_callback will be called for each vnode
1512	 * hung off of this mount point... the vnode will be
1513	 * properly referenced and unreferenced around the callback
1514	 */
1515	vnode_iterate(mp, VNODE_ITERATE_ACTIVE, msdosfs_sync_callback, (void *)&args);
1516
1517	if (args.error)
1518		allerror = args.error;
1519
1520	/*
1521	 * Flush directories.
1522	 */
1523	error = VNOP_FSYNC(pmp->pm_devvp, waitfor, context);
1524	if (error)
1525		allerror = error;
1526
1527	KERNEL_DEBUG_CONSTANT(MSDOSFS_VFS_SYNC|DBG_FUNC_END, allerror, 0, 0, 0, 0);
1528	return allerror;
1529}
1530
1531
1532struct vfsops msdosfs_vfsops = {
1533	msdosfs_vfs_mount,
1534	msdosfs_start,
1535	msdosfs_vfs_unmount,
1536	msdosfs_vfs_root,
1537	NULL, /* msdosfs_quotactl */
1538	msdosfs_vfs_getattr,
1539	msdosfs_vfs_sync,
1540	NULL, /* msdosfs_vget */
1541	NULL, /* msdosfs_fhtovp */
1542	NULL, /* msdosfs_vptofh */
1543	msdosfs_init,
1544	NULL, /* msdosfs_sysctl */
1545	msdosfs_vfs_setattr,
1546	{0}
1547};
1548
1549extern struct vnodeopv_desc msdosfs_vnodeop_opv_desc;
1550extern struct vnodeopv_desc msdosfs_fat_vnodeop_opv_desc;
1551static struct vnodeopv_desc *msdosfs_vnodeop_opv_desc_list[2] =
1552{
1553	&msdosfs_vnodeop_opv_desc,
1554	&msdosfs_fat_vnodeop_opv_desc
1555};
1556
1557
1558static vfstable_t msdosfs_vfsconf;
1559
1560int msdosfs_module_start(kmod_info_t *ki, void *data)
1561{
1562#pragma unused(ki)
1563#pragma unused(data)
1564	errno_t error;
1565	struct vfs_fsentry vfe;
1566
1567	vfe.vfe_vfsops = &msdosfs_vfsops;
1568	vfe.vfe_vopcnt = 2;		/* We just have vnode operations for regular files and directories, and the FAT */
1569	vfe.vfe_opvdescs = msdosfs_vnodeop_opv_desc_list;
1570	strlcpy(vfe.vfe_fsname, "msdos", sizeof(vfe.vfe_fsname));
1571	vfe.vfe_flags = VFS_TBLTHREADSAFE | VFS_TBLNOTYPENUM | VFS_TBLLOCALVOL | VFS_TBL64BITREADY | VFS_TBLREADDIR_EXTENDED;
1572	vfe.vfe_reserv[0] = 0;
1573	vfe.vfe_reserv[1] = 0;
1574
1575	error = vfs_fsadd(&vfe, &msdosfs_vfsconf);
1576
1577#if DEBUG
1578	if (!error)
1579	{
1580		sysctl_register_oid(&sysctl__vfs_generic_msdosfs);
1581		sysctl_register_oid(&sysctl__vfs_generic_msdosfs_meta_delay);
1582	}
1583#endif
1584
1585	return error ? KERN_FAILURE : KERN_SUCCESS;
1586}
1587
1588int msdosfs_module_stop(kmod_info_t *ki, void *data)
1589{
1590#pragma unused(ki)
1591#pragma unused(data)
1592    errno_t error;
1593
1594    error = vfs_fsremove(msdosfs_vfsconf);
1595
1596    if (!error)
1597    {
1598	msdosfs_uninit();
1599#if DEBUG
1600	sysctl_unregister_oid(&sysctl__vfs_generic_msdosfs_meta_delay);
1601	sysctl_unregister_oid(&sysctl__vfs_generic_msdosfs);
1602#endif
1603    }
1604
1605    return error ? KERN_FAILURE : KERN_SUCCESS;
1606}
1607
1608
1609/*
1610 * Look through the root directory for a volume label entry.
1611 * If found, use it to replace the label in the mount point.
1612 * Also look for a file with short name HIBERFIL.SYS; if it is less than
1613 * 4KiB in size, or has non-zero bytes in the first 4KiB, then force the
1614 * mount to read-only because Windows is hibernated on this volume.
1615 */
1616int msdosfs_scan_root_dir(struct mount *mp, vfs_context_t context)
1617{
1618    int error;
1619    struct msdosfsmount *pmp;
1620    vnode_t vp = NULL;
1621    struct buf *bp = NULL;
1622    uint32_t frcn;	/* file relative cluster number in root directory */
1623    daddr64_t bn;		/* block number of current dir block */
1624    uint32_t cluster;	/* cluster number of current dir block */
1625    uint32_t blsize;	/* size of current dir block */
1626    unsigned blkoff;		/* dir entry offset within current dir block */
1627	unsigned diroff;	/* offset from start of directory */
1628    struct dosdirentry *dep = NULL;
1629    struct denode *root;
1630    u_int16_t unichars;
1631    u_int16_t ucfn[12];
1632    u_char uc;
1633    int i;
1634    size_t outbytes;
1635    char *bdata = NULL;
1636
1637    pmp = VFSTOMSDOSFS(mp);
1638
1639    error = msdosfs_vfs_root(mp, &vp, context);
1640    if (error)
1641        return error;
1642    root = VTODE(vp);
1643
1644	diroff = 0;
1645    for (frcn=0; ; frcn++) {
1646        error = msdosfs_pcbmap(root, frcn, 1, &bn, &cluster, &blsize);
1647        if (error) {
1648            /* It is fine if no volume label entry was found in the root directory */
1649            if (error == E2BIG)
1650                error = 0;
1651            goto not_found;
1652        }
1653
1654        for (blkoff = 0; blkoff < blsize; blkoff += sizeof(struct dosdirentry), diroff += sizeof(struct dosdirentry)) {
1655			/* Make sure we have the buffer containing the current entry */
1656			if (bp == NULL) {
1657				error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
1658				if (error) {
1659					goto not_found;
1660				}
1661				bdata = (char *)buf_dataptr(bp);
1662			}
1663
1664            dep = (struct dosdirentry *) (bdata + blkoff);
1665
1666            /* Skip deleted directory entries */
1667            if (dep->deName[0] == SLOT_DELETED)
1668                continue;
1669
1670            /* Stop if we hit the end of the directory (a never used entry) */
1671            if (dep->deName[0] == SLOT_EMPTY) {
1672                goto not_found;
1673            }
1674
1675            /* Skip long name entries */
1676            if (dep->deAttributes == ATTR_WIN95)
1677                continue;
1678
1679            if (dep->deAttributes & ATTR_VOLUME) {
1680                pmp->pm_label_cluster = cluster;
1681                pmp->pm_label_offset = blkoff;
1682
1683                /*
1684                 * Copy the dates from the label to the root vnode.
1685                 */
1686                root->de_CHun = dep->deCHundredth;
1687                root->de_CTime = getuint16(dep->deCTime);
1688                root->de_CDate = getuint16(dep->deCDate);
1689                root->de_ADate = getuint16(dep->deADate);
1690                root->de_MTime = getuint16(dep->deMTime);
1691                root->de_MDate = getuint16(dep->deMDate);
1692
1693				/*
1694                 * We don't call msdosfs_dos2unicodefn() because it assumes the last three
1695                 * characters are an extension, and it will put a period before the
1696                 * extension.
1697                 */
1698				for (i=0; i<SHORT_NAME_LEN; i++) {
1699					uc = dep->deName[i];
1700					if (i==0 && uc == SLOT_E5)
1701						uc = 0xE5;
1702					ucfn[i] = (uc < 0x80 || uc > 0x9F ? (u_int16_t)uc : dos2unicode[uc - 0x80]);
1703				}
1704				for (i=10; i>=0 && ucfn[i]==' '; --i)
1705					;
1706				unichars = i+1;
1707
1708				/* translate the name in ucfn into UTF-8 */
1709				error = utf8_encodestr(ucfn, unichars * 2,
1710								pmp->pm_label, &outbytes,
1711								sizeof(pmp->pm_label), 0, UTF_DECOMPOSED);
1712                goto found;
1713            }
1714
1715			if (!bcmp(dep->deName, "HIBERFILSYS", SHORT_NAME_LEN))
1716			{
1717				struct denode *hibernate = NULL;
1718				buf_t hibernate_bp = NULL;
1719				char *hibernate_data = NULL;
1720
1721				if (getuint32(dep->deFileSize) < 4096)
1722				{
1723					if (DEBUG) printf("msdosfs: Volume is hibernated; hiberfile.sys < 4096 bytes\n");
1724					goto hibernated;
1725				}
1726
1727				/* Release the current directory block so we can msdosfs_deget() the current entry. */
1728				buf_brelse(bp);
1729				bp = NULL;
1730
1731				/* Need to open the file so we can check the first 4KiB */
1732				error = msdosfs_deget(pmp, cluster, diroff, NULL, NULL, &hibernate, context);
1733				if (error)
1734				{
1735					printf("msdosfs: error %d trying to open hiberfil.sys\n", error);
1736					error = 0;
1737					goto hibernated;
1738				}
1739				error = buf_meta_bread(DETOV(hibernate), 0, 4096, vfs_context_ucred(context), &hibernate_bp);
1740				if (error)
1741				{
1742					printf("msdosfs: error %d trying to read hiberfil.sys\n", error);
1743					error = 0;
1744					goto hibernated;
1745				}
1746				hibernate_data = (char *) buf_dataptr(hibernate_bp);
1747				if (!strncmp(hibernate_data, "hibr", 4))
1748				{
1749					if (DEBUG) printf("msdosfs: Volume is hibernated; signature = 'hibr'\n");
1750					goto hibernated;
1751				}
1752				if (!strncmp(hibernate_data, "HIBR", 4))
1753				{
1754					if (DEBUG) printf("msdosfs: Volume is hibernated; signature = 'HIBR'\n");
1755					goto hibernated;
1756				}
1757				for (i=0; i<4096; ++i)
1758				{
1759					if (hibernate_data[i])
1760					{
1761						if (DEBUG) printf("msdosfs: Volume is hibernated (non-zero header)\n");
1762						goto hibernated;
1763					}
1764				}
1765
1766				if (DEBUG) printf("msdosfs: Volume is not hibernated (hiberfil.sys header all zeroes)\n");
1767				goto not_hibernated;
1768
1769hibernated:
1770				printf("msdosfs: Mounting hibernated volume read-only\n");
1771				vfs_setflags(mp, MNT_RDONLY);
1772
1773not_hibernated:
1774				if (hibernate_bp)
1775					buf_brelse(hibernate_bp);
1776				if (hibernate)
1777				{
1778					vnode_recycle(DETOV(hibernate));
1779					vnode_put(DETOV(hibernate));
1780				}
1781			}
1782        }
1783
1784		/* We're done with the current block.  Release it if we still have it. */
1785		if (bp != NULL) {
1786			buf_brelse(bp);
1787			bp = NULL;
1788		}
1789    }
1790
1791found:
1792not_found:
1793    if (bp)
1794        buf_brelse(bp);
1795
1796    if (vp) {
1797        if (error)
1798            vnode_recycle(vp);
1799        vnode_put(vp);
1800    }
1801
1802    return error;
1803}
1804