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