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 /*      $NetBSD: msdosfs_lookup.c,v 1.3 2003/06/29 22:31:09 fvdl Exp $  */
    2 
    3 /*-
    4  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
    5  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
    6  * All rights reserved.
    7  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by TooLs GmbH.
   20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 /*
   35  * Written by Paul Popelka (paulp@uts.amdahl.com)
   36  *
   37  * You can do anything you want with this software, just don't say you wrote
   38  * it, and don't remove this notice.
   39  *
   40  * This software is provided "as is".
   41  *
   42  * The author supplies this software to be publicly redistributed on the
   43  * understanding that the author is not responsible for the correct
   44  * functioning of this software in any circumstances and is not liable for
   45  * any damages caused by this software.
   46  *
   47  * October 1992
   48  */
   49 
   50 #include <sys/cdefs.h>
   51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.3 2003/06/29 22:31:09 fvdl Exp $");
   52 
   53 #include <sys/param.h>
   54 #include <sys/systm.h>
   55 #include <sys/namei.h>
   56 #include <sys/buf.h>
   57 #include <sys/vnode.h>
   58 #include <sys/mount.h>
   59 #include <sys/dirent.h>
   60 
   61 #include <fs/msdosfs/bpb.h>
   62 #include <fs/msdosfs/direntry.h>
   63 #include <fs/msdosfs/denode.h>
   64 #include <fs/msdosfs/msdosfsmount.h>
   65 #include <fs/msdosfs/fat.h>
   66 
   67 /*
   68  * When we search a directory the blocks containing directory entries are
   69  * read and examined.  The directory entries contain information that would
   70  * normally be in the inode of a unix filesystem.  This means that some of
   71  * a directory's contents may also be in memory resident denodes (sort of
   72  * an inode).  This can cause problems if we are searching while some other
   73  * process is modifying a directory.  To prevent one process from accessing
   74  * incompletely modified directory information we depend upon being the
   75  * sole owner of a directory block.  bread/brelse provide this service.
   76  * This being the case, when a process modifies a directory it must first
   77  * acquire the disk block that contains the directory entry to be modified.
   78  * Then update the disk block and the denode, and then write the disk block
   79  * out to disk.  This way disk blocks containing directory entries and in
   80  * memory denode's will be in synch.
   81  */
   82 int
   83 msdosfs_lookup(v)
   84         void *v;
   85 {
   86         struct vop_lookup_args /* {
   87                 struct vnode *a_dvp;
   88                 struct vnode **a_vpp;
   89                 struct componentname *a_cnp;
   90         } */ *ap = v;
   91         struct vnode *vdp = ap->a_dvp;
   92         struct vnode **vpp = ap->a_vpp;
   93         struct componentname *cnp = ap->a_cnp;
   94         daddr_t bn;
   95         int error;
   96         int lockparent;
   97         int wantparent;
   98         int slotcount;
   99         int slotoffset = 0;
  100         int frcn;
  101         u_long cluster;
  102         int blkoff;
  103         int diroff;
  104         int blsize;
  105         int isadir;             /* ~0 if found direntry is a directory   */
  106         u_long scn;             /* starting cluster number               */
  107         struct vnode *pdp;
  108         struct denode *dp;
  109         struct denode *tdp;
  110         struct msdosfsmount *pmp;
  111         struct buf *bp = 0;
  112         struct direntry *dep;
  113         u_char dosfilename[12];
  114         int flags;
  115         int nameiop = cnp->cn_nameiop;
  116         int wincnt = 1;
  117         int chksum = -1, chksum_ok;
  118         int olddos = 1;
  119 
  120         cnp->cn_flags &= ~PDIRUNLOCK; /* XXX why this ?? */
  121         flags = cnp->cn_flags;
  122 
  123 #ifdef MSDOSFS_DEBUG
  124         printf("msdosfs_lookup(): looking for %.*s\n",
  125                 (int)cnp->cn_namelen, cnp->cn_nameptr);
  126 #endif
  127         dp = VTODE(vdp);
  128         pmp = dp->de_pmp;
  129         *vpp = NULL;
  130         lockparent = flags & LOCKPARENT;
  131         wantparent = flags & (LOCKPARENT | WANTPARENT);
  132 #ifdef MSDOSFS_DEBUG
  133         printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
  134             vdp, dp, dp->de_Attributes);
  135 #endif
  136 
  137         /*
  138          * Check accessiblity of directory.
  139          */
  140         if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred, cnp->cn_proc)) != 0)
  141                 return (error);
  142 
  143         if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
  144             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  145                 return (EROFS);
  146 
  147         /*
  148          * We now have a segment name to search for, and a directory to search.
  149          *
  150          * Before tediously performing a linear scan of the directory,
  151          * check the name cache to see if the directory/name pair
  152          * we are looking for is known already.
  153          */
  154         if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
  155                 return (error);
  156 
  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_flag & VROOT) && 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)) {
  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) + 1;
  184                 break;
  185         case 3:
  186                 olddos = 0;
  187                 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
  188                     cnp->cn_namelen) + 1;
  189                 break;
  190         }
  191         if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
  192                 wincnt = 1;
  193 
  194         /*
  195          * Suppress search for slots unless creating
  196          * file and at end of pathname, in which case
  197          * we watch for a place to put the new file in
  198          * case it doesn't already exist.
  199          */
  200         slotcount = wincnt;
  201         if ((nameiop == CREATE || nameiop == RENAME) &&
  202             (flags & ISLASTCN))
  203                 slotcount = 0;
  204 
  205 #ifdef MSDOSFS_DEBUG
  206         printf("msdosfs_lookup(): dos filename: %s\n", dosfilename);
  207 #endif
  208         /*
  209          * Search the directory pointed at by vdp for the name pointed at
  210          * by cnp->cn_nameptr.
  211          */
  212         tdp = NULL;
  213         /*
  214          * The outer loop ranges over the clusters that make up the
  215          * directory.  Note that the root directory is different from all
  216          * other directories.  It has a fixed number of blocks that are not
  217          * part of the pool of allocatable clusters.  So, we treat it a
  218          * little differently. The root directory starts at "cluster" 0.
  219          */
  220         diroff = 0;
  221         for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
  222                 if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
  223                         if (error == E2BIG)
  224                                 break;
  225                         return (error);
  226                 }
  227                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
  228                 if (error) {
  229                         brelse(bp);
  230                         return (error);
  231                 }
  232                 for (blkoff = 0; blkoff < blsize;
  233                      blkoff += sizeof(struct direntry),
  234                      diroff += sizeof(struct direntry)) {
  235                         dep = (struct direntry *)(bp->b_data + blkoff);
  236                         /*
  237                          * If the slot is empty and we are still looking
  238                          * for an empty then remember this one.  If the
  239                          * slot is not empty then check to see if it
  240                          * matches what we are looking for.  If the slot
  241                          * has never been filled with anything, then the
  242                          * remainder of the directory has never been used,
  243                          * so there is no point in searching it.
  244                          */
  245                         if (dep->deName[0] == SLOT_EMPTY ||
  246                             dep->deName[0] == SLOT_DELETED) {
  247                                 /*
  248                                  * Drop memory of previous long matches
  249                                  */
  250                                 chksum = -1;
  251 
  252                                 if (slotcount < wincnt) {
  253                                         slotcount++;
  254                                         slotoffset = diroff;
  255                                 }
  256                                 if (dep->deName[0] == SLOT_EMPTY) {
  257                                         brelse(bp);
  258                                         goto notfound;
  259                                 }
  260                         } else {
  261                                 /*
  262                                  * If there wasn't enough space for our
  263                                  * winentries, forget about the empty space
  264                                  */
  265                                 if (slotcount < wincnt)
  266                                         slotcount = 0;
  267 
  268                                 /*
  269                                  * Check for Win95 long filename entry
  270                                  */
  271                                 if (dep->deAttributes == ATTR_WIN95) {
  272                                         if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
  273                                                 continue;
  274 
  275                                         chksum = winChkName((const u_char *)cnp->cn_nameptr,
  276                                                             cnp->cn_namelen,
  277                                                             (struct winentry *)dep,
  278                                                             chksum);
  279                                         continue;
  280                                 }
  281 
  282                                 /*
  283                                  * Ignore volume labels (anywhere, not just
  284                                  * the root directory).
  285                                  */
  286                                 if (dep->deAttributes & ATTR_VOLUME) {
  287                                         chksum = -1;
  288                                         continue;
  289                                 }
  290 
  291                                 /*
  292                                  * Check for a checksum or name match
  293                                  */
  294                                 chksum_ok = (chksum == winChksum(dep->deName));
  295                                 if (!chksum_ok
  296                                     && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
  297                                         chksum = -1;
  298                                         continue;
  299                                 }
  300 #ifdef MSDOSFS_DEBUG
  301                                 printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
  302                                     blkoff, diroff);
  303 #endif
  304                                 /*
  305                                  * Remember where this directory
  306                                  * entry came from for whoever did
  307                                  * this lookup.
  308                                  */
  309                                 dp->de_fndoffset = diroff;
  310                                 if (chksum_ok && nameiop == RENAME) {
  311                                         /*
  312                                          * Target had correct long name
  313                                          * directory entries, reuse them
  314                                          * as needed.
  315                                          */
  316                                         dp->de_fndcnt = wincnt - 1;
  317                                 } else {
  318                                         /*
  319                                          * Long name directory entries
  320                                          * not present or corrupt, can only
  321                                          * reuse dos directory entry.
  322                                          */
  323                                         dp->de_fndcnt = 0;
  324                                 }
  325 
  326                                 goto found;
  327                         }
  328                 }       /* for (blkoff = 0; .... */
  329                 /*
  330                  * Release the buffer holding the directory cluster just
  331                  * searched.
  332                  */
  333                 brelse(bp);
  334         }       /* for (frcn = 0; ; frcn++) */
  335 
  336 notfound:
  337         /*
  338          * We hold no disk buffers at this point.
  339          */
  340 
  341         /*
  342          * If we get here we didn't find the entry we were looking for. But
  343          * that's ok if we are creating or renaming and are at the end of
  344          * the pathname and the directory hasn't been removed.
  345          */
  346 #ifdef MSDOSFS_DEBUG
  347         printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n",
  348             nameiop, dp->de_refcnt, slotcount, slotoffset);
  349 #endif
  350         if ((nameiop == CREATE || nameiop == RENAME) &&
  351             (flags & ISLASTCN) && dp->de_refcnt != 0) {
  352                 /*
  353                  * Access for write is interpreted as allowing
  354                  * creation of files in the directory.
  355                  */
  356                 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
  357                 if (error)
  358                         return (error);
  359 
  360                 /*
  361                  * Fixup the slot description to point to the place where
  362                  * we might put the new DOS direntry (putting the Win95
  363                  * long name entries before that)
  364                  */
  365                 if (!slotcount) {
  366                         slotcount = 1;
  367                         slotoffset = diroff;
  368                 }
  369                 if (wincnt > slotcount) {
  370                         slotoffset +=
  371                                 sizeof(struct direntry) * (wincnt - slotcount);
  372                 }
  373         
  374                 /*
  375                  * Return an indication of where the new directory
  376                  * entry should be put.
  377                  */
  378                 dp->de_fndoffset = slotoffset;
  379                 dp->de_fndcnt = wincnt - 1;
  380 
  381                 /*
  382                  * We return with the directory locked, so that
  383                  * the parameters we set up above will still be
  384                  * valid if we actually decide to do a direnter().
  385                  * We return ni_vp == NULL to indicate that the entry
  386                  * does not currently exist; we leave a pointer to
  387                  * the (locked) directory inode in ndp->ni_dvp.
  388                  * The pathname buffer is saved so that the name
  389                  * can be obtained later.
  390                  *
  391                  * NB - if the directory is unlocked, then this
  392                  * information cannot be used.
  393                  */
  394                 cnp->cn_flags |= SAVENAME;
  395                 if (!lockparent)
  396                         VOP_UNLOCK(vdp, 0);
  397                 return (EJUSTRETURN);
  398         }
  399 
  400         /*
  401          * Insert name into cache (as non-existent) if appropriate.
  402          */
  403         if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
  404                 cache_enter(vdp, *vpp, cnp);
  405 
  406         return (ENOENT);
  407 
  408 found:
  409         /*
  410          * NOTE:  We still have the buffer with matched directory entry at
  411          * this point.
  412          */
  413         isadir = dep->deAttributes & ATTR_DIRECTORY;
  414         scn = getushort(dep->deStartCluster);
  415         if (FAT32(pmp)) {
  416                 scn |= getushort(dep->deHighClust) << 16;
  417                 if (scn == pmp->pm_rootdirblk) {
  418                         /*
  419                          * There should actually be 0 here.
  420                          * Just ignore the error.
  421                          */
  422                         scn = MSDOSFSROOT;
  423                 }
  424         }
  425 
  426         if (isadir) {
  427                 cluster = scn;
  428                 if (cluster == MSDOSFSROOT)
  429                         blkoff = MSDOSFSROOT_OFS;
  430                 else
  431                         blkoff = 0;
  432         } else if (cluster == MSDOSFSROOT)
  433                 blkoff = diroff;
  434 
  435         /*
  436          * Now release buf to allow deget to read the entry again.
  437          * Reserving it here and giving it to deget could result
  438          * in a deadlock.
  439          */
  440         brelse(bp);
  441 
  442 foundroot:
  443         /*
  444          * If we entered at foundroot, then we are looking for the . or ..
  445          * entry of the filesystems root directory.  isadir and scn were
  446          * setup before jumping here.  And, bp is already null.
  447          */
  448         if (FAT32(pmp) && scn == MSDOSFSROOT)
  449                 scn = pmp->pm_rootdirblk;
  450 
  451         /*
  452          * If deleting, and at end of pathname, return
  453          * parameters which can be used to remove file.
  454          * If the wantparent flag isn't set, we return only
  455          * the directory (in ndp->ni_dvp), otherwise we go
  456          * on and lock the inode, being careful with ".".
  457          */
  458         if (nameiop == DELETE && (flags & ISLASTCN)) {
  459                 /*
  460                  * Don't allow deleting the root.
  461                  */
  462                 if (blkoff == MSDOSFSROOT_OFS)
  463                         return EROFS;                   /* really? XXX */
  464 
  465                 /*
  466                  * Write access to directory required to delete files.
  467                  */
  468                 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
  469                 if (error)
  470                         return (error);
  471 
  472                 /*
  473                  * Return pointer to current entry in dp->i_offset.
  474                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
  475                  */
  476                 if (dp->de_StartCluster == scn && isadir) {     /* "." */
  477                         VREF(vdp);
  478                         *vpp = vdp;
  479                         return (0);
  480                 }
  481                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
  482                         return (error);
  483                 *vpp = DETOV(tdp);
  484                 if (!lockparent) {
  485                         VOP_UNLOCK(vdp, 0);
  486                         cnp->cn_flags |= PDIRUNLOCK;
  487                 }
  488                 return (0);
  489         }
  490 
  491         /*
  492          * If rewriting (RENAME), return the inode and the
  493          * information required to rewrite the present directory
  494          * Must get inode of directory entry to verify it's a
  495          * regular file, or empty directory.
  496          */
  497         if (nameiop == RENAME && wantparent &&
  498             (flags & ISLASTCN)) {
  499 
  500                 if (vdp->v_mount->mnt_flag & MNT_RDONLY)
  501                         return (EROFS);
  502 
  503                 if (blkoff == MSDOSFSROOT_OFS)
  504                         return EROFS;                           /* really? XXX */
  505 
  506                 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
  507                 if (error)
  508                         return (error);
  509 
  510                 /*
  511                  * Careful about locking second inode.
  512                  * This can only occur if the target is ".".
  513                  */
  514                 if (dp->de_StartCluster == scn && isadir)
  515                         return (EISDIR);
  516 
  517                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
  518                         return (error);
  519                 *vpp = DETOV(tdp);
  520                 cnp->cn_flags |= SAVENAME;
  521                 if (!lockparent) {
  522                         VOP_UNLOCK(vdp, 0);
  523                         cnp->cn_flags |= PDIRUNLOCK;
  524                 }
  525                 return (0);
  526         }
  527 
  528         /*
  529          * Step through the translation in the name.  We do not `vput' the
  530          * directory because we may need it again if a symbolic link
  531          * is relative to the current directory.  Instead we save it
  532          * unlocked as "pdp".  We must get the target inode before unlocking
  533          * the directory to insure that the inode will not be removed
  534          * before we get it.  We prevent deadlock by always fetching
  535          * inodes from the root, moving down the directory tree. Thus
  536          * when following backward pointers ".." we must unlock the
  537          * parent directory before getting the requested directory.
  538          * There is a potential race condition here if both the current
  539          * and parent directories are removed before the VFS_VGET for the
  540          * inode associated with ".." returns.  We hope that this occurs
  541          * infrequently since we cannot avoid this race condition without
  542          * implementing a sophisticated deadlock detection algorithm.
  543          * Note also that this simple deadlock detection scheme will not
  544          * work if the file system has any hard links other than ".."
  545          * that point backwards in the directory structure.
  546          */
  547         pdp = vdp;
  548         if (flags & ISDOTDOT) {
  549                 VOP_UNLOCK(pdp, 0);     /* race to get the inode */
  550                 cnp->cn_flags |= PDIRUNLOCK;
  551                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) {
  552                         if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
  553                                 cnp->cn_flags &= ~PDIRUNLOCK;
  554                         return (error);
  555                 }
  556                 if (lockparent && (flags & ISLASTCN)) {
  557                         if ((error = vn_lock(pdp, LK_EXCLUSIVE))) {
  558                                 vput(DETOV(tdp));
  559                                 return (error);
  560                         }
  561                         cnp->cn_flags &= ~PDIRUNLOCK;
  562                 }
  563                 *vpp = DETOV(tdp);
  564         } else if (dp->de_StartCluster == scn && isadir) {
  565                 VREF(vdp);      /* we want ourself, ie "." */
  566                 *vpp = vdp;
  567         } else {
  568                 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
  569                         return (error);
  570                 if (!lockparent || !(flags & ISLASTCN)) {
  571                         VOP_UNLOCK(pdp, 0);
  572                         cnp->cn_flags |= PDIRUNLOCK;
  573                 }
  574                 *vpp = DETOV(tdp);
  575         }
  576 
  577         /*
  578          * Insert name into cache if appropriate.
  579          */
  580         if (cnp->cn_flags & MAKEENTRY)
  581                 cache_enter(vdp, *vpp, cnp);
  582 
  583         return (0);
  584 }
  585 
  586 /*
  587  * dep  - directory entry to copy into the directory
  588  * ddep - directory to add to
  589  * depp - return the address of the denode for the created directory entry
  590  *        if depp != 0
  591  * cnp  - componentname needed for Win95 long filenames
  592  */
  593 int
  594 createde(dep, ddep, depp, cnp)
  595         struct denode *dep;
  596         struct denode *ddep;
  597         struct denode **depp;
  598         struct componentname *cnp;
  599 {
  600         int error, rberror;
  601         u_long dirclust, clusoffset;
  602         u_long fndoffset, havecnt=0, wcnt=1;
  603         struct direntry *ndep;
  604         struct msdosfsmount *pmp = ddep->de_pmp;
  605         struct buf *bp;
  606         daddr_t bn;
  607         int blsize, i;
  608         int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC;
  609 
  610 #ifdef MSDOSFS_DEBUG
  611         printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
  612             dep, ddep, depp, cnp);
  613 #endif
  614 
  615         /*
  616          * If no space left in the directory then allocate another cluster
  617          * and chain it onto the end of the file.  There is one exception
  618          * to this.  That is, if the root directory has no more space it
  619          * can NOT be expanded.  extendfile() checks for and fails attempts
  620          * to extend the root directory.  We just return an error in that
  621          * case.
  622          */
  623         if (ddep->de_fndoffset >= ddep->de_FileSize) {
  624                 u_long needlen = ddep->de_fndoffset + sizeof(struct direntry)
  625                     - ddep->de_FileSize;
  626                 dirclust = de_clcount(pmp, needlen);
  627                 if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) {
  628                         (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
  629                         goto err_norollback;
  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                 goto err_norollback;
  647         clusoffset = ddep->de_fndoffset;
  648         if (dirclust != MSDOSFSROOT)
  649                 clusoffset &= pmp->pm_crbomask;
  650         if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
  651                 brelse(bp);
  652                 goto err_norollback;
  653         }
  654         ndep = bptoep(pmp, bp, clusoffset);
  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                 u_long havecnt;
  666 
  667                 fndoffset = ddep->de_fndoffset;
  668                 havecnt = ddep->de_fndcnt + 1;
  669 
  670                 for(; wcnt < havecnt; wcnt++) {
  671                         if ((fndoffset & pmp->pm_crbomask) == 0) {
  672                                 /* we should never get here if ddep is root
  673                                  * directory */
  674 
  675                                 if (async)
  676                                         (void) bdwrite(bp);
  677                                 else if ((error = bwrite(bp)) != 0)
  678                                         goto rollback;
  679 
  680                                 fndoffset -= sizeof(struct direntry);
  681                                 error = pcbmap(ddep,
  682                                                de_cluster(pmp, fndoffset),
  683                                                &bn, 0, &blsize);
  684                                 if (error)
  685                                         goto rollback;
  686 
  687                                 error = bread(pmp->pm_devvp, bn, blsize,
  688                                               NOCRED, &bp);
  689                                 if (error) {
  690                                         brelse(bp);
  691                                         goto rollback;
  692                                 }
  693                                 ndep = bptoep(pmp, bp,
  694                                                 fndoffset & pmp->pm_crbomask);
  695                         } else {
  696                                 ndep--;
  697                                 fndoffset -= sizeof(struct direntry);
  698                         }
  699                         if (!unix2winfn(un, unlen, (struct winentry *)ndep,
  700                                                 wcnt, chksum))
  701                                 break;
  702                 }
  703         }
  704 
  705         if (async)
  706                 bdwrite(bp);
  707         else if ((error = bwrite(bp)) != 0)
  708                 goto rollback;
  709 
  710         /*
  711          * If they want us to return with the denode gotten.
  712          */
  713         if (depp) {
  714                 u_long diroffset = clusoffset;
  715                 if (dep->de_Attributes & ATTR_DIRECTORY) {
  716                         dirclust = dep->de_StartCluster;
  717                         if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
  718                                 dirclust = MSDOSFSROOT;
  719                         if (dirclust == MSDOSFSROOT)
  720                                 diroffset = MSDOSFSROOT_OFS;
  721                         else
  722                                 diroffset = 0;
  723                 }
  724                 return deget(pmp, dirclust, diroffset, depp);
  725         }
  726 
  727         return 0;
  728 
  729     rollback:
  730         /*
  731          * Mark all slots modified so far as deleted. Note that we
  732          * can't just call removede(), since directory is not in
  733          * consistent state.
  734          */
  735         fndoffset = ddep->de_fndoffset;
  736         rberror = pcbmap(ddep, de_cluster(pmp, fndoffset),
  737                &bn, NULL, &blsize);
  738         if (rberror)
  739                 goto err_norollback;
  740         if ((rberror = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
  741                 brelse(bp);
  742                 goto err_norollback;
  743         }
  744         ndep = bptoep(pmp, bp, clusoffset);
  745 
  746         havecnt = ddep->de_fndcnt + 1;
  747         for(i=wcnt; i <= havecnt; i++) {
  748                 /* mark entry as deleted */
  749                 ndep->deName[0] = SLOT_DELETED;
  750 
  751                 if ((fndoffset & pmp->pm_crbomask) == 0) {
  752                         /* we should never get here if ddep is root
  753                          * directory */
  754 
  755                         if (async)
  756                                 bdwrite(bp);
  757                         else if ((rberror = bwrite(bp)) != 0)
  758                                 goto err_norollback;
  759 
  760                         fndoffset -= sizeof(struct direntry);
  761                         rberror = pcbmap(ddep,
  762                                        de_cluster(pmp, fndoffset),
  763                                        &bn, 0, &blsize);
  764                         if (rberror)
  765                                 goto err_norollback;
  766 
  767                         rberror = bread(pmp->pm_devvp, bn, blsize,
  768                                       NOCRED, &bp);
  769                         if (rberror) {
  770                                 brelse(bp);
  771                                 goto err_norollback;
  772                         }
  773                         ndep = bptoep(pmp, bp, fndoffset);
  774                 } else {
  775                         ndep--;
  776                         fndoffset -= sizeof(struct direntry);
  777                 }
  778         }
  779 
  780         /* ignore any further error */
  781         if (async)
  782                 (void) bdwrite(bp);
  783         else
  784                 (void) bwrite(bp);
  785 
  786     err_norollback:
  787         return error;
  788 }
  789 
  790 /*
  791  * Be sure a directory is empty except for "." and "..". Return 1 if empty,
  792  * return 0 if not empty or error.
  793  */
  794 int
  795 dosdirempty(dep)
  796         struct denode *dep;
  797 {
  798         int blsize;
  799         int error;
  800         u_long cn;
  801         daddr_t bn;
  802         struct buf *bp;
  803         struct msdosfsmount *pmp = dep->de_pmp;
  804         struct direntry *dentp;
  805 
  806         /*
  807          * Since the filesize field in directory entries for a directory is
  808          * zero, we just have to feel our way through the directory until
  809          * we hit end of file.
  810          */
  811         for (cn = 0;; cn++) {
  812                 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
  813                         if (error == E2BIG)
  814                                 return (1);     /* it's empty */
  815                         return (0);
  816                 }
  817                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
  818                 if (error) {
  819                         brelse(bp);
  820                         return (0);
  821                 }
  822                 for (dentp = (struct direntry *)bp->b_data;
  823                      (char *)dentp < bp->b_data + blsize;
  824                      dentp++) {
  825                         if (dentp->deName[0] != SLOT_DELETED &&
  826                             (dentp->deAttributes & ATTR_VOLUME) == 0) {
  827                                 /*
  828                                  * In dos directories an entry whose name
  829                                  * starts with SLOT_EMPTY (0) starts the
  830                                  * beginning of the unused part of the
  831                                  * directory, so we can just return that it
  832                                  * is empty.
  833                                  */
  834                                 if (dentp->deName[0] == SLOT_EMPTY) {
  835                                         brelse(bp);
  836                                         return (1);
  837                                 }
  838                                 /*
  839                                  * Any names other than "." and ".." in a
  840                                  * directory mean it is not empty.
  841                                  */
  842                                 if (memcmp(dentp->deName, ".          ", 11) &&
  843                                     memcmp(dentp->deName, "..         ", 11)) {
  844                                         brelse(bp);
  845 #ifdef MSDOSFS_DEBUG
  846                                         printf("dosdirempty(): found %.11s, %d, %d\n",
  847                                             dentp->deName, dentp->deName[0],
  848                                                 dentp->deName[1]);
  849 #endif
  850                                         return (0);     /* not empty */
  851                                 }
  852                         }
  853                 }
  854                 brelse(bp);
  855         }
  856         /* NOTREACHED */
  857 }
  858 
  859 /*
  860  * Check to see if the directory described by target is in some
  861  * subdirectory of source.  This prevents something like the following from
  862  * succeeding and leaving a bunch or files and directories orphaned. mv
  863  * /a/b/c /a/b/c/d/e/f Where c and f are directories.
  864  *
  865  * source - the inode for /a/b/c
  866  * target - the inode for /a/b/c/d/e/f
  867  *
  868  * Returns 0 if target is NOT a subdirectory of source.
  869  * Otherwise returns a non-zero error number.
  870  * The target inode is always unlocked on return.
  871  */
  872 int
  873 doscheckpath(source, target)
  874         struct denode *source;
  875         struct denode *target;
  876 {
  877         u_long scn;
  878         struct msdosfsmount *pmp;
  879         struct direntry *ep;
  880         struct denode *dep;
  881         struct buf *bp = NULL;
  882         int error = 0;
  883 
  884         dep = target;
  885         if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
  886             (source->de_Attributes & ATTR_DIRECTORY) == 0) {
  887                 error = ENOTDIR;
  888                 goto out;
  889         }
  890         if (dep->de_StartCluster == source->de_StartCluster) {
  891                 error = EEXIST;
  892                 goto out;
  893         }
  894         if (dep->de_StartCluster == MSDOSFSROOT)
  895                 goto out;
  896         pmp = dep->de_pmp;
  897 #ifdef  DIAGNOSTIC
  898         if (pmp != source->de_pmp)
  899                 panic("doscheckpath: source and target on different filesystems");
  900 #endif
  901         if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
  902                 goto out;
  903 
  904         for (;;) {
  905                 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
  906                         error = ENOTDIR;
  907                         break;
  908                 }
  909                 scn = dep->de_StartCluster;
  910                 error = bread(pmp->pm_devvp, cntobn(pmp, scn),
  911                               pmp->pm_bpcluster, NOCRED, &bp);
  912                 if (error)
  913                         break;
  914 
  915                 ep = (struct direntry *) bp->b_data + 1;
  916                 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
  917                     memcmp(ep->deName, "..         ", 11) != 0) {
  918                         error = ENOTDIR;
  919                         break;
  920                 }
  921                 scn = getushort(ep->deStartCluster);
  922                 if (FAT32(pmp))
  923                         scn |= getushort(ep->deHighClust) << 16;
  924 
  925                 if (scn == source->de_StartCluster) {
  926                         error = EINVAL;
  927                         break;
  928                 }
  929                 if (scn == MSDOSFSROOT)
  930                         break;
  931                 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
  932                         /*
  933                          * scn should be 0 in this case,
  934                          * but we silently ignore the error.
  935                          */
  936                         break;
  937                 }
  938 
  939                 vput(DETOV(dep));
  940                 brelse(bp);
  941                 bp = NULL;
  942                 /* NOTE: deget() clears dep on error */
  943                 if ((error = deget(pmp, scn, 0, &dep)) != 0)
  944                         break;
  945         }
  946 out:
  947         if (bp)
  948                 brelse(bp);
  949         if (error == ENOTDIR)
  950                 printf("doscheckpath(): .. not a directory?\n");
  951         if (dep != NULL)
  952                 vput(DETOV(dep));
  953         return (error);
  954 }
  955 
  956 /*
  957  * Read in the disk block containing the directory entry (dirclu, dirofs)
  958  * and return the address of the buf header, and the address of the
  959  * directory entry within the block.
  960  */
  961 int
  962 readep(pmp, dirclust, diroffset, bpp, epp)
  963         struct msdosfsmount *pmp;
  964         u_long dirclust, diroffset;
  965         struct buf **bpp;
  966         struct direntry **epp;
  967 {
  968         int error;
  969         daddr_t bn;
  970         int blsize;
  971 
  972         blsize = pmp->pm_bpcluster;
  973         if (dirclust == MSDOSFSROOT
  974             && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
  975                 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
  976         bn = detobn(pmp, dirclust, diroffset);
  977         if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
  978                 brelse(*bpp);
  979                 *bpp = NULL;
  980                 return (error);
  981         }
  982         if (epp)
  983                 *epp = bptoep(pmp, *bpp, diroffset);
  984         return (0);
  985 }
  986 
  987 /*
  988  * Read in the disk block containing the directory entry dep came from and
  989  * return the address of the buf header, and the address of the directory
  990  * entry within the block.
  991  */
  992 int
  993 readde(dep, bpp, epp)
  994         struct denode *dep;
  995         struct buf **bpp;
  996         struct direntry **epp;
  997 {
  998         return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
  999                         bpp, epp));
 1000 }
 1001 
 1002 /*
 1003  * Remove a directory entry. At this point the file represented by the
 1004  * directory entry to be removed is still full length until noone has it
 1005  * open.  When the file no longer being used msdosfs_inactive() is called
 1006  * and will truncate the file to 0 length.  When the vnode containing the
 1007  * denode is needed for some other purpose by VFS it will call
 1008  * msdosfs_reclaim() which will remove the denode from the denode cache.
 1009  */
 1010 int
 1011 removede(pdep, dep)
 1012         struct denode *pdep;    /* directory where the entry is removed */
 1013         struct denode *dep;     /* file to be removed */
 1014 {
 1015         int error;
 1016         struct direntry *ep;
 1017         struct buf *bp;
 1018         daddr_t bn;
 1019         int blsize;
 1020         struct msdosfsmount *pmp = pdep->de_pmp;
 1021         u_long offset = pdep->de_fndoffset;
 1022         int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC;
 1023 
 1024 #ifdef MSDOSFS_DEBUG
 1025         printf("removede(): filename %s, dep %p, offset %08lx\n",
 1026             dep->de_Name, dep, offset);
 1027 #endif
 1028 
 1029         dep->de_refcnt--;
 1030         offset += sizeof(struct direntry);
 1031         do {
 1032                 offset -= sizeof(struct direntry);
 1033                 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
 1034                 if (error)
 1035                         return error;
 1036                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
 1037                 if (error) {
 1038                         brelse(bp);
 1039                         return error;
 1040                 }
 1041                 ep = bptoep(pmp, bp, offset);
 1042                 /*
 1043                  * Check whether, if we came here the second time, i.e.
 1044                  * when underflowing into the previous block, the last
 1045                  * entry in this block is a longfilename entry, too.
 1046                  */
 1047                 if (ep->deAttributes != ATTR_WIN95
 1048                     && offset != pdep->de_fndoffset) {
 1049                         brelse(bp);
 1050                         break;
 1051                 }
 1052                 offset += sizeof(struct direntry);
 1053                 while (1) {
 1054                         /*
 1055                          * We are a bit agressive here in that we delete any Win95
 1056                          * entries preceding this entry, not just the ones we "own".
 1057                          * Since these presumably aren't valid anyway,
 1058                          * there should be no harm.
 1059                          */
 1060                         offset -= sizeof(struct direntry);
 1061                         ep--->deName[0] = SLOT_DELETED;
 1062                         if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
 1063                             || !(offset & pmp->pm_crbomask)
 1064                             || ep->deAttributes != ATTR_WIN95)
 1065                                 break;
 1066                 }
 1067                 if (async)
 1068                         bdwrite(bp);
 1069                 else if ((error = bwrite(bp)) != 0)
 1070                         return error;
 1071         } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
 1072             && !(offset & pmp->pm_crbomask)
 1073             && offset);
 1074         return 0;
 1075 }
 1076 
 1077 /*
 1078  * Create a unique DOS name in dvp
 1079  */
 1080 int
 1081 uniqdosname(dep, cnp, cp)
 1082         struct denode *dep;
 1083         struct componentname *cnp;
 1084         u_char *cp;
 1085 {
 1086         struct msdosfsmount *pmp = dep->de_pmp;
 1087         struct direntry *dentp;
 1088         int gen;
 1089         int blsize;
 1090         u_long cn;
 1091         daddr_t bn;
 1092         struct buf *bp;
 1093         int error;
 1094 
 1095         for (gen = 1;; gen++) {
 1096                 /*
 1097                  * Generate DOS name with generation number
 1098                  */
 1099                 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
 1100                     cnp->cn_namelen, gen))
 1101                         return gen == 1 ? EINVAL : EEXIST;
 1102 
 1103                 /*
 1104                  * Now look for a dir entry with this exact name
 1105                  */
 1106                 for (cn = error = 0; !error; cn++) {
 1107                         if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
 1108                                 if (error == E2BIG)     /* EOF reached and not found */
 1109                                         return 0;
 1110                                 return error;
 1111                         }
 1112                         error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
 1113                         if (error) {
 1114                                 brelse(bp);
 1115                                 return error;
 1116                         }
 1117                         for (dentp = (struct direntry *)bp->b_data;
 1118                              (char *)dentp < bp->b_data + blsize;
 1119                              dentp++) {
 1120                                 if (dentp->deName[0] == SLOT_EMPTY) {
 1121                                         /*
 1122                                          * Last used entry and not found
 1123                                          */
 1124                                         brelse(bp);
 1125                                         return 0;
 1126                                 }
 1127                                 /*
 1128                                  * Ignore volume labels and Win95 entries
 1129                                  */
 1130                                 if (dentp->deAttributes & ATTR_VOLUME)
 1131                                         continue;
 1132                                 if (!memcmp(dentp->deName, cp, 11)) {
 1133                                         error = EEXIST;
 1134                                         break;
 1135                                 }
 1136                         }
 1137                         brelse(bp);
 1138                 }
 1139         }
 1140 }
 1141 
 1142 /*
 1143  * Find any Win'95 long filename entry in directory dep
 1144  */
 1145 int
 1146 findwin95(dep)
 1147         struct denode *dep;
 1148 {
 1149         struct msdosfsmount *pmp = dep->de_pmp;
 1150         struct direntry *dentp;
 1151         int blsize;
 1152         u_long cn;
 1153         daddr_t bn;
 1154         struct buf *bp;
 1155 
 1156         /*
 1157          * Read through the directory looking for Win'95 entries
 1158          * XXX Note: Error currently handled just as EOF
 1159          */
 1160         for (cn = 0;; cn++) {
 1161                 if (pcbmap(dep, cn, &bn, 0, &blsize))
 1162                         return 0;
 1163                 if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
 1164                         brelse(bp);
 1165                         return 0;
 1166                 }
 1167                 for (dentp = (struct direntry *)bp->b_data;
 1168                      (char *)dentp < bp->b_data + blsize;
 1169                      dentp++) {
 1170                         if (dentp->deName[0] == SLOT_EMPTY) {
 1171                                 /*
 1172                                  * Last used entry and not found
 1173                                  */
 1174                                 brelse(bp);
 1175                                 return 0;
 1176                         }
 1177                         if (dentp->deName[0] == SLOT_DELETED) {
 1178                                 /*
 1179                                  * Ignore deleted files
 1180                                  * Note: might be an indication of Win'95
 1181                                  * anyway       XXX
 1182                                  */
 1183                                 continue;
 1184                         }
 1185                         if (dentp->deAttributes == ATTR_WIN95) {
 1186                                 brelse(bp);
 1187                                 return 1;
 1188                         }
 1189                 }
 1190                 brelse(bp);
 1191         }
 1192 }

Cache object: b20b3b9955c2901543b4151f718a9496


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