[BACK]Return to linux_file64.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / compat / linux / common

Annotation of src/sys/compat/linux/common/linux_file64.c, Revision 1.28.2.4

1.28.2.4! yamt        1: /*     $NetBSD: linux_file64.c,v 1.28.2.3 2007/02/26 09:09:19 yamt Exp $       */
1.1       jdolecek    2:
                      3: /*-
                      4:  * Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Frank van der Linden and Eric Haszlakiewicz.
                      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 the NetBSD
                     21:  *     Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
                     38:
                     39: /*
                     40:  * Linux 64bit filesystem calls. Used on 32bit archs, not used on 64bit ones.
                     41:  */
1.6       lukem      42:
                     43: #include <sys/cdefs.h>
1.28.2.4! yamt       44: __KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.28.2.3 2007/02/26 09:09:19 yamt Exp $");
1.1       jdolecek   45:
                     46: #include <sys/param.h>
                     47: #include <sys/systm.h>
                     48: #include <sys/namei.h>
                     49: #include <sys/proc.h>
1.11      tron       50: #include <sys/dirent.h>
1.1       jdolecek   51: #include <sys/file.h>
                     52: #include <sys/stat.h>
                     53: #include <sys/filedesc.h>
                     54: #include <sys/ioctl.h>
                     55: #include <sys/kernel.h>
                     56: #include <sys/mount.h>
                     57: #include <sys/malloc.h>
1.28.2.4! yamt       58: #include <sys/namei.h>
        !            59: #include <sys/vfs_syscalls.h>
1.1       jdolecek   60: #include <sys/vnode.h>
                     61: #include <sys/tty.h>
                     62: #include <sys/conf.h>
                     63:
                     64: #include <sys/syscallargs.h>
                     65:
                     66: #include <compat/linux/common/linux_types.h>
                     67: #include <compat/linux/common/linux_signal.h>
                     68: #include <compat/linux/common/linux_fcntl.h>
                     69: #include <compat/linux/common/linux_util.h>
                     70: #include <compat/linux/common/linux_machdep.h>
1.11      tron       71: #include <compat/linux/common/linux_dirent.h>
1.1       jdolecek   72:
                     73: #include <compat/linux/linux_syscallargs.h>
                     74:
1.15      matt       75: #ifndef alpha
                     76:
1.28.2.1  yamt       77: # ifndef COMPAT_LINUX32
                     78:
1.1       jdolecek   79: static void bsd_to_linux_stat __P((struct stat *, struct linux_stat64 *));
1.19      thorpej    80: static int linux_do_stat64 __P((struct lwp *, void *, register_t *, int));
1.1       jdolecek   81:
                     82: /*
                     83:  * Convert a NetBSD stat structure to a Linux stat structure.
                     84:  * Only the order of the fields and the padding in the structure
                     85:  * is different. linux_fakedev is a machine-dependent function
                     86:  * which optionally converts device driver major/minor numbers
                     87:  * (XXX horrible, but what can you do against code that compares
                     88:  * things against constant major device numbers? sigh)
                     89:  */
                     90: static void
                     91: bsd_to_linux_stat(bsp, lsp)
                     92:        struct stat *bsp;
                     93:        struct linux_stat64 *lsp;
                     94: {
1.7       christos   95:        lsp->lst_dev     = linux_fakedev(bsp->st_dev, 0);
1.1       jdolecek   96:        lsp->lst_ino     = bsp->st_ino;
                     97:        lsp->lst_mode    = (linux_mode_t)bsp->st_mode;
                     98:        if (bsp->st_nlink >= (1 << 15))
                     99:                lsp->lst_nlink = (1 << 15) - 1;
                    100:        else
                    101:                lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink;
                    102:        lsp->lst_uid     = bsp->st_uid;
                    103:        lsp->lst_gid     = bsp->st_gid;
1.7       christos  104:        lsp->lst_rdev    = linux_fakedev(bsp->st_rdev, 1);
1.1       jdolecek  105:        lsp->lst_size    = bsp->st_size;
                    106:        lsp->lst_blksize = bsp->st_blksize;
                    107:        lsp->lst_blocks  = bsp->st_blocks;
                    108:        lsp->lst_atime   = bsp->st_atime;
                    109:        lsp->lst_mtime   = bsp->st_mtime;
                    110:        lsp->lst_ctime   = bsp->st_ctime;
1.28.2.1  yamt      111: #  ifdef LINUX_STAT64_HAS_NSEC
1.25      christos  112:        lsp->lst_atime_nsec   = bsp->st_atimensec;
                    113:        lsp->lst_mtime_nsec   = bsp->st_mtimensec;
                    114:        lsp->lst_ctime_nsec   = bsp->st_ctimensec;
1.28.2.1  yamt      115: #  endif
                    116: #  if LINUX_STAT64_HAS_BROKEN_ST_INO
1.16      jdolecek  117:        lsp->__lst_ino   = (linux_ino_t) bsp->st_ino;
1.28.2.1  yamt      118: #  endif
1.1       jdolecek  119: }
                    120:
                    121: /*
                    122:  * The stat functions below are plain sailing. stat and lstat are handled
                    123:  * by one function to avoid code duplication.
                    124:  */
                    125: int
1.19      thorpej   126: linux_sys_fstat64(l, v, retval)
                    127:        struct lwp *l;
1.1       jdolecek  128:        void *v;
                    129:        register_t *retval;
                    130: {
                    131:        struct linux_sys_fstat64_args /* {
                    132:                syscallarg(int) fd;
1.5       manu      133:                syscallarg(struct linux_stat64 *) sp;
1.1       jdolecek  134:        } */ *uap = v;
                    135:        struct linux_stat64 tmplst;
1.28.2.4! yamt      136:        struct stat tmpst;
1.1       jdolecek  137:        int error;
                    138:
1.28.2.4! yamt      139:        error = do_sys_fstat(l,  SCARG(uap, fd), &tmpst);
        !           140:        if (error != 0)
1.1       jdolecek  141:                return error;
                    142:
                    143:        bsd_to_linux_stat(&tmpst, &tmplst);
                    144:
1.28.2.4! yamt      145:        return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst);
1.1       jdolecek  146: }
                    147:
                    148: static int
1.28.2.4! yamt      149: linux_do_stat64(l, v, retval, flags)
1.19      thorpej   150:        struct lwp *l;
1.1       jdolecek  151:        void *v;
                    152:        register_t *retval;
1.28.2.4! yamt      153:        int flags;
1.1       jdolecek  154: {
                    155:        struct linux_stat64 tmplst;
1.28.2.4! yamt      156:        struct stat tmpst;
1.1       jdolecek  157:        int error;
                    158:        struct linux_sys_stat64_args *uap = v;
                    159:
1.28.2.4! yamt      160:        error = do_sys_stat(l, SCARG(uap, path), flags, &tmpst);
        !           161:        if (error != 0)
1.1       jdolecek  162:                return error;
                    163:
                    164:        bsd_to_linux_stat(&tmpst, &tmplst);
                    165:
1.28.2.4! yamt      166:        return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst);
1.1       jdolecek  167: }
                    168:
                    169: int
1.19      thorpej   170: linux_sys_stat64(l, v, retval)
                    171:        struct lwp *l;
1.1       jdolecek  172:        void *v;
                    173:        register_t *retval;
                    174: {
                    175:        struct linux_sys_stat64_args /* {
                    176:                syscallarg(const char *) path;
                    177:                syscallarg(struct linux_stat64 *) sp;
                    178:        } */ *uap = v;
                    179:
1.28.2.4! yamt      180:        return linux_do_stat64(l, uap, retval, FOLLOW);
1.1       jdolecek  181: }
                    182:
                    183: int
1.19      thorpej   184: linux_sys_lstat64(l, v, retval)
                    185:        struct lwp *l;
1.1       jdolecek  186:        void *v;
                    187:        register_t *retval;
                    188: {
                    189:        struct linux_sys_lstat64_args /* {
                    190:                syscallarg(const char *) path;
                    191:                syscallarg(struct linux_stat64 *) sp;
                    192:        } */ *uap = v;
                    193:
1.28.2.4! yamt      194:        return linux_do_stat64(l, uap, retval, NOFOLLOW);
1.2       jdolecek  195: }
                    196:
                    197: int
1.19      thorpej   198: linux_sys_truncate64(l, v, retval)
                    199:        struct lwp *l;
1.2       jdolecek  200:        void *v;
                    201:        register_t *retval;
                    202: {
                    203:        struct linux_sys_truncate64_args /* {
                    204:                syscallarg(const char *) path;
                    205:                syscallarg(off_t) length;
                    206:        } */ *uap = v;
1.22      jdolecek  207:        struct sys_truncate_args ta;
1.2       jdolecek  208:
1.22      jdolecek  209:        /* Linux doesn't have the 'pad' pseudo-parameter */
                    210:        SCARG(&ta, path) = SCARG(uap, path);
                    211:        SCARG(&ta, pad) = 0;
                    212:        SCARG(&ta, length) = SCARG(uap, length);
                    213:
                    214:        return sys_truncate(l, &ta, retval);
                    215: }
                    216:
                    217: int
                    218: linux_sys_ftruncate64(l, v, retval)
                    219:        struct lwp *l;
                    220:        void *v;
                    221:        register_t *retval;
                    222: {
                    223:        struct linux_sys_ftruncate64_args /* {
                    224:                syscallarg(unsigned int) fd;
                    225:                syscallarg(off_t) length;
                    226:        } */ *uap = v;
                    227:        struct sys_ftruncate_args ta;
                    228:
                    229:        /* Linux doesn't have the 'pad' pseudo-parameter */
                    230:        SCARG(&ta, fd) = SCARG(uap, fd);
                    231:        SCARG(&ta, pad) = 0;
                    232:        SCARG(&ta, length) = SCARG(uap, length);
                    233:
                    234:        return sys_ftruncate(l, &ta, retval);
1.1       jdolecek  235: }
1.28.2.1  yamt      236: # endif /* !COMPAT_LINUX32 */
1.3       manu      237:
1.28.2.1  yamt      238: # if !defined(__m68k__) && (!defined(__amd64__) || defined(COMPAT_LINUX32))
1.9       christos  239: static void bsd_to_linux_flock64 __P((struct linux_flock64 *,
                    240:     const struct flock *));
1.24      perry     241: static void linux_to_bsd_flock64 __P((struct flock *,
1.9       christos  242:     const struct linux_flock64 *));
                    243:
                    244: static void
                    245: bsd_to_linux_flock64(lfp, bfp)
                    246:        struct linux_flock64 *lfp;
                    247:        const struct flock *bfp;
                    248: {
                    249:
                    250:        lfp->l_start = bfp->l_start;
                    251:        lfp->l_len = bfp->l_len;
                    252:        lfp->l_pid = bfp->l_pid;
                    253:        lfp->l_whence = bfp->l_whence;
                    254:        switch (bfp->l_type) {
                    255:        case F_RDLCK:
                    256:                lfp->l_type = LINUX_F_RDLCK;
                    257:                break;
                    258:        case F_UNLCK:
                    259:                lfp->l_type = LINUX_F_UNLCK;
                    260:                break;
                    261:        case F_WRLCK:
                    262:                lfp->l_type = LINUX_F_WRLCK;
                    263:                break;
                    264:        }
                    265: }
                    266:
                    267: static void
                    268: linux_to_bsd_flock64(bfp, lfp)
                    269:        struct flock *bfp;
                    270:        const struct linux_flock64 *lfp;
                    271: {
                    272:
                    273:        bfp->l_start = lfp->l_start;
                    274:        bfp->l_len = lfp->l_len;
                    275:        bfp->l_pid = lfp->l_pid;
                    276:        bfp->l_whence = lfp->l_whence;
                    277:        switch (lfp->l_type) {
                    278:        case LINUX_F_RDLCK:
                    279:                bfp->l_type = F_RDLCK;
                    280:                break;
                    281:        case LINUX_F_UNLCK:
                    282:                bfp->l_type = F_UNLCK;
                    283:                break;
                    284:        case LINUX_F_WRLCK:
                    285:                bfp->l_type = F_WRLCK;
                    286:                break;
                    287:        }
                    288: }
1.13      jdolecek  289:
1.3       manu      290: int
1.19      thorpej   291: linux_sys_fcntl64(l, v, retval)
                    292:        struct lwp *l;
1.3       manu      293:        void *v;
                    294:        register_t *retval;
                    295: {
                    296:        struct linux_sys_fcntl64_args /* {
1.9       christos  297:                syscallarg(int) fd;
                    298:                syscallarg(int) cmd;
                    299:                syscallarg(void *) arg;
1.3       manu      300:        } */ *uap = v;
1.9       christos  301:        struct linux_flock64 lfl;
1.28.2.4! yamt      302:        struct flock bfl;
1.3       manu      303:        int error;
1.9       christos  304:        void *arg = SCARG(uap, arg);
                    305:        int cmd = SCARG(uap, cmd);
                    306:        int fd = SCARG(uap, fd);
1.3       manu      307:
                    308:        switch (cmd) {
1.9       christos  309:        case LINUX_F_GETLK64:
                    310:                if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
                    311:                        return error;
                    312:                linux_to_bsd_flock64(&bfl, &lfl);
1.28.2.4! yamt      313:                error = do_fcntl_lock(l, fd, F_GETLK, &bfl);
        !           314:                if (error != 0)
1.9       christos  315:                        return error;
                    316:                bsd_to_linux_flock64(&lfl, &bfl);
                    317:                return copyout(&lfl, arg, sizeof lfl);
                    318:        case LINUX_F_SETLK64:
                    319:        case LINUX_F_SETLKW64:
                    320:                cmd = (cmd == LINUX_F_SETLK64 ? F_SETLK : F_SETLKW);
                    321:                if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
                    322:                        return error;
                    323:                linux_to_bsd_flock64(&bfl, &lfl);
1.28.2.4! yamt      324:                return do_fcntl_lock(l, fd, cmd, &bfl);
1.9       christos  325:        default:
1.19      thorpej   326:                return linux_sys_fcntl(l, v, retval);
1.3       manu      327:        }
1.11      tron      328: }
1.28.2.1  yamt      329: # endif /* !m69k && !amd64  && !COMPAT_LINUX32 */
1.15      matt      330:
                    331: #endif /* !alpha */
1.11      tron      332:
                    333: /*
                    334:  * Linux 'readdir' call. This code is mostly taken from the
                    335:  * SunOS getdents call (see compat/sunos/sunos_misc.c), though
1.18      jdolecek  336:  * an attempt has been made to keep it a little cleaner.
1.11      tron      337:  *
1.18      jdolecek  338:  * The d_off field contains the offset of the next valid entry,
                    339:  * unless the older Linux getdents(2), which used to have it set
                    340:  * to the offset of the entry itself. This function also doesn't
                    341:  * need to deal with the old count == 1 glibc problem.
1.11      tron      342:  *
                    343:  * Read in BSD-style entries, convert them, and copy them out.
                    344:  *
                    345:  * Note that this doesn't handle union-mounted filesystems.
                    346:  */
1.28.2.1  yamt      347: #ifndef COMPAT_LINUX32
1.11      tron      348: int
1.19      thorpej   349: linux_sys_getdents64(l, v, retval)
                    350:        struct lwp *l;
1.11      tron      351:        void *v;
                    352:        register_t *retval;
                    353: {
                    354:        struct linux_sys_getdents_args /* {
                    355:                syscallarg(int) fd;
                    356:                syscallarg(struct linux_dirent64 *) dent;
                    357:                syscallarg(unsigned int) count;
                    358:        } */ *uap = v;
                    359:        struct dirent *bdp;
                    360:        struct vnode *vp;
1.28.2.4! yamt      361:        char *inp, *tbuf;               /* BSD-format */
1.11      tron      362:        int len, reclen;                /* BSD-format */
1.28.2.4! yamt      363:        char *outp;                     /* Linux-format */
1.11      tron      364:        int resid, linux_reclen = 0;    /* Linux-format */
                    365:        struct file *fp;
                    366:        struct uio auio;
                    367:        struct iovec aiov;
                    368:        struct linux_dirent64 idb;
                    369:        off_t off;              /* true file offset */
1.18      jdolecek  370:        int buflen, error, eofflag, nbytes;
1.11      tron      371:        struct vattr va;
                    372:        off_t *cookiebuf = NULL, *cookie;
                    373:        int ncookies;
                    374:
                    375:        /* getvnode() will use the descriptor for us */
1.28.2.2  yamt      376:        if ((error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
1.11      tron      377:                return (error);
                    378:
                    379:        if ((fp->f_flag & FREAD) == 0) {
                    380:                error = EBADF;
                    381:                goto out1;
                    382:        }
                    383:
                    384:        vp = (struct vnode *)fp->f_data;
                    385:        if (vp->v_type != VDIR) {
                    386:                error = EINVAL;
                    387:                goto out1;
                    388:        }
                    389:
1.28.2.2  yamt      390:        if ((error = VOP_GETATTR(vp, &va, l->l_cred, l)))
1.11      tron      391:                goto out1;
                    392:
                    393:        nbytes = SCARG(uap, count);
1.18      jdolecek  394:        buflen = min(MAXBSIZE, nbytes);
                    395:        if (buflen < va.va_blocksize)
                    396:                buflen = va.va_blocksize;
1.28      christos  397:        tbuf = malloc(buflen, M_TEMP, M_WAITOK);
1.11      tron      398:
                    399:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    400:        off = fp->f_offset;
                    401: again:
1.28      christos  402:        aiov.iov_base = tbuf;
1.11      tron      403:        aiov.iov_len = buflen;
                    404:        auio.uio_iov = &aiov;
                    405:        auio.uio_iovcnt = 1;
                    406:        auio.uio_rw = UIO_READ;
                    407:        auio.uio_resid = buflen;
                    408:        auio.uio_offset = off;
1.28.2.1  yamt      409:        UIO_SETUP_SYSSPACE(&auio);
1.11      tron      410:        /*
                    411:          * First we read into the malloc'ed buffer, then
                    412:          * we massage it into user space, one record at a time.
                    413:          */
                    414:        error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
                    415:            &ncookies);
                    416:        if (error)
                    417:                goto out;
                    418:
1.28      christos  419:        inp = tbuf;
1.28.2.4! yamt      420:        outp = (void *)SCARG(uap, dent);
1.11      tron      421:        resid = nbytes;
                    422:        if ((len = buflen - auio.uio_resid) == 0)
                    423:                goto eof;
                    424:
                    425:        for (cookie = cookiebuf; len > 0; len -= reclen) {
                    426:                bdp = (struct dirent *)inp;
                    427:                reclen = bdp->d_reclen;
                    428:                if (reclen & 3)
                    429:                        panic("linux_readdir");
                    430:                if (bdp->d_fileno == 0) {
                    431:                        inp += reclen;  /* it is a hole; squish it out */
1.26      christos  432:                        if (cookie)
                    433:                                off = *cookie++;
                    434:                        else
                    435:                                off += reclen;
1.11      tron      436:                        continue;
                    437:                }
                    438:                linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
                    439:                if (reclen > len || resid < linux_reclen) {
                    440:                        /* entry too big for buffer, so just stop */
                    441:                        outp++;
                    442:                        break;
                    443:                }
1.26      christos  444:                if (cookie)
                    445:                        off = *cookie++;        /* each entry points to next */
                    446:                else
                    447:                        off += reclen;
1.11      tron      448:                /*
                    449:                 * Massage in place to make a Linux-shaped dirent (otherwise
                    450:                 * we have to worry about touching user memory outside of
                    451:                 * the copyout() call).
                    452:                 */
                    453:                idb.d_ino = bdp->d_fileno;
                    454:                idb.d_type = bdp->d_type;
1.18      jdolecek  455:                idb.d_off = off;
                    456:                idb.d_reclen = (u_short)linux_reclen;
1.11      tron      457:                strcpy(idb.d_name, bdp->d_name);
1.28.2.4! yamt      458:                if ((error = copyout((void *)&idb, outp, linux_reclen)))
1.11      tron      459:                        goto out;
                    460:                /* advance past this real entry */
                    461:                inp += reclen;
                    462:                /* advance output past Linux-shaped entry */
                    463:                outp += linux_reclen;
                    464:                resid -= linux_reclen;
                    465:        }
                    466:
                    467:        /* if we squished out the whole block, try again */
1.28.2.4! yamt      468:        if (outp == (void *)SCARG(uap, dent))
1.11      tron      469:                goto again;
                    470:        fp->f_offset = off;     /* update the vnode offset */
                    471:
                    472: eof:
                    473:        *retval = nbytes - resid;
                    474: out:
                    475:        VOP_UNLOCK(vp, 0);
                    476:        if (cookiebuf)
                    477:                free(cookiebuf, M_TEMP);
1.28      christos  478:        free(tbuf, M_TEMP);
1.11      tron      479: out1:
1.28.2.1  yamt      480:        FILE_UNUSE(fp, l);
1.3       manu      481:        return error;
                    482: }
1.28.2.1  yamt      483: #endif /* !COMPAT_LINUX32 */

CVSweb <webmaster@jp.NetBSD.org>