Module Name:    src
Committed By:   christos
Date:           Sat Jan 26 00:20:40 UTC 2013

Modified Files:
        src/usr.sbin/makefs: msdos.c
        src/usr.sbin/makefs/msdos: Makefile.inc
Added Files:
        src/usr.sbin/makefs: msdos.h
        src/usr.sbin/makefs/msdos: msdosfs_denode.c msdosfs_vfsops.c
            msdosfs_vnops.c

Log Message:
add more msdos stuff.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/makefs/msdos.c
cvs rdiff -u -r0 -r1.1 src/usr.sbin/makefs/msdos.h
cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/makefs/msdos/Makefile.inc
cvs rdiff -u -r0 -r1.1 src/usr.sbin/makefs/msdos/msdosfs_denode.c \
    src/usr.sbin/makefs/msdos/msdosfs_vfsops.c \
    src/usr.sbin/makefs/msdos/msdosfs_vnops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/makefs/msdos.c
diff -u src/usr.sbin/makefs/msdos.c:1.5 src/usr.sbin/makefs/msdos.c:1.6
--- src/usr.sbin/makefs/msdos.c:1.5	Wed Jan 23 20:10:47 2013
+++ src/usr.sbin/makefs/msdos.c	Fri Jan 25 19:20:40 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdos.c,v 1.5 2013/01/24 01:10:47 christos Exp $	*/
+/*	$NetBSD: msdos.c,v 1.6 2013/01/26 00:20:40 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(__lint)
-__RCSID("$NetBSD: msdos.c,v 1.5 2013/01/24 01:10:47 christos Exp $");
+__RCSID("$NetBSD: msdos.c,v 1.6 2013/01/26 00:20:40 christos Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -54,10 +54,17 @@ __RCSID("$NetBSD: msdos.c,v 1.5 2013/01/
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <dirent.h>
 
+#include <ffs/buf.h>
+#include <fs/msdosfs/denode.h>
 #include "makefs.h"
+#include "msdos.h"
 #include "mkfs_msdos.h"
 
+static int msdos_populate_dir(const char *, struct denode *, fsnode *,
+    fsnode *, fsinfo_t *);
+
 void
 msdos_prep_opts(fsinfo_t *fsopts)
 {
@@ -128,6 +135,14 @@ void
 msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
 	struct msdos_options *msdos_opt = fsopts->fs_specific;
+	struct vnode vp, rootvp;
+	struct timeval	start;
+	struct msdosfsmount *pmp;
+
+	assert(image != NULL);
+	assert(dir != NULL);
+	assert(root != NULL);
+	assert(fsopts != NULL);
 
 	/*
 	 * XXX: pick up other options from the msdos specific ones?
@@ -135,51 +150,94 @@ msdos_makefs(const char *image, const ch
 	 */
 	msdos_opt->create_size = MAX(msdos_opt->create_size, fsopts->minsize);
 
+		/* create image */
+	printf("Creating `%s'\n", image);
+	TIMER_START(start);
 	if (mkfs_msdos(image, NULL, msdos_opt) == -1)
 		return;
-#ifdef notyet
-	struct fs	*superblock;
-	struct timeval	start;
+	TIMER_RESULTS(start, "mkfs_msdos");
 
-	assert(image != NULL);
-	assert(dir != NULL);
-	assert(root != NULL);
-	assert(fsopts != NULL);
+	vp.fd = open(image, O_RDWR);
+	vp.fs = msdos_opt;
+	vp.offset = 1;
+
+	if ((pmp = msdosfs_mount(&vp, 0)) == NULL)
+		err(1, "msdosfs_mount");
+
+	if (msdosfs_root(pmp, &rootvp) != 0)
+		err(1, "msdosfs_root");
 
 	if (debug & DEBUG_FS_MAKEFS)
 		printf("msdos_makefs: image %s directory %s root %p\n",
 		    image, dir, root);
 
-		/* validate tree and options */
-	TIMER_START(start);
-	msdos_validate(dir, root, fsopts);
-	TIMER_RESULTS(start, "msdos_validate");
-
 	printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
 	    image, (long long)fsopts->size, (long long)fsopts->inodes);
 
-		/* create image */
+		/* populate image */
+	printf("Populating `%s'\n", image);
 	TIMER_START(start);
-	if (msdos_create_image(image, fsopts) == -1)
+	if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1)
 		errx(1, "Image file `%s' not created.", image);
-	TIMER_RESULTS(start, "msdos_create_image");
-
-	fsopts->curinode = ROOTINO;
+	TIMER_RESULTS(start, "msdos_populate_dir");
 
 	if (debug & DEBUG_FS_MAKEFS)
 		putchar('\n');
 
-		/* populate image */
-	printf("Populating `%s'\n", image);
-	TIMER_START(start);
-	if (! msdos_populate_dir(dir, root, fsopts))
-		errx(1, "Image file `%s' not populated.", image);
-	TIMER_RESULTS(start, "msdos_populate_dir");
-
 		/* ensure no outstanding buffers remain */
 	if (debug & DEBUG_FS_MAKEFS)
 		bcleanup();
 
 	printf("Image `%s' complete\n", image);
-#endif
+}
+
+static int
+msdos_populate_dir(const char *path, struct denode *dir, fsnode *root,
+    fsnode *parent, fsinfo_t *fsopts)
+{
+	fsnode *cur;
+	char pbuf[MAXPATHLEN];
+
+	assert(dir != NULL);
+	assert(root != NULL);
+	assert(fsopts != NULL);	
+	
+	for (cur = root->next; cur != NULL; cur = cur->next) {
+		if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path,
+		    cur->name) >= sizeof(pbuf)) {
+			warnx("path %s too long", pbuf);
+			return -1;
+		}
+
+		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
+			cur->inode->flags |= FI_ALLOCATED;
+			if (cur != root) {
+				fsopts->curinode++;
+				cur->inode->ino = fsopts->curinode;
+				cur->parent = parent;
+			}
+		}
+
+		if (cur->inode->flags & FI_WRITTEN) {
+			continue;	// hard link
+		}
+		cur->inode->flags |= FI_WRITTEN;
+
+		if (cur->child) {
+			struct denode *de;
+			if ((de = msdosfs_mkdire(pbuf, dir, cur)) == NULL)
+				err(1, "msdosfs_mkdire");
+			if (!msdos_populate_dir(pbuf, de, cur->child, cur,
+			    fsopts))
+				err(1, "populate_dir");
+			continue;
+		} else if (!S_ISREG(cur->type)) {
+			warnx("skipping non-regular file %s/%s", cur->path,
+			    cur->name);
+			continue;
+		}
+		if (msdosfs_mkfile(pbuf, dir, cur) == NULL)
+			err(1, "msdosfs_mkfile");
+	}
+	return 0;
 }

Index: src/usr.sbin/makefs/msdos/Makefile.inc
diff -u src/usr.sbin/makefs/msdos/Makefile.inc:1.3 src/usr.sbin/makefs/msdos/Makefile.inc:1.4
--- src/usr.sbin/makefs/msdos/Makefile.inc:1.3	Wed Jan 23 17:47:18 2013
+++ src/usr.sbin/makefs/msdos/Makefile.inc	Fri Jan 25 19:20:40 2013
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile.inc,v 1.3 2013/01/23 22:47:18 christos Exp $
+#	$NetBSD: Makefile.inc,v 1.4 2013/01/26 00:20:40 christos Exp $
 #
 
 MSDOS=	${NETBSDSRCDIR}/sys/fs/msdosfs
@@ -6,6 +6,7 @@ MSDOS_NEWFS=	${NETBSDSRCDIR}/sbin/newfs_
 
 .PATH:	${.CURDIR}/msdos ${MSDOS} ${MSDOS_NEWFS}
 
-CPPFLAGS+= -DMSDOS_EI -I${MSDOS} -I${MSDOS_NEWFS}
+CPPFLAGS+= -DMSDOS_EI -I${MSDOS} -I${MSDOS_NEWFS} -I${NETBSDSRCDIR}/sys
 
-SRCS+= mkfs_msdos.c
+SRCS+= mkfs_msdos.c msdosfs_fat.c msdosfs_conv.c msdosfs_vfsops.c
+SRCS+= msdosfs_lookup.c msdosfs_denode.c msdosfs_vnops.c

Added files:

Index: src/usr.sbin/makefs/msdos.h
diff -u /dev/null src/usr.sbin/makefs/msdos.h:1.1
--- /dev/null	Fri Jan 25 19:20:41 2013
+++ src/usr.sbin/makefs/msdos.h	Fri Jan 25 19:20:40 2013
@@ -0,0 +1,41 @@
+/*	$NetBSD: msdos.h,v 1.1 2013/01/26 00:20:40 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct vnode;
+
+struct msdosfsmount *msdosfs_mount(struct vnode *, int);
+int msdosfs_root(struct msdosfsmount *, struct vnode *);
+
+struct denode * msdosfs_mkfile(const char *, struct denode *, fsnode *);
+struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *);

Index: src/usr.sbin/makefs/msdos/msdosfs_denode.c
diff -u /dev/null src/usr.sbin/makefs/msdos/msdosfs_denode.c:1.1
--- /dev/null	Fri Jan 25 19:20:41 2013
+++ src/usr.sbin/makefs/msdos/msdosfs_denode.c	Fri Jan 25 19:20:40 2013
@@ -0,0 +1,379 @@
+/*	$NetBSD: msdosfs_denode.c,v 1.1 2013/01/26 00:20:40 christos Exp $	*/
+
+/*-
+ * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
+ * All rights reserved.
+ * Original code by Paul Popelka (pa...@uts.amdahl.com) (see below).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Written by Paul Popelka (pa...@uts.amdahl.com)
+ *
+ * You can do anything you want with this software, just don't say you wrote
+ * it, and don't remove this notice.
+ *
+ * This software is provided "as is".
+ *
+ * The author supplies this software to be publicly redistributed on the
+ * understanding that the author is not responsible for the correct
+ * functioning of this software in any circumstances and is not liable for
+ * any damages caused by this software.
+ *
+ * October 1992
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.1 2013/01/26 00:20:40 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>		/* defines "time" */
+#include <sys/dirent.h>
+#include <sys/namei.h>
+#include <sys/kauth.h>
+#include <sys/rbtree.h>
+
+#ifdef _KERNEL
+#include <sys/fstrans.h>
+#include <uvm/uvm_extern.h>
+#include <sys/buf.h>
+#include <sys/vnode.h>
+#else
+#include <ffs/buf.h>
+#endif
+
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/msdosfsmount.h>
+#include <fs/msdosfs/direntry.h>
+#include <fs/msdosfs/denode.h>
+#include <fs/msdosfs/fat.h>
+
+/*
+ * If deget() succeeds it returns with the gotten denode locked().
+ *
+ * pmp	     - address of msdosfsmount structure of the filesystem containing
+ *	       the denode of interest.  The pm_dev field and the address of
+ *	       the msdosfsmount structure are used.
+ * dirclust  - which cluster bp contains, if dirclust is 0 (root directory)
+ *	       diroffset is relative to the beginning of the root directory,
+ *	       otherwise it is cluster relative.
+ * diroffset - offset past begin of cluster of denode we want
+ * depp	     - returns the address of the gotten denode.
+ */
+int
+deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode **depp)
+	/* pmp:	 so we know the maj/min number */
+	/* dirclust:		 cluster this dir entry came from */
+	/* diroffset:		 index of entry within the cluster */
+	/* depp:		 returns the addr of the gotten denode */
+{
+	int error;
+	struct direntry *direntptr;
+	struct denode *ldep;
+	struct buf *bp;
+
+#ifdef MSDOSFS_DEBUG
+	printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
+	    pmp, dirclust, diroffset, depp);
+#endif
+
+	/*
+	 * On FAT32 filesystems, root is a (more or less) normal
+	 * directory
+	 */
+	if (FAT32(pmp) && dirclust == MSDOSFSROOT)
+		dirclust = pmp->pm_rootdirblk;
+
+	ldep = calloc(1, sizeof(*ldep));
+	if (ldep == NULL)
+		err(1, "calloc");
+	ldep->de_vnode = NULL;
+	ldep->de_flag = 0;
+	ldep->de_devvp = 0;
+	ldep->de_lockf = 0;
+	ldep->de_dev = pmp->pm_dev;
+	ldep->de_dirclust = dirclust;
+	ldep->de_diroffset = diroffset;
+	ldep->de_pmp = pmp;
+	ldep->de_devvp = pmp->pm_devvp;
+	ldep->de_refcnt = 1;
+	/*
+	 * Copy the directory entry into the denode area of the vnode.
+	 */
+	if ((dirclust == MSDOSFSROOT
+	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
+	    && diroffset == MSDOSFSROOT_OFS) {
+		/*
+		 * Directory entry for the root directory. There isn't one,
+		 * so we manufacture one. We should probably rummage
+		 * through the root directory and find a label entry (if it
+		 * exists), and then use the time and date from that entry
+		 * as the time and date for the root denode.
+		 */
+		ldep->de_vnode = (struct vnode *)-1;
+
+		ldep->de_Attributes = ATTR_DIRECTORY;
+		if (FAT32(pmp))
+			ldep->de_StartCluster = pmp->pm_rootdirblk;
+			/* de_FileSize will be filled in further down */
+		else {
+			ldep->de_StartCluster = MSDOSFSROOT;
+			ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
+		}
+		/*
+		 * fill in time and date so that dos2unixtime() doesn't
+		 * spit up when called from msdosfs_getattr() with root
+		 * denode
+		 */
+		ldep->de_CHun = 0;
+		ldep->de_CTime = 0x0000;	/* 00:00:00	 */
+		ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
+		    | (1 << DD_DAY_SHIFT);
+		/* Jan 1, 1980	 */
+		ldep->de_ADate = ldep->de_CDate;
+		ldep->de_MTime = ldep->de_CTime;
+		ldep->de_MDate = ldep->de_CDate;
+		/* leave the other fields as garbage */
+	} else {
+		error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
+		if (error) {
+			ldep->de_devvp = NULL;
+			ldep->de_Name[0] = SLOT_DELETED;
+			return (error);
+		}
+		DE_INTERNALIZE(ldep, direntptr);
+		brelse(bp, 0);
+	}
+
+	/*
+	 * Fill in a few fields of the vnode and finish filling in the
+	 * denode.  Then return the address of the found denode.
+	 */
+	if (ldep->de_Attributes & ATTR_DIRECTORY) {
+		/*
+		 * Since DOS directory entries that describe directories
+		 * have 0 in the filesize field, we take this opportunity
+		 * to find out the length of the directory and plug it into
+		 * the denode structure.
+		 */
+		u_long size;
+
+		if (ldep->de_StartCluster != MSDOSFSROOT) {
+			error = pcbmap(ldep, CLUST_END, 0, &size, 0);
+			if (error == E2BIG) {
+				ldep->de_FileSize = de_cn2off(pmp, size);
+				error = 0;
+			} else
+				printf("deget(): pcbmap returned %d\n", error);
+		}
+	}
+	*depp = ldep;
+	return (0);
+}
+
+/*
+ * Truncate the file described by dep to the length specified by length.
+ */
+int
+detrunc(struct denode *dep, u_long length, int flags, kauth_cred_t cred)
+{
+	int error;
+	int allerror = 0;
+	u_long eofentry;
+	u_long chaintofree = 0;
+	daddr_t bn, lastblock;
+	int boff;
+	int isadir = dep->de_Attributes & ATTR_DIRECTORY;
+	struct buf *bp;
+	struct msdosfsmount *pmp = dep->de_pmp;
+
+#ifdef MSDOSFS_DEBUG
+	printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
+#endif
+
+	/*
+	 * Disallow attempts to truncate the root directory since it is of
+	 * fixed size.  That's just the way dos filesystems are.  We use
+	 * the VROOT bit in the vnode because checking for the directory
+	 * bit and a startcluster of 0 in the denode is not adequate to
+	 * recognize the root directory at this point in a file or
+	 * directory's life.
+	 */
+	if ((DETOV(dep) == (struct vnode *)-1) && !FAT32(pmp)) {
+		printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
+		    dep->de_dirclust, dep->de_diroffset);
+		return (EINVAL);
+	}
+
+	if (dep->de_FileSize < length)
+		return (deextend(dep, length, cred));
+	lastblock = de_clcount(pmp, length) - 1;
+
+	/*
+	 * If the desired length is 0 then remember the starting cluster of
+	 * the file and set the StartCluster field in the directory entry
+	 * to 0.  If the desired length is not zero, then get the number of
+	 * the last cluster in the shortened file.  Then get the number of
+	 * the first cluster in the part of the file that is to be freed.
+	 * Then set the next cluster pointer in the last cluster of the
+	 * file to CLUST_EOFE.
+	 */
+	if (length == 0) {
+		chaintofree = dep->de_StartCluster;
+		dep->de_StartCluster = 0;
+		eofentry = ~0;
+	} else {
+		error = pcbmap(dep, lastblock, 0, &eofentry, 0);
+		if (error) {
+#ifdef MSDOSFS_DEBUG
+			printf("detrunc(): pcbmap fails %d\n", error);
+#endif
+			return (error);
+		}
+	}
+
+	/*
+	 * If the new length is not a multiple of the cluster size then we
+	 * must zero the tail end of the new last cluster in case it
+	 * becomes part of the file again because of a seek.
+	 */
+	if ((boff = length & pmp->pm_crbomask) != 0) {
+		if (isadir) {
+			bn = cntobn(pmp, eofentry);
+			error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
+			    pmp->pm_bpcluster, NOCRED, B_MODIFY, &bp);
+			if (error) {
+#ifdef MSDOSFS_DEBUG
+				printf("detrunc(): bread fails %d\n", error);
+#endif
+				return (error);
+			}
+			memset((char *)bp->b_data + boff, 0,
+			    pmp->pm_bpcluster - boff);
+			if (flags & IO_SYNC)
+				bwrite(bp);
+			else
+				bdwrite(bp);
+		}
+	}
+
+	/*
+	 * Write out the updated directory entry.  Even if the update fails
+	 * we free the trailing clusters.
+	 */
+	dep->de_FileSize = length;
+	if (!isadir)
+		dep->de_flag |= DE_UPDATE|DE_MODIFIED;
+#ifdef MSDOSFS_DEBUG
+	printf("detrunc(): allerror %d, eofentry %lu\n",
+	       allerror, eofentry);
+#endif
+
+	/*
+	 * If we need to break the cluster chain for the file then do it
+	 * now.
+	 */
+	if (eofentry != (u_long)~0) {
+		error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
+				 &chaintofree, CLUST_EOFE);
+		if (error) {
+#ifdef MSDOSFS_DEBUG
+			printf("detrunc(): fatentry errors %d\n", error);
+#endif
+			return (error);
+		}
+	}
+
+	/*
+	 * Now free the clusters removed from the file because of the
+	 * truncation.
+	 */
+	if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask))
+		freeclusterchain(pmp, chaintofree);
+
+	return (allerror);
+}
+
+/*
+ * Extend the file described by dep to length specified by length.
+ */
+int
+deextend(struct denode *dep, u_long length, kauth_cred_t cred)
+{
+	struct msdosfsmount *pmp = dep->de_pmp;
+	u_long count, osize;
+	int error;
+
+	/*
+	 * The root of a DOS filesystem cannot be extended.
+	 */
+	if ((DETOV(dep) == (struct vnode *)-1) && !FAT32(pmp))
+		return (EINVAL);
+
+	/*
+	 * Directories cannot be extended.
+	 */
+	if (dep->de_Attributes & ATTR_DIRECTORY)
+		return (EISDIR);
+
+	if (length <= dep->de_FileSize)
+		panic("deextend: file too large");
+
+	/*
+	 * Compute the number of clusters to allocate.
+	 */
+	count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
+	if (count > 0) {
+		if (count > pmp->pm_freeclustercount)
+			return (ENOSPC);
+		error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
+		if (error) {
+			/* truncate the added clusters away again */
+			(void) detrunc(dep, dep->de_FileSize, 0, cred);
+			return (error);
+		}
+	}
+
+	/*
+	 * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a
+	 * memset(); we set the write size so ubc won't read in file data that
+	 * is zero'd later.
+	 */
+	osize = dep->de_FileSize;
+	dep->de_FileSize = length;
+	dep->de_flag |= DE_UPDATE|DE_MODIFIED;
+	return 0;
+}
Index: src/usr.sbin/makefs/msdos/msdosfs_vfsops.c
diff -u /dev/null src/usr.sbin/makefs/msdos/msdosfs_vfsops.c:1.1
--- /dev/null	Fri Jan 25 19:20:41 2013
+++ src/usr.sbin/makefs/msdos/msdosfs_vfsops.c	Fri Jan 25 19:20:40 2013
@@ -0,0 +1,429 @@
+/*-
+ * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
+ * All rights reserved.
+ * Original code by Paul Popelka (pa...@uts.amdahl.com) (see below).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Written by Paul Popelka (pa...@uts.amdahl.com)
+ *
+ * You can do anything you want with this software, just don't say you wrote
+ * it, and don't remove this notice.
+ *
+ * This software is provided "as is".
+ *
+ * The author supplies this software to be publicly redistributed on the
+ * understanding that the author is not responsible for the correct
+ * functioning of this software in any circumstances and is not liable for
+ * any damages caused by this software.
+ *
+ * October 1992
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.1 2013/01/26 00:20:40 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/dirent.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+
+#include <ffs/buf.h>
+
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/bootsect.h>
+#include <fs/msdosfs/direntry.h>
+#include <fs/msdosfs/denode.h>
+#include <fs/msdosfs/msdosfsmount.h>
+#include <fs/msdosfs/fat.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "msdos.h"
+#include "mkfs_msdos.h"
+#define NOCRED NULL
+
+#ifdef MSDOSFS_DEBUG
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
+
+struct msdosfsmount *
+msdosfs_mount(struct vnode *devvp, int flags)
+{
+	struct msdosfsmount *pmp = NULL;
+	struct buf *bp;
+	union bootsector *bsp;
+	struct byte_bpb33 *b33;
+	struct byte_bpb50 *b50;
+	struct byte_bpb710 *b710;
+	uint8_t SecPerClust;
+	int	ronly = 0, error, tmp;
+	int	bsize;
+	struct msdos_options *m = devvp->fs;
+	uint64_t psize = m->create_size;
+	unsigned secsize = 512;
+
+	if ((error = bread(devvp, 1, secsize, NOCRED, 0, &bp)) != 0)
+		goto error_exit;
+
+	bsp = (union bootsector *)bp->b_data;
+	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
+	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
+	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
+
+	if (!(flags & MSDOSFSMNT_GEMDOSFS)) {
+		if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
+		    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
+			DPRINTF(("bootsig0 %d bootsig1 %d\n", 
+			    bsp->bs50.bsBootSectSig0,
+			    bsp->bs50.bsBootSectSig1));
+			error = EINVAL;
+			goto error_exit;
+		}
+		bsize = 0;
+	} else
+		bsize = 512;
+
+	pmp = calloc(1, sizeof *pmp);
+	if (pmp == NULL)
+		goto error_exit;
+
+	/*
+	 * Compute several useful quantities from the bpb in the
+	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
+	 * the fields that are different between dos 5 and dos 3.3.
+	 */
+	SecPerClust = b50->bpbSecPerClust;
+	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
+	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
+	pmp->pm_FATs = b50->bpbFATs;
+	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
+	pmp->pm_Sectors = getushort(b50->bpbSectors);
+	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
+	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
+	pmp->pm_Heads = getushort(b50->bpbHeads);
+	pmp->pm_Media = b50->bpbMedia;
+
+	if (!(flags & MSDOSFSMNT_GEMDOSFS)) {
+		/* XXX - We should probably check more values here */
+    		if (!pmp->pm_BytesPerSec || !SecPerClust
+	    		|| pmp->pm_SecPerTrack > 63) {
+			DPRINTF(("bytespersec %d secperclust %d "
+			    "secpertrack %d\n", 
+			    pmp->pm_BytesPerSec, SecPerClust,
+			    pmp->pm_SecPerTrack));
+			error = EINVAL;
+			goto error_exit;
+		}
+	}
+
+	if (pmp->pm_Sectors == 0) {
+		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
+		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
+	} else {
+		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
+		pmp->pm_HugeSectors = pmp->pm_Sectors;
+	}
+
+	if (pmp->pm_RootDirEnts == 0) {
+		unsigned short vers = getushort(b710->bpbFSVers);
+		/*
+		 * Some say that bsBootSectSig[23] must be zero, but
+		 * Windows does not require this and some digital cameras
+		 * do not set these to zero.  Therefore, do not insist.
+		 */
+		if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) {
+			DPRINTF(("sectors %d fatsecs %lu vers %d\n",
+			    pmp->pm_Sectors, pmp->pm_FATsecs, vers));
+			error = EINVAL;
+			goto error_exit;
+		}
+		pmp->pm_fatmask = FAT32_MASK;
+		pmp->pm_fatmult = 4;
+		pmp->pm_fatdiv = 1;
+		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
+
+		/* mirrorring is enabled if the FATMIRROR bit is not set */
+		if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0)
+			pmp->pm_flags |= MSDOSFS_FATMIRROR;
+		else
+			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
+	} else
+		pmp->pm_flags |= MSDOSFS_FATMIRROR;
+
+	if (flags & MSDOSFSMNT_GEMDOSFS) {
+		if (FAT32(pmp)) {
+			DPRINTF(("FAT32 for GEMDOS\n"));
+			/*
+			 * GEMDOS doesn't know FAT32.
+			 */
+			error = EINVAL;
+			goto error_exit;
+		}
+
+		/*
+		 * Check a few values (could do some more):
+		 * - logical sector size: power of 2, >= block size
+		 * - sectors per cluster: power of 2, >= 1
+		 * - number of sectors:   >= 1, <= size of partition
+		 */
+		if ( (SecPerClust == 0)
+		  || (SecPerClust & (SecPerClust - 1))
+		  || (pmp->pm_BytesPerSec < bsize)
+		  || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
+		  || (pmp->pm_HugeSectors == 0)
+		  || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
+		      > psize)) {
+			DPRINTF(("consistency checks for GEMDOS\n"));
+			error = EINVAL;
+			goto error_exit;
+		}
+		/*
+		 * XXX - Many parts of the msdosfs driver seem to assume that
+		 * the number of bytes per logical sector (BytesPerSec) will
+		 * always be the same as the number of bytes per disk block
+		 * Let's pretend it is.
+		 */
+		tmp = pmp->pm_BytesPerSec / bsize;
+		pmp->pm_BytesPerSec  = bsize;
+		pmp->pm_HugeSectors *= tmp;
+		pmp->pm_HiddenSects *= tmp;
+		pmp->pm_ResSectors  *= tmp;
+		pmp->pm_Sectors     *= tmp;
+		pmp->pm_FATsecs     *= tmp;
+		SecPerClust         *= tmp;
+	}
+
+	/* Check that fs has nonzero FAT size */
+	if (pmp->pm_FATsecs == 0) {
+		DPRINTF(("FATsecs is 0\n"));
+		error = EINVAL;
+		goto error_exit;
+	}
+
+	pmp->pm_fatblk = pmp->pm_ResSectors;
+	if (FAT32(pmp)) {
+		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
+		pmp->pm_firstcluster = pmp->pm_fatblk
+			+ (pmp->pm_FATs * pmp->pm_FATsecs);
+		pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
+	} else {
+		pmp->pm_rootdirblk = pmp->pm_fatblk +
+			(pmp->pm_FATs * pmp->pm_FATsecs);
+		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
+				       + pmp->pm_BytesPerSec - 1)
+			/ pmp->pm_BytesPerSec;/* in sectors */
+		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
+	}
+
+	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
+	    SecPerClust;
+	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
+	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
+
+	if (flags & MSDOSFSMNT_GEMDOSFS) {
+		if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) {
+			pmp->pm_fatmask = FAT12_MASK;
+			pmp->pm_fatmult = 3;
+			pmp->pm_fatdiv = 2;
+		} else {
+			pmp->pm_fatmask = FAT16_MASK;
+			pmp->pm_fatmult = 2;
+			pmp->pm_fatdiv = 1;
+		}
+	} else if (pmp->pm_fatmask == 0) {
+		if (pmp->pm_maxcluster
+		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
+			/*
+			 * This will usually be a floppy disk. This size makes
+			 * sure that one FAT entry will not be split across
+			 * multiple blocks.
+			 */
+			pmp->pm_fatmask = FAT12_MASK;
+			pmp->pm_fatmult = 3;
+			pmp->pm_fatdiv = 2;
+		} else {
+			pmp->pm_fatmask = FAT16_MASK;
+			pmp->pm_fatmult = 2;
+			pmp->pm_fatdiv = 1;
+		}
+	}
+	if (FAT12(pmp))
+		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
+	else
+		pmp->pm_fatblocksize = MAXBSIZE;
+
+	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
+	pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
+
+	/*
+	 * Compute mask and shift value for isolating cluster relative byte
+	 * offsets and cluster numbers from a file offset.
+	 */
+	pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
+	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
+	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
+
+	/*
+	 * Check for valid cluster size
+	 * must be a power of 2
+	 */
+	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
+		DPRINTF(("bpcluster %lu cnshift %lu\n", 
+		    pmp->pm_bpcluster, pmp->pm_cnshift));
+		error = EINVAL;
+		goto error_exit;
+	}
+
+	/*
+	 * Release the bootsector buffer.
+	 */
+	brelse(bp, BC_AGE);
+	bp = NULL;
+
+	/*
+	 * Check FSInfo.
+	 */
+	if (pmp->pm_fsinfo) {
+		struct fsinfo *fp;
+
+		/*
+		 * XXX	If the fsinfo block is stored on media with
+		 *	2KB or larger sectors, is the fsinfo structure
+		 *	padded at the end or in the middle?
+		 */
+		if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
+		    pmp->pm_BytesPerSec, NOCRED, 0, &bp)) != 0)
+			goto error_exit;
+		fp = (struct fsinfo *)bp->b_data;
+		if (!memcmp(fp->fsisig1, "RRaA", 4)
+		    && !memcmp(fp->fsisig2, "rrAa", 4)
+		    && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
+		    && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
+			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
+		else
+			pmp->pm_fsinfo = 0;
+		brelse(bp, 0);
+		bp = NULL;
+	}
+
+	/*
+	 * Check and validate (or perhaps invalidate?) the fsinfo structure?
+	 * XXX
+	 */
+	if (pmp->pm_fsinfo) {
+		if ((pmp->pm_nxtfree == 0xffffffffUL) ||
+		    (pmp->pm_nxtfree > pmp->pm_maxcluster))
+			pmp->pm_fsinfo = 0;
+	}
+
+	/*
+	 * Allocate memory for the bitmap of allocated clusters, and then
+	 * fill it in.
+	 */
+	pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS)
+				   / N_INUSEBITS)
+				  * sizeof(*pmp->pm_inusemap));
+	if (pmp->pm_inusemap == NULL)
+		goto error_exit;
+
+	/*
+	 * fillinusemap() needs pm_devvp.
+	 */
+	pmp->pm_dev = 0;
+	pmp->pm_devvp = devvp;
+
+	/*
+	 * Have the inuse map filled in.
+	 */
+	if ((error = fillinusemap(pmp)) != 0) {
+		DPRINTF(("fillinusemap %d\n", error));
+		goto error_exit;
+	}
+
+	/*
+	 * If they want FAT updates to be synchronous then let them suffer
+	 * the performance degradation in exchange for the on disk copy of
+	 * the FAT being correct just about all the time.  I suppose this
+	 * would be a good thing to turn on if the kernel is still flakey.
+	 */
+	if (flags & MNT_SYNCHRONOUS)
+		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
+
+	/*
+	 * Finish up.
+	 */
+	if (ronly)
+		pmp->pm_flags |= MSDOSFSMNT_RONLY;
+	else
+		pmp->pm_fmod = 1;
+
+	/*
+	 * If we ever do quotas for DOS filesystems this would be a place
+	 * to fill in the info in the msdosfsmount structure. You dolt,
+	 * quotas on dos filesystems make no sense because files have no
+	 * owners on dos filesystems. of course there is some empty space
+	 * in the directory entry where we could put uid's and gid's.
+	 */
+
+	return pmp;
+
+error_exit:
+	if (bp)
+		brelse(bp, BC_AGE);
+	if (pmp) {
+		if (pmp->pm_inusemap)
+			free(pmp->pm_inusemap);
+		free(pmp);
+	}
+	errno = error;
+	return pmp;
+}
+
+int
+msdosfs_root(struct msdosfsmount *pmp, struct vnode *vp) {
+	struct denode *ndep;
+	int error;
+
+	*vp = *pmp->pm_devvp;
+	if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) {
+		errno = error;
+		return -1;
+	}
+	vp->v_data = ndep;
+	return 0;
+}
Index: src/usr.sbin/makefs/msdos/msdosfs_vnops.c
diff -u /dev/null src/usr.sbin/makefs/msdos/msdosfs_vnops.c:1.1
--- /dev/null	Fri Jan 25 19:20:41 2013
+++ src/usr.sbin/makefs/msdos/msdosfs_vnops.c	Fri Jan 25 19:20:40 2013
@@ -0,0 +1,359 @@
+/*	$NetBSD: msdosfs_vnops.c,v 1.1 2013/01/26 00:20:40 christos Exp $	*/
+
+/*-
+ * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
+ * All rights reserved.
+ * Original code by Paul Popelka (pa...@uts.amdahl.com) (see below).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Written by Paul Popelka (pa...@uts.amdahl.com)
+ *
+ * You can do anything you want with this software, just don't say you wrote
+ * it, and don't remove this notice.
+ *
+ * This software is provided "as is".
+ *
+ * The author supplies this software to be publicly redistributed on the
+ * understanding that the author is not responsible for the correct
+ * functioning of this software in any circumstances and is not liable for
+ * any damages caused by this software.
+ *
+ * October 1992
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.1 2013/01/26 00:20:40 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <ffs/buf.h>
+
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/direntry.h>
+#include <fs/msdosfs/denode.h>
+#include <fs/msdosfs/msdosfsmount.h>
+#include <fs/msdosfs/fat.h>
+
+#include "makefs.h"
+#include "msdos.h"
+
+/*
+ * Some general notes:
+ *
+ * In the ufs filesystem the inodes, superblocks, and indirect blocks are
+ * read/written using the vnode for the filesystem. Blocks that represent
+ * the contents of a file are read/written using the vnode for the file
+ * (including directories when they are read/written as files). This
+ * presents problems for the dos filesystem because data that should be in
+ * an inode (if dos had them) resides in the directory itself.  Since we
+ * must update directory entries without the benefit of having the vnode
+ * for the directory we must use the vnode for the filesystem.  This means
+ * that when a directory is actually read/written (via read, write, or
+ * readdir, or seek) we must use the vnode for the filesystem instead of
+ * the vnode for the directory as would happen in ufs. This is to insure we
+ * retrieve the correct block from the buffer cache since the hash value is
+ * based upon the vnode address and the desired block number.
+ */
+
+static int msdosfs_wfile(const char *, struct denode *, fsnode *);
+
+static void
+msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
+    const struct stat *st)
+{
+	unix2dostime(&st->st_atimespec, pmp->pm_gmtoff, &dep->de_ADate,
+	    NULL, NULL);
+	unix2dostime(&st->st_mtimespec, pmp->pm_gmtoff, &dep->de_MDate,
+	    &dep->de_MTime, NULL);
+}
+
+/*
+ * Create a regular file. On entry the directory to contain the file being
+ * created is locked.  We must release before we return.
+ */
+struct denode *
+msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
+{
+	struct componentname cn;
+	struct denode ndirent;
+	struct denode *dep;
+	int error;
+	struct stat *st = &node->inode->st;
+	struct msdosfsmount *pmp = pdep->de_pmp;
+
+	cn.cn_nameptr = node->name;
+	cn.cn_namelen = strlen(node->name);
+
+#ifdef MSDOSFS_DEBUG
+	printf("msdosfs_create(cn %s, vap 0%o\n", node->name, st->st_mode);
+#endif
+
+	/*
+	 * If this is the root directory and there is no space left we
+	 * can't do anything.  This is because the root directory can not
+	 * change size.
+	 */
+	if (pdep->de_StartCluster == MSDOSFSROOT
+	    && pdep->de_fndoffset >= pdep->de_FileSize) {
+		error = ENOSPC;
+		goto bad;
+	}
+
+	/*
+	 * Create a directory entry for the file, then call createde() to
+	 * have it installed. NOTE: DOS files are always executable.  We
+	 * use the absence of the owner write bit to make the file
+	 * readonly.
+	 */
+	memset(&ndirent, 0, sizeof(ndirent));
+	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
+		goto bad;
+
+	ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
+				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
+	ndirent.de_StartCluster = 0;
+	ndirent.de_FileSize = 0;
+	ndirent.de_dev = pdep->de_dev;
+	ndirent.de_devvp = pdep->de_devvp;
+	ndirent.de_pmp = pdep->de_pmp;
+	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+	msdosfs_times(pmp, &ndirent, st);
+	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
+		goto bad;
+	if ((error = msdosfs_wfile(path, dep, node)) == -1)
+		goto bad;
+	return dep;
+
+bad:
+	errno = error;
+	return NULL;
+}
+
+/*
+ * Write data to a file or directory.
+ */
+static int
+msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
+{
+	int error, fd;
+	size_t osize = dep->de_FileSize;
+	struct stat *st = &node->inode->st;
+	size_t nsize = st->st_size;
+	size_t offs = 0;
+	struct msdosfsmount *pmp = dep->de_pmp;
+	struct buf *bp;
+	char *dat;
+
+#ifdef MSDOSFS_DEBUG
+	printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
+	    dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
+#endif
+	if (nsize == 0)
+		return 0;
+
+	/* Don't bother to try to write files larger than the fs limit */
+	if (nsize > MSDOSFS_FILESIZE_MAX) {
+		errno = EFBIG;
+		return -1;
+	}
+
+	if (nsize > osize) {
+		if ((error = deextend(dep, nsize, NULL)) != 0) {
+			errno = error;
+			return -1;
+		}
+	}
+
+	if ((fd = open(path, O_RDONLY)) == -1)
+		err(1, "open %s", path);
+
+	if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED)
+		err(1, "mmap %s", node->name);
+	close(fd);
+
+        for (u_long cn = 0;; cn++) {
+		int blsize, cpsize;
+		daddr_t bn;
+                if (pcbmap(dep, cn, &bn, 0, &blsize)) {
+			fprintf(stderr, "pcbmap %ld\n", cn);
+			goto out;
+		}
+
+                if (bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NULL,
+                    0, &bp)) {
+			fprintf(stderr, "bread\n");
+                } 
+		cpsize = MIN((int)(nsize - offs), blsize);
+		memcpy(bp->b_data, dat + offs, cpsize);
+		bwrite(bp);
+		brelse(bp, 0);
+		offs += blsize;
+		if (offs >= nsize)
+			break;
+	}
+
+	munmap(dat, nsize);
+	return 0;
+out:
+	munmap(dat, nsize);
+	return -1;
+}
+
+
+static const struct {
+	struct direntry dot;
+	struct direntry dotdot;
+} dosdirtemplate = {
+	{	".       ", "   ",			/* the . entry */
+		ATTR_DIRECTORY,				/* file attribute */
+		0,	 				/* reserved */
+		0, { 0, 0 }, { 0, 0 },			/* create time & date */
+		{ 0, 0 },				/* access date */
+		{ 0, 0 },				/* high bits of start cluster */
+		{ 210, 4 }, { 210, 4 },			/* modify time & date */
+		{ 0, 0 },				/* startcluster */
+		{ 0, 0, 0, 0 } 				/* filesize */
+	},
+	{	"..      ", "   ",			/* the .. entry */
+		ATTR_DIRECTORY,				/* file attribute */
+		0,	 				/* reserved */
+		0, { 0, 0 }, { 0, 0 },			/* create time & date */
+		{ 0, 0 },				/* access date */
+		{ 0, 0 },				/* high bits of start cluster */
+		{ 210, 4 }, { 210, 4 },			/* modify time & date */
+		{ 0, 0 },				/* startcluster */
+		{ 0, 0, 0, 0 }				/* filesize */
+	}
+};
+
+struct denode *
+msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
+	struct denode ndirent;
+	struct denode *dep;
+	struct componentname cn;
+	struct stat *st = &node->inode->st;
+	struct msdosfsmount *pmp = pdep->de_pmp;
+	int error;
+	u_long newcluster, pcl, bn;
+	daddr_t lbn;
+	struct direntry *denp;
+	struct buf *bp;
+
+	cn.cn_nameptr = node->name;
+	cn.cn_namelen = strlen(node->name);
+	/*
+	 * If this is the root directory and there is no space left we
+	 * can't do anything.  This is because the root directory can not
+	 * change size.
+	 */
+	if (pdep->de_StartCluster == MSDOSFSROOT
+	    && pdep->de_fndoffset >= pdep->de_FileSize) {
+		error = ENOSPC;
+		goto bad2;
+	}
+
+	/*
+	 * Allocate a cluster to hold the about to be created directory.
+	 */
+	error = clusteralloc(pmp, 0, 1, &newcluster, NULL);
+	if (error)
+		goto bad2;
+
+	memset(&ndirent, 0, sizeof(ndirent));
+	ndirent.de_pmp = pmp;
+	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+	msdosfs_times(pmp, &ndirent, st);
+
+	/*
+	 * Now fill the cluster with the "." and ".." entries. And write
+	 * the cluster to disk.  This way it is there for the parent
+	 * directory to be pointing at if there were a crash.
+	 */
+	bn = cntobn(pmp, newcluster);
+	lbn = de_bn2kb(pmp, bn);
+	/* always succeeds */
+	bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0);
+	memset(bp->b_data, 0, pmp->pm_bpcluster);
+	memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
+	denp = (struct direntry *)bp->b_data;
+	putushort(denp[0].deStartCluster, newcluster);
+	putushort(denp[0].deCDate, ndirent.de_CDate);
+	putushort(denp[0].deCTime, ndirent.de_CTime);
+	denp[0].deCHundredth = ndirent.de_CHun;
+	putushort(denp[0].deADate, ndirent.de_ADate);
+	putushort(denp[0].deMDate, ndirent.de_MDate);
+	putushort(denp[0].deMTime, ndirent.de_MTime);
+	pcl = pdep->de_StartCluster;
+	if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
+		pcl = 0;
+	putushort(denp[1].deStartCluster, pcl);
+	putushort(denp[1].deCDate, ndirent.de_CDate);
+	putushort(denp[1].deCTime, ndirent.de_CTime);
+	denp[1].deCHundredth = ndirent.de_CHun;
+	putushort(denp[1].deADate, ndirent.de_ADate);
+	putushort(denp[1].deMDate, ndirent.de_MDate);
+	putushort(denp[1].deMTime, ndirent.de_MTime);
+	if (FAT32(pmp)) {
+		putushort(denp[0].deHighClust, newcluster >> 16);
+		putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
+	} else {
+		putushort(denp[0].deHighClust, 0);
+		putushort(denp[1].deHighClust, 0);
+	}
+
+	if ((error = bwrite(bp)) != 0)
+		goto bad;
+
+	/*
+	 * Now build up a directory entry pointing to the newly allocated
+	 * cluster.  This will be written to an empty slot in the parent
+	 * directory.
+	 */
+	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
+		goto bad;
+
+	ndirent.de_Attributes = ATTR_DIRECTORY;
+	ndirent.de_StartCluster = newcluster;
+	ndirent.de_FileSize = 0;
+	ndirent.de_dev = pdep->de_dev;
+	ndirent.de_devvp = pdep->de_devvp;
+	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
+		goto bad;
+	return dep;
+
+bad:
+	clusterfree(pmp, newcluster, NULL);
+bad2:
+	errno = error;
+	return NULL;
+}

Reply via email to