root/ufs/ext2fs/ext2fs_readwrite.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ext2fs_read
  2. ext2fs_write

    1 /*      $OpenBSD: ext2fs_readwrite.c,v 1.22 2007/06/17 20:15:25 jasper 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/file.h>
   42 #include <sys/stat.h>
   43 #include <sys/buf.h>
   44 #include <sys/proc.h>
   45 #include <sys/conf.h>
   46 #include <sys/mount.h>
   47 #include <sys/vnode.h>
   48 #include <sys/malloc.h>
   49 #include <sys/signalvar.h>
   50 
   51 #include <ufs/ufs/quota.h>
   52 #include <ufs/ufs/inode.h>
   53 #include <ufs/ext2fs/ext2fs.h>
   54 #include <ufs/ext2fs/ext2fs_extern.h>
   55 
   56 
   57 #define doclusterread 0 /* XXX underway */
   58 #define doclusterwrite 0
   59 
   60 /*
   61  * Vnode op for reading.
   62  */
   63 /* ARGSUSED */
   64 int
   65 ext2fs_read(void *v)
   66 {
   67         struct vop_read_args *ap = v;
   68         struct vnode *vp;
   69         struct inode *ip;
   70         struct uio *uio;
   71         struct m_ext2fs *fs;
   72         struct buf *bp;
   73         daddr64_t lbn, nextlbn;
   74         off_t bytesinfile;
   75         long size, xfersize, blkoffset;
   76         int error;
   77 
   78         vp = ap->a_vp;
   79         ip = VTOI(vp);
   80         uio = ap->a_uio;
   81 
   82 #ifdef DIAGNOSTIC
   83         if (uio->uio_rw != UIO_READ)
   84                 panic("%s: mode", "ext2fs_read");
   85 
   86         if (vp->v_type == VLNK) {
   87                 if ((int)ext2fs_size(ip) < vp->v_mount->mnt_maxsymlinklen ||
   88                         (vp->v_mount->mnt_maxsymlinklen == 0 &&
   89                          ip->i_e2fs_nblock == 0))
   90                         panic("%s: short symlink", "ext2fs_read");
   91         } else if (vp->v_type != VREG && vp->v_type != VDIR)
   92                 panic("%s: type %d", "ext2fs_read", vp->v_type);
   93 #endif
   94         fs = ip->i_e2fs;
   95         if ((u_int64_t)uio->uio_offset >
   96                 ((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
   97                 return (EFBIG);
   98         if (uio->uio_resid == 0)
   99                 return (0);
  100 
  101         for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
  102                 if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0)
  103                         break;
  104                 lbn = lblkno(fs, uio->uio_offset);
  105                 nextlbn = lbn + 1;
  106                 size = fs->e2fs_bsize;
  107                 blkoffset = blkoff(fs, uio->uio_offset);
  108                 xfersize = fs->e2fs_bsize - blkoffset;
  109                 if (uio->uio_resid < xfersize)
  110                         xfersize = uio->uio_resid;
  111                 if (bytesinfile < xfersize)
  112                         xfersize = bytesinfile;
  113 
  114                 if (lblktosize(fs, nextlbn) >= ext2fs_size(ip))
  115                         error = bread(vp, lbn, size, NOCRED, &bp);
  116                 else if (lbn - 1 == ip->i_ci.ci_lastr) {
  117                         int nextsize = fs->e2fs_bsize;
  118                         error = breadn(vp, lbn,
  119                                 size, &nextlbn, &nextsize, 1, NOCRED, &bp);
  120                 } else
  121                         error = bread(vp, lbn, size, NOCRED, &bp);
  122                 if (error)
  123                         break;
  124                 ip->i_ci.ci_lastr = lbn;
  125 
  126                 /*
  127                  * We should only get non-zero b_resid when an I/O error
  128                  * has occurred, which should cause us to break above.
  129                  * However, if the short read did not cause an error,
  130                  * then we want to ensure that we do not uiomove bad
  131                  * or uninitialized data.
  132                  */
  133                 size -= bp->b_resid;
  134                 if (size < xfersize) {
  135                         if (size == 0)
  136                                 break;
  137                         xfersize = size;
  138                 }
  139                 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
  140                 if (error)
  141                         break;
  142                 brelse(bp);
  143         }
  144         if (bp != NULL)
  145                 brelse(bp);
  146 
  147         if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
  148                 ip->i_flag |= IN_ACCESS;
  149         }
  150         return (error);
  151 }
  152 
  153 /*
  154  * Vnode op for writing.
  155  */
  156 int
  157 ext2fs_write(void *v)
  158 {
  159         struct vop_write_args *ap = v;
  160         struct vnode *vp;
  161         struct uio *uio;
  162         struct inode *ip;
  163         struct m_ext2fs *fs;
  164         struct buf *bp;
  165         struct proc *p;
  166         int32_t lbn;
  167         off_t osize;
  168         int blkoffset, error, flags, ioflag, resid, size, xfersize;
  169 
  170         ioflag = ap->a_ioflag;
  171         uio = ap->a_uio;
  172         vp = ap->a_vp;
  173         ip = VTOI(vp);
  174 
  175 #ifdef DIAGNOSTIC
  176         if (uio->uio_rw != UIO_WRITE)
  177                 panic("%s: mode", "ext2fs_write");
  178 #endif
  179 
  180         /*
  181          * If writing 0 bytes, succeed and do not change
  182          * update time or file offset (standards compliance)
  183          */
  184         if (uio->uio_resid == 0)
  185                 return (0);
  186 
  187         switch (vp->v_type) {
  188         case VREG:
  189                 if (ioflag & IO_APPEND)
  190                         uio->uio_offset = ext2fs_size(ip);
  191                 if ((ip->i_e2fs_flags & EXT2_APPEND) &&
  192                         uio->uio_offset != ext2fs_size(ip))
  193                         return (EPERM);
  194                 /* FALLTHROUGH */
  195         case VLNK:
  196                 break;
  197         case VDIR:
  198                 if ((ioflag & IO_SYNC) == 0)
  199                         panic("%s: nonsync dir write", "ext2fs_write");
  200                 break;
  201         default:
  202                 panic("%s: type", "ext2fs_write");
  203         }
  204 
  205         fs = ip->i_e2fs;
  206         if (uio->uio_offset < 0 ||
  207                 (u_int64_t)uio->uio_offset + uio->uio_resid >
  208                 ((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
  209                 return (EFBIG);
  210         /*
  211          * Maybe this should be above the vnode op call, but so long as
  212          * file servers have no limits, I don't think it matters.
  213          */
  214         p = uio->uio_procp;
  215         if (vp->v_type == VREG && p &&
  216                 uio->uio_offset + uio->uio_resid >
  217                 p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  218                 psignal(p, SIGXFSZ);
  219                 return (EFBIG);
  220         }
  221 
  222         resid = uio->uio_resid;
  223         osize = ext2fs_size(ip);
  224         flags = ioflag & IO_SYNC ? B_SYNC : 0;
  225 
  226         for (error = 0; uio->uio_resid > 0;) {
  227                 lbn = lblkno(fs, uio->uio_offset);
  228                 blkoffset = blkoff(fs, uio->uio_offset);
  229                 xfersize = fs->e2fs_bsize - blkoffset;
  230                 if (uio->uio_resid < xfersize)
  231                         xfersize = uio->uio_resid;
  232                 if (fs->e2fs_bsize > xfersize)
  233                         flags |= B_CLRBUF;
  234                 else
  235                         flags &= ~B_CLRBUF;
  236 
  237                 error = ext2fs_buf_alloc(ip,
  238                         lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
  239                 if (error)
  240                         break;
  241                 if (uio->uio_offset + xfersize > ext2fs_size(ip)) {
  242                         error = ext2fs_setsize(ip, uio->uio_offset + xfersize);
  243                         if (error)
  244                                 break;
  245                         uvm_vnp_setsize(vp, ip->i_e2fs_size);
  246                 }
  247                 uvm_vnp_uncache(vp);
  248 
  249                 size = fs->e2fs_bsize - bp->b_resid;
  250                 if (size < xfersize)
  251                         xfersize = size;
  252 
  253                 error =
  254                         uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
  255                 if (ioflag & IO_SYNC)
  256                         (void)bwrite(bp);
  257                 else if (xfersize + blkoffset == fs->e2fs_bsize) {
  258                         if (doclusterwrite)
  259                                 cluster_write(bp, &ip->i_ci, ext2fs_size(ip));
  260                         else
  261                                 bawrite(bp);
  262                 } else
  263                         bdwrite(bp);
  264                 if (error || xfersize == 0)
  265                         break;
  266                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  267         }
  268         /*
  269          * If we successfully wrote any data, and we are not the superuser
  270          * we clear the setuid and setgid bits as a precaution against
  271          * tampering.
  272          */
  273         if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
  274                 ip->i_e2fs_mode &= ~(ISUID | ISGID);
  275         if (error) {
  276                 if (ioflag & IO_UNIT) {
  277                         (void)ext2fs_truncate(ip, osize,
  278                                 ioflag & IO_SYNC, ap->a_cred);
  279                         uio->uio_offset -= resid - uio->uio_resid;
  280                         uio->uio_resid = resid;
  281                 }
  282         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
  283                 error = ext2fs_update(ip, NULL, NULL, 1);
  284         }
  285         return (error);
  286 }

/* [<][>][^][v][top][bottom][index][help] */