LCOV - code coverage report
Current view: top level - msdosfs - msdosfs_denode.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 257 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: msdosfs_denode.c,v 1.63 2018/05/27 06:02:14 visa Exp $        */
       2             : /*      $NetBSD: msdosfs_denode.c,v 1.23 1997/10/17 11:23:58 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/mount.h>
      54             : #include <sys/malloc.h>
      55             : #include <sys/buf.h>
      56             : #include <sys/vnode.h>
      57             : #include <sys/lock.h>
      58             : #include <sys/kernel.h>           /* defines "time" */
      59             : #include <sys/dirent.h>
      60             : #include <sys/namei.h>
      61             : 
      62             : #include <crypto/siphash.h>
      63             : 
      64             : #include <msdosfs/bpb.h>
      65             : #include <msdosfs/msdosfsmount.h>
      66             : #include <msdosfs/direntry.h>
      67             : #include <msdosfs/denode.h>
      68             : #include <msdosfs/fat.h>
      69             : 
      70             : u_int msdosfs_dehash(dev_t, uint32_t, uint32_t);
      71             : 
      72             : struct denode **dehashtbl;
      73             : SIPHASH_KEY dehashkey;
      74             : u_long dehash;                  /* size of hash table - 1 */
      75             : #define DEHASH(dev, dcl, doff) msdosfs_dehash((dev), (dcl), (doff))
      76             : 
      77             : static struct denode *msdosfs_hashget(dev_t, uint32_t, uint32_t);
      78             : static int msdosfs_hashins(struct denode *);
      79             : static void msdosfs_hashrem(struct denode *);
      80             : 
      81             : /*ARGSUSED*/
      82             : int
      83           0 : msdosfs_init(struct vfsconf *vfsp)
      84             : {
      85           0 :         dehashtbl = hashinit(initialvnodes / 2, M_MSDOSFSMNT, M_WAITOK, &dehash);
      86           0 :         arc4random_buf(&dehashkey, sizeof(dehashkey));
      87           0 :         return (0);
      88             : }
      89             : 
      90             : u_int
      91           0 : msdosfs_dehash(dev_t dev, uint32_t dirclust, uint32_t diroff)
      92             : {
      93           0 :         SIPHASH_CTX ctx;
      94             : 
      95           0 :         SipHash24_Init(&ctx, &dehashkey);
      96           0 :         SipHash24_Update(&ctx, &dev, sizeof(dev));
      97           0 :         SipHash24_Update(&ctx, &dirclust, sizeof(dirclust));
      98           0 :         SipHash24_Update(&ctx, &diroff, sizeof(diroff));
      99             : 
     100           0 :         return (SipHash24_End(&ctx) & dehash);
     101           0 : }
     102             : 
     103             : static struct denode *
     104           0 : msdosfs_hashget(dev_t dev, uint32_t dirclust, uint32_t diroff)
     105             : {
     106             :         struct denode *dep;
     107             : 
     108           0 :         for (;;)
     109           0 :                 for (dep = dehashtbl[DEHASH(dev, dirclust, diroff)]; ;
     110           0 :                      dep = dep->de_next) {
     111           0 :                         if (dep == NULL)
     112           0 :                                 return (NULL);
     113           0 :                         if (dirclust == dep->de_dirclust &&
     114           0 :                             diroff == dep->de_diroffset &&
     115           0 :                             dev == dep->de_dev &&
     116           0 :                             dep->de_refcnt != 0) {
     117           0 :                                 struct vnode *vp = DETOV(dep);
     118             : 
     119           0 :                                 if (!vget(vp, LK_EXCLUSIVE))
     120           0 :                                         return (dep);
     121           0 :                                 break;
     122             :                         }
     123             :                 }
     124             :         /* NOTREACHED */
     125           0 : }
     126             : 
     127             : static int
     128           0 : msdosfs_hashins(struct denode *dep)
     129             : {
     130             :         struct denode **depp, *deq;
     131             : 
     132           0 :         depp = &dehashtbl[DEHASH(dep->de_dev, dep->de_dirclust,
     133             :                                  dep->de_diroffset)];
     134             : 
     135           0 :         for (deq = *depp; deq; deq = deq->de_next) {
     136           0 :                 if (dep->de_dirclust == deq->de_dirclust &&
     137           0 :                     dep->de_diroffset == deq->de_diroffset &&
     138           0 :                     dep->de_dev == deq->de_dev &&
     139           0 :                     deq->de_refcnt != 0) {
     140           0 :                         return (EEXIST);
     141             :                 }
     142             :         }
     143             : 
     144           0 :         if ((deq = *depp) != NULL)
     145           0 :                 deq->de_prev = &dep->de_next;
     146           0 :         dep->de_next = deq;
     147           0 :         dep->de_prev = depp;
     148           0 :         *depp = dep;
     149           0 :         return (0);
     150           0 : }
     151             : 
     152             : static void
     153           0 : msdosfs_hashrem(struct denode *dep)
     154             : {
     155             :         struct denode *deq;
     156             : 
     157           0 :         if (dep->de_prev == NULL)
     158           0 :                 return;
     159             : 
     160           0 :         if ((deq = dep->de_next) != NULL)
     161           0 :                 deq->de_prev = dep->de_prev;
     162           0 :         *dep->de_prev = deq;
     163             : #ifdef DIAGNOSTIC
     164           0 :         dep->de_next = NULL;
     165           0 :         dep->de_prev = NULL;
     166             : #endif
     167           0 : }
     168             : 
     169             : /*
     170             :  * If deget() succeeds it returns with the gotten denode locked().
     171             :  *
     172             :  * pmp       - address of msdosfsmount structure of the filesystem containing
     173             :  *             the denode of interest.  The pm_dev field and the address of
     174             :  *             the msdosfsmount structure are used.
     175             :  * dirclust  - which cluster bp contains, if dirclust is 0 (root directory)
     176             :  *             diroffset is relative to the beginning of the root directory,
     177             :  *             otherwise it is cluster relative.
     178             :  * diroffset - offset past begin of cluster of denode we want
     179             :  * depp      - returns the address of the gotten denode.
     180             :  */
     181             : int
     182           0 : deget(struct msdosfsmount *pmp, uint32_t dirclust, uint32_t diroffset,
     183             :     struct denode **depp)
     184             : {
     185             :         int error;
     186             :         extern struct vops msdosfs_vops;
     187           0 :         struct direntry *direntptr;
     188             :         struct denode *ldep;
     189           0 :         struct vnode *nvp;
     190           0 :         struct buf *bp;
     191             : 
     192             : #ifdef MSDOSFS_DEBUG
     193             :         printf("deget(pmp %p, dirclust %d, diroffset %x, depp %p)\n",
     194             :             pmp, dirclust, diroffset, depp);
     195             : #endif
     196             : 
     197             :         /*
     198             :          * On FAT32 filesystems, root is a (more or less) normal
     199             :          * directory
     200             :          */
     201           0 :         if (FAT32(pmp) && dirclust == MSDOSFSROOT)
     202           0 :                 dirclust = pmp->pm_rootdirblk;
     203             : 
     204             :         /*
     205             :          * See if the denode is in the denode cache. Use the location of
     206             :          * the directory entry to compute the hash value. For subdir use
     207             :          * address of "." entry. For root dir (if not FAT32) use cluster
     208             :          * MSDOSFSROOT, offset MSDOSFSROOT_OFS
     209             :          *
     210             :          * NOTE: The check for de_refcnt > 0 below insures the denode being
     211             :          * examined does not represent an unlinked but still open file.
     212             :          * These files are not to be accessible even when the directory
     213             :          * entry that represented the file happens to be reused while the
     214             :          * deleted file is still open.
     215             :          */
     216             : retry:
     217           0 :         ldep = msdosfs_hashget(pmp->pm_dev, dirclust, diroffset);
     218           0 :         if (ldep) {
     219           0 :                 *depp = ldep;
     220           0 :                 return (0);
     221             :         }
     222             : 
     223             :         /*
     224             :          * Directory entry was not in cache, have to create a vnode and
     225             :          * copy it from the passed disk buffer.
     226             :          */
     227             :         /* getnewvnode() does a vref() on the vnode */
     228           0 :         error = getnewvnode(VT_MSDOSFS, pmp->pm_mountp, &msdosfs_vops, &nvp);
     229           0 :         if (error) {
     230           0 :                 *depp = 0;
     231           0 :                 return (error);
     232             :         }
     233           0 :         ldep = malloc(sizeof(*ldep), M_MSDOSFSNODE, M_WAITOK | M_ZERO);
     234           0 :         rrw_init_flags(&ldep->de_lock, "denode", RWL_DUPOK | RWL_IS_VNODE);
     235           0 :         nvp->v_data = ldep;
     236           0 :         ldep->de_vnode = nvp;
     237           0 :         ldep->de_flag = 0;
     238           0 :         ldep->de_devvp = 0;
     239           0 :         ldep->de_lockf = 0;
     240           0 :         ldep->de_dev = pmp->pm_dev;
     241           0 :         ldep->de_dirclust = dirclust;
     242           0 :         ldep->de_diroffset = diroffset;
     243           0 :         fc_purge(ldep, 0);      /* init the fat cache for this denode */
     244             : 
     245             :         /*
     246             :          * Insert the denode into the hash queue and lock the denode so it
     247             :          * can't be accessed until we've read it in and have done what we
     248             :          * need to it.
     249             :          */
     250           0 :         vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY);
     251           0 :         error = msdosfs_hashins(ldep);
     252             : 
     253           0 :         if (error) {
     254           0 :                 vput (nvp);
     255             : 
     256           0 :                 if (error == EEXIST)
     257           0 :                         goto retry;
     258             : 
     259           0 :                 return (error);
     260             :         }
     261             : 
     262           0 :         ldep->de_pmp = pmp;
     263           0 :         ldep->de_devvp = pmp->pm_devvp;
     264           0 :         ldep->de_refcnt = 1;
     265             :         /*
     266             :          * Copy the directory entry into the denode area of the vnode.
     267             :          */
     268           0 :         if ((dirclust == MSDOSFSROOT
     269           0 :              || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
     270           0 :             && diroffset == MSDOSFSROOT_OFS) {
     271             :                 /*
     272             :                  * Directory entry for the root directory. There isn't one,
     273             :                  * so we manufacture one. We should probably rummage
     274             :                  * through the root directory and find a label entry (if it
     275             :                  * exists), and then use the time and date from that entry
     276             :                  * as the time and date for the root denode.
     277             :                  */
     278           0 :                 nvp->v_flag |= VROOT; /* should be further down         XXX */
     279             : 
     280           0 :                 ldep->de_Attributes = ATTR_DIRECTORY;
     281           0 :                 if (FAT32(pmp))
     282           0 :                         ldep->de_StartCluster = pmp->pm_rootdirblk;
     283             :                         /* de_FileSize will be filled in further down */
     284             :                 else {
     285           0 :                         ldep->de_StartCluster = MSDOSFSROOT;
     286           0 :                         ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
     287             :                 }
     288             :                 /*
     289             :                  * fill in time and date so that dos2unixtime() doesn't
     290             :                  * spit up when called from msdosfs_getattr() with root
     291             :                  * denode
     292             :                  */
     293           0 :                 ldep->de_CTime = 0x0000;     /* 00:00:00      */
     294           0 :                 ldep->de_CTimeHundredth = 0;
     295           0 :                 ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
     296             :                     | (1 << DD_DAY_SHIFT);
     297             :                 /* Jan 1, 1980   */
     298           0 :                 ldep->de_ADate = ldep->de_CDate;
     299           0 :                 ldep->de_MTime = ldep->de_CTime;
     300           0 :                 ldep->de_MDate = ldep->de_CDate;
     301             :                 /* leave the other fields as garbage */
     302           0 :         } else {
     303           0 :                 error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
     304           0 :                 if (error)
     305           0 :                         return (error);
     306           0 :                 DE_INTERNALIZE(ldep, direntptr);
     307           0 :                 brelse(bp);
     308             :         }
     309             : 
     310             :         /*
     311             :          * Fill in a few fields of the vnode and finish filling in the
     312             :          * denode.  Then return the address of the found denode.
     313             :          */
     314           0 :         if (ldep->de_Attributes & ATTR_DIRECTORY) {
     315             :                 /*
     316             :                  * Since DOS directory entries that describe directories
     317             :                  * have 0 in the filesize field, we take this opportunity
     318             :                  * to find out the length of the directory and plug it into
     319             :                  * the denode structure.
     320             :                  */
     321           0 :                 uint32_t size;
     322             : 
     323           0 :                 nvp->v_type = VDIR;
     324           0 :                 if (ldep->de_StartCluster != MSDOSFSROOT) {
     325           0 :                         error = pcbmap(ldep, CLUST_END, 0, &size, 0);
     326           0 :                         if (error == E2BIG) {
     327           0 :                                 ldep->de_FileSize = de_cn2off(pmp, size);
     328             :                                 error = 0;
     329           0 :                         } else if (error) {
     330           0 :                                 printf("deget(): pcbmap returned %d\n", error);
     331           0 :                                 return (error);
     332             :                         }
     333             :                 }
     334           0 :         } else
     335           0 :                 nvp->v_type = VREG;
     336           0 :         vref(ldep->de_devvp);
     337           0 :         *depp = ldep;
     338           0 :         return (0);
     339           0 : }
     340             : 
     341             : int
     342           0 : deupdat(struct denode *dep, int waitfor)
     343             : {
     344           0 :         struct buf *bp;
     345           0 :         struct direntry *dirp;
     346             :         int error;
     347           0 :         struct timespec ts;
     348             : 
     349           0 :         if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY)
     350           0 :                 return (0);
     351           0 :         getnanotime(&ts);
     352           0 :         DETIMES(dep, &ts, &ts, &ts);
     353           0 :         if ((dep->de_flag & DE_MODIFIED) == 0)
     354           0 :                 return (0);
     355           0 :         dep->de_flag &= ~DE_MODIFIED;
     356           0 :         if (dep->de_Attributes & ATTR_DIRECTORY)
     357           0 :                 return (0);
     358           0 :         if (dep->de_refcnt <= 0)
     359           0 :                 return (0);
     360           0 :         error = readde(dep, &bp, &dirp);
     361           0 :         if (error)
     362           0 :                 return (error);
     363           0 :         DE_EXTERNALIZE(dirp, dep);
     364           0 :         if (waitfor)
     365           0 :                 return (bwrite(bp));
     366             :         else {
     367           0 :                 bdwrite(bp);
     368           0 :                 return (0);
     369             :         }
     370           0 : }
     371             : 
     372             : /*
     373             :  * Truncate the file described by dep to the length specified by length.
     374             :  */
     375             : int
     376           0 : detrunc(struct denode *dep, uint32_t length, int flags, struct ucred *cred,
     377             :     struct proc *p)
     378             : {
     379             :         int error;
     380             :         int allerror;
     381             :         int vflags;
     382           0 :         uint32_t eofentry;
     383           0 :         uint32_t chaintofree = 0;
     384             :         daddr_t bn;
     385             :         int boff;
     386           0 :         int isadir = dep->de_Attributes & ATTR_DIRECTORY;
     387           0 :         struct buf *bp;
     388           0 :         struct msdosfsmount *pmp = dep->de_pmp;
     389             : 
     390             : #ifdef MSDOSFS_DEBUG
     391             :         printf("detrunc(): file %.11s, length %u, flags %d\n",
     392             :             dep->de_Name, length, flags);
     393             : #endif
     394             : 
     395             :         /*
     396             :          * Disallow attempts to truncate the root directory since it is of
     397             :          * fixed size.  That's just the way dos filesystems are.  We use
     398             :          * the VROOT bit in the vnode because checking for the directory
     399             :          * bit and a startcluster of 0 in the denode is not adequate to
     400             :          * recognize the root directory at this point in a file or
     401             :          * directory's life.
     402             :          */
     403           0 :         if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp)) {
     404           0 :                 printf("detrunc(): can't truncate root directory, clust %u, offset %u\n",
     405           0 :                     dep->de_dirclust, dep->de_diroffset);
     406           0 :                 return (EINVAL);
     407             :         }
     408             : 
     409           0 :         uvm_vnp_setsize(DETOV(dep), length);
     410             : 
     411           0 :         if (dep->de_FileSize < length)
     412           0 :                 return (deextend(dep, length, cred));
     413             : 
     414             :         /*
     415             :          * If the desired length is 0 then remember the starting cluster of
     416             :          * the file and set the StartCluster field in the directory entry
     417             :          * to 0.  If the desired length is not zero, then get the number of
     418             :          * the last cluster in the shortened file.  Then get the number of
     419             :          * the first cluster in the part of the file that is to be freed.
     420             :          * Then set the next cluster pointer in the last cluster of the
     421             :          * file to CLUST_EOFE.
     422             :          */
     423           0 :         if (length == 0) {
     424           0 :                 chaintofree = dep->de_StartCluster;
     425           0 :                 dep->de_StartCluster = 0;
     426           0 :                 eofentry = ~0;
     427           0 :         } else {
     428           0 :                 error = pcbmap(dep, de_clcount(pmp, length) - 1, 0,
     429             :                                &eofentry, 0);
     430           0 :                 if (error) {
     431             : #ifdef MSDOSFS_DEBUG
     432             :                         printf("detrunc(): pcbmap fails %d\n", error);
     433             : #endif
     434           0 :                         return (error);
     435             :                 }
     436             :         }
     437             : 
     438           0 :         fc_purge(dep, de_clcount(pmp, length));
     439             : 
     440             :         /*
     441             :          * If the new length is not a multiple of the cluster size then we
     442             :          * must zero the tail end of the new last cluster in case it
     443             :          * becomes part of the file again because of a seek.
     444             :          */
     445           0 :         if ((boff = length & pmp->pm_crbomask) != 0) {
     446           0 :                 if (isadir) {
     447           0 :                         bn = cntobn(pmp, eofentry);
     448           0 :                         error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, &bp);
     449           0 :                 } else {
     450           0 :                         bn = de_blk(pmp, length);
     451           0 :                         error = bread(DETOV(dep), bn, pmp->pm_bpcluster, &bp);
     452             :                 }
     453           0 :                 if (error) {
     454           0 :                         brelse(bp);
     455             : #ifdef MSDOSFS_DEBUG
     456             :                         printf("detrunc(): bread fails %d\n", error);
     457             : #endif
     458           0 :                         return (error);
     459             :                 }
     460           0 :                 uvm_vnp_uncache(DETOV(dep));
     461             :                 /*
     462             :                  * is this the right place for it?
     463             :                  */
     464           0 :                 bzero(bp->b_data + boff, pmp->pm_bpcluster - boff);
     465           0 :                 if (flags & IO_SYNC)
     466           0 :                         bwrite(bp);
     467             :                 else
     468           0 :                         bdwrite(bp);
     469             :         }
     470             : 
     471             :         /*
     472             :          * Write out the updated directory entry.  Even if the update fails
     473             :          * we free the trailing clusters.
     474             :          */
     475           0 :         dep->de_FileSize = length;
     476           0 :         if (!isadir)
     477           0 :                 dep->de_flag |= DE_UPDATE|DE_MODIFIED;
     478           0 :         vflags = (length > 0 ? V_SAVE : 0) | V_SAVEMETA;
     479           0 :         vinvalbuf(DETOV(dep), vflags, cred, p, 0, 0);
     480           0 :         allerror = deupdat(dep, 1);
     481             : #ifdef MSDOSFS_DEBUG
     482             :         printf("detrunc(): allerror %d, eofentry %d\n",
     483             :                allerror, eofentry);
     484             : #endif
     485             : 
     486             :         /*
     487             :          * If we need to break the cluster chain for the file then do it
     488             :          * now.
     489             :          */
     490           0 :         if (eofentry != ~0) {
     491           0 :                 error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
     492             :                                  &chaintofree, CLUST_EOFE);
     493           0 :                 if (error) {
     494             : #ifdef MSDOSFS_DEBUG
     495             :                         printf("detrunc(): fatentry errors %d\n", error);
     496             : #endif
     497           0 :                         return (error);
     498             :                 }
     499           0 :                 fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
     500             :                             eofentry);
     501           0 :         }
     502             : 
     503             :         /*
     504             :          * Now free the clusters removed from the file because of the
     505             :          * truncation.
     506             :          */
     507           0 :         if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
     508           0 :                 freeclusterchain(pmp, chaintofree);
     509             : 
     510           0 :         return (allerror);
     511           0 : }
     512             : 
     513             : /*
     514             :  * Extend the file described by dep to length specified by length.
     515             :  */
     516             : int
     517           0 : deextend(struct denode *dep, uint32_t length, struct ucred *cred)
     518             : {
     519           0 :         struct msdosfsmount *pmp = dep->de_pmp;
     520             :         uint32_t count;
     521             :         int error;
     522             : 
     523             :         /*
     524             :          * The root of a DOS filesystem cannot be extended.
     525             :          */
     526           0 :         if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
     527           0 :                 return (EINVAL);
     528             : 
     529             :         /*
     530             :          * Directories cannot be extended.
     531             :          */
     532           0 :         if (dep->de_Attributes & ATTR_DIRECTORY)
     533           0 :                 return (EISDIR);
     534             : 
     535           0 :         if (length <= dep->de_FileSize)
     536           0 :                 panic("deextend: file too large");
     537             : 
     538             :         /*
     539             :          * Compute the number of clusters to allocate.
     540             :          */
     541           0 :         count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
     542           0 :         if (count > 0) {
     543           0 :                 if (count > pmp->pm_freeclustercount)
     544           0 :                         return (ENOSPC);
     545           0 :                 error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
     546           0 :                 if (error) {
     547             :                         /* truncate the added clusters away again */
     548           0 :                         (void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
     549           0 :                         return (error);
     550             :                 }
     551             :         }
     552             : 
     553           0 :         dep->de_FileSize = length;
     554           0 :         dep->de_flag |= DE_UPDATE|DE_MODIFIED;
     555           0 :         return (deupdat(dep, 1));
     556           0 : }
     557             : 
     558             : /*
     559             :  * Move a denode to its correct hash queue after the file it represents has
     560             :  * been moved to a new directory.
     561             :  */
     562             : void
     563           0 : reinsert(struct denode *dep)
     564             : {
     565             :         /*
     566             :          * Fix up the denode cache.  If the denode is for a directory,
     567             :          * there is nothing to do since the hash is based on the starting
     568             :          * cluster of the directory file and that hasn't changed.  If for a
     569             :          * file the hash is based on the location of the directory entry,
     570             :          * so we must remove it from the cache and re-enter it with the
     571             :          * hash based on the new location of the directory entry.
     572             :          */
     573           0 :         if (dep->de_Attributes & ATTR_DIRECTORY)
     574             :                 return;
     575           0 :         msdosfs_hashrem(dep);
     576           0 :         msdosfs_hashins(dep);
     577           0 : }
     578             : 
     579             : int
     580           0 : msdosfs_reclaim(void *v)
     581             : {
     582           0 :         struct vop_reclaim_args *ap = v;
     583           0 :         struct vnode *vp = ap->a_vp;
     584           0 :         struct denode *dep = VTODE(vp);
     585             : #ifdef DIAGNOSTIC
     586             :         extern int prtactive;
     587             : 
     588           0 :         if (prtactive && vp->v_usecount != 0)
     589           0 :                 vprint("msdosfs_reclaim(): pushing active", vp);
     590             : #endif
     591             : 
     592             : #ifdef MSDOSFS_DEBUG
     593             :         printf("msdosfs_reclaim(): dep %p, file %.11s, refcnt %ld\n",
     594             :             dep, dep->de_Name, dep->de_refcnt);
     595             : #endif
     596             : 
     597             :         /*
     598             :          * Remove the denode from its hash chain.
     599             :          */
     600           0 :         msdosfs_hashrem(dep);
     601             :         /*
     602             :          * Purge old data structures associated with the denode.
     603             :          */
     604           0 :         cache_purge(vp);
     605           0 :         if (dep->de_devvp) {
     606           0 :                 vrele(dep->de_devvp);
     607           0 :                 dep->de_devvp = 0;
     608           0 :         }
     609             : #if 0 /* XXX */
     610             :         dep->de_flag = 0;
     611             : #endif
     612           0 :         free(dep, M_MSDOSFSNODE, 0);
     613           0 :         vp->v_data = NULL;
     614           0 :         return (0);
     615             : }
     616             : 
     617             : int
     618           0 : msdosfs_inactive(void *v)
     619             : {
     620           0 :         struct vop_inactive_args *ap = v;
     621           0 :         struct vnode *vp = ap->a_vp;
     622           0 :         struct denode *dep = VTODE(vp);
     623           0 :         struct proc *p = ap->a_p;
     624             :         int error;
     625             : #ifdef DIAGNOSTIC
     626             :         extern int prtactive;
     627             : 
     628           0 :         if (prtactive && vp->v_usecount != 0)
     629           0 :                 vprint("msdosfs_inactive(): pushing active", vp);
     630             : #endif
     631             : 
     632             : #ifdef MSDOSFS_DEBUG
     633             :         printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep,
     634             :             dep->de_Name[0]);
     635             : #endif
     636             : 
     637             :         error = 0;
     638             : 
     639             :         /*
     640             :          * Get rid of denodes related to stale file handles.
     641             :          */
     642           0 :         if (dep->de_Name[0] == SLOT_DELETED)
     643             :                 goto out;
     644             : 
     645             :         /*
     646             :          * If the file has been deleted and it is on a read/write
     647             :          * filesystem, then truncate the file, and mark the directory slot
     648             :          * as empty.  (This may not be necessary for the dos filesystem.)
     649             :          */
     650             : #ifdef MSDOSFS_DEBUG
     651             :         printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x, "
     652             :             "MNT_RDONLY %x\n", dep, dep->de_refcnt, vp->v_mount->mnt_flag,
     653             :             MNT_RDONLY);
     654             : #endif
     655           0 :         if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
     656           0 :                 error = detrunc(dep, (uint32_t)0, 0, NOCRED, NULL);
     657           0 :                 dep->de_Name[0] = SLOT_DELETED;
     658           0 :         }
     659           0 :         deupdat(dep, 0);
     660             : 
     661             : out:
     662           0 :         VOP_UNLOCK(vp);
     663             :         /*
     664             :          * If we are done with the denode, reclaim it
     665             :          * so that it can be reused immediately.
     666             :          */
     667             : #ifdef MSDOSFS_DEBUG
     668             :         printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n",
     669             :             vp->v_usecount, dep->de_Name[0]);
     670             : #endif
     671           0 :         if (dep->de_Name[0] == SLOT_DELETED)
     672           0 :                 vrecycle(vp, p);
     673           0 :         return (error);
     674             : }

Generated by: LCOV version 1.13