diff --git a/sys/include/posix.h b/sys/include/posix.h index 37c9075..95e60db 100644 --- a/sys/include/posix.h +++ b/sys/include/posix.h @@ -36,6 +36,7 @@ #ifndef _LIBPOSIX_DIRENT #define _LIBPOSIX_DIRENT + /* dirent alias of stat(5) message. * We (ab)use the fact that both 9P and Jehanne are little endian. * With the new file protocol this might change. @@ -53,7 +54,7 @@ struct __attribute__((__packed__)) dirent unsigned int __pad4__; /* don't use */ unsigned long d_filesize; unsigned short d_namlen; - char* d_name; + char d_name[]; }; #define _DIRENT_HAVE_D_RECLEN @@ -64,6 +65,16 @@ struct __attribute__((__packed__)) dirent #define _DIRENT_HAVE_D_NAMLEN #undef _DIRENT_HAVE_D_OFF +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + #endif /* _LIBPOSIX_DIRENT */ #ifndef _LIBPOSIX_H @@ -110,7 +121,7 @@ extern void POSIX_free(void *ptr); extern unsigned int POSIX_sleep(unsigned int seconds); extern int POSIX_pipe(int *errnop, int fildes[2]); -extern int libposix_getdents(int *errnop, int fd, struct dirent *buf, int buf_bytes); +extern int libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes); /* Library initialization */ diff --git a/sys/src/lib/posix/files.c b/sys/src/lib/posix/files.c index 39d8324..49cedd3 100644 --- a/sys/src/lib/posix/files.c +++ b/sys/src/lib/posix/files.c @@ -17,6 +17,7 @@ */ #include #include +#include <9P2000.h> #include #include "internal.h" @@ -360,7 +361,84 @@ POSIX_stat(int *errnop, const char *file, void *pstat) } int -libposix_getdents(int *errnop, int fd, struct dirent *buf, int buf_bytes) +libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes) { - return 0; +#define MINSTATLEN (STATFIXLEN + 4) /* 4 = min (1 char) name, uid, gid, muid */ + + int r; + Dir *d; + struct dirent *dp; + char *p; + + if(fd < 0) + goto FailWithEBADF; + if(buf == nil) + goto FailWithEFAULT; + if(buf_bytes < MINSTATLEN) + goto FailWithEINVAL; + + d = dirfstat(fd); + if(d == nil) + goto FailWithENOENT; /* removed? */ + r = d->mode & DMDIR; + free(d); + + if(r == 0) + goto FailWithENOTDIR; /* not a directory */ + + r = read(fd, buf, buf_bytes); + if(r < 0) + goto FailWithENOENT; /* removed? */ + if(r < MINSTATLEN) + goto FailWithEIO; + + p = buf; + while(p - buf < r){ + /* here we adjust 9P2000 stat info to match + * dirent specification + */ + dp = (struct dirent *)p; + + /* the count field in stat structure exclude itself */ + dp->d_reclen += BIT16SZ; + + /* 9P2000 strings are not NUL-terminated */ + dp->d_name[dp->d_namlen] = '\0'; + + /* we have to map types to UNIX */ + if(dp->d_type & (DMDIR >> 24)) + dp->d_type = DT_DIR; + else if(dp->__pad1__ == '|') /* kernel device == devpipe */ + dp->d_type = DT_FIFO; + else + dp->d_type = DT_REG; /* UNIX lack fantasy :-) */ + + p += dp->d_reclen; + } + + return r; + +FailWithEBADF: + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + +FailWithEFAULT: + *errnop = __libposix_get_errno(PosixEFAULT); + return -1; + +FailWithEINVAL: + *errnop = __libposix_get_errno(PosixEINVAL); + return -1; + +FailWithENOENT: + *errnop = __libposix_get_errno(PosixENOENT); + return -1; + +FailWithENOTDIR: + *errnop = __libposix_get_errno(PosixENOTDIR); + return -1; + +FailWithEIO: + *errnop = __libposix_get_errno(PosixEIO); + return -1; }