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