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

          Line data    Source code
       1             : /*      $OpenBSD: ext2fs_readwrite.c,v 1.44 2018/01/13 15:57:58 millert Exp $   */
       2             : /*      $NetBSD: ext2fs_readwrite.c,v 1.16 2001/02/27 04:37:47 chs Exp $        */
       3             : 
       4             : /*-
       5             :  * Copyright (c) 1997 Manuel Bouyer.
       6             :  * Copyright (c) 1993
       7             :  *      The Regents of the University of California.  All rights reserved.
       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. Neither the name of the University nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  *
      33             :  *      @(#)ufs_readwrite.c     8.8 (Berkeley) 8/4/94
      34             :  * Modified for ext2fs by Manuel Bouyer.
      35             :  */
      36             : 
      37             : #include <sys/param.h>
      38             : #include <sys/systm.h>
      39             : #include <sys/resourcevar.h>
      40             : #include <sys/kernel.h>
      41             : #include <sys/stat.h>
      42             : #include <sys/buf.h>
      43             : #include <sys/mount.h>
      44             : #include <sys/vnode.h>
      45             : #include <sys/malloc.h>
      46             : #include <sys/signalvar.h>
      47             : #include <sys/event.h>
      48             : 
      49             : #include <ufs/ufs/quota.h>
      50             : #include <ufs/ufs/ufsmount.h>
      51             : #include <ufs/ufs/inode.h>
      52             : #include <ufs/ext2fs/ext2fs.h>
      53             : #include <ufs/ext2fs/ext2fs_extern.h>
      54             : 
      55             : 
      56             : static int      ext2_ind_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *);
      57             : static int      ext4_ext_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *);
      58             : 
      59             : /*
      60             :  * Vnode op for reading.
      61             :  */
      62             : /* ARGSUSED */
      63             : int
      64           0 : ext2fs_read(void *v)
      65             : {
      66           0 :         struct vop_read_args *ap = v;
      67             :         struct vnode *vp;
      68             :         struct inode *ip;
      69             :         struct uio *uio;
      70             :         struct m_ext2fs *fs;
      71             : 
      72           0 :         vp = ap->a_vp;
      73           0 :         ip = VTOI(vp);
      74           0 :         uio = ap->a_uio;
      75           0 :         fs = ip->i_e2fs;
      76             : 
      77           0 :         if (ip->i_e2fs_flags & EXT4_EXTENTS)
      78           0 :                 return ext4_ext_read(vp, ip, fs, uio);
      79             :         else
      80           0 :                 return ext2_ind_read(vp, ip, fs, uio);
      81           0 : }
      82             : 
      83             : static int
      84           0 : ext2_ind_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs,
      85             :     struct uio *uio)
      86             : {
      87           0 :         struct buf *bp;
      88           0 :         daddr_t lbn, nextlbn;
      89             :         off_t bytesinfile;
      90             :         int size, xfersize, blkoffset;
      91             :         int error;
      92             : 
      93             : #ifdef DIAGNOSTIC
      94           0 :         if (uio->uio_rw != UIO_READ)
      95           0 :                 panic("%s: mode", "ext2fs_read");
      96             : 
      97           0 :         if (vp->v_type == VLNK) {
      98           0 :                 if (ext2fs_size(ip) < EXT2_MAXSYMLINKLEN)
      99           0 :                         panic("%s: short symlink", "ext2fs_read");
     100           0 :         } else if (vp->v_type != VREG && vp->v_type != VDIR)
     101           0 :                 panic("%s: type %d", "ext2fs_read", vp->v_type);
     102             : #endif
     103           0 :         if (uio->uio_offset < 0)
     104           0 :                 return (EINVAL);
     105           0 :         if (uio->uio_resid == 0)
     106           0 :                 return (0);
     107             : 
     108           0 :         for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
     109           0 :                 if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0)
     110             :                         break;
     111           0 :                 lbn = lblkno(fs, uio->uio_offset);
     112           0 :                 nextlbn = lbn + 1;
     113           0 :                 size = fs->e2fs_bsize;
     114           0 :                 blkoffset = blkoff(fs, uio->uio_offset);
     115           0 :                 xfersize = fs->e2fs_bsize - blkoffset;
     116           0 :                 if (uio->uio_resid < xfersize)
     117           0 :                         xfersize = uio->uio_resid;
     118           0 :                 if (bytesinfile < xfersize)
     119           0 :                         xfersize = bytesinfile;
     120             : 
     121           0 :                 if (lblktosize(fs, nextlbn) >= ext2fs_size(ip))
     122           0 :                         error = bread(vp, lbn, size, &bp);
     123           0 :                 else if (lbn - 1 == ip->i_ci.ci_lastr) {
     124           0 :                         int nextsize = fs->e2fs_bsize;
     125           0 :                         error = breadn(vp, lbn, size, &nextlbn, &nextsize,
     126             :                             1, &bp);
     127           0 :                 } else
     128           0 :                         error = bread(vp, lbn, size, &bp);
     129           0 :                 if (error)
     130             :                         break;
     131           0 :                 ip->i_ci.ci_lastr = lbn;
     132             : 
     133             :                 /*
     134             :                  * We should only get non-zero b_resid when an I/O error
     135             :                  * has occurred, which should cause us to break above.
     136             :                  * However, if the short read did not cause an error,
     137             :                  * then we want to ensure that we do not uiomove bad
     138             :                  * or uninitialized data.
     139             :                  */
     140           0 :                 size -= bp->b_resid;
     141           0 :                 if (size < xfersize) {
     142           0 :                         if (size == 0)
     143             :                                 break;
     144             :                         xfersize = size;
     145           0 :                 }
     146           0 :                 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
     147           0 :                 if (error)
     148             :                         break;
     149           0 :                 brelse(bp);
     150             :         }
     151           0 :         if (bp != NULL)
     152           0 :                 brelse(bp);
     153             : 
     154           0 :         if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
     155           0 :                 ip->i_flag |= IN_ACCESS;
     156           0 :         }
     157           0 :         return (error);
     158           0 : }
     159             : 
     160             : int
     161           0 : ext4_ext_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs, struct uio *uio)
     162             : {
     163           0 :         struct ext4_extent_path path;
     164           0 :         struct ext4_extent nex, *ep;
     165           0 :         struct buf *bp;
     166             :         daddr_t lbn, pos;
     167             :         off_t bytesinfile;
     168             :         int size, xfersize, blkoffset;
     169             :         int error, cache_type;
     170             : 
     171           0 :         memset(&path, 0, sizeof path);
     172             : 
     173           0 :         if (uio->uio_offset < 0)
     174           0 :                 return (EINVAL);
     175           0 :         if (uio->uio_resid == 0)
     176           0 :                 return (0);
     177             : 
     178           0 :         while (uio->uio_resid > 0) {
     179           0 :                 if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0)
     180             :                         break;
     181           0 :                 lbn = lblkno(fs, uio->uio_offset);
     182           0 :                 size = fs->e2fs_bsize;
     183           0 :                 blkoffset = blkoff(fs, uio->uio_offset);
     184             : 
     185           0 :                 xfersize = fs->e2fs_fsize - blkoffset;
     186           0 :                 xfersize = MIN(xfersize, uio->uio_resid);
     187           0 :                 xfersize = MIN(xfersize, bytesinfile);
     188             : 
     189           0 :                 cache_type = ext4_ext_in_cache(ip, lbn, &nex);
     190           0 :                 switch (cache_type) {
     191             :                 case EXT4_EXT_CACHE_NO:
     192           0 :                         ext4_ext_find_extent(fs, ip, lbn, &path);
     193           0 :                         if ((ep = path.ep_ext) == NULL)
     194           0 :                                 return (EIO);
     195           0 :                         ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN);
     196             : 
     197           0 :                         pos = lbn - ep->e_blk + (((daddr_t) ep->e_start_hi << 32) | ep->e_start_lo);
     198           0 :                         if (path.ep_bp != NULL) {
     199           0 :                                 brelse(path.ep_bp);
     200           0 :                                 path.ep_bp = NULL;
     201           0 :                         }
     202             :                         break;
     203             :                 case EXT4_EXT_CACHE_GAP:
     204             :                         /* block has not been allocated yet */
     205           0 :                         return (0);
     206             :                 case EXT4_EXT_CACHE_IN:
     207           0 :                         pos = lbn - nex.e_blk + (((daddr_t) nex.e_start_hi << 32) | nex.e_start_lo);
     208           0 :                         break;
     209             :                 }
     210           0 :                 error = bread(ip->i_devvp, fsbtodb(fs, pos), size, &bp);
     211           0 :                 if (error) {
     212           0 :                         brelse(bp);
     213           0 :                         return (error);
     214             :                 }
     215           0 :                 size -= bp->b_resid;
     216           0 :                 if (size < xfersize) {
     217           0 :                         if (size == 0) {
     218           0 :                                 brelse(bp);
     219           0 :                                 break;
     220             :                         }
     221             :                         xfersize = size;
     222           0 :                 }
     223           0 :                 error = uiomove(bp->b_data + blkoffset, xfersize, uio);
     224           0 :                 brelse(bp);
     225           0 :                 if (error)
     226           0 :                         return (error);
     227             :         }
     228           0 :         return (0);
     229           0 : }
     230             : 
     231             : /*
     232             :  * Vnode op for writing.
     233             :  */
     234             : int
     235           0 : ext2fs_write(void *v)
     236             : {
     237           0 :         struct vop_write_args *ap = v;
     238             :         struct vnode *vp;
     239             :         struct uio *uio;
     240             :         struct inode *ip;
     241             :         struct m_ext2fs *fs;
     242           0 :         struct buf *bp;
     243             :         int32_t lbn;
     244             :         off_t osize;
     245             :         int blkoffset, error, extended, flags, ioflag, size, xfersize;
     246             :         size_t resid;
     247           0 :         ssize_t overrun;
     248             : 
     249             :         extended = 0;
     250           0 :         ioflag = ap->a_ioflag;
     251           0 :         uio = ap->a_uio;
     252           0 :         vp = ap->a_vp;
     253           0 :         ip = VTOI(vp);
     254             : 
     255             : #ifdef DIAGNOSTIC
     256           0 :         if (uio->uio_rw != UIO_WRITE)
     257           0 :                 panic("%s: mode", "ext2fs_write");
     258             : #endif
     259             : 
     260             :         /*
     261             :          * If writing 0 bytes, succeed and do not change
     262             :          * update time or file offset (standards compliance)
     263             :          */
     264           0 :         if (uio->uio_resid == 0)
     265           0 :                 return (0);
     266             : 
     267           0 :         switch (vp->v_type) {
     268             :         case VREG:
     269           0 :                 if (ioflag & IO_APPEND)
     270           0 :                         uio->uio_offset = ext2fs_size(ip);
     271           0 :                 if ((ip->i_e2fs_flags & EXT2_APPEND) &&
     272           0 :                         uio->uio_offset != ext2fs_size(ip))
     273           0 :                         return (EPERM);
     274             :                 /* FALLTHROUGH */
     275             :         case VLNK:
     276             :                 break;
     277             :         case VDIR:
     278           0 :                 if ((ioflag & IO_SYNC) == 0)
     279           0 :                         panic("%s: nonsync dir write", "ext2fs_write");
     280             :                 break;
     281             :         default:
     282           0 :                 panic("%s: type", "ext2fs_write");
     283             :         }
     284             : 
     285           0 :         fs = ip->i_e2fs;
     286           0 :         if (e2fs_overflow(fs, uio->uio_resid, uio->uio_offset + uio->uio_resid))
     287           0 :                 return (EFBIG);
     288             : 
     289             :         /* do the filesize rlimit check */
     290           0 :         if ((error = vn_fsizechk(vp, uio, ioflag, &overrun)))
     291           0 :                 return (error);
     292             : 
     293           0 :         resid = uio->uio_resid;
     294           0 :         osize = ext2fs_size(ip);
     295           0 :         flags = ioflag & IO_SYNC ? B_SYNC : 0;
     296             : 
     297           0 :         for (error = 0; uio->uio_resid > 0;) {
     298           0 :                 lbn = lblkno(fs, uio->uio_offset);
     299           0 :                 blkoffset = blkoff(fs, uio->uio_offset);
     300           0 :                 xfersize = fs->e2fs_bsize - blkoffset;
     301           0 :                 if (uio->uio_resid < xfersize)
     302           0 :                         xfersize = uio->uio_resid;
     303           0 :                 if (fs->e2fs_bsize > xfersize)
     304           0 :                         flags |= B_CLRBUF;
     305             :                 else
     306           0 :                         flags &= ~B_CLRBUF;
     307             : 
     308           0 :                 error = ext2fs_buf_alloc(ip,
     309           0 :                         lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
     310           0 :                 if (error)
     311             :                         break;
     312           0 :                 if (uio->uio_offset + xfersize > ext2fs_size(ip)) {
     313           0 :                         error = ext2fs_setsize(ip, uio->uio_offset + xfersize);
     314           0 :                         if (error)
     315             :                                 break;
     316           0 :                         uvm_vnp_setsize(vp, ext2fs_size(ip));
     317             :                         extended = 1;
     318           0 :                 }
     319           0 :                 uvm_vnp_uncache(vp);
     320             : 
     321           0 :                 size = fs->e2fs_bsize - bp->b_resid;
     322           0 :                 if (size < xfersize)
     323           0 :                         xfersize = size;
     324             : 
     325           0 :                 error = uiomove(bp->b_data + blkoffset, xfersize, uio);
     326             :                 /*
     327             :                  * If the buffer is not already filled and we encounter an
     328             :                  * error while trying to fill it, we have to clear out any
     329             :                  * garbage data from the pages instantiated for the buffer.
     330             :                  * If we do not, a failed uiomove() during a write can leave
     331             :                  * the prior contents of the pages exposed to a userland mmap.
     332             :                  *
     333             :                  * Note that we don't need to clear buffers that were
     334             :                  * allocated with the B_CLRBUF flag set.
     335             :                  */
     336           0 :                 if (error != 0 && !(flags & B_CLRBUF))
     337           0 :                         memset(bp->b_data + blkoffset, 0, xfersize);
     338             : #if 0
     339             :                 if (ioflag & IO_NOCACHE)
     340             :                         bp->b_flags |= B_NOCACHE;
     341             : #endif
     342           0 :                 if (ioflag & IO_SYNC)
     343           0 :                         (void)bwrite(bp);
     344           0 :                 else if (xfersize + blkoffset == fs->e2fs_bsize)
     345           0 :                         bawrite(bp);
     346             :                 else
     347           0 :                         bdwrite(bp);
     348           0 :                 if (error || xfersize == 0)
     349             :                         break;
     350           0 :                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
     351             :         }
     352             :         /*
     353             :          * If we successfully wrote any data, and we are not the superuser
     354             :          * we clear the setuid and setgid bits as a precaution against
     355             :          * tampering.
     356             :          */
     357           0 :         if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
     358           0 :                 ip->i_e2fs_mode &= ~(ISUID | ISGID);
     359           0 :         if (resid > uio->uio_resid)
     360           0 :                 VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
     361           0 :         if (error) {
     362           0 :                 if (ioflag & IO_UNIT) {
     363           0 :                         (void)ext2fs_truncate(ip, osize,
     364           0 :                                 ioflag & IO_SYNC, ap->a_cred);
     365           0 :                         uio->uio_offset -= resid - uio->uio_resid;
     366           0 :                         uio->uio_resid = resid;
     367           0 :                 }
     368           0 :         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
     369           0 :                 error = ext2fs_update(ip, 1);
     370           0 :         }
     371             :         /* correct the result for writes clamped by vn_fsizechk() */
     372           0 :         uio->uio_resid += overrun;
     373           0 :         return (error);
     374           0 : }

Generated by: LCOV version 1.13