[Libsysio-commit] gmdev: libsysio/drivers/native fs_native.c
Brought to you by:
lward
From: Ruth K. <rk...@us...> - 2004-04-27 22:55:49
|
Update of /cvsroot/libsysio/libsysio/drivers/native In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29858/native Modified Files: Tag: gmdev fs_native.c Log Message: merge head changes into gmdev branch Index: fs_native.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/drivers/native/fs_native.c,v retrieving revision 1.33.2.1 retrieving revision 1.33.2.2 diff -u -w -b -B -p -r1.33.2.1 -r1.33.2.2 --- fs_native.c 4 Mar 2004 18:08:06 -0000 1.33.2.1 +++ fs_native.c 27 Apr 2004 22:55:40 -0000 1.33.2.2 @@ -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. */ @@ -220,6 +247,7 @@ static int native_inop_unlink(struct pno static int native_inop_rename(struct pnode *old, struct pnode *new); static int native_inop_read(struct inode *ino, struct ioctx *ioctx); static int native_inop_write(struct inode *ino, struct ioctx *ioctx); +static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off); static int native_inop_iodone(struct ioctx *ioctx); static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap); static int native_inop_sync(struct inode *ino); @@ -257,6 +285,7 @@ static struct inode_ops native_i_ops = { native_inop_rename, native_inop_read, native_inop_write, + native_inop_pos, native_inop_iodone, native_inop_fcntl, native_inop_sync, @@ -890,46 +919,125 @@ 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 - _SYSIO_OFF_T result; -#endif ssize_t cc; - assert(nino->ni_fd >= 0); + if (*basep < 0) + return -EINVAL; -#ifndef SYS_getdirentries - result = *basep; - if (*basep != nino->ni_fpos) { - err = native_pos(nino->ni_fd, &result, SEEK_SET); - if (err) +#if !DIR_STREAMED + /* + * Stream-oriented access requires that we reposition prior to the + * fill call. + */ + if ((err = native_pos(nino->ni_fd, basep, SEEK_SET)) != 0) return err; - } - 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); #endif -#else /* defined(SYS_getdirentries) */ + nino->ni_fpos = *basep; + cc = +#if defined(SYS_getdirentries) syscall(SYS_getdirentries, nino->ni_fd, buf, nbytes, basep, &nino->ni_fpos); -#endif /* !defined(SYS_getdirentries) */ +#elif defined(SYS_getdents64) + syscall(SYS_getdents64, nino->ni_fd, buf, nbytes); +#elif defined(SYS_getdents) + syscall(SYS_getdents, nino->ni_fd, buf, nbytes); +#endif + if (cc < 0) return -errno; -#ifndef SYS_getdirentries - nino->ni_fpos += cc; +#if !DIR_STREAMED + /* + * Stream-oriented access requires that we discover where we are + * after the call. + */ + *basep = 0; + if ((err = native_pos(nino->ni_fd, basep, SEEK_CUR)) != 0) + return err; +#endif + nino->ni_fpos = *basep; + 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; } @@ -1197,24 +1305,49 @@ out: static ssize_t dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio) { +#if defined(_LARGEFILE64_SOURCE) && \ + defined(SYS_pread64) && \ + defined(SYS_pwrite64) +#define _NATIVE_SYSCALL_PREAD SYS_pread64 +#define _NATIVE_SYSCALL_PWRITE SYS_pwrite64 +#else +#define _NATIVE_SYSCALL_PREAD SYS_pread +#define _NATIVE_SYSCALL_PWRITE SYS_pwrite +#endif + ssize_t cc; + + if (!(off == nio->nio_nino->ni_fpos || nio->nio_nino->ni_seekok)) + return -ESPIPE; + if (!nio->nio_nino->ni_seekok) { + if (off != nio->nio_nino->ni_fpos) { /* - * Avoid the reposition call if we're already at the right place. - * Allows us to access pipes and fifos. + * They've done a p{read,write} or somesuch. Can't + * seek on this descriptor so we err out now. */ - if (off != nio->nio_nino->ni_fpos) { - int err; - - err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET); - if (err) - return err; - nio->nio_nino->ni_fpos = off; + errno = ESPIPE; + return -1; } - - return syscall(nio->nio_op == 'r' ? SYS_read : SYS_write, + cc = + syscall(nio->nio_op == 'r' ? SYS_read : SYS_write, nio->nio_nino->ni_fd, buf, count); + if (cc > 0) + nio->nio_nino->ni_fpos += cc; + } else + cc = + syscall((nio->nio_op == 'r' + ? _NATIVE_SYSCALL_PREAD + : _NATIVE_SYSCALL_PWRITE), + nio->nio_nino->ni_fd, + buf, + count, + off); + + return cc; +#undef _NATIVE_SYSCALL_PREAD +#undef _NATIVE_SYSCALL_PWRITE } static ssize_t @@ -1419,6 +1552,16 @@ native_inop_write(struct inode *ino __IS return doio('w', ioctx); } +static _SYSIO_OFF_T +native_inop_pos(struct inode *ino, _SYSIO_OFF_T off) +{ + struct native_inode *nino = I2NI(ino); + int err; + + err = native_pos(nino->ni_fd, &off, SEEK_SET); + return err < 0 ? err : off; +} + static int native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED) { |