[Libsysio-commit] HEAD: libsysio/drivers/native fs_native.c
Brought to you by:
lward
From: Lee W. <lw...@us...> - 2004-04-14 17:26:00
|
Update of /cvsroot/libsysio/libsysio/drivers/native In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18582/drivers/native Modified Files: fs_native.c Log Message: Fixed the missing first letter of entry names returned by native_getdirentries. The x86_64 service node does not support getdents64. Only getdents. We had assumed, wrongly, that getdents == getdents64 on this platform (and ia64 too it seems) but the kernel structure used by getdents does not include a type field. Must convert now. The resulting type field in the internals structure, and that passed back to the user too of course, will be set to DT_UNKNOWN. There must be a Cray SPR filed for this but I'll be duurned if I can find a reference. Oh well, no association then. Just an out of the blue fix. Index: fs_native.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/drivers/native/fs_native.c,v retrieving revision 1.33 retrieving revision 1.34 diff -u -w -b -B -p -r1.33 -r1.34 --- fs_native.c 25 Feb 2004 16:23:58 -0000 1.33 +++ fs_native.c 14 Apr 2004 17:25:43 -0000 1.34 @@ -82,6 +82,33 @@ #include <sys/uio.h> #endif +#if defined(SYS_getdirentries) +#define DIR_STREAMED 0 +#define DIR_CVT_64 0 +#elif defined(SYS_getdents64) +#define DIR_STREAMED 0 +#define DIR_CVT_64 0 +#elif defined(SYS_getdents) +#define DIR_STREAMED 0 +#if defined(_LARGEFILE64_SOURCE) +#define DIR_CVT_64 1 +/* + * Kernel version of directory entry. + */ +struct linux_dirent { + unsigned long ld_ino; + unsigned long ld_off; + unsigned short ld_reclen; + char ld_name[1]; +}; +#include <dirent.h> +#else /* !defined(_LARGEFILE64_SOURCE) */ +#define DIR_CVT_64 0 +#endif /* defined(_LARGEFILE64_SOURCE) */ +#else /* catch-none */ +#error No usable directory fill entries interface available +#endif + /* * Local host file system driver. */ @@ -883,34 +910,34 @@ native_pos(int fd, _SYSIO_OFF_T *offset, } static ssize_t -native_getdirentries(struct inode *ino, +native_filldirentries(struct native_inode *nino, char *buf, size_t nbytes, _SYSIO_OFF_T *basep) { - struct native_inode *nino = I2NI(ino); - int err; -#ifndef SYS_getdirentries +#if !DIR_STREAMED _SYSIO_OFF_T result; #endif ssize_t cc; - assert(nino->ni_fd >= 0); + if (*basep < 0) + return -EINVAL; -#ifndef SYS_getdirentries +#if !DIR_STREAMED + /* + * Stream-oriented access requires that we reposition prior to the + * fill call. + */ result = *basep; - if (*basep != nino->ni_fpos) { - err = native_pos(nino->ni_fd, &result, SEEK_SET); - if (err) - return err; - } + if (*basep != nino->ni_fpos && + (cc = native_pos(nino->ni_fd, &result, SEEK_SET)) != 0) + return cc; nino->ni_fpos = result; -#ifdef SYS_getdents64 - cc = syscall(SYS_getdents64, nino->ni_fd, buf, nbytes); #else - cc = syscall(SYS_getdents, nino->ni_fd, buf, nbytes); + nino->ni_fpos = *basep; #endif -#else /* defined(SYS_getdirentries) */ + +#if defined(SYS_getdirentries) cc = syscall(SYS_getdirentries, nino->ni_fd, @@ -918,11 +945,87 @@ native_getdirentries(struct inode *ino, nbytes, basep, &nino->ni_fpos); -#endif /* !defined(SYS_getdirentries) */ +#elif defined(SYS_getdents64) + cc = syscall(SYS_getdents64, nino->ni_fd, buf, nbytes); +#elif defined(SYS_getdents) + cc = syscall(SYS_getdents, nino->ni_fd, buf, nbytes); +#endif + if (cc < 0) return -errno; -#ifndef SYS_getdirentries nino->ni_fpos += cc; + return cc; +} + +static ssize_t +native_getdirentries(struct inode *ino, + char *buf, + size_t nbytes, + _SYSIO_OFF_T *basep) +{ + struct native_inode *nino = I2NI(ino); +#if DIR_CVT_64 + char *bp; + size_t count; + struct linux_dirent *ldp; + struct dirent64 *d64p; + size_t namlen; + size_t reclen; +#else +#define bp buf +#define count nbytes +#endif + ssize_t cc; + + assert(nino->ni_fd >= 0); + +#if DIR_CVT_64 + count = nbytes; + while (!(bp = malloc(count))) { + count /= 2; + if (count < sizeof(struct dirent)) + return -ENOMEM; + } +#endif + cc = native_filldirentries(nino, bp, count, basep); + if (cc < 0) { +#if DIR_CVT_64 + free(bp); +#endif + return cc; + } +#if DIR_CVT_64 + ldp = (struct linux_dirent *)bp; + d64p = (struct dirent64 *)buf; + for (;;) { + if (cc < 0 || (size_t )cc <= sizeof(*ldp)) + break; + namlen = strlen(ldp->ld_name); + reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen + 1; + if (nbytes < reclen) + break; + d64p->d_ino = ldp->ld_ino; + d64p->d_off = ldp->ld_off; + d64p->d_reclen = + (((reclen + sizeof(long) - 1)) / sizeof(long)) * + sizeof(long); + if (nbytes < d64p->d_reclen) + d64p->d_reclen = reclen; + d64p->d_type = DT_UNKNOWN; /* you lose -- sorry. */ + (void )strncpy(d64p->d_name, ldp->ld_name, namlen); + *(d64p->d_name + namlen) = '\0'; + cc -= ldp->ld_reclen; + ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen); + nbytes -= d64p->d_reclen; + d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen); + } + free(bp); + if (d64p == (struct dirent64 *)buf && cc) + cc = -EINVAL; /* buf too small */ + cc = (char *)d64p - buf; +#else +#undef bp +#undef count #endif return cc; } |