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: releng/11.0/sys/fs/msdosfs/msdosfs_lookup.c 298806 2016-04-29 20:51:24Z pfg $ */
    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 = NULL;
  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(struct denode *dep, struct denode *ddep, struct denode **depp,
  596     struct componentname *cnp)
  597 {
  598         int error;
  599         u_long dirclust, diroffset;
  600         struct direntry *ndep;
  601         struct msdosfsmount *pmp = ddep->de_pmp;
  602         struct buf *bp;
  603         daddr_t bn;
  604         int blsize;
  605 
  606 #ifdef MSDOSFS_DEBUG
  607         printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
  608             dep, ddep, depp, cnp);
  609 #endif
  610 
  611         /*
  612          * If no space left in the directory then allocate another cluster
  613          * and chain it onto the end of the file.  There is one exception
  614          * to this.  That is, if the root directory has no more space it
  615          * can NOT be expanded.  extendfile() checks for and fails attempts
  616          * to extend the root directory.  We just return an error in that
  617          * case.
  618          */
  619         if (ddep->de_fndoffset >= ddep->de_FileSize) {
  620                 diroffset = ddep->de_fndoffset + sizeof(struct direntry)
  621                     - ddep->de_FileSize;
  622                 dirclust = de_clcount(pmp, diroffset);
  623                 error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
  624                 if (error) {
  625                         (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED);
  626                         return error;
  627                 }
  628 
  629                 /*
  630                  * Update the size of the directory
  631                  */
  632                 ddep->de_FileSize += de_cn2off(pmp, dirclust);
  633         }
  634 
  635         /*
  636          * We just read in the cluster with space.  Copy the new directory
  637          * entry in.  Then write it to disk. NOTE:  DOS directories
  638          * do not get smaller as clusters are emptied.
  639          */
  640         error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
  641                        &bn, &dirclust, &blsize);
  642         if (error)
  643                 return error;
  644         diroffset = ddep->de_fndoffset;
  645         if (dirclust != MSDOSFSROOT)
  646                 diroffset &= pmp->pm_crbomask;
  647         if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
  648                 brelse(bp);
  649                 return error;
  650         }
  651         ndep = bptoep(pmp, bp, ddep->de_fndoffset);
  652 
  653         DE_EXTERNALIZE(ndep, dep);
  654 
  655         /*
  656          * Now write the Win95 long name
  657          */
  658         if (ddep->de_fndcnt > 0) {
  659                 u_int8_t chksum = winChksum(ndep->deName);
  660                 const u_char *un = (const u_char *)cnp->cn_nameptr;
  661                 int unlen = cnp->cn_namelen;
  662                 int cnt = 1;
  663 
  664                 while (--ddep->de_fndcnt >= 0) {
  665                         if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
  666                                 if (DOINGASYNC(DETOV(ddep)))
  667                                         bdwrite(bp);
  668                                 else if ((error = bwrite(bp)) != 0)
  669                                         return error;
  670 
  671                                 ddep->de_fndoffset -= sizeof(struct direntry);
  672                                 error = pcbmap(ddep,
  673                                                de_cluster(pmp,
  674                                                           ddep->de_fndoffset),
  675                                                &bn, 0, &blsize);
  676                                 if (error)
  677                                         return error;
  678 
  679                                 error = bread(pmp->pm_devvp, bn, blsize,
  680                                               NOCRED, &bp);
  681                                 if (error) {
  682                                         brelse(bp);
  683                                         return error;
  684                                 }
  685                                 ndep = bptoep(pmp, bp, ddep->de_fndoffset);
  686                         } else {
  687                                 ndep--;
  688                                 ddep->de_fndoffset -= sizeof(struct direntry);
  689                         }
  690                         if (!unix2winfn(un, unlen, (struct winentry *)ndep,
  691                                         cnt++, chksum, pmp))
  692                                 break;
  693                 }
  694         }
  695 
  696         if (DOINGASYNC(DETOV(ddep)))
  697                 bdwrite(bp);
  698         else if ((error = bwrite(bp)) != 0)
  699                 return error;
  700 
  701         /*
  702          * If they want us to return with the denode gotten.
  703          */
  704         if (depp) {
  705                 if (dep->de_Attributes & ATTR_DIRECTORY) {
  706                         dirclust = dep->de_StartCluster;
  707                         if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
  708                                 dirclust = MSDOSFSROOT;
  709                         if (dirclust == MSDOSFSROOT)
  710                                 diroffset = MSDOSFSROOT_OFS;
  711                         else
  712                                 diroffset = 0;
  713                 }
  714                 return deget(pmp, dirclust, diroffset, depp);
  715         }
  716 
  717         return 0;
  718 }
  719 
  720 /*
  721  * Be sure a directory is empty except for "." and "..". Return 1 if empty,
  722  * return 0 if not empty or error.
  723  */
  724 int
  725 dosdirempty(struct denode *dep)
  726 {
  727         int blsize;
  728         int error;
  729         u_long cn;
  730         daddr_t bn;
  731         struct buf *bp;
  732         struct msdosfsmount *pmp = dep->de_pmp;
  733         struct direntry *dentp;
  734 
  735         /*
  736          * Since the filesize field in directory entries for a directory is
  737          * zero, we just have to feel our way through the directory until
  738          * we hit end of file.
  739          */
  740         for (cn = 0;; cn++) {
  741                 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
  742                         if (error == E2BIG)
  743                                 return (1);     /* it's empty */
  744                         return (0);
  745                 }
  746                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
  747                 if (error) {
  748                         brelse(bp);
  749                         return (0);
  750                 }
  751                 for (dentp = (struct direntry *)bp->b_data;
  752                      (char *)dentp < bp->b_data + blsize;
  753                      dentp++) {
  754                         if (dentp->deName[0] != SLOT_DELETED &&
  755                             (dentp->deAttributes & ATTR_VOLUME) == 0) {
  756                                 /*
  757                                  * In dos directories an entry whose name
  758                                  * starts with SLOT_EMPTY (0) starts the
  759                                  * beginning of the unused part of the
  760                                  * directory, so we can just return that it
  761                                  * is empty.
  762                                  */
  763                                 if (dentp->deName[0] == SLOT_EMPTY) {
  764                                         brelse(bp);
  765                                         return (1);
  766                                 }
  767                                 /*
  768                                  * Any names other than "." and ".." in a
  769                                  * directory mean it is not empty.
  770                                  */
  771                                 if (bcmp(dentp->deName, ".          ", 11) &&
  772                                     bcmp(dentp->deName, "..         ", 11)) {
  773                                         brelse(bp);
  774 #ifdef MSDOSFS_DEBUG
  775                                         printf("dosdirempty(): entry found %02x, %02x\n",
  776                                             dentp->deName[0], dentp->deName[1]);
  777 #endif
  778                                         return (0);     /* not empty */
  779                                 }
  780                         }
  781                 }
  782                 brelse(bp);
  783         }
  784         /* NOTREACHED */
  785 }
  786 
  787 /*
  788  * Check to see if the directory described by target is in some
  789  * subdirectory of source.  This prevents something like the following from
  790  * succeeding and leaving a bunch or files and directories orphaned. mv
  791  * /a/b/c /a/b/c/d/e/f Where c and f are directories.
  792  *
  793  * source - the inode for /a/b/c
  794  * target - the inode for /a/b/c/d/e/f
  795  *
  796  * Returns 0 if target is NOT a subdirectory of source.
  797  * Otherwise returns a non-zero error number.
  798  * The target inode is always unlocked on return.
  799  */
  800 int
  801 doscheckpath(struct denode *source, struct denode *target)
  802 {
  803         daddr_t scn;
  804         struct msdosfsmount *pmp;
  805         struct direntry *ep;
  806         struct denode *dep;
  807         struct buf *bp = NULL;
  808         int error = 0;
  809 
  810         dep = target;
  811         if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
  812             (source->de_Attributes & ATTR_DIRECTORY) == 0) {
  813                 error = ENOTDIR;
  814                 goto out;
  815         }
  816         if (dep->de_StartCluster == source->de_StartCluster) {
  817                 error = EEXIST;
  818                 goto out;
  819         }
  820         if (dep->de_StartCluster == MSDOSFSROOT)
  821                 goto out;
  822         pmp = dep->de_pmp;
  823 #ifdef  DIAGNOSTIC
  824         if (pmp != source->de_pmp)
  825                 panic("doscheckpath: source and target on different filesystems");
  826 #endif
  827         if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
  828                 goto out;
  829 
  830         for (;;) {
  831                 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
  832                         error = ENOTDIR;
  833                         break;
  834                 }
  835                 scn = dep->de_StartCluster;
  836                 error = bread(pmp->pm_devvp, cntobn(pmp, scn),
  837                               pmp->pm_bpcluster, NOCRED, &bp);
  838                 if (error)
  839                         break;
  840 
  841                 ep = (struct direntry *) bp->b_data + 1;
  842                 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
  843                     bcmp(ep->deName, "..         ", 11) != 0) {
  844                         error = ENOTDIR;
  845                         break;
  846                 }
  847                 scn = getushort(ep->deStartCluster);
  848                 if (FAT32(pmp))
  849                         scn |= getushort(ep->deHighClust) << 16;
  850 
  851                 if (scn == source->de_StartCluster) {
  852                         error = EINVAL;
  853                         break;
  854                 }
  855                 if (scn == MSDOSFSROOT)
  856                         break;
  857                 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
  858                         /*
  859                          * scn should be 0 in this case,
  860                          * but we silently ignore the error.
  861                          */
  862                         break;
  863                 }
  864 
  865                 vput(DETOV(dep));
  866                 brelse(bp);
  867                 bp = NULL;
  868                 /* NOTE: deget() clears dep on error */
  869                 if ((error = deget(pmp, scn, 0, &dep)) != 0)
  870                         break;
  871         }
  872 out:;
  873         if (bp)
  874                 brelse(bp);
  875 #ifdef MSDOSFS_DEBUG
  876         if (error == ENOTDIR)
  877                 printf("doscheckpath(): .. not a directory?\n");
  878 #endif
  879         if (dep != NULL)
  880                 vput(DETOV(dep));
  881         return (error);
  882 }
  883 
  884 /*
  885  * Read in the disk block containing the directory entry (dirclu, dirofs)
  886  * and return the address of the buf header, and the address of the
  887  * directory entry within the block.
  888  */
  889 int
  890 readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
  891     struct buf **bpp, struct direntry **epp)
  892 {
  893         int error;
  894         daddr_t bn;
  895         int blsize;
  896 
  897         blsize = pmp->pm_bpcluster;
  898         if (dirclust == MSDOSFSROOT
  899             && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
  900                 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
  901         bn = detobn(pmp, dirclust, diroffset);
  902         if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
  903                 brelse(*bpp);
  904                 *bpp = NULL;
  905                 return (error);
  906         }
  907         if (epp)
  908                 *epp = bptoep(pmp, *bpp, diroffset);
  909         return (0);
  910 }
  911 
  912 /*
  913  * Read in the disk block containing the directory entry dep came from and
  914  * return the address of the buf header, and the address of the directory
  915  * entry within the block.
  916  */
  917 int
  918 readde(struct denode *dep, struct buf **bpp, struct direntry **epp)
  919 {
  920 
  921         return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
  922             bpp, epp));
  923 }
  924 
  925 /*
  926  * Remove a directory entry. At this point the file represented by the
  927  * directory entry to be removed is still full length until no one has it
  928  * open.  When the file no longer being used msdosfs_inactive() is called
  929  * and will truncate the file to 0 length.  When the vnode containing the
  930  * denode is needed for some other purpose by VFS it will call
  931  * msdosfs_reclaim() which will remove the denode from the denode cache.
  932  *
  933  * pdep directory where the entry is removed
  934  * dep  file to be removed
  935  */
  936 int
  937 removede(struct denode *pdep, struct denode *dep)
  938 {
  939         int error;
  940         struct direntry *ep;
  941         struct buf *bp;
  942         daddr_t bn;
  943         int blsize;
  944         struct msdosfsmount *pmp = pdep->de_pmp;
  945         u_long offset = pdep->de_fndoffset;
  946 
  947 #ifdef MSDOSFS_DEBUG
  948         printf("removede(): filename %s, dep %p, offset %08lx\n",
  949             dep->de_Name, dep, offset);
  950 #endif
  951 
  952         dep->de_refcnt--;
  953         offset += sizeof(struct direntry);
  954         do {
  955                 offset -= sizeof(struct direntry);
  956                 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
  957                 if (error)
  958                         return error;
  959                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
  960                 if (error) {
  961                         brelse(bp);
  962                         return error;
  963                 }
  964                 ep = bptoep(pmp, bp, offset);
  965                 /*
  966                  * Check whether, if we came here the second time, i.e.
  967                  * when underflowing into the previous block, the last
  968                  * entry in this block is a longfilename entry, too.
  969                  */
  970                 if (ep->deAttributes != ATTR_WIN95
  971                     && offset != pdep->de_fndoffset) {
  972                         brelse(bp);
  973                         break;
  974                 }
  975                 offset += sizeof(struct direntry);
  976                 while (1) {
  977                         /*
  978                          * We are a bit aggressive here in that we delete any Win95
  979                          * entries preceding this entry, not just the ones we "own".
  980                          * Since these presumably aren't valid anyway,
  981                          * there should be no harm.
  982                          */
  983                         offset -= sizeof(struct direntry);
  984                         ep--->deName[0] = SLOT_DELETED;
  985                         if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  986                             || !(offset & pmp->pm_crbomask)
  987                             || ep->deAttributes != ATTR_WIN95)
  988                                 break;
  989                 }
  990                 if (DOINGASYNC(DETOV(pdep)))
  991                         bdwrite(bp);
  992                 else if ((error = bwrite(bp)) != 0)
  993                         return error;
  994         } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  995             && !(offset & pmp->pm_crbomask)
  996             && offset);
  997         return 0;
  998 }
  999 
 1000 /*
 1001  * Create a unique DOS name in dvp
 1002  */
 1003 int
 1004 uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
 1005 {
 1006         struct msdosfsmount *pmp = dep->de_pmp;
 1007         struct direntry *dentp;
 1008         int gen;
 1009         int blsize;
 1010         u_long cn;
 1011         daddr_t bn;
 1012         struct buf *bp;
 1013         int error;
 1014         
 1015         if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 1016                 return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
 1017                     cnp->cn_namelen, 0, pmp) ? 0 : EINVAL);
 1018 
 1019         for (gen = 1;; gen++) {
 1020                 /*
 1021                  * Generate DOS name with generation number
 1022                  */
 1023                 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
 1024                     cnp->cn_namelen, gen, pmp))
 1025                         return gen == 1 ? EINVAL : EEXIST;
 1026 
 1027                 /*
 1028                  * Now look for a dir entry with this exact name
 1029                  */
 1030                 for (cn = error = 0; !error; cn++) {
 1031                         if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
 1032                                 if (error == E2BIG)     /* EOF reached and not found */
 1033                                         return 0;
 1034                                 return error;
 1035                         }
 1036                         error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
 1037                         if (error) {
 1038                                 brelse(bp);
 1039                                 return error;
 1040                         }
 1041                         for (dentp = (struct direntry *)bp->b_data;
 1042                              (char *)dentp < bp->b_data + blsize;
 1043                              dentp++) {
 1044                                 if (dentp->deName[0] == SLOT_EMPTY) {
 1045                                         /*
 1046                                          * Last used entry and not found
 1047                                          */
 1048                                         brelse(bp);
 1049                                         return 0;
 1050                                 }
 1051                                 /*
 1052                                  * Ignore volume labels and Win95 entries
 1053                                  */
 1054                                 if (dentp->deAttributes & ATTR_VOLUME)
 1055                                         continue;
 1056                                 if (!bcmp(dentp->deName, cp, 11)) {
 1057                                         error = EEXIST;
 1058                                         break;
 1059                                 }
 1060                         }
 1061                         brelse(bp);
 1062                 }
 1063         }
 1064 }
 1065 
 1066 /*
 1067  * Find any Win'95 long filename entry in directory dep
 1068  */
 1069 int
 1070 findwin95(struct denode *dep)
 1071 {
 1072         struct msdosfsmount *pmp = dep->de_pmp;
 1073         struct direntry *dentp;
 1074         int blsize, win95;
 1075         u_long cn;
 1076         daddr_t bn;
 1077         struct buf *bp;
 1078 
 1079         win95 = 1;
 1080         /*
 1081          * Read through the directory looking for Win'95 entries
 1082          * Note: Error currently handled just as EOF                    XXX
 1083          */
 1084         for (cn = 0;; cn++) {
 1085                 if (pcbmap(dep, cn, &bn, 0, &blsize))
 1086                         return (win95);
 1087                 if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
 1088                         brelse(bp);
 1089                         return (win95);
 1090                 }
 1091                 for (dentp = (struct direntry *)bp->b_data;
 1092                      (char *)dentp < bp->b_data + blsize;
 1093                      dentp++) {
 1094                         if (dentp->deName[0] == SLOT_EMPTY) {
 1095                                 /*
 1096                                  * Last used entry and not found
 1097                                  */
 1098                                 brelse(bp);
 1099                                 return (win95);
 1100                         }
 1101                         if (dentp->deName[0] == SLOT_DELETED) {
 1102                                 /*
 1103                                  * Ignore deleted files
 1104                                  * Note: might be an indication of Win'95 anyway        XXX
 1105                                  */
 1106                                 continue;
 1107                         }
 1108                         if (dentp->deAttributes == ATTR_WIN95) {
 1109                                 brelse(bp);
 1110                                 return 1;
 1111                         }
 1112                         win95 = 0;
 1113                 }
 1114                 brelse(bp);
 1115         }
 1116 }

Cache object: 3a1fdc45c3cd712abc2a8d52c1ad3ef2


[ 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.