[Libsysio-commit] HEAD: libsysio/src getdirentries.c
Brought to you by:
lward
From: Lee W. <lw...@us...> - 2005-08-02 20:25:34
|
Update of /cvsroot/libsysio/libsysio/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8877/src Modified Files: getdirentries.c Log Message: Simplified and, hopefully, a bug corrected. Both Jim Schutt, at Sandia, and Oleg Drokin, at CFS, reported that getdirentries fails with Lustre as the base pointer is being reset improperly. The base pointer is now advanced as the directory entries are processed by giving it the value from the d_off field prior to advancing. Index: getdirentries.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/getdirentries.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -w -b -B -p -r1.18 -r1.19 --- getdirentries.c 21 Sep 2004 16:18:30 -0000 1.18 +++ getdirentries.c 2 Aug 2005 20:25:25 -0000 1.19 @@ -85,30 +85,35 @@ #endif static ssize_t +filldirents(int fd, char *buf, size_t nbytes, _SYSIO_OFF_T * __restrict basep) +{ + struct file *fil; + + fil = _sysio_fd_find(fd); + if (!(fil && fil->f_ino)) + return -EBADF; + + if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode)) + return -ENOTDIR; + + return (*fil->f_ino->i_ops.inop_getdirentries)(fil->f_ino, + buf, nbytes, + basep); +} + +static ssize_t PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd, char *buf, size_t nbytes, _SYSIO_OFF_T * __restrict basep) { - struct file *fil; ssize_t cc; SYSIO_INTERFACE_DISPLAY_BLOCK; SYSIO_INTERFACE_ENTER; - fil = _sysio_fd_find(fd); - 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(fd, buf, nbytes, basep); SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0); } @@ -137,6 +142,17 @@ sysio_sym_strong_alias(PREPEND(_, SYSIO_ ((((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 +167,78 @@ SYSIO_INTERFACE_NAME(getdirentries)(int 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; + _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) { + b = *basep; + count = cc = filldirents(fd, buf, nbytes, &b); + d64p = (void *)buf; + dp = (void *)buf; + reclen = 0; + while (cc > 0) { + n = _namlen(d64p); + reclen = _dreclen(n); + d64.d_ino = d64p->d_ino; + d64.d_off = d64p->d_off; + d64.d_type = d64p->d_type; + d64.d_reclen = d64p->d_reclen; /* - * Limit stack use. + * 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. */ - 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; } - -#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 - 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; break; } - dp->d_type = d64p->d_type; + *basep = 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 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), |