1 /*	$OpenBSD: msdosfs_vnops.c,v 1.8 2016/12/17 16:43:30 krw Exp $	*/
2 /*	$NetBSD: msdosfs_vnops.c,v 1.17 2016/01/30 09:59:27 mlelstv Exp $ */
3 
4 /*-
5  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7  * All rights reserved.
8  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by TooLs GmbH.
21  * 4. The name of TooLs GmbH may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /*
36  * Written by Paul Popelka (paulp@uts.amdahl.com)
37  *
38  * You can do anything you want with this software, just don't say you wrote
39  * it, and don't remove this notice.
40  *
41  * This software is provided "as is".
42  *
43  * The author supplies this software to be publicly redistributed on the
44  * understanding that the author is not responsible for the correct
45  * functioning of this software in any circumstances and is not liable for
46  * any damages caused by this software.
47  *
48  * October 1992
49  */
50 
51 #include <sys/param.h>
52 #include <sys/mman.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55 
56 #include "ffs/buf.h"
57 
58 #include <msdosfs/bpb.h>
59 #include "msdos/direntry.h"
60 #include "msdos/denode.h"
61 #include "msdos/msdosfsmount.h"
62 #include "msdos/fat.h"
63 
64 #include "makefs.h"
65 #include "msdos.h"
66 
67 #ifdef MSDOSFS_DEBUG
68 #define DPRINTF(a) printf a
69 #else
70 #define DPRINTF(a)
71 #endif
72 /*
73  * Some general notes:
74  *
75  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
76  * read/written using the mkfsvnode for the filesystem. Blocks that represent
77  * the contents of a file are read/written using the mkfsvnode for the file
78  * (including directories when they are read/written as files). This
79  * presents problems for the dos filesystem because data that should be in
80  * an inode (if dos had them) resides in the directory itself.	Since we
81  * must update directory entries without the benefit of having the mkfsvnode
82  * for the directory we must use the mkfsvnode for the filesystem.	This means
83  * that when a directory is actually read/written (via read, write, or
84  * readdir, or seek) we must use the mkfsvnode for the filesystem instead of
85  * the mkfsvnode for the directory as would happen in ufs. This is to insure we
86  * retrieve the correct block from the buffer cache since the hash value is
87  * based upon the mkfsvnode address and the desired block number.
88  */
89 
90 static int msdosfs_wfile(const char *, struct denode *, fsnode *);
91 
92 static void
93 msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
94     const struct stat *st)
95 {
96 	struct timespec at = st->st_atimespec;
97 	struct timespec mt = st->st_mtimespec;
98 	unix2dostime(&at, pmp->pm_minuteswest, &dep->de_ADate, NULL, NULL);
99 	unix2dostime(&mt, pmp->pm_minuteswest, &dep->de_MDate, &dep->de_MTime, NULL);
100 }
101 
102 /*
103  * When we search a directory the blocks containing directory entries are
104  * read and examined.  The directory entries contain information that would
105  * normally be in the inode of a unix filesystem.  This means that some of
106  * a directory's contents may also be in memory resident denodes (sort of
107  * an inode).  This can cause problems if we are searching while some other
108  * process is modifying a directory.  To prevent one process from accessing
109  * incompletely modified directory information we depend upon being the
110  * sole owner of a directory block.  bread/brelse provide this service.
111  * This being the case, when a process modifies a directory it must first
112  * acquire the disk block that contains the directory entry to be modified.
113  * Then update the disk block and the denode, and then write the disk block
114  * out to disk.	 This way disk blocks containing directory entries and in
115  * memory denode's will be in synch.
116  */
117 static int
118 msdosfs_findslot(struct denode *dp, struct componentname *cnp)
119 {
120 	daddr_t bn;
121 	int error;
122 	int slotcount;
123 	int slotoffset = 0;
124 	int frcn;
125 	u_long cluster;
126 	int blkoff;
127 	u_int diroff;
128 	int blsize;
129 	struct msdosfsmount *pmp;
130 	struct mkfsbuf *bp = 0;
131 	struct direntry *dep;
132 	u_char dosfilename[12];
133 	int wincnt = 1;
134 	int chksum = -1, chksum_ok;
135 	int olddos = 1;
136 
137 	pmp = dp->de_pmp;
138 
139 	switch (unix2dosfn(cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0)) {
140 	case 0:
141 		return (EINVAL);
142 	case 1:
143 		break;
144 	case 2:
145 		wincnt = winSlotCnt(cnp->cn_nameptr, cnp->cn_namelen) + 1;
146 		break;
147 	case 3:
148 		olddos = 0;
149 		wincnt = winSlotCnt(cnp->cn_nameptr, cnp->cn_namelen) + 1;
150 		break;
151 	}
152 
153 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
154 		wincnt = 1;
155 
156 	/*
157 	 * Suppress search for slots unless creating
158 	 * file and at end of pathname, in which case
159 	 * we watch for a place to put the new file in
160 	 * case it doesn't already exist.
161 	 */
162 	slotcount = 0;
163 	DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename));
164 	/*
165 	 * Search the directory pointed at by vdp for the name pointed at
166 	 * by cnp->cn_nameptr.
167 	 */
168 	/*
169 	 * The outer loop ranges over the clusters that make up the
170 	 * directory.  Note that the root directory is different from all
171 	 * other directories.  It has a fixed number of blocks that are not
172 	 * part of the pool of allocatable clusters.  So, we treat it a
173 	 * little differently. The root directory starts at "cluster" 0.
174 	 */
175 	diroff = 0;
176 	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
177 		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
178 			if (error == E2BIG)
179 				break;
180 			return (error);
181 		}
182 		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
183 		    0, &bp);
184 		if (error) {
185 			return (error);
186 		}
187 		for (blkoff = 0; blkoff < blsize;
188 		     blkoff += sizeof(struct direntry),
189 		     diroff += sizeof(struct direntry)) {
190 			dep = (struct direntry *)((char *)bp->b_data + blkoff);
191 			/*
192 			 * If the slot is empty and we are still looking
193 			 * for an empty then remember this one.	 If the
194 			 * slot is not empty then check to see if it
195 			 * matches what we are looking for.  If the slot
196 			 * has never been filled with anything, then the
197 			 * remainder of the directory has never been used,
198 			 * so there is no point in searching it.
199 			 */
200 			if (dep->deName[0] == SLOT_EMPTY ||
201 			    dep->deName[0] == SLOT_DELETED) {
202 				/*
203 				 * Drop memory of previous long matches
204 				 */
205 				chksum = -1;
206 
207 				if (slotcount < wincnt) {
208 					slotcount++;
209 					slotoffset = diroff;
210 				}
211 				if (dep->deName[0] == SLOT_EMPTY) {
212 					brelse(bp, 0);
213 					goto notfound;
214 				}
215 			} else {
216 				/*
217 				 * If there wasn't enough space for our
218 				 * winentries, forget about the empty space
219 				 */
220 				if (slotcount < wincnt)
221 					slotcount = 0;
222 
223 				/*
224 				 * Check for Win95 long filename entry
225 				 */
226 				if (dep->deAttributes == ATTR_WIN95) {
227 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
228 						continue;
229 
230 					chksum = winChkName(cnp->cn_nameptr,
231 							    cnp->cn_namelen,
232 							    (struct winentry *)dep,
233 							    chksum);
234 					continue;
235 				}
236 
237 				/*
238 				 * Ignore volume labels (anywhere, not just
239 				 * the root directory).
240 				 */
241 				if (dep->deAttributes & ATTR_VOLUME) {
242 					chksum = -1;
243 					continue;
244 				}
245 
246 				/*
247 				 * Check for a checksum or name match
248 				 */
249 				chksum_ok = (chksum == winChksum(dep->deName));
250 				if (!chksum_ok
251 				    && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
252 					chksum = -1;
253 					continue;
254 				}
255 				DPRINTF(("%s(): match blkoff %d, diroff %d\n",
256 				    __func__, blkoff, diroff));
257 				/*
258 				 * Remember where this directory
259 				 * entry came from for whoever did
260 				 * this lookup.
261 				 */
262 				dp->de_fndoffset = diroff;
263 				dp->de_fndcnt = 0;
264 
265 				return EEXIST;
266 			}
267 		}	/* for (blkoff = 0; .... */
268 		/*
269 		 * Release the buffer holding the directory cluster just
270 		 * searched.
271 		 */
272 		brelse(bp, 0);
273 	}	/* for (frcn = 0; ; frcn++) */
274 
275 notfound:
276 	/*
277 	 * We hold no disk buffers at this point.
278 	 */
279 
280 	/*
281 	 * If we get here we didn't find the entry we were looking for. But
282 	 * that's ok if we are creating or renaming and are at the end of
283 	 * the pathname and the directory hasn't been removed.
284 	 */
285 	DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n",
286 	    __func__, dp->de_refcnt, slotcount, slotoffset));
287 	/*
288 	 * Fixup the slot description to point to the place where
289 	 * we might put the new DOS direntry (putting the Win95
290 	 * long name entries before that)
291 	 */
292 	if (!slotcount) {
293 		slotcount = 1;
294 		slotoffset = diroff;
295 	}
296 	if (wincnt > slotcount) {
297 		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
298 	}
299 
300 	/*
301 	 * Return an indication of where the new directory
302 	 * entry should be put.
303 	 */
304 	dp->de_fndoffset = slotoffset;
305 	dp->de_fndcnt = wincnt - 1;
306 
307 	/*
308 	 * We return with the directory locked, so that
309 	 * the parameters we set up above will still be
310 	 * valid if we actually decide to do a direnter().
311 	 * We return ni_vp == NULL to indicate that the entry
312 	 * does not currently exist; we leave a pointer to
313 	 * the (locked) directory inode in ndp->ni_dvp.
314 	 *
315 	 * NB - if the directory is unlocked, then this
316 	 * information cannot be used.
317 	 */
318 	return 0;
319 }
320 
321 /*
322  * Create a regular file. On entry the directory to contain the file being
323  * created is locked.  We must release before we return.
324  */
325 struct denode *
326 msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
327 {
328 	struct componentname cn;
329 	struct denode ndirent;
330 	struct denode *dep;
331 	int error;
332 	struct stat *st = &node->inode->st;
333 	struct msdosfsmount *pmp = pdep->de_pmp;
334 
335 	cn.cn_nameptr = node->name;
336 	cn.cn_namelen = strlen(node->name);
337 
338 	DPRINTF(("%s(name %s, mode 0%o size %zu)\n", __func__, node->name,
339 	    st->st_mode, (size_t)st->st_size));
340 
341 	/*
342 	 * If this is the root directory and there is no space left we
343 	 * can't do anything.  This is because the root directory can not
344 	 * change size.
345 	 */
346 	if (pdep->de_StartCluster == MSDOSFSROOT
347 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
348 		error = ENOSPC;
349 		goto bad;
350 	}
351 
352 	/*
353 	 * Create a directory entry for the file, then call createde() to
354 	 * have it installed. NOTE: DOS files are always executable.  We
355 	 * use the absence of the owner write bit to make the file
356 	 * readonly.
357 	 */
358 	memset(&ndirent, 0, sizeof(ndirent));
359 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
360 		goto bad;
361 
362 	ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
363 				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
364 	ndirent.de_StartCluster = 0;
365 	ndirent.de_FileSize = 0;
366 	ndirent.de_dev = pdep->de_dev;
367 	ndirent.de_devvp = pdep->de_devvp;
368 	ndirent.de_pmp = pdep->de_pmp;
369 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
370 	msdosfs_times(pmp, &ndirent, st);
371 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
372 		goto bad;
373 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
374 		goto bad;
375 	if ((error = msdosfs_wfile(path, dep, node)) != 0)
376 		goto bad;
377 	return dep;
378 
379 bad:
380 	errno = error;
381 	return NULL;
382 }
383 static int
384 msdosfs_updatede(struct denode *dep)
385 {
386 	struct mkfsbuf *bp;
387 	struct direntry *dirp;
388 	int error;
389 
390 	dep->de_flag &= ~DE_MODIFIED;
391 	error = readde(dep, &bp, &dirp);
392 	if (error)
393 		return error;
394 	DE_EXTERNALIZE(dirp, dep);
395 	error = bwrite(bp);
396 	return error;
397 }
398 
399 /*
400  * Write data to a file or directory.
401  */
402 static int
403 msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
404 {
405 	int error, fd;
406 	size_t osize = dep->de_FileSize;
407 	struct stat *st = &node->inode->st;
408 	size_t nsize, offs;
409 	struct msdosfsmount *pmp = dep->de_pmp;
410 	struct mkfsbuf *bp;
411 	char *dat;
412 	u_long cn = 0;
413 
414 	error = 0;	/* XXX: gcc/vax */
415 	DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__,
416 	    dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster));
417 	if (st->st_size == 0)
418 		return 0;
419 
420 	/* Don't bother to try to write files larger than the fs limit */
421 	if (st->st_size > MSDOSFS_FILESIZE_MAX) {
422 		errno = EFBIG;
423 		return -1;
424 	}
425 
426 	nsize = st->st_size;
427 	DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize));
428 	if (nsize > osize) {
429 		if ((error = deextend(dep, nsize)) != 0) {
430 			errno = error;
431 			return -1;
432 		}
433 		if ((error = msdosfs_updatede(dep)) != 0) {
434 			errno = error;
435 			return -1;
436 		}
437 	}
438 
439 	if ((fd = open(path, O_RDONLY)) == -1)
440 		err(1, "open %s", path);
441 
442 	if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0))
443 	    == MAP_FAILED) {
444 		DPRINTF(("%s: mmap %s %s", __func__, node->name,
445 		    strerror(errno)));
446 		close(fd);
447 		goto out;
448 	}
449 	close(fd);
450 
451 	for (offs = 0; offs < nsize;) {
452 		int blsize, cpsize;
453 		daddr_t bn;
454 		u_long on = offs & pmp->pm_crbomask;
455 #ifdef HACK
456 		cn = dep->de_StartCluster;
457 		if (cn == MSDOSFSROOT) {
458 			DPRINTF(("%s: bad lbn %lu", __func__, cn));
459 			goto out;
460 		}
461 		bn = cntobn(pmp, cn);
462 		blsize = pmp->pm_bpcluster;
463 #else
464 		if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) {
465 			DPRINTF(("%s: pcbmap %lu", __func__, bn));
466 			goto out;
467 		}
468 #endif
469 		DPRINTF(("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__,
470 		    cn, (unsigned long long)bn,
471 		    (unsigned long long)de_bn2kb(pmp, bn), blsize));
472 		if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
473 		    0, &bp)) != 0) {
474 			DPRINTF(("bread %d\n", error));
475 			goto out;
476 		}
477 		cpsize = MIN((nsize - offs), blsize - on);
478 		memcpy((char *)bp->b_data + on, dat + offs, cpsize);
479 		bwrite(bp);
480 		offs += cpsize;
481 	}
482 
483 	munmap(dat, nsize);
484 	return 0;
485 out:
486 	munmap(dat, nsize);
487 	return error;
488 }
489 
490 
491 static const struct {
492 	struct direntry dot;
493 	struct direntry dotdot;
494 } dosdirtemplate = {
495 	{	".       ", "   ",			/* the . entry */
496 		ATTR_DIRECTORY,				/* file attribute */
497 		0,					/* reserved */
498 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
499 		{ 0, 0 },				/* access date */
500 		{ 0, 0 },				/* high bits of start cluster */
501 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
502 		{ 0, 0 },				/* startcluster */
503 		{ 0, 0, 0, 0 }				/* filesize */
504 	},
505 	{	"..      ", "   ",			/* the .. entry */
506 		ATTR_DIRECTORY,				/* file attribute */
507 		0,					/* reserved */
508 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
509 		{ 0, 0 },				/* access date */
510 		{ 0, 0 },				/* high bits of start cluster */
511 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
512 		{ 0, 0 },				/* startcluster */
513 		{ 0, 0, 0, 0 }				/* filesize */
514 	}
515 };
516 
517 struct denode *
518 msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
519 	struct denode ndirent;
520 	struct denode *dep;
521 	struct componentname cn;
522 	struct stat *st = &node->inode->st;
523 	struct msdosfsmount *pmp = pdep->de_pmp;
524 	int error;
525 	u_long newcluster, pcl, bn;
526 	daddr_t lbn;
527 	struct direntry *denp;
528 	struct mkfsbuf *bp;
529 
530 	cn.cn_nameptr = node->name;
531 	cn.cn_namelen = strlen(node->name);
532 	/*
533 	 * If this is the root directory and there is no space left we
534 	 * can't do anything.  This is because the root directory can not
535 	 * change size.
536 	 */
537 	if (pdep->de_StartCluster == MSDOSFSROOT
538 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
539 		error = ENOSPC;
540 		goto bad2;
541 	}
542 
543 	/*
544 	 * Allocate a cluster to hold the about to be created directory.
545 	 */
546 	error = clusteralloc(pmp, 0, 1, &newcluster, NULL);
547 	if (error)
548 		goto bad2;
549 
550 	memset(&ndirent, 0, sizeof(ndirent));
551 	ndirent.de_pmp = pmp;
552 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
553 	msdosfs_times(pmp, &ndirent, st);
554 
555 	/*
556 	 * Now fill the cluster with the "." and ".." entries. And write
557 	 * the cluster to disk.	 This way it is there for the parent
558 	 * directory to be pointing at if there were a crash.
559 	 */
560 	bn = cntobn(pmp, newcluster);
561 	lbn = de_bn2kb(pmp, bn);
562 	DPRINTF(("%s(newcluster %lu, bn=%lu, lbn=%lu)\n", __func__, newcluster,
563 	    bn, lbn));
564 	/* always succeeds */
565 	bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0);
566 	memset(bp->b_data, 0, pmp->pm_bpcluster);
567 	memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
568 	denp = (struct direntry *)bp->b_data;
569 	putushort(denp[0].deStartCluster, newcluster);
570 	putushort(denp[0].deCDate, ndirent.de_CDate);
571 	putushort(denp[0].deCTime, ndirent.de_CTime);
572 	denp[0].deCTimeHundredth = ndirent.de_CHun;
573 	putushort(denp[0].deADate, ndirent.de_ADate);
574 	putushort(denp[0].deMDate, ndirent.de_MDate);
575 	putushort(denp[0].deMTime, ndirent.de_MTime);
576 	pcl = pdep->de_StartCluster;
577 	DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl,
578 	    pmp->pm_rootdirblk));
579 	if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
580 		pcl = 0;
581 	putushort(denp[1].deStartCluster, pcl);
582 	putushort(denp[1].deCDate, ndirent.de_CDate);
583 	putushort(denp[1].deCTime, ndirent.de_CTime);
584 	denp[1].deCTimeHundredth = ndirent.de_CHun;
585 	putushort(denp[1].deADate, ndirent.de_ADate);
586 	putushort(denp[1].deMDate, ndirent.de_MDate);
587 	putushort(denp[1].deMTime, ndirent.de_MTime);
588 	if (FAT32(pmp)) {
589 		putushort(denp[0].deHighClust, newcluster >> 16);
590 		putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
591 	} else {
592 		putushort(denp[0].deHighClust, 0);
593 		putushort(denp[1].deHighClust, 0);
594 	}
595 
596 	if ((error = bwrite(bp)) != 0)
597 		goto bad;
598 
599 	/*
600 	 * Now build up a directory entry pointing to the newly allocated
601 	 * cluster.  This will be written to an empty slot in the parent
602 	 * directory.
603 	 */
604 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
605 		goto bad;
606 
607 	ndirent.de_Attributes = ATTR_DIRECTORY;
608 	ndirent.de_StartCluster = newcluster;
609 	ndirent.de_FileSize = 0;
610 	ndirent.de_dev = pdep->de_dev;
611 	ndirent.de_devvp = pdep->de_devvp;
612 	ndirent.de_pmp = pdep->de_pmp;
613 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
614 		goto bad;
615 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
616 		goto bad;
617 	if ((error = msdosfs_updatede(dep)) != 0)
618 		goto bad;
619 	return dep;
620 
621 bad:
622 	clusterfree(pmp, newcluster, NULL);
623 bad2:
624 	errno = error;
625 	return NULL;
626 }
627