The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/common/linux_file64.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: linux_file64.c,v 1.22 2003/08/10 20:16:27 jdolecek Exp $       */
    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  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.22 2003/08/10 20:16:27 jdolecek Exp $");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/namei.h>
   49 #include <sys/proc.h>
   50 #include <sys/dirent.h>
   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>
   58 #include <sys/vnode.h>
   59 #include <sys/tty.h>
   60 #include <sys/conf.h>
   61 
   62 #include <sys/sa.h>
   63 #include <sys/syscallargs.h>
   64 
   65 #include <compat/linux/common/linux_types.h>
   66 #include <compat/linux/common/linux_signal.h>
   67 #include <compat/linux/common/linux_fcntl.h>
   68 #include <compat/linux/common/linux_util.h>
   69 #include <compat/linux/common/linux_machdep.h>
   70 #include <compat/linux/common/linux_dirent.h>
   71 
   72 #include <compat/linux/linux_syscallargs.h>
   73 
   74 #ifndef alpha
   75 
   76 static void bsd_to_linux_stat __P((struct stat *, struct linux_stat64 *));
   77 static int linux_do_stat64 __P((struct lwp *, void *, register_t *, int));
   78 
   79 /*
   80  * Convert a NetBSD stat structure to a Linux stat structure.
   81  * Only the order of the fields and the padding in the structure
   82  * is different. linux_fakedev is a machine-dependent function
   83  * which optionally converts device driver major/minor numbers
   84  * (XXX horrible, but what can you do against code that compares
   85  * things against constant major device numbers? sigh)
   86  */
   87 static void
   88 bsd_to_linux_stat(bsp, lsp)
   89         struct stat *bsp;
   90         struct linux_stat64 *lsp;
   91 {
   92         lsp->lst_dev     = linux_fakedev(bsp->st_dev, 0);
   93         lsp->lst_ino     = bsp->st_ino;
   94         lsp->lst_mode    = (linux_mode_t)bsp->st_mode;
   95         if (bsp->st_nlink >= (1 << 15))
   96                 lsp->lst_nlink = (1 << 15) - 1;
   97         else
   98                 lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink;
   99         lsp->lst_uid     = bsp->st_uid;
  100         lsp->lst_gid     = bsp->st_gid;
  101         lsp->lst_rdev    = linux_fakedev(bsp->st_rdev, 1);
  102         lsp->lst_size    = bsp->st_size;
  103         lsp->lst_blksize = bsp->st_blksize;
  104         lsp->lst_blocks  = bsp->st_blocks;
  105         lsp->lst_atime   = bsp->st_atime;
  106         lsp->lst_mtime   = bsp->st_mtime;
  107         lsp->lst_ctime   = bsp->st_ctime;
  108 #if LINUX_STAT64_HAS_BROKEN_ST_INO
  109         lsp->__lst_ino   = (linux_ino_t) bsp->st_ino;
  110 #endif
  111 }
  112 
  113 /*
  114  * The stat functions below are plain sailing. stat and lstat are handled
  115  * by one function to avoid code duplication.
  116  */
  117 int
  118 linux_sys_fstat64(l, v, retval)
  119         struct lwp *l;
  120         void *v;
  121         register_t *retval;
  122 {
  123         struct linux_sys_fstat64_args /* {
  124                 syscallarg(int) fd;
  125                 syscallarg(struct linux_stat64 *) sp;
  126         } */ *uap = v;
  127         struct proc *p = l->l_proc;
  128         struct sys___fstat13_args fsa;
  129         struct linux_stat64 tmplst;
  130         struct stat *st,tmpst;
  131         caddr_t sg;
  132         int error;
  133 
  134         sg = stackgap_init(p, 0);
  135 
  136         st = stackgap_alloc(p, &sg, sizeof (struct stat));
  137 
  138         SCARG(&fsa, fd) = SCARG(uap, fd);
  139         SCARG(&fsa, sb) = st;
  140 
  141         if ((error = sys___fstat13(l, &fsa, retval)))
  142                 return error;
  143 
  144         if ((error = copyin(st, &tmpst, sizeof tmpst)))
  145                 return error;
  146 
  147         bsd_to_linux_stat(&tmpst, &tmplst);
  148 
  149         if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
  150                 return error;
  151 
  152         return 0;
  153 }
  154 
  155 static int
  156 linux_do_stat64(l, v, retval, dolstat)
  157         struct lwp *l;
  158         void *v;
  159         register_t *retval;
  160         int dolstat;
  161 {
  162         struct proc *p = l->l_proc;
  163         struct sys___stat13_args sa;
  164         struct linux_stat64 tmplst;
  165         struct stat *st, tmpst;
  166         caddr_t sg;
  167         int error;
  168         struct linux_sys_stat64_args *uap = v;
  169 
  170         sg = stackgap_init(p, 0);
  171         st = stackgap_alloc(p, &sg, sizeof (struct stat));
  172         CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
  173 
  174         SCARG(&sa, ub) = st;
  175         SCARG(&sa, path) = SCARG(uap, path);
  176 
  177         if ((error = (dolstat ? sys___lstat13(l, &sa, retval) :
  178                                 sys___stat13(l, &sa, retval))))
  179                 return error;
  180 
  181         if ((error = copyin(st, &tmpst, sizeof tmpst)))
  182                 return error;
  183 
  184         bsd_to_linux_stat(&tmpst, &tmplst);
  185 
  186         if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
  187                 return error;
  188 
  189         return 0;
  190 }
  191 
  192 int
  193 linux_sys_stat64(l, v, retval)
  194         struct lwp *l;
  195         void *v;
  196         register_t *retval;
  197 {
  198         struct linux_sys_stat64_args /* {
  199                 syscallarg(const char *) path;
  200                 syscallarg(struct linux_stat64 *) sp;
  201         } */ *uap = v;
  202 
  203         return linux_do_stat64(l, uap, retval, 0);
  204 }
  205 
  206 int
  207 linux_sys_lstat64(l, v, retval)
  208         struct lwp *l;
  209         void *v;
  210         register_t *retval;
  211 {
  212         struct linux_sys_lstat64_args /* {
  213                 syscallarg(const char *) path;
  214                 syscallarg(struct linux_stat64 *) sp;
  215         } */ *uap = v;
  216 
  217         return linux_do_stat64(l, uap, retval, 1);
  218 }
  219 
  220 int
  221 linux_sys_truncate64(l, v, retval)
  222         struct lwp *l;
  223         void *v;
  224         register_t *retval;
  225 {
  226         struct linux_sys_truncate64_args /* {
  227                 syscallarg(const char *) path;
  228                 syscallarg(off_t) length;
  229         } */ *uap = v;
  230         struct sys_truncate_args ta;
  231         struct proc *p = l->l_proc;
  232         caddr_t sg = stackgap_init(p, 0);
  233 
  234         CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
  235 
  236         /* Linux doesn't have the 'pad' pseudo-parameter */
  237         SCARG(&ta, path) = SCARG(uap, path);
  238         SCARG(&ta, pad) = 0;
  239         SCARG(&ta, length) = SCARG(uap, length);
  240 
  241         return sys_truncate(l, &ta, retval);
  242 }
  243 
  244 int
  245 linux_sys_ftruncate64(l, v, retval)
  246         struct lwp *l;
  247         void *v;
  248         register_t *retval;
  249 {
  250         struct linux_sys_ftruncate64_args /* {
  251                 syscallarg(unsigned int) fd;
  252                 syscallarg(off_t) length;
  253         } */ *uap = v;
  254         struct sys_ftruncate_args ta;
  255 
  256         /* Linux doesn't have the 'pad' pseudo-parameter */
  257         SCARG(&ta, fd) = SCARG(uap, fd);
  258         SCARG(&ta, pad) = 0;
  259         SCARG(&ta, length) = SCARG(uap, length);
  260 
  261         return sys_ftruncate(l, &ta, retval);
  262 }
  263 
  264 #if !defined(__m68k__)
  265 static void bsd_to_linux_flock64 __P((struct linux_flock64 *,
  266     const struct flock *));
  267 static void linux_to_bsd_flock64 __P((struct flock *, 
  268     const struct linux_flock64 *));
  269 
  270 static void
  271 bsd_to_linux_flock64(lfp, bfp)
  272         struct linux_flock64 *lfp;
  273         const struct flock *bfp;
  274 {
  275 
  276         lfp->l_start = bfp->l_start;
  277         lfp->l_len = bfp->l_len;
  278         lfp->l_pid = bfp->l_pid;
  279         lfp->l_whence = bfp->l_whence;
  280         switch (bfp->l_type) {
  281         case F_RDLCK:
  282                 lfp->l_type = LINUX_F_RDLCK;
  283                 break;
  284         case F_UNLCK:
  285                 lfp->l_type = LINUX_F_UNLCK;
  286                 break;
  287         case F_WRLCK:
  288                 lfp->l_type = LINUX_F_WRLCK;
  289                 break;
  290         }
  291 }
  292 
  293 static void
  294 linux_to_bsd_flock64(bfp, lfp)
  295         struct flock *bfp;
  296         const struct linux_flock64 *lfp;
  297 {
  298 
  299         bfp->l_start = lfp->l_start;
  300         bfp->l_len = lfp->l_len;
  301         bfp->l_pid = lfp->l_pid;
  302         bfp->l_whence = lfp->l_whence;
  303         switch (lfp->l_type) {
  304         case LINUX_F_RDLCK:
  305                 bfp->l_type = F_RDLCK;
  306                 break;
  307         case LINUX_F_UNLCK:
  308                 bfp->l_type = F_UNLCK;
  309                 break;
  310         case LINUX_F_WRLCK:
  311                 bfp->l_type = F_WRLCK;
  312                 break;
  313         }
  314 }
  315 
  316 int
  317 linux_sys_fcntl64(l, v, retval)
  318         struct lwp *l;
  319         void *v;
  320         register_t *retval;
  321 {
  322         struct linux_sys_fcntl64_args /* {
  323                 syscallarg(int) fd;
  324                 syscallarg(int) cmd;
  325                 syscallarg(void *) arg;
  326         } */ *uap = v;
  327         struct proc *p = l->l_proc;
  328         struct sys_fcntl_args fca;
  329         struct linux_flock64 lfl;
  330         struct flock bfl, *bfp;
  331         int error;
  332         caddr_t sg;
  333         void *arg = SCARG(uap, arg);
  334         int cmd = SCARG(uap, cmd);
  335         int fd = SCARG(uap, fd);
  336 
  337         switch (cmd) {
  338         case LINUX_F_GETLK64:
  339                 sg = stackgap_init(p, 0);
  340                 bfp = (struct flock *) stackgap_alloc(p, &sg, sizeof *bfp);
  341                 if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
  342                         return error;
  343                 linux_to_bsd_flock64(&bfl, &lfl);
  344                 if ((error = copyout(&bfl, bfp, sizeof bfl)) != 0)
  345                         return error;
  346                 SCARG(&fca, fd) = fd;
  347                 SCARG(&fca, cmd) = F_GETLK;
  348                 SCARG(&fca, arg) = bfp;
  349                 if ((error = sys_fcntl(l, &fca, retval)) != 0)
  350                         return error;
  351                 if ((error = copyin(bfp, &bfl, sizeof bfl)) != 0)
  352                         return error;
  353                 bsd_to_linux_flock64(&lfl, &bfl);
  354                 return copyout(&lfl, arg, sizeof lfl);
  355         case LINUX_F_SETLK64:
  356         case LINUX_F_SETLKW64:
  357                 cmd = (cmd == LINUX_F_SETLK64 ? F_SETLK : F_SETLKW);
  358                 if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
  359                         return error;
  360                 linux_to_bsd_flock64(&bfl, &lfl);
  361                 sg = stackgap_init(p, 0);
  362                 bfp = (struct flock *) stackgap_alloc(p, &sg, sizeof *bfp);
  363                 if ((error = copyout(&bfl, bfp, sizeof bfl)) != 0)
  364                         return error;
  365                 SCARG(&fca, fd) = fd;
  366                 SCARG(&fca, cmd) = cmd;
  367                 SCARG(&fca, arg) = bfp;
  368                 return sys_fcntl(l, &fca, retval);
  369         default:
  370                 return linux_sys_fcntl(l, v, retval);
  371         }
  372 }
  373 #endif /* !m68k */
  374 
  375 #endif /* !alpha */
  376 
  377 /*
  378  * Linux 'readdir' call. This code is mostly taken from the
  379  * SunOS getdents call (see compat/sunos/sunos_misc.c), though
  380  * an attempt has been made to keep it a little cleaner.
  381  *
  382  * The d_off field contains the offset of the next valid entry,
  383  * unless the older Linux getdents(2), which used to have it set
  384  * to the offset of the entry itself. This function also doesn't
  385  * need to deal with the old count == 1 glibc problem.
  386  *
  387  * Read in BSD-style entries, convert them, and copy them out.
  388  *
  389  * Note that this doesn't handle union-mounted filesystems.
  390  */
  391 int
  392 linux_sys_getdents64(l, v, retval)
  393         struct lwp *l;
  394         void *v;
  395         register_t *retval;
  396 {
  397         struct linux_sys_getdents_args /* {
  398                 syscallarg(int) fd;
  399                 syscallarg(struct linux_dirent64 *) dent;
  400                 syscallarg(unsigned int) count;
  401         } */ *uap = v;
  402         struct proc *p = l->l_proc;
  403         struct dirent *bdp;
  404         struct vnode *vp;
  405         caddr_t inp, buf;               /* BSD-format */
  406         int len, reclen;                /* BSD-format */
  407         caddr_t outp;                   /* Linux-format */
  408         int resid, linux_reclen = 0;    /* Linux-format */
  409         struct file *fp;
  410         struct uio auio;
  411         struct iovec aiov;
  412         struct linux_dirent64 idb;
  413         off_t off;              /* true file offset */
  414         int buflen, error, eofflag, nbytes;
  415         struct vattr va;
  416         off_t *cookiebuf = NULL, *cookie;
  417         int ncookies;
  418 
  419         /* getvnode() will use the descriptor for us */
  420         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
  421                 return (error);
  422 
  423         if ((fp->f_flag & FREAD) == 0) {
  424                 error = EBADF;
  425                 goto out1;
  426         }
  427 
  428         vp = (struct vnode *)fp->f_data;
  429         if (vp->v_type != VDIR) {
  430                 error = EINVAL;
  431                 goto out1;
  432         }
  433 
  434         if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
  435                 goto out1;
  436 
  437         nbytes = SCARG(uap, count);
  438         buflen = min(MAXBSIZE, nbytes);
  439         if (buflen < va.va_blocksize)
  440                 buflen = va.va_blocksize;
  441         buf = malloc(buflen, M_TEMP, M_WAITOK);
  442 
  443         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  444         off = fp->f_offset;
  445 again:
  446         aiov.iov_base = buf;
  447         aiov.iov_len = buflen;
  448         auio.uio_iov = &aiov;
  449         auio.uio_iovcnt = 1;
  450         auio.uio_rw = UIO_READ;
  451         auio.uio_segflg = UIO_SYSSPACE;
  452         auio.uio_procp = p;
  453         auio.uio_resid = buflen;
  454         auio.uio_offset = off;
  455         /*
  456          * First we read into the malloc'ed buffer, then
  457          * we massage it into user space, one record at a time.
  458          */
  459         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
  460             &ncookies);
  461         if (error)
  462                 goto out;
  463 
  464         inp = buf;
  465         outp = (caddr_t)SCARG(uap, dent);
  466         resid = nbytes;
  467         if ((len = buflen - auio.uio_resid) == 0)
  468                 goto eof;
  469 
  470         for (cookie = cookiebuf; len > 0; len -= reclen) {
  471                 bdp = (struct dirent *)inp;
  472                 reclen = bdp->d_reclen;
  473                 if (reclen & 3)
  474                         panic("linux_readdir");
  475                 if (bdp->d_fileno == 0) {
  476                         inp += reclen;  /* it is a hole; squish it out */
  477                         off = *cookie++;
  478                         continue;
  479                 }
  480                 linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
  481                 if (reclen > len || resid < linux_reclen) {
  482                         /* entry too big for buffer, so just stop */
  483                         outp++;
  484                         break;
  485                 }
  486                 off = *cookie++;        /* each entry points to next */
  487                 /*
  488                  * Massage in place to make a Linux-shaped dirent (otherwise
  489                  * we have to worry about touching user memory outside of
  490                  * the copyout() call).
  491                  */
  492                 idb.d_ino = bdp->d_fileno;
  493                 idb.d_type = bdp->d_type;
  494                 idb.d_off = off;
  495                 idb.d_reclen = (u_short)linux_reclen;
  496                 strcpy(idb.d_name, bdp->d_name);
  497                 if ((error = copyout((caddr_t)&idb, outp, linux_reclen)))
  498                         goto out;
  499                 /* advance past this real entry */
  500                 inp += reclen;
  501                 /* advance output past Linux-shaped entry */
  502                 outp += linux_reclen;
  503                 resid -= linux_reclen;
  504         }
  505 
  506         /* if we squished out the whole block, try again */
  507         if (outp == (caddr_t)SCARG(uap, dent))
  508                 goto again;
  509         fp->f_offset = off;     /* update the vnode offset */
  510 
  511 eof:
  512         *retval = nbytes - resid;
  513 out:
  514         VOP_UNLOCK(vp, 0);
  515         if (cookiebuf)
  516                 free(cookiebuf, M_TEMP);
  517         free(buf, M_TEMP);
  518 out1:
  519         FILE_UNUSE(fp, p);
  520         return error;
  521 }

Cache object: bceb9a5ca238e07147d23bc85bc39977


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.