xref: /minix/usr.sbin/makefs/msdos/msdosfs_vnops.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: msdosfs_vnops.c,v 1.16 2015/03/29 05:52:59 agc Exp $ */
29f988b79SJean-Baptiste Boric 
39f988b79SJean-Baptiste Boric /*-
49f988b79SJean-Baptiste Boric  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
59f988b79SJean-Baptiste Boric  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
69f988b79SJean-Baptiste Boric  * All rights reserved.
79f988b79SJean-Baptiste Boric  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
89f988b79SJean-Baptiste Boric  *
99f988b79SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
109f988b79SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
119f988b79SJean-Baptiste Boric  * are met:
129f988b79SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
139f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
149f988b79SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
159f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in the
169f988b79SJean-Baptiste Boric  *    documentation and/or other materials provided with the distribution.
179f988b79SJean-Baptiste Boric  * 3. All advertising materials mentioning features or use of this software
189f988b79SJean-Baptiste Boric  *    must display the following acknowledgement:
199f988b79SJean-Baptiste Boric  *	This product includes software developed by TooLs GmbH.
209f988b79SJean-Baptiste Boric  * 4. The name of TooLs GmbH may not be used to endorse or promote products
219f988b79SJean-Baptiste Boric  *    derived from this software without specific prior written permission.
229f988b79SJean-Baptiste Boric  *
239f988b79SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
249f988b79SJean-Baptiste Boric  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
259f988b79SJean-Baptiste Boric  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
269f988b79SJean-Baptiste Boric  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
279f988b79SJean-Baptiste Boric  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
289f988b79SJean-Baptiste Boric  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
299f988b79SJean-Baptiste Boric  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
309f988b79SJean-Baptiste Boric  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
319f988b79SJean-Baptiste Boric  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
329f988b79SJean-Baptiste Boric  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
339f988b79SJean-Baptiste Boric  */
349f988b79SJean-Baptiste Boric /*
359f988b79SJean-Baptiste Boric  * Written by Paul Popelka (paulp@uts.amdahl.com)
369f988b79SJean-Baptiste Boric  *
379f988b79SJean-Baptiste Boric  * You can do anything you want with this software, just don't say you wrote
389f988b79SJean-Baptiste Boric  * it, and don't remove this notice.
399f988b79SJean-Baptiste Boric  *
409f988b79SJean-Baptiste Boric  * This software is provided "as is".
419f988b79SJean-Baptiste Boric  *
429f988b79SJean-Baptiste Boric  * The author supplies this software to be publicly redistributed on the
439f988b79SJean-Baptiste Boric  * understanding that the author is not responsible for the correct
449f988b79SJean-Baptiste Boric  * functioning of this software in any circumstances and is not liable for
459f988b79SJean-Baptiste Boric  * any damages caused by this software.
469f988b79SJean-Baptiste Boric  *
479f988b79SJean-Baptiste Boric  * October 1992
489f988b79SJean-Baptiste Boric  */
499f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
509f988b79SJean-Baptiste Boric #include "nbtool_config.h"
519f988b79SJean-Baptiste Boric #endif
529f988b79SJean-Baptiste Boric 
539f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
54*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.16 2015/03/29 05:52:59 agc Exp $");
559f988b79SJean-Baptiste Boric 
569f988b79SJean-Baptiste Boric #include <sys/param.h>
579f988b79SJean-Baptiste Boric #include <sys/mman.h>
589f988b79SJean-Baptiste Boric #include <fcntl.h>
599f988b79SJean-Baptiste Boric #include <unistd.h>
609f988b79SJean-Baptiste Boric 
619f988b79SJean-Baptiste Boric #include <ffs/buf.h>
629f988b79SJean-Baptiste Boric 
639f988b79SJean-Baptiste Boric #include <fs/msdosfs/bpb.h>
649f988b79SJean-Baptiste Boric #include <fs/msdosfs/direntry.h>
659f988b79SJean-Baptiste Boric #include <fs/msdosfs/denode.h>
669f988b79SJean-Baptiste Boric #include <fs/msdosfs/msdosfsmount.h>
679f988b79SJean-Baptiste Boric #include <fs/msdosfs/fat.h>
689f988b79SJean-Baptiste Boric 
699f988b79SJean-Baptiste Boric #include "makefs.h"
709f988b79SJean-Baptiste Boric #include "msdos.h"
719f988b79SJean-Baptiste Boric 
729f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
739f988b79SJean-Baptiste Boric #define DPRINTF(a) printf a
749f988b79SJean-Baptiste Boric #else
759f988b79SJean-Baptiste Boric #define DPRINTF(a)
769f988b79SJean-Baptiste Boric #endif
779f988b79SJean-Baptiste Boric /*
789f988b79SJean-Baptiste Boric  * Some general notes:
799f988b79SJean-Baptiste Boric  *
809f988b79SJean-Baptiste Boric  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
819f988b79SJean-Baptiste Boric  * read/written using the vnode for the filesystem. Blocks that represent
829f988b79SJean-Baptiste Boric  * the contents of a file are read/written using the vnode for the file
839f988b79SJean-Baptiste Boric  * (including directories when they are read/written as files). This
849f988b79SJean-Baptiste Boric  * presents problems for the dos filesystem because data that should be in
859f988b79SJean-Baptiste Boric  * an inode (if dos had them) resides in the directory itself.	Since we
869f988b79SJean-Baptiste Boric  * must update directory entries without the benefit of having the vnode
879f988b79SJean-Baptiste Boric  * for the directory we must use the vnode for the filesystem.	This means
889f988b79SJean-Baptiste Boric  * that when a directory is actually read/written (via read, write, or
899f988b79SJean-Baptiste Boric  * readdir, or seek) we must use the vnode for the filesystem instead of
909f988b79SJean-Baptiste Boric  * the vnode for the directory as would happen in ufs. This is to insure we
919f988b79SJean-Baptiste Boric  * retrieve the correct block from the buffer cache since the hash value is
929f988b79SJean-Baptiste Boric  * based upon the vnode address and the desired block number.
939f988b79SJean-Baptiste Boric  */
949f988b79SJean-Baptiste Boric 
959f988b79SJean-Baptiste Boric static int msdosfs_wfile(const char *, struct denode *, fsnode *);
969f988b79SJean-Baptiste Boric 
979f988b79SJean-Baptiste Boric static void
msdosfs_times(struct msdosfsmount * pmp,struct denode * dep,const struct stat * st)989f988b79SJean-Baptiste Boric msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
999f988b79SJean-Baptiste Boric     const struct stat *st)
1009f988b79SJean-Baptiste Boric {
1019f988b79SJean-Baptiste Boric #ifndef HAVE_NBTOOL_CONFIG_H
1029f988b79SJean-Baptiste Boric 	struct timespec at = st->st_atimespec;
1039f988b79SJean-Baptiste Boric 	struct timespec mt = st->st_mtimespec;
1049f988b79SJean-Baptiste Boric #else
1059f988b79SJean-Baptiste Boric 	struct timespec at = { st->st_atime, 0 };
1069f988b79SJean-Baptiste Boric 	struct timespec mt = { st->st_mtime, 0 };
1079f988b79SJean-Baptiste Boric #endif
1089f988b79SJean-Baptiste Boric 	unix2dostime(&at, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL);
1099f988b79SJean-Baptiste Boric 	unix2dostime(&mt, pmp->pm_gmtoff, &dep->de_MDate, &dep->de_MTime, NULL);
1109f988b79SJean-Baptiste Boric }
1119f988b79SJean-Baptiste Boric 
1129f988b79SJean-Baptiste Boric /*
1139f988b79SJean-Baptiste Boric  * When we search a directory the blocks containing directory entries are
1149f988b79SJean-Baptiste Boric  * read and examined.  The directory entries contain information that would
1159f988b79SJean-Baptiste Boric  * normally be in the inode of a unix filesystem.  This means that some of
1169f988b79SJean-Baptiste Boric  * a directory's contents may also be in memory resident denodes (sort of
1179f988b79SJean-Baptiste Boric  * an inode).  This can cause problems if we are searching while some other
1189f988b79SJean-Baptiste Boric  * process is modifying a directory.  To prevent one process from accessing
1199f988b79SJean-Baptiste Boric  * incompletely modified directory information we depend upon being the
1209f988b79SJean-Baptiste Boric  * sole owner of a directory block.  bread/brelse provide this service.
1219f988b79SJean-Baptiste Boric  * This being the case, when a process modifies a directory it must first
1229f988b79SJean-Baptiste Boric  * acquire the disk block that contains the directory entry to be modified.
1239f988b79SJean-Baptiste Boric  * Then update the disk block and the denode, and then write the disk block
1249f988b79SJean-Baptiste Boric  * out to disk.	 This way disk blocks containing directory entries and in
1259f988b79SJean-Baptiste Boric  * memory denode's will be in synch.
1269f988b79SJean-Baptiste Boric  */
1279f988b79SJean-Baptiste Boric static int
msdosfs_findslot(struct denode * dp,struct componentname * cnp)1289f988b79SJean-Baptiste Boric msdosfs_findslot(struct denode *dp, struct componentname *cnp)
1299f988b79SJean-Baptiste Boric {
1309f988b79SJean-Baptiste Boric 	daddr_t bn;
1319f988b79SJean-Baptiste Boric 	int error;
1329f988b79SJean-Baptiste Boric 	int slotcount;
1339f988b79SJean-Baptiste Boric 	int slotoffset = 0;
1349f988b79SJean-Baptiste Boric 	int frcn;
1359f988b79SJean-Baptiste Boric 	u_long cluster;
1369f988b79SJean-Baptiste Boric 	int blkoff;
1379f988b79SJean-Baptiste Boric 	u_int diroff;
1389f988b79SJean-Baptiste Boric 	int blsize;
1399f988b79SJean-Baptiste Boric 	struct msdosfsmount *pmp;
1409f988b79SJean-Baptiste Boric 	struct buf *bp = 0;
1419f988b79SJean-Baptiste Boric 	struct direntry *dep;
1429f988b79SJean-Baptiste Boric 	u_char dosfilename[12];
1439f988b79SJean-Baptiste Boric 	int wincnt = 1;
1449f988b79SJean-Baptiste Boric 	int chksum = -1, chksum_ok;
1459f988b79SJean-Baptiste Boric 	int olddos = 1;
1469f988b79SJean-Baptiste Boric 
1479f988b79SJean-Baptiste Boric 	pmp = dp->de_pmp;
1489f988b79SJean-Baptiste Boric 
1499f988b79SJean-Baptiste Boric 	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
1509f988b79SJean-Baptiste Boric 	    cnp->cn_namelen, 0)) {
1519f988b79SJean-Baptiste Boric 	case 0:
1529f988b79SJean-Baptiste Boric 		return (EINVAL);
1539f988b79SJean-Baptiste Boric 	case 1:
1549f988b79SJean-Baptiste Boric 		break;
1559f988b79SJean-Baptiste Boric 	case 2:
1569f988b79SJean-Baptiste Boric 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
1579f988b79SJean-Baptiste Boric 		    cnp->cn_namelen) + 1;
1589f988b79SJean-Baptiste Boric 		break;
1599f988b79SJean-Baptiste Boric 	case 3:
1609f988b79SJean-Baptiste Boric 		olddos = 0;
1619f988b79SJean-Baptiste Boric 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
1629f988b79SJean-Baptiste Boric 		    cnp->cn_namelen) + 1;
1639f988b79SJean-Baptiste Boric 		break;
1649f988b79SJean-Baptiste Boric 	}
1659f988b79SJean-Baptiste Boric 
1669f988b79SJean-Baptiste Boric 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
1679f988b79SJean-Baptiste Boric 		wincnt = 1;
1689f988b79SJean-Baptiste Boric 
1699f988b79SJean-Baptiste Boric 	/*
1709f988b79SJean-Baptiste Boric 	 * Suppress search for slots unless creating
1719f988b79SJean-Baptiste Boric 	 * file and at end of pathname, in which case
1729f988b79SJean-Baptiste Boric 	 * we watch for a place to put the new file in
1739f988b79SJean-Baptiste Boric 	 * case it doesn't already exist.
1749f988b79SJean-Baptiste Boric 	 */
1759f988b79SJean-Baptiste Boric 	slotcount = 0;
1769f988b79SJean-Baptiste Boric 	DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename));
1779f988b79SJean-Baptiste Boric 	/*
1789f988b79SJean-Baptiste Boric 	 * Search the directory pointed at by vdp for the name pointed at
1799f988b79SJean-Baptiste Boric 	 * by cnp->cn_nameptr.
1809f988b79SJean-Baptiste Boric 	 */
1819f988b79SJean-Baptiste Boric 	/*
1829f988b79SJean-Baptiste Boric 	 * The outer loop ranges over the clusters that make up the
1839f988b79SJean-Baptiste Boric 	 * directory.  Note that the root directory is different from all
1849f988b79SJean-Baptiste Boric 	 * other directories.  It has a fixed number of blocks that are not
1859f988b79SJean-Baptiste Boric 	 * part of the pool of allocatable clusters.  So, we treat it a
1869f988b79SJean-Baptiste Boric 	 * little differently. The root directory starts at "cluster" 0.
1879f988b79SJean-Baptiste Boric 	 */
1889f988b79SJean-Baptiste Boric 	diroff = 0;
1899f988b79SJean-Baptiste Boric 	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
1909f988b79SJean-Baptiste Boric 		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
1919f988b79SJean-Baptiste Boric 			if (error == E2BIG)
1929f988b79SJean-Baptiste Boric 				break;
1939f988b79SJean-Baptiste Boric 			return (error);
1949f988b79SJean-Baptiste Boric 		}
195*0a6a1f1dSLionel Sambuc 		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
1969f988b79SJean-Baptiste Boric 		    0, &bp);
1979f988b79SJean-Baptiste Boric 		if (error) {
1989f988b79SJean-Baptiste Boric 			return (error);
1999f988b79SJean-Baptiste Boric 		}
2009f988b79SJean-Baptiste Boric 		for (blkoff = 0; blkoff < blsize;
2019f988b79SJean-Baptiste Boric 		     blkoff += sizeof(struct direntry),
2029f988b79SJean-Baptiste Boric 		     diroff += sizeof(struct direntry)) {
2039f988b79SJean-Baptiste Boric 			dep = (struct direntry *)((char *)bp->b_data + blkoff);
2049f988b79SJean-Baptiste Boric 			/*
2059f988b79SJean-Baptiste Boric 			 * If the slot is empty and we are still looking
2069f988b79SJean-Baptiste Boric 			 * for an empty then remember this one.	 If the
2079f988b79SJean-Baptiste Boric 			 * slot is not empty then check to see if it
2089f988b79SJean-Baptiste Boric 			 * matches what we are looking for.  If the slot
2099f988b79SJean-Baptiste Boric 			 * has never been filled with anything, then the
2109f988b79SJean-Baptiste Boric 			 * remainder of the directory has never been used,
2119f988b79SJean-Baptiste Boric 			 * so there is no point in searching it.
2129f988b79SJean-Baptiste Boric 			 */
2139f988b79SJean-Baptiste Boric 			if (dep->deName[0] == SLOT_EMPTY ||
2149f988b79SJean-Baptiste Boric 			    dep->deName[0] == SLOT_DELETED) {
2159f988b79SJean-Baptiste Boric 				/*
2169f988b79SJean-Baptiste Boric 				 * Drop memory of previous long matches
2179f988b79SJean-Baptiste Boric 				 */
2189f988b79SJean-Baptiste Boric 				chksum = -1;
2199f988b79SJean-Baptiste Boric 
2209f988b79SJean-Baptiste Boric 				if (slotcount < wincnt) {
2219f988b79SJean-Baptiste Boric 					slotcount++;
2229f988b79SJean-Baptiste Boric 					slotoffset = diroff;
2239f988b79SJean-Baptiste Boric 				}
2249f988b79SJean-Baptiste Boric 				if (dep->deName[0] == SLOT_EMPTY) {
2259f988b79SJean-Baptiste Boric 					brelse(bp, 0);
2269f988b79SJean-Baptiste Boric 					goto notfound;
2279f988b79SJean-Baptiste Boric 				}
2289f988b79SJean-Baptiste Boric 			} else {
2299f988b79SJean-Baptiste Boric 				/*
2309f988b79SJean-Baptiste Boric 				 * If there wasn't enough space for our
2319f988b79SJean-Baptiste Boric 				 * winentries, forget about the empty space
2329f988b79SJean-Baptiste Boric 				 */
2339f988b79SJean-Baptiste Boric 				if (slotcount < wincnt)
2349f988b79SJean-Baptiste Boric 					slotcount = 0;
2359f988b79SJean-Baptiste Boric 
2369f988b79SJean-Baptiste Boric 				/*
2379f988b79SJean-Baptiste Boric 				 * Check for Win95 long filename entry
2389f988b79SJean-Baptiste Boric 				 */
2399f988b79SJean-Baptiste Boric 				if (dep->deAttributes == ATTR_WIN95) {
2409f988b79SJean-Baptiste Boric 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
2419f988b79SJean-Baptiste Boric 						continue;
2429f988b79SJean-Baptiste Boric 
2439f988b79SJean-Baptiste Boric 					chksum = winChkName((const u_char *)cnp->cn_nameptr,
2449f988b79SJean-Baptiste Boric 							    cnp->cn_namelen,
2459f988b79SJean-Baptiste Boric 							    (struct winentry *)dep,
2469f988b79SJean-Baptiste Boric 							    chksum);
2479f988b79SJean-Baptiste Boric 					continue;
2489f988b79SJean-Baptiste Boric 				}
2499f988b79SJean-Baptiste Boric 
2509f988b79SJean-Baptiste Boric 				/*
2519f988b79SJean-Baptiste Boric 				 * Ignore volume labels (anywhere, not just
2529f988b79SJean-Baptiste Boric 				 * the root directory).
2539f988b79SJean-Baptiste Boric 				 */
2549f988b79SJean-Baptiste Boric 				if (dep->deAttributes & ATTR_VOLUME) {
2559f988b79SJean-Baptiste Boric 					chksum = -1;
2569f988b79SJean-Baptiste Boric 					continue;
2579f988b79SJean-Baptiste Boric 				}
2589f988b79SJean-Baptiste Boric 
2599f988b79SJean-Baptiste Boric 				/*
2609f988b79SJean-Baptiste Boric 				 * Check for a checksum or name match
2619f988b79SJean-Baptiste Boric 				 */
2629f988b79SJean-Baptiste Boric 				chksum_ok = (chksum == winChksum(dep->deName));
2639f988b79SJean-Baptiste Boric 				if (!chksum_ok
2649f988b79SJean-Baptiste Boric 				    && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
2659f988b79SJean-Baptiste Boric 					chksum = -1;
2669f988b79SJean-Baptiste Boric 					continue;
2679f988b79SJean-Baptiste Boric 				}
2689f988b79SJean-Baptiste Boric 				DPRINTF(("%s(): match blkoff %d, diroff %d\n",
2699f988b79SJean-Baptiste Boric 				    __func__, blkoff, diroff));
2709f988b79SJean-Baptiste Boric 				/*
2719f988b79SJean-Baptiste Boric 				 * Remember where this directory
2729f988b79SJean-Baptiste Boric 				 * entry came from for whoever did
2739f988b79SJean-Baptiste Boric 				 * this lookup.
2749f988b79SJean-Baptiste Boric 				 */
2759f988b79SJean-Baptiste Boric 				dp->de_fndoffset = diroff;
2769f988b79SJean-Baptiste Boric 				dp->de_fndcnt = 0;
2779f988b79SJean-Baptiste Boric 
2789f988b79SJean-Baptiste Boric 				return EEXIST;
2799f988b79SJean-Baptiste Boric 			}
2809f988b79SJean-Baptiste Boric 		}	/* for (blkoff = 0; .... */
2819f988b79SJean-Baptiste Boric 		/*
2829f988b79SJean-Baptiste Boric 		 * Release the buffer holding the directory cluster just
2839f988b79SJean-Baptiste Boric 		 * searched.
2849f988b79SJean-Baptiste Boric 		 */
2859f988b79SJean-Baptiste Boric 		brelse(bp, 0);
2869f988b79SJean-Baptiste Boric 	}	/* for (frcn = 0; ; frcn++) */
2879f988b79SJean-Baptiste Boric 
2889f988b79SJean-Baptiste Boric notfound:
2899f988b79SJean-Baptiste Boric 	/*
2909f988b79SJean-Baptiste Boric 	 * We hold no disk buffers at this point.
2919f988b79SJean-Baptiste Boric 	 */
2929f988b79SJean-Baptiste Boric 
2939f988b79SJean-Baptiste Boric 	/*
2949f988b79SJean-Baptiste Boric 	 * If we get here we didn't find the entry we were looking for. But
2959f988b79SJean-Baptiste Boric 	 * that's ok if we are creating or renaming and are at the end of
2969f988b79SJean-Baptiste Boric 	 * the pathname and the directory hasn't been removed.
2979f988b79SJean-Baptiste Boric 	 */
2989f988b79SJean-Baptiste Boric 	DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n",
2999f988b79SJean-Baptiste Boric 	    __func__, dp->de_refcnt, slotcount, slotoffset));
3009f988b79SJean-Baptiste Boric 	/*
3019f988b79SJean-Baptiste Boric 	 * Fixup the slot description to point to the place where
3029f988b79SJean-Baptiste Boric 	 * we might put the new DOS direntry (putting the Win95
3039f988b79SJean-Baptiste Boric 	 * long name entries before that)
3049f988b79SJean-Baptiste Boric 	 */
3059f988b79SJean-Baptiste Boric 	if (!slotcount) {
3069f988b79SJean-Baptiste Boric 		slotcount = 1;
3079f988b79SJean-Baptiste Boric 		slotoffset = diroff;
3089f988b79SJean-Baptiste Boric 	}
3099f988b79SJean-Baptiste Boric 	if (wincnt > slotcount) {
3109f988b79SJean-Baptiste Boric 		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
3119f988b79SJean-Baptiste Boric 	}
3129f988b79SJean-Baptiste Boric 
3139f988b79SJean-Baptiste Boric 	/*
3149f988b79SJean-Baptiste Boric 	 * Return an indication of where the new directory
3159f988b79SJean-Baptiste Boric 	 * entry should be put.
3169f988b79SJean-Baptiste Boric 	 */
3179f988b79SJean-Baptiste Boric 	dp->de_fndoffset = slotoffset;
3189f988b79SJean-Baptiste Boric 	dp->de_fndcnt = wincnt - 1;
3199f988b79SJean-Baptiste Boric 
3209f988b79SJean-Baptiste Boric 	/*
3219f988b79SJean-Baptiste Boric 	 * We return with the directory locked, so that
3229f988b79SJean-Baptiste Boric 	 * the parameters we set up above will still be
3239f988b79SJean-Baptiste Boric 	 * valid if we actually decide to do a direnter().
3249f988b79SJean-Baptiste Boric 	 * We return ni_vp == NULL to indicate that the entry
3259f988b79SJean-Baptiste Boric 	 * does not currently exist; we leave a pointer to
3269f988b79SJean-Baptiste Boric 	 * the (locked) directory inode in ndp->ni_dvp.
3279f988b79SJean-Baptiste Boric 	 *
3289f988b79SJean-Baptiste Boric 	 * NB - if the directory is unlocked, then this
3299f988b79SJean-Baptiste Boric 	 * information cannot be used.
3309f988b79SJean-Baptiste Boric 	 */
3319f988b79SJean-Baptiste Boric 	return 0;
3329f988b79SJean-Baptiste Boric }
3339f988b79SJean-Baptiste Boric 
3349f988b79SJean-Baptiste Boric /*
3359f988b79SJean-Baptiste Boric  * Create a regular file. On entry the directory to contain the file being
3369f988b79SJean-Baptiste Boric  * created is locked.  We must release before we return.
3379f988b79SJean-Baptiste Boric  */
3389f988b79SJean-Baptiste Boric struct denode *
msdosfs_mkfile(const char * path,struct denode * pdep,fsnode * node)3399f988b79SJean-Baptiste Boric msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
3409f988b79SJean-Baptiste Boric {
3419f988b79SJean-Baptiste Boric 	struct componentname cn;
3429f988b79SJean-Baptiste Boric 	struct denode ndirent;
3439f988b79SJean-Baptiste Boric 	struct denode *dep;
3449f988b79SJean-Baptiste Boric 	int error;
3459f988b79SJean-Baptiste Boric 	struct stat *st = &node->inode->st;
3469f988b79SJean-Baptiste Boric 	struct msdosfsmount *pmp = pdep->de_pmp;
3479f988b79SJean-Baptiste Boric 
3489f988b79SJean-Baptiste Boric 	cn.cn_nameptr = node->name;
3499f988b79SJean-Baptiste Boric 	cn.cn_namelen = strlen(node->name);
3509f988b79SJean-Baptiste Boric 
3519f988b79SJean-Baptiste Boric 	DPRINTF(("%s(name %s, mode 0%o size %zu)\n", __func__, node->name,
3529f988b79SJean-Baptiste Boric 	    st->st_mode, (size_t)st->st_size));
3539f988b79SJean-Baptiste Boric 
3549f988b79SJean-Baptiste Boric 	/*
3559f988b79SJean-Baptiste Boric 	 * If this is the root directory and there is no space left we
3569f988b79SJean-Baptiste Boric 	 * can't do anything.  This is because the root directory can not
3579f988b79SJean-Baptiste Boric 	 * change size.
3589f988b79SJean-Baptiste Boric 	 */
3599f988b79SJean-Baptiste Boric 	if (pdep->de_StartCluster == MSDOSFSROOT
3609f988b79SJean-Baptiste Boric 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
3619f988b79SJean-Baptiste Boric 		error = ENOSPC;
3629f988b79SJean-Baptiste Boric 		goto bad;
3639f988b79SJean-Baptiste Boric 	}
3649f988b79SJean-Baptiste Boric 
3659f988b79SJean-Baptiste Boric 	/*
3669f988b79SJean-Baptiste Boric 	 * Create a directory entry for the file, then call createde() to
3679f988b79SJean-Baptiste Boric 	 * have it installed. NOTE: DOS files are always executable.  We
3689f988b79SJean-Baptiste Boric 	 * use the absence of the owner write bit to make the file
3699f988b79SJean-Baptiste Boric 	 * readonly.
3709f988b79SJean-Baptiste Boric 	 */
3719f988b79SJean-Baptiste Boric 	memset(&ndirent, 0, sizeof(ndirent));
3729f988b79SJean-Baptiste Boric 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
3739f988b79SJean-Baptiste Boric 		goto bad;
3749f988b79SJean-Baptiste Boric 
3759f988b79SJean-Baptiste Boric 	ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
3769f988b79SJean-Baptiste Boric 				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
3779f988b79SJean-Baptiste Boric 	ndirent.de_StartCluster = 0;
3789f988b79SJean-Baptiste Boric 	ndirent.de_FileSize = 0;
3799f988b79SJean-Baptiste Boric 	ndirent.de_dev = pdep->de_dev;
3809f988b79SJean-Baptiste Boric 	ndirent.de_devvp = pdep->de_devvp;
3819f988b79SJean-Baptiste Boric 	ndirent.de_pmp = pdep->de_pmp;
3829f988b79SJean-Baptiste Boric 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
3839f988b79SJean-Baptiste Boric 	msdosfs_times(pmp, &ndirent, st);
3849f988b79SJean-Baptiste Boric 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
3859f988b79SJean-Baptiste Boric 		goto bad;
3869f988b79SJean-Baptiste Boric 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
3879f988b79SJean-Baptiste Boric 		goto bad;
3889f988b79SJean-Baptiste Boric 	if ((error = msdosfs_wfile(path, dep, node)) != 0)
3899f988b79SJean-Baptiste Boric 		goto bad;
3909f988b79SJean-Baptiste Boric 	return dep;
3919f988b79SJean-Baptiste Boric 
3929f988b79SJean-Baptiste Boric bad:
3939f988b79SJean-Baptiste Boric 	errno = error;
3949f988b79SJean-Baptiste Boric 	return NULL;
3959f988b79SJean-Baptiste Boric }
3969f988b79SJean-Baptiste Boric static int
msdosfs_updatede(struct denode * dep)3979f988b79SJean-Baptiste Boric msdosfs_updatede(struct denode *dep)
3989f988b79SJean-Baptiste Boric {
3999f988b79SJean-Baptiste Boric 	struct buf *bp;
4009f988b79SJean-Baptiste Boric 	struct direntry *dirp;
4019f988b79SJean-Baptiste Boric 	int error;
4029f988b79SJean-Baptiste Boric 
4039f988b79SJean-Baptiste Boric 	dep->de_flag &= ~DE_MODIFIED;
4049f988b79SJean-Baptiste Boric 	error = readde(dep, &bp, &dirp);
4059f988b79SJean-Baptiste Boric 	if (error)
4069f988b79SJean-Baptiste Boric 		return error;
4079f988b79SJean-Baptiste Boric 	DE_EXTERNALIZE(dirp, dep);
4089f988b79SJean-Baptiste Boric 	error = bwrite(bp);
4099f988b79SJean-Baptiste Boric 	return error;
4109f988b79SJean-Baptiste Boric }
4119f988b79SJean-Baptiste Boric 
4129f988b79SJean-Baptiste Boric /*
4139f988b79SJean-Baptiste Boric  * Write data to a file or directory.
4149f988b79SJean-Baptiste Boric  */
4159f988b79SJean-Baptiste Boric static int
msdosfs_wfile(const char * path,struct denode * dep,fsnode * node)4169f988b79SJean-Baptiste Boric msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
4179f988b79SJean-Baptiste Boric {
4189f988b79SJean-Baptiste Boric 	int error, fd;
4199f988b79SJean-Baptiste Boric 	size_t osize = dep->de_FileSize;
4209f988b79SJean-Baptiste Boric 	struct stat *st = &node->inode->st;
4219f988b79SJean-Baptiste Boric 	size_t nsize, offs;
4229f988b79SJean-Baptiste Boric 	struct msdosfsmount *pmp = dep->de_pmp;
4239f988b79SJean-Baptiste Boric 	struct buf *bp;
4249f988b79SJean-Baptiste Boric 	char *dat;
4259f988b79SJean-Baptiste Boric 	u_long cn = 0;
4269f988b79SJean-Baptiste Boric 
4279f988b79SJean-Baptiste Boric 	error = 0;	/* XXX: gcc/vax */
4289f988b79SJean-Baptiste Boric 	DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__,
4299f988b79SJean-Baptiste Boric 	    dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster));
4309f988b79SJean-Baptiste Boric 	if (st->st_size == 0)
4319f988b79SJean-Baptiste Boric 		return 0;
4329f988b79SJean-Baptiste Boric 
4339f988b79SJean-Baptiste Boric 	/* Don't bother to try to write files larger than the fs limit */
4349f988b79SJean-Baptiste Boric 	if (st->st_size > MSDOSFS_FILESIZE_MAX) {
4359f988b79SJean-Baptiste Boric 		errno = EFBIG;
4369f988b79SJean-Baptiste Boric 		return -1;
4379f988b79SJean-Baptiste Boric 	}
4389f988b79SJean-Baptiste Boric 
4399f988b79SJean-Baptiste Boric 	nsize = st->st_size;
4409f988b79SJean-Baptiste Boric 	DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize));
4419f988b79SJean-Baptiste Boric 	if (nsize > osize) {
4429f988b79SJean-Baptiste Boric 		if ((error = deextend(dep, nsize, NULL)) != 0) {
4439f988b79SJean-Baptiste Boric 			errno = error;
4449f988b79SJean-Baptiste Boric 			return -1;
4459f988b79SJean-Baptiste Boric 		}
4469f988b79SJean-Baptiste Boric 		if ((error = msdosfs_updatede(dep)) != 0) {
4479f988b79SJean-Baptiste Boric 			errno = error;
4489f988b79SJean-Baptiste Boric 			return -1;
4499f988b79SJean-Baptiste Boric 		}
4509f988b79SJean-Baptiste Boric 	}
4519f988b79SJean-Baptiste Boric 
4529f988b79SJean-Baptiste Boric 	if ((fd = open(path, O_RDONLY)) == -1)
4539f988b79SJean-Baptiste Boric 		err(1, "open %s", path);
4549f988b79SJean-Baptiste Boric 
4559f988b79SJean-Baptiste Boric 	if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0))
4569f988b79SJean-Baptiste Boric 	    == MAP_FAILED) {
4579f988b79SJean-Baptiste Boric 		DPRINTF(("%s: mmap %s %s", __func__, node->name,
4589f988b79SJean-Baptiste Boric 		    strerror(errno)));
4599f988b79SJean-Baptiste Boric 		close(fd);
4609f988b79SJean-Baptiste Boric 		goto out;
4619f988b79SJean-Baptiste Boric 	}
4629f988b79SJean-Baptiste Boric 	close(fd);
4639f988b79SJean-Baptiste Boric 
4649f988b79SJean-Baptiste Boric 	for (offs = 0; offs < nsize;) {
4659f988b79SJean-Baptiste Boric 		int blsize, cpsize;
4669f988b79SJean-Baptiste Boric 		daddr_t bn;
4679f988b79SJean-Baptiste Boric 		u_long on = offs & pmp->pm_crbomask;
4689f988b79SJean-Baptiste Boric #ifdef HACK
4699f988b79SJean-Baptiste Boric 		cn = dep->de_StartCluster;
4709f988b79SJean-Baptiste Boric 		if (cn == MSDOSFSROOT) {
4719f988b79SJean-Baptiste Boric 			DPRINTF(("%s: bad lbn %lu", __func__, cn));
4729f988b79SJean-Baptiste Boric 			goto out;
4739f988b79SJean-Baptiste Boric 		}
4749f988b79SJean-Baptiste Boric 		bn = cntobn(pmp, cn);
4759f988b79SJean-Baptiste Boric 		blsize = pmp->pm_bpcluster;
4769f988b79SJean-Baptiste Boric #else
4779f988b79SJean-Baptiste Boric 		if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) {
4789f988b79SJean-Baptiste Boric 			DPRINTF(("%s: pcbmap %lu", __func__, bn));
4799f988b79SJean-Baptiste Boric 			goto out;
4809f988b79SJean-Baptiste Boric 		}
4819f988b79SJean-Baptiste Boric #endif
4829f988b79SJean-Baptiste Boric 		DPRINTF(("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__,
4839f988b79SJean-Baptiste Boric 		    cn, (unsigned long long)bn,
4849f988b79SJean-Baptiste Boric 		    (unsigned long long)de_bn2kb(pmp, bn), blsize));
4859f988b79SJean-Baptiste Boric 		if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
486*0a6a1f1dSLionel Sambuc 		    0, &bp)) != 0) {
4879f988b79SJean-Baptiste Boric 			DPRINTF(("bread %d\n", error));
4889f988b79SJean-Baptiste Boric 			goto out;
4899f988b79SJean-Baptiste Boric 		}
4909f988b79SJean-Baptiste Boric 		cpsize = MIN((nsize - offs), blsize - on);
4919f988b79SJean-Baptiste Boric 		memcpy((char *)bp->b_data + on, dat + offs, cpsize);
4929f988b79SJean-Baptiste Boric 		bwrite(bp);
4939f988b79SJean-Baptiste Boric 		offs += cpsize;
4949f988b79SJean-Baptiste Boric 	}
4959f988b79SJean-Baptiste Boric 
4969f988b79SJean-Baptiste Boric 	munmap(dat, nsize);
4979f988b79SJean-Baptiste Boric 	return 0;
4989f988b79SJean-Baptiste Boric out:
4999f988b79SJean-Baptiste Boric 	munmap(dat, nsize);
5009f988b79SJean-Baptiste Boric 	return error;
5019f988b79SJean-Baptiste Boric }
5029f988b79SJean-Baptiste Boric 
5039f988b79SJean-Baptiste Boric 
5049f988b79SJean-Baptiste Boric static const struct {
5059f988b79SJean-Baptiste Boric 	struct direntry dot;
5069f988b79SJean-Baptiste Boric 	struct direntry dotdot;
5079f988b79SJean-Baptiste Boric } dosdirtemplate = {
5089f988b79SJean-Baptiste Boric 	{	".       ", "   ",			/* the . entry */
5099f988b79SJean-Baptiste Boric 		ATTR_DIRECTORY,				/* file attribute */
5109f988b79SJean-Baptiste Boric 		0,					/* reserved */
5119f988b79SJean-Baptiste Boric 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
5129f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* access date */
5139f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* high bits of start cluster */
5149f988b79SJean-Baptiste Boric 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
5159f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* startcluster */
5169f988b79SJean-Baptiste Boric 		{ 0, 0, 0, 0 }				/* filesize */
5179f988b79SJean-Baptiste Boric 	},
5189f988b79SJean-Baptiste Boric 	{	"..      ", "   ",			/* the .. entry */
5199f988b79SJean-Baptiste Boric 		ATTR_DIRECTORY,				/* file attribute */
5209f988b79SJean-Baptiste Boric 		0,					/* reserved */
5219f988b79SJean-Baptiste Boric 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
5229f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* access date */
5239f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* high bits of start cluster */
5249f988b79SJean-Baptiste Boric 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
5259f988b79SJean-Baptiste Boric 		{ 0, 0 },				/* startcluster */
5269f988b79SJean-Baptiste Boric 		{ 0, 0, 0, 0 }				/* filesize */
5279f988b79SJean-Baptiste Boric 	}
5289f988b79SJean-Baptiste Boric };
5299f988b79SJean-Baptiste Boric 
5309f988b79SJean-Baptiste Boric struct denode *
msdosfs_mkdire(const char * path,struct denode * pdep,fsnode * node)5319f988b79SJean-Baptiste Boric msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
5329f988b79SJean-Baptiste Boric 	struct denode ndirent;
5339f988b79SJean-Baptiste Boric 	struct denode *dep;
5349f988b79SJean-Baptiste Boric 	struct componentname cn;
5359f988b79SJean-Baptiste Boric 	struct stat *st = &node->inode->st;
5369f988b79SJean-Baptiste Boric 	struct msdosfsmount *pmp = pdep->de_pmp;
5379f988b79SJean-Baptiste Boric 	int error;
5389f988b79SJean-Baptiste Boric 	u_long newcluster, pcl, bn;
5399f988b79SJean-Baptiste Boric 	daddr_t lbn;
5409f988b79SJean-Baptiste Boric 	struct direntry *denp;
5419f988b79SJean-Baptiste Boric 	struct buf *bp;
5429f988b79SJean-Baptiste Boric 
5439f988b79SJean-Baptiste Boric 	cn.cn_nameptr = node->name;
5449f988b79SJean-Baptiste Boric 	cn.cn_namelen = strlen(node->name);
5459f988b79SJean-Baptiste Boric 	/*
5469f988b79SJean-Baptiste Boric 	 * If this is the root directory and there is no space left we
5479f988b79SJean-Baptiste Boric 	 * can't do anything.  This is because the root directory can not
5489f988b79SJean-Baptiste Boric 	 * change size.
5499f988b79SJean-Baptiste Boric 	 */
5509f988b79SJean-Baptiste Boric 	if (pdep->de_StartCluster == MSDOSFSROOT
5519f988b79SJean-Baptiste Boric 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
5529f988b79SJean-Baptiste Boric 		error = ENOSPC;
5539f988b79SJean-Baptiste Boric 		goto bad2;
5549f988b79SJean-Baptiste Boric 	}
5559f988b79SJean-Baptiste Boric 
5569f988b79SJean-Baptiste Boric 	/*
5579f988b79SJean-Baptiste Boric 	 * Allocate a cluster to hold the about to be created directory.
5589f988b79SJean-Baptiste Boric 	 */
5599f988b79SJean-Baptiste Boric 	error = clusteralloc(pmp, 0, 1, &newcluster, NULL);
5609f988b79SJean-Baptiste Boric 	if (error)
5619f988b79SJean-Baptiste Boric 		goto bad2;
5629f988b79SJean-Baptiste Boric 
5639f988b79SJean-Baptiste Boric 	memset(&ndirent, 0, sizeof(ndirent));
5649f988b79SJean-Baptiste Boric 	ndirent.de_pmp = pmp;
5659f988b79SJean-Baptiste Boric 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
5669f988b79SJean-Baptiste Boric 	msdosfs_times(pmp, &ndirent, st);
5679f988b79SJean-Baptiste Boric 
5689f988b79SJean-Baptiste Boric 	/*
5699f988b79SJean-Baptiste Boric 	 * Now fill the cluster with the "." and ".." entries. And write
5709f988b79SJean-Baptiste Boric 	 * the cluster to disk.	 This way it is there for the parent
5719f988b79SJean-Baptiste Boric 	 * directory to be pointing at if there were a crash.
5729f988b79SJean-Baptiste Boric 	 */
5739f988b79SJean-Baptiste Boric 	bn = cntobn(pmp, newcluster);
5749f988b79SJean-Baptiste Boric 	lbn = de_bn2kb(pmp, bn);
5759f988b79SJean-Baptiste Boric 	DPRINTF(("%s(newcluster %lu, bn=%lu, lbn=%lu)\n", __func__, newcluster,
5769f988b79SJean-Baptiste Boric 	    bn, lbn));
5779f988b79SJean-Baptiste Boric 	/* always succeeds */
5789f988b79SJean-Baptiste Boric 	bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0);
5799f988b79SJean-Baptiste Boric 	memset(bp->b_data, 0, pmp->pm_bpcluster);
5809f988b79SJean-Baptiste Boric 	memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
5819f988b79SJean-Baptiste Boric 	denp = (struct direntry *)bp->b_data;
5829f988b79SJean-Baptiste Boric 	putushort(denp[0].deStartCluster, newcluster);
5839f988b79SJean-Baptiste Boric 	putushort(denp[0].deCDate, ndirent.de_CDate);
5849f988b79SJean-Baptiste Boric 	putushort(denp[0].deCTime, ndirent.de_CTime);
5859f988b79SJean-Baptiste Boric 	denp[0].deCHundredth = ndirent.de_CHun;
5869f988b79SJean-Baptiste Boric 	putushort(denp[0].deADate, ndirent.de_ADate);
5879f988b79SJean-Baptiste Boric 	putushort(denp[0].deMDate, ndirent.de_MDate);
5889f988b79SJean-Baptiste Boric 	putushort(denp[0].deMTime, ndirent.de_MTime);
5899f988b79SJean-Baptiste Boric 	pcl = pdep->de_StartCluster;
5909f988b79SJean-Baptiste Boric 	DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl,
5919f988b79SJean-Baptiste Boric 	    pmp->pm_rootdirblk));
5929f988b79SJean-Baptiste Boric 	if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
5939f988b79SJean-Baptiste Boric 		pcl = 0;
5949f988b79SJean-Baptiste Boric 	putushort(denp[1].deStartCluster, pcl);
5959f988b79SJean-Baptiste Boric 	putushort(denp[1].deCDate, ndirent.de_CDate);
5969f988b79SJean-Baptiste Boric 	putushort(denp[1].deCTime, ndirent.de_CTime);
5979f988b79SJean-Baptiste Boric 	denp[1].deCHundredth = ndirent.de_CHun;
5989f988b79SJean-Baptiste Boric 	putushort(denp[1].deADate, ndirent.de_ADate);
5999f988b79SJean-Baptiste Boric 	putushort(denp[1].deMDate, ndirent.de_MDate);
6009f988b79SJean-Baptiste Boric 	putushort(denp[1].deMTime, ndirent.de_MTime);
6019f988b79SJean-Baptiste Boric 	if (FAT32(pmp)) {
6029f988b79SJean-Baptiste Boric 		putushort(denp[0].deHighClust, newcluster >> 16);
6039f988b79SJean-Baptiste Boric 		putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
6049f988b79SJean-Baptiste Boric 	} else {
6059f988b79SJean-Baptiste Boric 		putushort(denp[0].deHighClust, 0);
6069f988b79SJean-Baptiste Boric 		putushort(denp[1].deHighClust, 0);
6079f988b79SJean-Baptiste Boric 	}
6089f988b79SJean-Baptiste Boric 
6099f988b79SJean-Baptiste Boric 	if ((error = bwrite(bp)) != 0)
6109f988b79SJean-Baptiste Boric 		goto bad;
6119f988b79SJean-Baptiste Boric 
6129f988b79SJean-Baptiste Boric 	/*
6139f988b79SJean-Baptiste Boric 	 * Now build up a directory entry pointing to the newly allocated
6149f988b79SJean-Baptiste Boric 	 * cluster.  This will be written to an empty slot in the parent
6159f988b79SJean-Baptiste Boric 	 * directory.
6169f988b79SJean-Baptiste Boric 	 */
6179f988b79SJean-Baptiste Boric 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
6189f988b79SJean-Baptiste Boric 		goto bad;
6199f988b79SJean-Baptiste Boric 
6209f988b79SJean-Baptiste Boric 	ndirent.de_Attributes = ATTR_DIRECTORY;
6219f988b79SJean-Baptiste Boric 	ndirent.de_StartCluster = newcluster;
6229f988b79SJean-Baptiste Boric 	ndirent.de_FileSize = 0;
6239f988b79SJean-Baptiste Boric 	ndirent.de_dev = pdep->de_dev;
6249f988b79SJean-Baptiste Boric 	ndirent.de_devvp = pdep->de_devvp;
6259f988b79SJean-Baptiste Boric 	ndirent.de_pmp = pdep->de_pmp;
6269f988b79SJean-Baptiste Boric 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
6279f988b79SJean-Baptiste Boric 		goto bad;
6289f988b79SJean-Baptiste Boric 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
6299f988b79SJean-Baptiste Boric 		goto bad;
6309f988b79SJean-Baptiste Boric 	if ((error = msdosfs_updatede(dep)) != 0)
6319f988b79SJean-Baptiste Boric 		goto bad;
6329f988b79SJean-Baptiste Boric 	return dep;
6339f988b79SJean-Baptiste Boric 
6349f988b79SJean-Baptiste Boric bad:
6359f988b79SJean-Baptiste Boric 	clusterfree(pmp, newcluster, NULL);
6369f988b79SJean-Baptiste Boric bad2:
6379f988b79SJean-Baptiste Boric 	errno = error;
6389f988b79SJean-Baptiste Boric 	return NULL;
6399f988b79SJean-Baptiste Boric }
640