The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/msdosfs/msdosfs_lookup.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 097ad187337c2c17b7f0534cc96a609f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.