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 ([email protected]) (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 ([email protected])
+ *
+ * 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 ([email protected]) (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 ([email protected])
+ *
+ * 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 ([email protected]) (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 ([email protected])
+ *
+ * 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;
+}