[BACK]Return to ext2fs_readwrite.c CVS log [TXT][DIR] Up to [local] / sys / ufs / ext2fs

Annotation of sys/ufs/ext2fs/ext2fs_readwrite.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb