root/compat/common/compat_dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. readdir_with_callback

    1 /*      $OpenBSD: compat_dir.c,v 1.4 2003/08/14 16:55:24 fgsch Exp $    */
    2 
    3 /*
    4  * Copyright (c) 2000 Constantine Sapuntzakis
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  */
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/namei.h>
   31 #include <sys/proc.h>
   32 #include <sys/file.h>
   33 #include <sys/stat.h>
   34 #include <sys/filedesc.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/vnode.h>
   39 #include <sys/dirent.h>
   40 
   41 #include <compat/common/compat_dir.h>
   42 
   43 int
   44 readdir_with_callback(fp, off, nbytes, appendfunc, arg)
   45         struct file *fp;
   46         off_t *off;
   47         u_long nbytes;
   48         int (*appendfunc)(void *, struct dirent *, off_t);
   49         void *arg;
   50 {
   51         struct dirent *bdp;
   52         caddr_t inp, buf;
   53         int buflen;
   54         struct uio auio;
   55         struct iovec aiov;
   56         int eofflag = 0;
   57         u_long *cookies = NULL, *cookiep;
   58         int ncookies = 0;
   59         int error, len, reclen;
   60         off_t newoff = *off;
   61         struct vnode *vp;
   62         struct vattr va;
   63                 
   64         if ((fp->f_flag & FREAD) == 0)
   65                 return (EBADF);
   66 
   67         vp = (struct vnode *)fp->f_data;
   68 
   69         if (vp->v_type != VDIR)
   70                 return (EINVAL);
   71 
   72         if ((error = VOP_GETATTR(vp, &va, fp->f_cred, curproc)) != 0)
   73                 return (error);
   74 
   75         buflen = min(MAXBSIZE, nbytes);
   76         buflen = max(buflen, va.va_blocksize);
   77         buf = malloc(buflen, M_TEMP, M_WAITOK);
   78         error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
   79         if (error)
   80                 goto out;
   81 
   82 again:
   83         aiov.iov_base = buf;
   84         aiov.iov_len = buflen;
   85         auio.uio_iov = &aiov;
   86         auio.uio_iovcnt = 1;
   87         auio.uio_rw = UIO_READ;
   88         auio.uio_segflg = UIO_SYSSPACE;
   89         auio.uio_procp = curproc;
   90         auio.uio_resid = buflen;
   91         auio.uio_offset = newoff;
   92 
   93         if (cookies) {
   94                 free(cookies, M_TEMP);
   95                 cookies = NULL;
   96         }
   97 
   98         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
   99             &cookies);
  100         if (error)
  101                 goto out;
  102 
  103         if ((len = buflen - auio.uio_resid) <= 0)
  104                 goto eof;       
  105 
  106         cookiep = cookies;
  107         inp = buf;
  108 
  109         if (cookies) {
  110                 /*
  111                  * When using cookies, the vfs has the option of reading from
  112                  * a different offset than that supplied (UFS truncates the
  113                  * offset to a block boundary to make sure that it never reads
  114                  * partway through a directory entry, even if the directory
  115                  * has been compacted).
  116                  */
  117                 while (len > 0 && ncookies > 0 && *cookiep <= newoff) {
  118                         bdp = (struct dirent *)inp;
  119                         len -= bdp->d_reclen;
  120                         inp += bdp->d_reclen;
  121                         cookiep++;
  122                         ncookies--;
  123                 }
  124         }
  125 
  126         for (; len > 0; len -= reclen, inp += reclen) {
  127                 if (cookiep && ncookies == 0)
  128                         break;
  129 
  130                 bdp = (struct dirent *)inp;
  131                 reclen = bdp->d_reclen;
  132 
  133                 if (len < reclen)
  134                         break;
  135 
  136                 if (reclen & 3) {
  137                         error = EFAULT;
  138                         goto out;
  139                 }
  140 
  141                 /* Skip holes */
  142                 if (bdp->d_fileno != 0) {
  143                         if ((error = (*appendfunc) (arg, bdp,
  144                             (cookiep) ? *cookiep : (newoff + reclen))) != 0) {
  145                                 if (error == ENOMEM)
  146                                         error = 0;
  147                                 break;
  148                         }
  149                 }
  150 
  151                 if (cookiep) {
  152                         newoff = *cookiep++;
  153                         ncookies--;
  154                 } else
  155                         newoff += reclen;
  156         }
  157 
  158         if (len <= 0 && !eofflag)
  159                 goto again;
  160 
  161 eof:
  162 out:
  163         if (error == 0)
  164                 *off = newoff;
  165 
  166         if (cookies)
  167                 free(cookies, M_TEMP);
  168 
  169         VOP_UNLOCK(vp, 0, curproc);
  170         free(buf, M_TEMP);
  171         return (error);
  172 }

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