kernel: Use NULL for pointers.
[dragonfly.git] / sys / vfs / msdosfs / msdosfs_lookup.c
1 /* $FreeBSD: src/sys/msdosfs/msdosfs_lookup.c,v 1.30.2.1 2000/11/03 15:55:39 bp Exp $ */
2 /*      $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws 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/systm.h>
53 #include <sys/buf.h>
54 #include <sys/vnode.h>
55 #include <sys/proc.h>
56 #include <sys/namei.h>
57 #include <sys/mount.h>
58
59 #include <sys/buf2.h>
60
61 #include "bpb.h"
62 #include "direntry.h"
63 #include "denode.h"
64 #include "msdosfsmount.h"
65 #include "fat.h"
66
67 /*
68  * When we search a directory the blocks containing directory entries are
69  * read and examined.  The directory entries contain information that would
70  * normally be in the inode of a unix filesystem.  This means that some of
71  * a directory's contents may also be in memory resident denodes (sort of
72  * an inode).  This can cause problems if we are searching while some other
73  * process is modifying a directory.  To prevent one process from accessing
74  * incompletely modified directory information we depend upon being the
75  * sole owner of a directory block.  bread/brelse provide this service.
76  * This being the case, when a process modifies a directory it must first
77  * acquire the disk block that contains the directory entry to be modified.
78  * Then update the disk block and the denode, and then write the disk block
79  * out to disk.  This way disk blocks containing directory entries and in
80  * memory denode's will be in synch.
81  *
82  * msdosfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
83  *                struct componentname *a_cnp)
84  */
85 int
86 msdosfs_lookup(struct vop_old_lookup_args *ap)
87 {
88         struct mbnambuf nb;
89         struct vnode *vdp = ap->a_dvp;
90         struct vnode **vpp = ap->a_vpp;
91         struct componentname *cnp = ap->a_cnp;
92         daddr_t bn;
93         int error;
94         int lockparent;
95         int wantparent;
96         int slotcount;
97         int slotoffset = 0;
98         int frcn;
99         u_long cluster;
100         int blkoff;
101         int diroff;
102         int blsize;
103         int isadir;             /* ~0 if found direntry is a directory   */
104         u_long scn;             /* starting cluster number               */
105         struct vnode *pdp;
106         struct denode *dp;
107         struct denode *tdp;
108         struct msdosfsmount *pmp;
109         struct buf *bp = NULL;
110         struct direntry *dep = NULL;
111         u_char dosfilename[12];
112         int flags = cnp->cn_flags;
113         int nameiop = cnp->cn_nameiop;
114         int unlen;
115
116         int wincnt = 1;
117         int chksum = -1;
118         int olddos = 1;
119         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
120
121 #ifdef MSDOSFS_DEBUG
122         kprintf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
123 #endif
124         dp = VTODE(vdp);
125         pmp = dp->de_pmp;
126         *vpp = NULL;
127         lockparent = flags & CNP_LOCKPARENT;
128         wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
129 #ifdef MSDOSFS_DEBUG
130         kprintf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
131             vdp, dp, dp->de_Attributes);
132 #endif
133
134         /*
135          * If they are going after the . or .. entry in the root directory,
136          * they won't find it.  DOS filesystems don't have them in the root
137          * directory.  So, we fake it. deget() is in on this scam too.
138          */
139         if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' &&
140             (cnp->cn_namelen == 1 ||
141                 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
142                 isadir = ATTR_DIRECTORY;
143                 scn = MSDOSFSROOT;
144 #ifdef MSDOSFS_DEBUG
145                 kprintf("msdosfs_lookup(): looking for . or .. in root directory\n");
146 #endif
147                 cluster = MSDOSFSROOT;
148                 blkoff = MSDOSFSROOT_OFS;
149                 goto foundroot;
150         }
151         switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
152             cnp->cn_namelen, 0, pmp)) {
153         case 0:
154                 return (EINVAL);
155         case 1:
156                 break;
157         case 2:
158                 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
159                     cnp->cn_namelen, pmp) + 1;
160                 break;
161         case 3:
162                 olddos = 0;
163                 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
164                     cnp->cn_namelen, pmp) + 1;
165                 break;
166         }
167         if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
168                 wincnt = 1;
169                 olddos = 1;
170         }
171         unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen);
172
173         /*
174          * Suppress search for slots unless creating
175          * file and at end of pathname, in which case
176          * we watch for a place to put the new file in
177          * case it doesn't already exist.
178          */
179         slotcount = wincnt;
180         if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)
181                 slotcount = 0;
182
183 #ifdef MSDOSFS_DEBUG
184         kprintf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
185             dosfilename, cnp->cn_namelen);
186 #endif
187         /*
188          * Search the directory pointed at by vdp for the name pointed at
189          * by cnp->cn_nameptr.
190          */
191         tdp = NULL;
192         mbnambuf_init(&nb);
193         /*
194          * The outer loop ranges over the clusters that make up the
195          * directory.  Note that the root directory is different from all
196          * other directories.  It has a fixed number of blocks that are not
197          * part of the pool of allocatable clusters.  So, we treat it a
198          * little differently. The root directory starts at "cluster" 0.
199          */
200         diroff = 0;
201         for (frcn = 0;; frcn++) {
202                 error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
203                 if (error) {
204                         if (error == E2BIG)
205                                 break;
206                         return (error);
207                 }
208                 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
209                 if (error) {
210                         brelse(bp);
211                         return (error);
212                 }
213                 for (blkoff = 0; blkoff < blsize;
214                      blkoff += sizeof(struct direntry),
215                      diroff += sizeof(struct direntry)) {
216                         dep = (struct direntry *)(bp->b_data + blkoff);
217                         /*
218                          * If the slot is empty and we are still looking
219                          * for an empty then remember this one.  If the
220                          * slot is not empty then check to see if it
221                          * matches what we are looking for.  If the slot
222                          * has never been filled with anything, then the
223                          * remainder of the directory has never been used,
224                          * so there is no point in searching it.
225                          */
226                         if (dep->deName[0] == SLOT_EMPTY ||
227                             dep->deName[0] == SLOT_DELETED) {
228                                 /*
229                                  * Drop memory of previous long matches
230                                  */
231                                 chksum = -1;
232                                 mbnambuf_init(&nb);
233
234                                 if (slotcount < wincnt) {
235                                         slotcount++;
236                                         slotoffset = diroff;
237                                 }
238                                 if (dep->deName[0] == SLOT_EMPTY) {
239                                         brelse(bp);
240                                         goto notfound;
241                                 }
242                         } else {
243                                 /*
244                                  * If there wasn't enough space for our winentries,
245                                  * forget about the empty space
246                                  */
247                                 if (slotcount < wincnt)
248                                         slotcount = 0;
249
250                                 /*
251                                  * Check for Win95 long filename entry
252                                  */
253                                 if (dep->deAttributes == ATTR_WIN95) {
254                                 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
255                                                 continue;
256                                         chksum = win2unixfn(&nb,
257                                             (struct winentry *)dep, chksum,
258                                             pmp);
259                                         continue;
260                                 }
261
262                                 chksum = winChkName(&nb,
263                                     (const u_char *)cnp->cn_nameptr, unlen,
264                                     chksum, pmp);
265                                 if (chksum == -2) {
266                                         chksum = -1;
267                                         continue;
268                                 }
269
270                                 /*
271                                  * Ignore volume labels (anywhere, not just
272                                  * the root directory).
273                                  */
274                                 if (dep->deAttributes & ATTR_VOLUME) {
275                                         chksum = -1;
276                                         continue;
277                                 }
278
279                                 /*
280                                  * Check for a checksum or name match
281                                  */
282                                 if (chksum != winChksum(dep->deName)
283                                     && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
284                                         chksum = -1;
285                                         continue;
286                                 }
287 #ifdef MSDOSFS_DEBUG
288                                 kprintf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
289                                     blkoff, diroff);
290 #endif
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 = wincnt - 1;
298
299                                 goto found;
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          * Fixup the slot description to point to the place where
316          * we might put the new DOS direntry (putting the Win95
317          * long name entries before that)
318          */
319         if (!slotcount) {
320                 slotcount = 1;
321                 slotoffset = diroff;
322         }
323         if (wincnt > slotcount)
324                 slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
325
326         /*
327          * If we get here we didn't find the entry we were looking for. But
328          * that's ok if we are creating or renaming and are at the end of
329          * the pathname and the directory hasn't been removed.
330          */
331 #ifdef MSDOSFS_DEBUG
332         kprintf("msdosfs_lookup(): op %d, refcnt %ld\n",
333             nameiop, dp->de_refcnt);
334         kprintf("               slotcount %d, slotoffset %d\n",
335                slotcount, slotoffset);
336 #endif
337         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
338             dp->de_refcnt > 0) {
339                 /*
340                  * Access for write is interpreted as allowing
341                  * creation of files in the directory.
342                  */
343                 error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
344                 if (error)
345                         return (error);
346                 /*
347                  * Return an indication of where the new directory
348                  * entry should be put.
349                  */
350                 dp->de_fndoffset = slotoffset;
351                 dp->de_fndcnt = wincnt - 1;
352
353                 /*
354                  * We return with the directory locked, so that
355                  * the parameters we set up above will still be
356                  * valid if we actually decide to do a direnter().
357                  * We return ni_vp == NULL to indicate that the entry
358                  * does not currently exist; we leave a pointer to
359                  * the (locked) directory inode in ndp->ni_dvp.
360                  * The pathname buffer is saved so that the name
361                  * can be obtained later.
362                  *
363                  * NB - if the directory is unlocked, then this
364                  * information cannot be used.
365                  */
366                 if (!lockparent) {
367                         vn_unlock(vdp);
368                         cnp->cn_flags |= CNP_PDIRUNLOCK;
369                 }
370                 return (EJUSTRETURN);
371         }
372         return (ENOENT);
373
374 found:
375         /*
376          * NOTE:  We still have the buffer with matched directory entry at
377          * this point.
378          */
379         isadir = dep->deAttributes & ATTR_DIRECTORY;
380         scn = getushort(dep->deStartCluster);
381         if (FAT32(pmp)) {
382                 scn |= getushort(dep->deHighClust) << 16;
383                 if (scn == pmp->pm_rootdirblk) {
384                         /*
385                          * There should actually be 0 here.
386                          * Just ignore the error.
387                          */
388                         scn = MSDOSFSROOT;
389                 }
390         }
391
392         if (isadir) {
393                 cluster = scn;
394                 if (cluster == MSDOSFSROOT)
395                         blkoff = MSDOSFSROOT_OFS;
396                 else
397                         blkoff = 0;
398         } else if (cluster == MSDOSFSROOT)
399                 blkoff = diroff;
400
401         /*
402          * Now release buf to allow deget to read the entry again.
403          * Reserving it here and giving it to deget could result
404          * in a deadlock.
405          */
406         brelse(bp);
407         bp = NULL;
408         
409 foundroot:
410         /*
411          * If we entered at foundroot, then we are looking for the . or ..
412          * entry of the filesystems root directory.  isadir and scn were
413          * setup before jumping here.  And, bp is already null.
414          */
415         if (FAT32(pmp) && scn == MSDOSFSROOT)
416                 scn = pmp->pm_rootdirblk;
417
418         /*
419          * If deleting, and at end of pathname, return
420          * parameters which can be used to remove file.
421          * If the wantparent flag isn't set, we return only
422          * the directory (in ndp->ni_dvp), otherwise we go
423          * on and lock the inode, being careful with ".".
424          */
425         if (nameiop == NAMEI_DELETE) {
426                 /*
427                  * Don't allow deleting the root.
428                  */
429                 if (blkoff == MSDOSFSROOT_OFS)
430                         return EROFS;                           /* really? XXX */
431
432                 /*
433                  * Write access to directory required to delete files.
434                  */
435                 error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
436                 if (error)
437                         return (error);
438
439                 /*
440                  * Return pointer to current entry in dp->i_offset.
441                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
442                  */
443                 if (dp->de_StartCluster == scn && isadir) {     /* "." */
444                         vref(vdp);
445                         *vpp = vdp;
446                         return (0);
447                 }
448                 error = deget(pmp, cluster, blkoff, &tdp);
449                 if (error)
450                         return (error);
451                 *vpp = DETOV(tdp);
452                 if (!lockparent) {
453                         vn_unlock(vdp);
454                         cnp->cn_flags |= CNP_PDIRUNLOCK;
455                 }
456                 return (0);
457         }
458
459         /*
460          * If rewriting (RENAME), return the inode and the
461          * information required to rewrite the present directory
462          * Must get inode of directory entry to verify it's a
463          * regular file, or empty directory.
464          */
465         if (nameiop == NAMEI_RENAME && wantparent) {
466                 if (blkoff == MSDOSFSROOT_OFS)
467                         return EROFS;                   /* really? XXX */
468
469                 error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
470                 if (error)
471                         return (error);
472
473                 /*
474                  * Careful about locking second inode.
475                  * This can only occur if the target is ".".
476                  */
477                 if (dp->de_StartCluster == scn && isadir)
478                         return (EISDIR);
479
480                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
481                         return (error);
482                 *vpp = DETOV(tdp);
483                 if (!lockparent) {
484                         vn_unlock(vdp);
485                         cnp->cn_flags |= CNP_PDIRUNLOCK;
486                 }
487                 return (0);
488         }
489
490         /*
491          * Step through the translation in the name.  We do not `vput' the
492          * directory because we may need it again if a symbolic link
493          * is relative to the current directory.  Instead we save it
494          * unlocked as "pdp".  We must get the target inode before unlocking
495          * the directory to insure that the inode will not be removed
496          * before we get it.  We prevent deadlock by always fetching
497          * inodes from the root, moving down the directory tree. Thus
498          * when following backward pointers ".." we must unlock the
499          * parent directory before getting the requested directory.
500          * There is a potential race condition here if both the current
501          * and parent directories are removed before the VFS_VGET for the
502          * inode associated with ".." returns.  We hope that this occurs
503          * infrequently since we cannot avoid this race condition without
504          * implementing a sophisticated deadlock detection algorithm.
505          * Note also that this simple deadlock detection scheme will not
506          * work if the file system has any hard links other than ".."
507          * that point backwards in the directory structure.
508          */
509         pdp = vdp;
510         if (flags & CNP_ISDOTDOT) {
511                 vn_unlock(pdp);
512                 cnp->cn_flags |= CNP_PDIRUNLOCK;
513                 error = deget(pmp, cluster, blkoff,  &tdp);
514                 if (error) {
515                         vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 
516                         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
517                         return (error);
518                 }
519                 if (lockparent) {
520                         error = vn_lock(pdp, LK_EXCLUSIVE);
521                         if (error) {
522                                 vput(DETOV(tdp));
523                                 return (error);
524                         }
525                         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
526                 }
527                 *vpp = DETOV(tdp);
528         } else if (dp->de_StartCluster == scn && isadir) {
529                 vref(vdp);      /* we want ourself, ie "." */
530                 *vpp = vdp;
531         } else {
532                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
533                         return (error);
534                 if (!lockparent) {
535                         vn_unlock(pdp);
536                         cnp->cn_flags |= CNP_PDIRUNLOCK;
537                 }
538                 *vpp = DETOV(tdp);
539         }
540         return (0);
541 }
542
543 /*
544  * dep  - directory entry to copy into the directory
545  * ddep - directory to add to
546  * depp - return the address of the denode for the created directory entry
547  *        if depp != 0
548  * cnp  - componentname needed for Win95 long filenames
549  */
550 int
551 createde(struct denode *dep, struct denode *ddep, struct denode **depp,
552          struct componentname *cnp)
553 {
554         int error;
555         u_long dirclust, diroffset;
556         struct direntry *ndep;
557         struct msdosfsmount *pmp = ddep->de_pmp;
558         struct buf *bp;
559         daddr_t bn;
560         int blsize;
561
562 #ifdef MSDOSFS_DEBUG
563         kprintf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
564             dep, ddep, depp, cnp);
565 #endif
566
567         /*
568          * If no space left in the directory then allocate another cluster
569          * and chain it onto the end of the file.  There is one exception
570          * to this.  That is, if the root directory has no more space it
571          * can NOT be expanded.  extendfile() checks for and fails attempts
572          * to extend the root directory.  We just return an error in that
573          * case.
574          */
575         if (ddep->de_fndoffset >= ddep->de_FileSize) {
576                 diroffset = ddep->de_fndoffset + sizeof(struct direntry)
577                     - ddep->de_FileSize;
578                 dirclust = de_clcount(pmp, diroffset);
579                 error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
580                 if (error) {
581                         detrunc(ddep, ddep->de_FileSize, 0);
582                         return error;
583                 }
584
585                 /*
586                  * Update the size of the directory
587                  */
588                 ddep->de_FileSize += de_cn2off(pmp, dirclust);
589         }
590
591         /*
592          * We just read in the cluster with space.  Copy the new directory
593          * entry in.  Then write it to disk. NOTE:  DOS directories
594          * do not get smaller as clusters are emptied.
595          */
596         error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
597                        &bn, &dirclust, &blsize);
598         if (error)
599                 return error;
600         diroffset = ddep->de_fndoffset;
601         if (dirclust != MSDOSFSROOT)
602                 diroffset &= pmp->pm_crbomask;
603         if ((error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp)) != 0) {
604                 brelse(bp);
605                 return error;
606         }
607         ndep = bptoep(pmp, bp, ddep->de_fndoffset);
608
609         DE_EXTERNALIZE(ndep, dep);
610
611         /*
612          * Now write the Win95 long name
613          */
614         if (ddep->de_fndcnt > 0) {
615                 u_int8_t chksum = winChksum(ndep->deName);
616                 const u_char *un = (const u_char *)cnp->cn_nameptr;
617                 int unlen = cnp->cn_namelen;
618                 int cnt = 1;
619
620                 while (--ddep->de_fndcnt >= 0) {
621                         if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
622                                 if ((error = bwrite(bp)) != 0)
623                                         return error;
624
625                                 ddep->de_fndoffset -= sizeof(struct direntry);
626                                 error = pcbmap(ddep,
627                                                de_cluster(pmp,
628                                                           ddep->de_fndoffset),
629                                                &bn, NULL, &blsize);
630                                 if (error)
631                                         return error;
632
633                                 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
634                                 if (error) {
635                                         brelse(bp);
636                                         return error;
637                                 }
638                                 ndep = bptoep(pmp, bp, ddep->de_fndoffset);
639                         } else {
640                                 ndep--;
641                                 ddep->de_fndoffset -= sizeof(struct direntry);
642                         }
643                         if (!unix2winfn(un, unlen, (struct winentry *)ndep,
644                                         cnt++, chksum,
645                                         pmp))
646                                 break;
647                 }
648         }
649
650         if ((error = bwrite(bp)) != 0)
651                 return error;
652
653         /*
654          * If they want us to return with the denode gotten.
655          */
656         if (depp) {
657                 if (dep->de_Attributes & ATTR_DIRECTORY) {
658                         dirclust = dep->de_StartCluster;
659                         if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
660                                 dirclust = MSDOSFSROOT;
661                         if (dirclust == MSDOSFSROOT)
662                                 diroffset = MSDOSFSROOT_OFS;
663                         else
664                                 diroffset = 0;
665                 }
666                 return deget(pmp, dirclust, diroffset, depp);
667         }
668
669         return 0;
670 }
671
672 /*
673  * Be sure a directory is empty except for "." and "..". Return 1 if empty,
674  * return 0 if not empty or error.
675  */
676 int
677 dosdirempty(struct denode *dep)
678 {
679         int blsize;
680         int error;
681         u_long cn;
682         daddr_t bn;
683         struct buf *bp;
684         struct msdosfsmount *pmp = dep->de_pmp;
685         struct direntry *dentp;
686
687         /*
688          * Since the filesize field in directory entries for a directory is
689          * zero, we just have to feel our way through the directory until
690          * we hit end of file.
691          */
692         for (cn = 0;; cn++) {
693                 if ((error = pcbmap(dep, cn, &bn, NULL, &blsize)) != 0) {
694                         if (error == E2BIG)
695                                 return (1);     /* it's empty */
696                         return (0);
697                 }
698                 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
699                 if (error) {
700                         brelse(bp);
701                         return (0);
702                 }
703                 for (dentp = (struct direntry *)bp->b_data;
704                      (char *)dentp < bp->b_data + blsize;
705                      dentp++) {
706                         if (dentp->deName[0] != SLOT_DELETED &&
707                             (dentp->deAttributes & ATTR_VOLUME) == 0) {
708                                 /*
709                                  * In dos directories an entry whose name
710                                  * starts with SLOT_EMPTY (0) starts the
711                                  * beginning of the unused part of the
712                                  * directory, so we can just return that it
713                                  * is empty.
714                                  */
715                                 if (dentp->deName[0] == SLOT_EMPTY) {
716                                         brelse(bp);
717                                         return (1);
718                                 }
719                                 /*
720                                  * Any names other than "." and ".." in a
721                                  * directory mean it is not empty.
722                                  */
723                                 if (bcmp(dentp->deName, ".          ", 11) &&
724                                     bcmp(dentp->deName, "..         ", 11)) {
725                                         brelse(bp);
726 #ifdef MSDOSFS_DEBUG
727                                         kprintf("dosdirempty(): entry found %02x, %02x\n",
728                                             dentp->deName[0], dentp->deName[1]);
729 #endif
730                                         return (0);     /* not empty */
731                                 }
732                         }
733                 }
734                 brelse(bp);
735         }
736         /* NOTREACHED */
737 }
738
739 /*
740  * Check to see if the directory described by target is in some
741  * subdirectory of source.  This prevents something like the following from
742  * succeeding and leaving a bunch or files and directories orphaned. mv
743  * /a/b/c /a/b/c/d/e/f Where c and f are directories.
744  *
745  * source - the inode for /a/b/c
746  * target - the inode for /a/b/c/d/e/f
747  *
748  * Returns 0 if target is NOT a subdirectory of source.
749  * Otherwise returns a non-zero error number.
750  * The target inode is always unlocked on return.
751  */
752 int
753 doscheckpath(struct denode *source, struct denode *target)
754 {
755         daddr_t scn;
756         struct msdosfsmount *pmp;
757         struct direntry *ep;
758         struct denode *dep;
759         struct buf *bp = NULL;
760         int error = 0;
761
762         dep = target;
763         if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
764             (source->de_Attributes & ATTR_DIRECTORY) == 0) {
765                 error = ENOTDIR;
766                 goto out;
767         }
768         if (dep->de_StartCluster == source->de_StartCluster) {
769                 error = EEXIST;
770                 goto out;
771         }
772         if (dep->de_StartCluster == MSDOSFSROOT)
773                 goto out;
774         pmp = dep->de_pmp;
775 #ifdef  DIAGNOSTIC
776         if (pmp != source->de_pmp)
777                 panic("doscheckpath: source and target on different filesystems");
778 #endif
779         if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
780                 goto out;
781
782         for (;;) {
783                 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
784                         error = ENOTDIR;
785                         break;
786                 }
787                 scn = dep->de_StartCluster;
788                 error = bread(pmp->pm_devvp, xcntodoff(pmp, scn),
789                               pmp->pm_bpcluster, &bp);
790                 if (error)
791                         break;
792
793                 ep = (struct direntry *) bp->b_data + 1;
794                 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
795                     bcmp(ep->deName, "..         ", 11) != 0) {
796                         error = ENOTDIR;
797                         break;
798                 }
799                 scn = getushort(ep->deStartCluster);
800                 if (FAT32(pmp))
801                         scn |= getushort(ep->deHighClust) << 16;
802
803                 if (scn == source->de_StartCluster) {
804                         error = EINVAL;
805                         break;
806                 }
807                 if (scn == MSDOSFSROOT)
808                         break;
809                 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
810                         /*
811                          * scn should be 0 in this case,
812                          * but we silently ignore the error.
813                          */
814                         break;
815                 }
816
817                 vput(DETOV(dep));
818                 brelse(bp);
819                 bp = NULL;
820                 /* NOTE: deget() clears dep on error */
821                 if ((error = deget(pmp, scn, 0, &dep)) != 0)
822                         break;
823         }
824 out:;
825         if (bp)
826                 brelse(bp);
827         if (error == ENOTDIR)
828                 kprintf("doscheckpath(): .. not a directory?\n");
829         if (dep != NULL)
830                 vput(DETOV(dep));
831         return (error);
832 }
833
834 /*
835  * Read in the disk block containing the directory entry (dirclu, dirofs)
836  * and return the address of the buf header, and the address of the
837  * directory entry within the block.
838  */
839 int
840 readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
841        struct buf **bpp, struct direntry **epp)
842 {
843         int error;
844         daddr_t bn;
845         int blsize;
846
847         blsize = pmp->pm_bpcluster;
848         if (dirclust == MSDOSFSROOT
849             && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
850                 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
851         bn = detobn(pmp, dirclust, diroffset);
852         if ((error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, bpp)) != 0) {
853                 brelse(*bpp);
854                 *bpp = NULL;
855                 return (error);
856         }
857         if (epp)
858                 *epp = bptoep(pmp, *bpp, diroffset);
859         return (0);
860 }
861
862 /*
863  * Read in the disk block containing the directory entry dep came from and
864  * return the address of the buf header, and the address of the directory
865  * entry within the block.
866  */
867 int
868 readde(struct denode *dep, struct buf **bpp, struct direntry **epp)
869 {
870         return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
871             bpp, epp));
872 }
873
874 /*
875  * Remove a directory entry. At this point the file represented by the
876  * directory entry to be removed is still full length until noone has it
877  * open.  When the file no longer being used msdosfs_inactive() is called
878  * and will truncate the file to 0 length.  When the vnode containing the
879  * denode is needed for some other purpose by VFS it will call
880  * msdosfs_reclaim() which will remove the denode from the denode cache.
881  */
882 int
883 removede(struct denode *pdep,   /* directory where the entry is removed */
884          struct denode *dep)    /* file to be removed */
885 {
886         int error;
887         struct direntry *ep;
888         struct buf *bp;
889         daddr_t bn;
890         int blsize;
891         struct msdosfsmount *pmp = pdep->de_pmp;
892         u_long offset = pdep->de_fndoffset;
893
894 #ifdef MSDOSFS_DEBUG
895         kprintf("removede(): filename %s, dep %p, offset %08lx\n",
896             dep->de_Name, dep, offset);
897 #endif
898
899         KKASSERT(dep->de_refcnt > 0);
900         dep->de_refcnt--;
901         offset += sizeof(struct direntry);
902         do {
903                 offset -= sizeof(struct direntry);
904                 error = pcbmap(pdep, de_cluster(pmp, offset),
905                                &bn, NULL, &blsize);
906                 if (error)
907                         return error;
908                 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
909                 if (error) {
910                         brelse(bp);
911                         return error;
912                 }
913                 ep = bptoep(pmp, bp, offset);
914                 /*
915                  * Check whether, if we came here the second time, i.e.
916                  * when underflowing into the previous block, the last
917                  * entry in this block is a longfilename entry, too.
918                  */
919                 if (ep->deAttributes != ATTR_WIN95
920                     && offset != pdep->de_fndoffset) {
921                         brelse(bp);
922                         break;
923                 }
924                 offset += sizeof(struct direntry);
925                 while (1) {
926                         /*
927                          * We are a bit agressive here in that we delete any Win95
928                          * entries preceding this entry, not just the ones we "own".
929                          * Since these presumably aren't valid anyway,
930                          * there should be no harm.
931                          */
932                         offset -= sizeof(struct direntry);
933                         ep--->deName[0] = SLOT_DELETED;
934                         if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
935                             || !(offset & pmp->pm_crbomask)
936                             || ep->deAttributes != ATTR_WIN95)
937                                 break;
938                 }
939                 if ((error = bwrite(bp)) != 0)
940                         return error;
941         } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
942             && !(offset & pmp->pm_crbomask)
943             && offset);
944         return 0;
945 }
946
947 /*
948  * Create a unique DOS name in dvp
949  */
950 int
951 uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
952 {
953         struct msdosfsmount *pmp = dep->de_pmp;
954         struct direntry *dentp;
955         int gen;
956         int blsize;
957         u_long cn;
958         daddr_t bn;
959         struct buf *bp;
960         int error;
961         
962         if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
963                 return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
964                     cnp->cn_namelen, 0, pmp) ?
965                     0 : EINVAL);
966
967         for (gen = 1;; gen++) {
968                 /*
969                  * Generate DOS name with generation number
970                  */
971                 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
972                     cnp->cn_namelen, gen, pmp))
973                         return gen == 1 ? EINVAL : EEXIST;
974
975                 /*
976                  * Now look for a dir entry with this exact name
977                  */
978                 for (cn = error = 0; !error; cn++) {
979                         if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
980                                 if (error == E2BIG)     /* EOF reached and not found */
981                                         return 0;
982                                 return error;
983                         }
984                         error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
985                         if (error) {
986                                 brelse(bp);
987                                 return error;
988                         }
989                         for (dentp = (struct direntry *)bp->b_data;
990                              (char *)dentp < bp->b_data + blsize;
991                              dentp++) {
992                                 if (dentp->deName[0] == SLOT_EMPTY) {
993                                         /*
994                                          * Last used entry and not found
995                                          */
996                                         brelse(bp);
997                                         return 0;
998                                 }
999                                 /*
1000                                  * Ignore volume labels and Win95 entries
1001                                  */
1002                                 if (dentp->deAttributes & ATTR_VOLUME)
1003                                         continue;
1004                                 if (!bcmp(dentp->deName, cp, 11)) {
1005                                         error = EEXIST;
1006                                         break;
1007                                 }
1008                         }
1009                         brelse(bp);
1010                 }
1011         }
1012 }
1013
1014 /*
1015  * Find any Win'95 long filename entry in directory dep
1016  */
1017 int
1018 findwin95(struct denode *dep)
1019 {
1020         struct msdosfsmount *pmp = dep->de_pmp;
1021         struct direntry *dentp;
1022         int blsize, win95;
1023         u_long cn;
1024         daddr_t bn;
1025         struct buf *bp;
1026
1027         win95 = 1;
1028         /*
1029          * Read through the directory looking for Win'95 entries
1030          * Note: Error currently handled just as EOF                    XXX
1031          */
1032         for (cn = 0;; cn++) {
1033                 if (pcbmap(dep, cn, &bn, 0, &blsize))
1034                         return (win95);
1035                 if (bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp)) {
1036                         brelse(bp);
1037                         return (win95);
1038                 }
1039                 for (dentp = (struct direntry *)bp->b_data;
1040                      (char *)dentp < bp->b_data + blsize;
1041                      dentp++) {
1042                         if (dentp->deName[0] == SLOT_EMPTY) {
1043                                 /*
1044                                  * Last used entry and not found
1045                                  */
1046                                 brelse(bp);
1047                                 return (win95);
1048                         }
1049                         if (dentp->deName[0] == SLOT_DELETED) {
1050                                 /*
1051                                  * Ignore deleted files
1052                                  * Note: might be an indication of Win'95 anyway        XXX
1053                                  */
1054                                 continue;
1055                         }
1056                         if (dentp->deAttributes == ATTR_WIN95) {
1057                                 brelse(bp);
1058                                 return 1;
1059                         }
1060                         win95 = 0;
1061                 }
1062                 brelse(bp);
1063         }
1064 }