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/linux32/common/linux32_dirent.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: linux32_dirent.c,v 1.6.4.1 2010/03/17 02:59:52 snj Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Emmanuel Dreyfus
   17  * 4. The name of the author may not be used to endorse or promote 
   18  *    products derived from this software without specific prior written 
   19  *    permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 
   22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
   23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 
   36 __KERNEL_RCSID(0, "$NetBSD: linux32_dirent.c,v 1.6.4.1 2010/03/17 02:59:52 snj Exp $");
   37 
   38 #include <sys/types.h>
   39 #include <sys/param.h>
   40 #include <sys/fstypes.h>
   41 #include <sys/signal.h>
   42 #include <sys/dirent.h>
   43 #include <sys/kernel.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/file.h>
   46 #include <sys/filedesc.h>
   47 #include <sys/malloc.h>
   48 #include <sys/select.h>
   49 #include <sys/proc.h>
   50 #include <sys/ucred.h>
   51 #include <sys/vnode.h>
   52 #include <sys/swap.h>
   53 
   54 #include <machine/types.h>
   55 
   56 #include <sys/syscallargs.h>
   57 
   58 #include <compat/netbsd32/netbsd32.h>
   59 #include <compat/netbsd32/netbsd32_conv.h>
   60 #include <compat/netbsd32/netbsd32_syscallargs.h>
   61 
   62 #include <compat/linux/common/linux_types.h>
   63 #include <compat/linux/common/linux_signal.h>
   64 #include <compat/linux/common/linux_machdep.h>
   65 #include <compat/linux/common/linux_misc.h>
   66 #include <compat/linux/common/linux_oldolduname.h>
   67 #include <compat/linux/common/linux_dirent.h>
   68 #include <compat/linux/linux_syscallargs.h>
   69 
   70 #include <compat/linux32/common/linux32_types.h>
   71 #include <compat/linux32/common/linux32_signal.h>
   72 #include <compat/linux32/common/linux32_machdep.h>
   73 #include <compat/linux32/common/linux32_sysctl.h>
   74 #include <compat/linux32/common/linux32_socketcall.h>
   75 #include <compat/linux32/linux32_syscallargs.h>
   76 
   77 /*
   78  * Linux 'readdir' call. This code is mostly taken from the
   79  * SunOS getdents call (see compat/sunos/sunos_misc.c), though
   80  * an attempt has been made to keep it a little cleaner (failing
   81  * miserably, because of the cruft needed if count 1 is passed).
   82  *
   83  * The d_off field should contain the offset of the next valid entry,
   84  * but in Linux it has the offset of the entry itself. We emulate
   85  * that bug here.
   86  *
   87  * Read in BSD-style entries, convert them, and copy them out.
   88  *
   89  * Note that this doesn't handle union-mounted filesystems.
   90  */
   91 
   92 int
   93 linux32_sys_getdents(struct lwp *l, const struct linux32_sys_getdents_args *uap, register_t *retval)
   94 {
   95         /* {
   96                 syscallarg(int) fd;
   97                 syscallarg(linux32_direntp_t) dent;
   98                 syscallarg(unsigned int) count;
   99         } */
  100         struct dirent *bdp;
  101         struct vnode *vp;
  102         char *inp, *tbuf;               /* BSD-format */
  103         int len, reclen;                /* BSD-format */
  104         char *outp;                     /* Linux-format */
  105         int resid, linux32_reclen = 0;  /* Linux-format */
  106         struct file *fp;
  107         struct uio auio;
  108         struct iovec aiov;
  109         struct linux32_dirent idb;
  110         off_t off;              /* true file offset */
  111         int buflen, error, eofflag, nbytes, oldcall;
  112         struct vattr va;
  113         off_t *cookiebuf = NULL, *cookie;
  114         int ncookies;
  115 
  116         /* fd_getvnode() will use the descriptor for us */
  117         if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
  118                 return (error);
  119 
  120         if ((fp->f_flag & FREAD) == 0) {
  121                 error = EBADF;
  122                 goto out1;
  123         }
  124 
  125         vp = (struct vnode *)fp->f_data;
  126         if (vp->v_type != VDIR) {
  127                 error = EINVAL;
  128                 goto out1;
  129         }
  130 
  131         if ((error = VOP_GETATTR(vp, &va, l->l_cred)))
  132                 goto out1;
  133 
  134         nbytes = SCARG(uap, count);
  135         if (nbytes == 1) {      /* emulating old, broken behaviour */
  136                 nbytes = sizeof (idb);
  137                 buflen = max(va.va_blocksize, nbytes);
  138                 oldcall = 1;
  139         } else {
  140                 buflen = min(MAXBSIZE, nbytes);
  141                 if (buflen < va.va_blocksize)
  142                         buflen = va.va_blocksize;
  143                 oldcall = 0;
  144         }
  145         tbuf = malloc(buflen, M_TEMP, M_WAITOK);
  146 
  147         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  148         off = fp->f_offset;
  149 again:
  150         aiov.iov_base = tbuf;
  151         aiov.iov_len = buflen;
  152         auio.uio_iov = &aiov;
  153         auio.uio_iovcnt = 1;
  154         auio.uio_rw = UIO_READ;
  155         auio.uio_resid = buflen;
  156         auio.uio_offset = off;
  157         UIO_SETUP_SYSSPACE(&auio);
  158         /*
  159          * First we read into the malloc'ed buffer, then
  160          * we massage it into user space, one record at a time.
  161          */
  162         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
  163             &ncookies);
  164         if (error)
  165                 goto out;
  166 
  167         inp = tbuf;
  168         outp = (void *)SCARG_P32(uap, dent);
  169         resid = nbytes;
  170         if ((len = buflen - auio.uio_resid) == 0)
  171                 goto eof;
  172 
  173         for (cookie = cookiebuf; len > 0; len -= reclen) {
  174                 bdp = (struct dirent *)inp;
  175                 reclen = bdp->d_reclen;
  176                 if (reclen & 3)
  177                         panic("linux32_readdir");
  178                 if (bdp->d_fileno == 0) {
  179                         inp += reclen;  /* it is a hole; squish it out */
  180                         if (cookie)
  181                                 off = *cookie++;
  182                         else
  183                                 off += reclen;
  184                         continue;
  185                 }
  186                 linux32_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
  187                 if (reclen > len || resid < linux32_reclen) {
  188                         /* entry too big for buffer, so just stop */
  189                         outp++;
  190                         break;
  191                 }
  192                 /*
  193                  * Massage in place to make a Linux-shaped dirent (otherwise
  194                  * we have to worry about touching user memory outside of
  195                  * the copyout() call).
  196                  */
  197                 idb.d_ino = bdp->d_fileno;
  198                 /*
  199                  * The old readdir() call misuses the offset and reclen fields.
  200                  */
  201                 if (oldcall) {
  202                         idb.d_off = (linux32_off_t)linux32_reclen;
  203                         idb.d_reclen = (u_short)bdp->d_namlen;
  204                 } else {
  205                         if (sizeof (idb.d_off) <= 4 && (off >> 32) != 0) {
  206                                 compat_offseterr(vp, "linux32_getdents");
  207                                 error = EINVAL;
  208                                 goto out;
  209                         }
  210                         idb.d_off = (linux32_off_t)off;
  211                         idb.d_reclen = (u_short)linux32_reclen;
  212                 }
  213                 strcpy(idb.d_name, bdp->d_name);
  214                 if ((error = copyout((void *)&idb, outp, linux32_reclen)))
  215                         goto out;
  216                 /* advance past this real entry */
  217                 inp += reclen;
  218                 if (cookie)
  219                         off = *cookie++; /* each entry points to itself */
  220                 else
  221                         off += reclen;
  222                 /* advance output past Linux-shaped entry */
  223                 outp += linux32_reclen;
  224                 resid -= linux32_reclen;
  225                 if (oldcall)
  226                         break;
  227         }
  228 
  229         /* if we squished out the whole block, try again */
  230         if (outp == (void *)SCARG_P32(uap, dent)) {
  231                 if (cookiebuf)
  232                         free(cookiebuf, M_TEMP);
  233                 cookiebuf = NULL;
  234                 goto again;
  235         }
  236         fp->f_offset = off;     /* update the vnode offset */
  237 
  238         if (oldcall)
  239                 nbytes = resid + linux32_reclen;
  240 
  241 eof:
  242         *retval = nbytes - resid;
  243 out:
  244         VOP_UNLOCK(vp, 0);
  245         if (cookiebuf)
  246                 free(cookiebuf, M_TEMP);
  247         free(tbuf, M_TEMP);
  248 out1:
  249         fd_putfile(SCARG(uap, fd));
  250         return error;
  251 }
  252 
  253 int
  254 linux32_sys_getdents64(struct lwp *l, const struct linux32_sys_getdents64_args *uap, register_t *retval)
  255 {
  256         /* {
  257                 syscallcarg(int) fd;
  258                 syscallcarg(linux32_dirent64p_t) dent;
  259                 syscallcarg(unsigned int) count;
  260         } */
  261         struct linux_sys_getdents64_args ua;
  262 
  263         NETBSD32TO64_UAP(fd);
  264         NETBSD32TOP_UAP(dent, struct linux_dirent64);
  265         NETBSD32TO64_UAP(count);
  266 
  267         return linux_sys_getdents64(l, &ua, retval);
  268 }
  269 
  270 int
  271 linux32_sys_readdir(struct lwp *l, const struct linux32_sys_readdir_args *uap, register_t *retval)
  272 {
  273         /* {
  274                 syscallarg(int) fd;
  275                 syscallarg(struct linux32_direntp_t) dent;
  276                 syscallarg(unsigned int) count;
  277         } */
  278         int error;
  279         struct linux32_sys_getdents_args da;
  280 
  281         SCARG(&da, fd) = SCARG(uap, fd);
  282         SCARG(&da, dent) = SCARG(uap, dent);
  283         SCARG(&da, count) = 1;
  284 
  285         error = linux32_sys_getdents(l, &da, retval);
  286         if (error == 0 && *retval > 1)
  287                 *retval = 1;
  288 
  289         return error;
  290 }

Cache object: e92ec56f061250cd376aea22e0d2a517


[ 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.