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