Whamcloud - gitweb
Branch b1_4
[fs/lustre-release.git] / libsysio / src / getdirentries.c
index d78f04e..151829d 100644 (file)
  */
 
 /*
- * #############################################################################
- * #
- * #     This Cplant(TM) source code is the property of Sandia National
- * #     Laboratories.
- * #
- * #     This Cplant(TM) source code is copyrighted by Sandia National
- * #     Laboratories.
- * #
- * #     The redistribution of this Cplant(TM) source code is subject to the
- * #     terms of the GNU Lesser General Public License
- * #     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
- * #
- * #     Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
- * #     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
- * #     license for use of this work by or on behalf of the US Government.
- * #     Export of this program may require a license from the United States
- * #     Government.
- * #
- * #############################################################################
- */
-
-/*
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
 #endif
 
 static ssize_t
+filldirents(struct file *fil,
+           char *buf, size_t nbytes,
+           _SYSIO_OFF_T *__restrict basep)
+{
+       _SYSIO_OFF_T opos;
+       ssize_t cc;
+
+       if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode))
+               return -ENOTDIR;
+
+       opos = fil->f_pos;
+       cc =
+           (*fil->f_ino->i_ops.inop_filldirentries)(fil->f_ino,
+                                                    &fil->f_pos,
+                                                    buf, nbytes);
+       if (cc < 0)
+               return cc;
+       *basep = opos;
+       return cc;
+}
+
+static ssize_t
 PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd,
                                                  char *buf,
                                                  size_t nbytes,
@@ -98,21 +98,15 @@ PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd,
        SYSIO_INTERFACE_ENTER;
 
        fil = _sysio_fd_find(fd);
-       if (!(fil && fil->f_ino))
+       if (!(fil && fil->f_ino)) {
                SYSIO_INTERFACE_RETURN(-1, -EBADF);
+       }
 
-       if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode))
-               SYSIO_INTERFACE_RETURN(-1, -ENOTDIR);
-
-       cc =
-           (*fil->f_ino->i_ops.inop_getdirentries)(fil->f_ino,
-                                                   buf,
-                                                   nbytes,
-                                                   basep);
+       cc = filldirents(fil, buf, nbytes, basep);
        SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
 }
 
-#if _LARGEFILE64_SOURCE
+#ifdef _LARGEFILE64_SOURCE
 #undef getdirentries64
 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
                       SYSIO_INTERFACE_NAME(getdirentries64))
@@ -137,6 +131,17 @@ sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
        ((((n) + (boundary) - 1 ) / (boundary)) * (boundary))
 #endif
 
+#define _dbaselen      ((size_t )&((struct dirent *)0)->d_name[0])
+
+#ifdef __GLIBC__
+#define _dreclen(namlen) \
+       ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
+        ~(__alignof__ (struct dirent) - 1))
+#else /* !defined(__GLIBC__) */
+#define _dreclen(namlen) \
+       _rndup(_dbaselen + (namlen) + 1, sizeof(int))
+#endif
+
 #ifndef BSD
 ssize_t
 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
@@ -151,144 +156,84 @@ SYSIO_INTERFACE_NAME(getdirentries)(int fd,
                                    long * __restrict basep)
 #endif
 {
-       size_t inbytes;
-       void    *ibuf;
-       _SYSIO_OFF_T ibase;
-       ssize_t cc;
-       struct dirent *dp, *nxtdp;
-#if defined(BSD)
-       int     off;
-#endif
-       struct intnl_dirent *od64p, *d64p;
-       size_t  n;
-       size_t  reclen;
+       struct file *fil;
+       _SYSIO_OFF_T b;
+       ssize_t cc, count;
+       struct dirent64 *d64p, d64;
+       struct dirent *dp;
+       size_t  n, reclen;
+       void    *p;
        char    *cp;
        SYSIO_INTERFACE_DISPLAY_BLOCK;
 
-#define _dbaselen      ((size_t )&((struct dirent *)0)->d_name[0])
-
-#ifdef __GLIBC__
-#define _dreclen(namlen) \
-       ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
-        ~(__alignof__ (struct dirent) - 1))
-#else /* !defined(__GLIBC__) */
-#define _dreclen(namlen) \
-       _rndup(_dbaselen + (namlen) + 1, sizeof(int))
-#endif
-
-#if defined(__GLIBC__)
-#define _fast_alloc(n) alloca(n)
-#define _fast_free(p)
-#else /* !defined(__GLIBC__) */
-#define _fast_alloc(n) malloc(n)
-#define _fast_free(p)  free(p)
-#endif
-
        SYSIO_INTERFACE_ENTER;
-#if defined(BSD)
-       if (nbytes < 0)
-               SYSIO_INTERFACE_RETURN(-1, -EINVAL);
-#endif
-
-       inbytes = nbytes;
-       if (inbytes > 8 * 1024) {
-               /*
-                * Limit stack use.
-                */
-               inbytes = 8 * 1024;
-       }
-       ibuf = _fast_alloc(inbytes);
-       if (!ibuf)
-               SYSIO_INTERFACE_RETURN(-1, -ENOMEM);
-
-       dp = (struct dirent *)buf;
 
-       ibase = *basep;
-       cc =
-           PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(fd,
-                                           ibuf,
-                                           inbytes,
-                                           &ibase);
-       if (cc < 0) {
-               cc = -errno;
-               goto out;
-       }
-       *basep = (off_t )ibase;
-       if (sizeof(*basep) != sizeof(ibase) && *basep != ibase) {
-               cc = -EOVERFLOW;
-               goto out;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && fil->f_ino)) {
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
        }
 
-#if defined(BSD)
-       off = *basep;
-#endif
-       od64p = NULL;
-       d64p = ibuf;
-       for (;;) {
-               if (!cc)
-                       break;
-#ifdef HAVE_D_NAMLEN
-               n = d64p->d_namlen;
-#else
-               n = strlen(d64p->d_name);
-#endif
+       count = cc = filldirents(fil, buf, nbytes, &b);
+       d64p = (void *)buf;
+       dp = (void *)buf;
+       reclen = 0;
+       while (cc > 0) {
+               n = _namlen(d64p);
                reclen = _dreclen(n);
-               if (reclen >= (unsigned )nbytes)
-                       break;
-               dp->d_ino = (ino_t )d64p->d_ino;
-#if !(defined(BSD))
-               dp->d_off = (off_t )d64p->d_off;
-#endif
-               if ((sizeof(dp->d_ino) != sizeof(d64p->d_ino) &&
-                    dp->d_ino != d64p->d_ino)
-                               ||
-#if !(defined(BSD))
-                   (sizeof(dp->d_off) != sizeof(d64p->d_off) &&
-                    dp->d_off != d64p->d_off)
-#else
-                   (off + (int )reclen < off)
-#endif
-                   ) {
-                       cc = -EOVERFLOW;
+               d64.d_ino = d64p->d_ino;
+               d64.d_off = d64p->d_off;
+               d64.d_type = d64p->d_type;
+               d64.d_reclen = d64p->d_reclen;
+               /*
+                * Copy name first.
+                */
+               (void )memcpy(dp->d_name, d64p->d_name, n);
+               /*
+                * Then, the rest.
+                */
+               dp->d_ino = d64.d_ino;
+               dp->d_off = d64.d_off;
+               if (dp->d_ino != d64.d_ino ||
+                   dp->d_off != d64.d_off) {
+                       /*
+                        * If conversion failure then we are done.
+                        */
+                       if (cc == count) {
+                               /*
+                                * Couldn't process any entries. We return
+                                * the error now.
+                                */
+                               cc = - EOVERFLOW;
+                       }
                        break;
                }
-               dp->d_type = d64p->d_type;
+               fil->f_pos = dp->d_off;
+               dp->d_type = d64.d_type;
                dp->d_reclen = reclen;
-               nxtdp = (struct dirent *)((char *)dp + dp->d_reclen);
-               (void )memcpy(dp->d_name, d64p->d_name, n);
-               for (cp = dp->d_name + n; cp < (char *)nxtdp; *cp++ = '\0')
-                       ;
-               cc -= d64p->d_reclen;
-               od64p = d64p;
-               d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
-               nbytes -= reclen;
-#if defined(BSD)
-               off += reclen;
+               /*
+                * Fill the remainder with zeros.
+                */
+               p = (char *)dp + dp->d_reclen;
+#ifdef HAVE_D_NAMLEN
+               dp->d_namlen = n;
 #endif
-               dp = nxtdp;
+               cp = dp->d_name + n;
+               do {
+                       *cp++ = 0;
+               } while (cp < (char *)p);
+               /*
+                * Advance.
+                */
+               dp = p;
+               cc -= d64.d_reclen;
+               d64p = (struct dirent64 *)((char *)d64p + d64.d_reclen);
        }
 
-out:
-       _fast_free(ibuf);
-
-       if (dp == (struct dirent *)buf && cc < 0)
-               SYSIO_INTERFACE_RETURN(-1, (int )cc);
+       if (cc < 0)
+               SYSIO_INTERFACE_RETURN(-1, cc);
        cc = (char *)dp - buf;
-       if (cc)
-               *basep =
-#if !(defined(BSD))
-                   od64p->d_off;
-#else
-                   off;
-#endif
+       *basep = b;
        SYSIO_INTERFACE_RETURN(cc, 0);
-
-#ifdef __GLIBC__
-#undef _fast_alloc
-#undef _fast_free
-#endif
-#undef _dreclen
-#undef _dbaselen
 }
 #else /* !defined(DIRENT64_IS_NATURAL) */
 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64),