GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/makefs/msdos/msdosfs_vnops.c Lines: 0 193 0.0 %
Date: 2017-11-13 Branches: 0 107 0.0 %

Line Branch Exec Source
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
}