From c3c9c7b6ae7c6a8bf9c6d040d3af89e020fd92de Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 May 2020 08:37:51 -0400 Subject: fmt: disable use of stdatomic on AIX XL C and old GCC C11 is apparently too new for these systems. Fixes #55. --- src/lib9/fmt/fmt.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/lib9') diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c index a86482c3..fdfff65d 100644 --- a/src/lib9/fmt/fmt.c +++ b/src/lib9/fmt/fmt.c @@ -1,7 +1,28 @@ /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include #include + +/* + * As of 2020, older systems like RHEL 6 and AIX still do not have C11 atomics. + * On those systems, make the code use volatile int accesses and hope for the best. + * (Most uses of fmtinstall are not actually racing with calls to print that lookup + * formats. The code used volatile here for years without too many problems, + * even though that's technically racy. A mutex is not OK, because we want to + * be able to call print from signal handlers.) + * + * RHEL is using an old GCC (atomics were added in GCC 4.8). + * AIX is using its own IBM compiler (XL C). + */ +#if __IBMC__ || !__clang__ && __GNUC__ && (__GNUC__ < 4 || (__GNUC__==4 && __GNUC_MINOR__<8)) +#warning not using C11 stdatomic on legacy system +#define _Atomic volatile +#define atomic_load(x) (*(x)) +#define atomic_store(x, y) (*(x)=(y)) +#define ATOMIC_VAR_INIT(x) (x) +#else #include +#endif + #include "plan9.h" #include "fmt.h" #include "fmtdef.h" -- cgit v1.2.3 From 5802b09e9d8ceadd2cefdccfd0391c04e492369b Mon Sep 17 00:00:00 2001 From: Ben Huntsman Date: Mon, 4 May 2020 19:53:21 -0700 Subject: all: fix #includes for AIX, add a few AIX "implementation" files --- src/lib9/readcons.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/lib9') diff --git a/src/lib9/readcons.c b/src/lib9/readcons.c index 8de44b8f..c07e5971 100644 --- a/src/lib9/readcons.c +++ b/src/lib9/readcons.c @@ -2,7 +2,9 @@ #define NOPLAN9DEFINES #include #include +#ifdef HAS_SYS_TERMIOS #include +#endif static int rawx(int fd, int echoing) -- cgit v1.2.3 From bd6f12068b28ba7eb96a3cd495e2201c852682b7 Mon Sep 17 00:00:00 2001 From: Kurt H Maier Date: Thu, 7 May 2020 17:55:15 -0700 Subject: fmt: adjust GCC version check atomics were added in GCC 4.9: https://gcc.gnu.org/gcc-4.9/changes.html --- src/lib9/fmt/fmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib9') diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c index fdfff65d..47b186a4 100644 --- a/src/lib9/fmt/fmt.c +++ b/src/lib9/fmt/fmt.c @@ -10,10 +10,10 @@ * even though that's technically racy. A mutex is not OK, because we want to * be able to call print from signal handlers.) * - * RHEL is using an old GCC (atomics were added in GCC 4.8). + * RHEL is using an old GCC (atomics were added in GCC 4.9). * AIX is using its own IBM compiler (XL C). */ -#if __IBMC__ || !__clang__ && __GNUC__ && (__GNUC__ < 4 || (__GNUC__==4 && __GNUC_MINOR__<8)) +#if __IBMC__ || !__clang__ && __GNUC__ && (__GNUC__ < 4 || (__GNUC__==4 && __GNUC_MINOR__<9)) #warning not using C11 stdatomic on legacy system #define _Atomic volatile #define atomic_load(x) (*(x)) -- cgit v1.2.3 From 58fdc083addda3f95eb8895f474da5a52f145be0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 17 May 2020 12:35:03 -0400 Subject: lib9: merge create, open, dirread into open.c Preparation for using opendir. --- src/lib9/create.c | 75 --------------- src/lib9/dirread.c | 207 ---------------------------------------- src/lib9/mkfile | 2 - src/lib9/open.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 284 deletions(-) delete mode 100644 src/lib9/create.c delete mode 100644 src/lib9/dirread.c (limited to 'src/lib9') diff --git a/src/lib9/create.c b/src/lib9/create.c deleted file mode 100644 index e4e3c715..00000000 --- a/src/lib9/create.c +++ /dev/null @@ -1,75 +0,0 @@ -#define _GNU_SOURCE /* for Linux O_DIRECT */ -#include -#define NOPLAN9DEFINES -#include -#include -#include -#include -#include -#ifndef O_DIRECT -#define O_DIRECT 0 -#endif - -int -p9create(char *path, int mode, ulong perm) -{ - int fd, cexec, umode, rclose, lock, rdwr; - struct flock fl; - - rdwr = mode&3; - lock = mode&OLOCK; - cexec = mode&OCEXEC; - rclose = mode&ORCLOSE; - mode &= ~(ORCLOSE|OCEXEC|OLOCK); - - /* XXX should get mode mask right? */ - fd = -1; - if(perm&DMDIR){ - if(mode != OREAD){ - werrstr("bad mode in directory create"); - goto out; - } - if(mkdir(path, perm&0777) < 0) - goto out; - fd = open(path, O_RDONLY); - }else{ - umode = (mode&3)|O_CREAT|O_TRUNC; - mode &= ~(3|OTRUNC); - if(mode&ODIRECT){ - umode |= O_DIRECT; - mode &= ~ODIRECT; - } - if(mode&OEXCL){ - umode |= O_EXCL; - mode &= ~OEXCL; - } - if(mode&OAPPEND){ - umode |= O_APPEND; - mode &= ~OAPPEND; - } - if(mode){ - werrstr("unsupported mode in create"); - goto out; - } - fd = open(path, umode, perm); - } -out: - if(fd >= 0){ - if(lock){ - fl.l_type = (rdwr==OREAD) ? F_RDLCK : F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - if(fcntl(fd, F_SETLK, &fl) < 0){ - close(fd); - werrstr("lock: %r"); - return -1; - } - } - if(cexec) - fcntl(fd, F_SETFL, FD_CLOEXEC); - if(rclose) - remove(path); - } - return fd; -} diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c deleted file mode 100644 index c232eb8d..00000000 --- a/src/lib9/dirread.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#define NOPLAN9DEFINES -#include -#include -#include - -extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); - -#if defined(__linux__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - off_t off; - int nn; - - /* This doesn't match the man page, but it works in Debian with a 2.2 kernel */ - off = p9seek(fd, 0, 1); - nn = getdirentries(fd, (void*)buf, n, &off); - return nn; -} -#elif defined(__APPLE__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - long off; - return getdirentries(fd, (void*)buf, n, &off); -} -#elif defined(__FreeBSD__) || defined(__DragonFly__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - off_t off; - return getdirentries(fd, (void*)buf, n, &off); -} -#elif defined(__sun__) || defined(__NetBSD__) || defined(__OpenBSD__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - return getdents(fd, (void*)buf, n); -} -#elif defined(__AIX__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - return getdirent(fd, (void*)buf, n); -} -#endif - -#if defined(__DragonFly__) -static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); } -#else -static inline int d_reclen(struct dirent *de) { return de->d_reclen; } -#endif - -static int -countde(char *p, int n) -{ - char *e; - int m; - struct dirent *de; - - e = p+n; - m = 0; - while(p < e){ - de = (struct dirent*)p; - if(d_reclen(de) <= 4+2+2+1 || p+d_reclen(de) > e) - break; - if(de->d_name[0]=='.' && de->d_name[1]==0) - de->d_name[0] = 0; - else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) - de->d_name[0] = 0; - m++; - p += d_reclen(de); - } - return m; -} - -static int -dirpackage(int fd, char *buf, int n, Dir **dp) -{ - int oldwd; - char *p, *str, *estr; - int i, nstr, m; - struct dirent *de; - struct stat st, lst; - Dir *d; - - n = countde(buf, n); - if(n <= 0) - return n; - - if((oldwd = open(".", O_RDONLY)) < 0) - return -1; - if(fchdir(fd) < 0) - return -1; - - p = buf; - nstr = 0; - - for(i=0; id_name[0] == 0) - /* nothing */ {} - else if(lstat(de->d_name, &lst) < 0) - de->d_name[0] = 0; - else{ - st = lst; - if(S_ISLNK(lst.st_mode)) - stat(de->d_name, &st); - nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil); - } - p += d_reclen(de); - } - - d = malloc(sizeof(Dir)*n+nstr); - if(d == nil){ - fchdir(oldwd); - close(oldwd); - return -1; - } - str = (char*)&d[n]; - estr = str+nstr; - - p = buf; - m = 0; - for(i=0; id_name[0] != 0 && lstat(de->d_name, &lst) >= 0){ - st = lst; - if((lst.st_mode&S_IFMT) == S_IFLNK) - stat(de->d_name, &st); - _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr); - } - p += d_reclen(de); - } - - fchdir(oldwd); - close(oldwd); - *dp = d; - return m; -} - -long -dirread(int fd, Dir **dp) -{ - char *buf; - struct stat st; - int n; - - *dp = 0; - - if(fstat(fd, &st) < 0) - return -1; - - if(st.st_blksize < 8192) - st.st_blksize = 8192; - - buf = malloc(st.st_blksize); - if(buf == nil) - return -1; - - n = mygetdents(fd, (void*)buf, st.st_blksize); - if(n < 0){ - free(buf); - return -1; - } - n = dirpackage(fd, buf, n, dp); - free(buf); - return n; -} - - -long -dirreadall(int fd, Dir **d) -{ - uchar *buf, *nbuf; - long n, ts; - struct stat st; - - if(fstat(fd, &st) < 0) - return -1; - - if(st.st_blksize < 8192) - st.st_blksize = 8192; - - buf = nil; - ts = 0; - for(;;){ - nbuf = realloc(buf, ts+st.st_blksize); - if(nbuf == nil){ - free(buf); - return -1; - } - buf = nbuf; - n = mygetdents(fd, (void*)(buf+ts), st.st_blksize); - if(n <= 0) - break; - ts += n; - } - if(ts >= 0) - ts = dirpackage(fd, (char*)buf, ts, d); - free(buf); - if(ts == 0 && n < 0) - return -1; - return ts; -} diff --git a/src/lib9/mkfile b/src/lib9/mkfile index 7c37de42..6fb3d4a7 100644 --- a/src/lib9/mkfile +++ b/src/lib9/mkfile @@ -86,14 +86,12 @@ LIB9OFILES=\ convM2D.$O\ convM2S.$O\ convS2M.$O\ - create.$O\ crypt.$O\ ctime.$O\ dial.$O\ dirfstat.$O\ dirfwstat.$O\ dirmodefmt.$O\ - dirread.$O\ dirstat.$O\ dirwstat.$O\ dup.$O\ diff --git a/src/lib9/open.c b/src/lib9/open.c index a0573ae7..44a4feee 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -2,11 +2,79 @@ #include #define NOPLAN9DEFINES #include +#include +#include #include +#include +#include #ifndef O_DIRECT #define O_DIRECT 0 #endif +int +p9create(char *path, int mode, ulong perm) +{ + int fd, cexec, umode, rclose, lock, rdwr; + struct flock fl; + + rdwr = mode&3; + lock = mode&OLOCK; + cexec = mode&OCEXEC; + rclose = mode&ORCLOSE; + mode &= ~(ORCLOSE|OCEXEC|OLOCK); + + /* XXX should get mode mask right? */ + fd = -1; + if(perm&DMDIR){ + if(mode != OREAD){ + werrstr("bad mode in directory create"); + goto out; + } + if(mkdir(path, perm&0777) < 0) + goto out; + fd = open(path, O_RDONLY); + }else{ + umode = (mode&3)|O_CREAT|O_TRUNC; + mode &= ~(3|OTRUNC); + if(mode&ODIRECT){ + umode |= O_DIRECT; + mode &= ~ODIRECT; + } + if(mode&OEXCL){ + umode |= O_EXCL; + mode &= ~OEXCL; + } + if(mode&OAPPEND){ + umode |= O_APPEND; + mode &= ~OAPPEND; + } + if(mode){ + werrstr("unsupported mode in create"); + goto out; + } + fd = open(path, umode, perm); + } +out: + if(fd >= 0){ + if(lock){ + fl.l_type = (rdwr==OREAD) ? F_RDLCK : F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + if(fcntl(fd, F_SETLK, &fl) < 0){ + close(fd); + werrstr("lock: %r"); + return -1; + } + } + if(cexec) + fcntl(fd, F_SETFL, FD_CLOEXEC); + if(rclose) + remove(path); + } + return fd; +} + int p9open(char *name, int mode) { @@ -60,3 +128,205 @@ p9open(char *name, int mode) } return fd; } + +extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); + +#if defined(__linux__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + off_t off; + int nn; + + /* This doesn't match the man page, but it works in Debian with a 2.2 kernel */ + off = p9seek(fd, 0, 1); + nn = getdirentries(fd, (void*)buf, n, &off); + return nn; +} +#elif defined(__APPLE__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + long off; + return getdirentries(fd, (void*)buf, n, &off); +} +#elif defined(__FreeBSD__) || defined(__DragonFly__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + off_t off; + return getdirentries(fd, (void*)buf, n, &off); +} +#elif defined(__sun__) || defined(__NetBSD__) || defined(__OpenBSD__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + return getdents(fd, (void*)buf, n); +} +#elif defined(__AIX__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + return getdirent(fd, (void*)buf, n); +} +#endif + +#if defined(__DragonFly__) +static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); } +#else +static inline int d_reclen(struct dirent *de) { return de->d_reclen; } +#endif + +static int +countde(char *p, int n) +{ + char *e; + int m; + struct dirent *de; + + e = p+n; + m = 0; + while(p < e){ + de = (struct dirent*)p; + if(d_reclen(de) <= 4+2+2+1 || p+d_reclen(de) > e) + break; + if(de->d_name[0]=='.' && de->d_name[1]==0) + de->d_name[0] = 0; + else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) + de->d_name[0] = 0; + m++; + p += d_reclen(de); + } + return m; +} + +static int +dirpackage(int fd, char *buf, int n, Dir **dp) +{ + int oldwd; + char *p, *str, *estr; + int i, nstr, m; + struct dirent *de; + struct stat st, lst; + Dir *d; + + n = countde(buf, n); + if(n <= 0) + return n; + + if((oldwd = open(".", O_RDONLY)) < 0) + return -1; + if(fchdir(fd) < 0) + return -1; + + p = buf; + nstr = 0; + + for(i=0; id_name[0] == 0) + /* nothing */ {} + else if(lstat(de->d_name, &lst) < 0) + de->d_name[0] = 0; + else{ + st = lst; + if(S_ISLNK(lst.st_mode)) + stat(de->d_name, &st); + nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil); + } + p += d_reclen(de); + } + + d = malloc(sizeof(Dir)*n+nstr); + if(d == nil){ + fchdir(oldwd); + close(oldwd); + return -1; + } + str = (char*)&d[n]; + estr = str+nstr; + + p = buf; + m = 0; + for(i=0; id_name[0] != 0 && lstat(de->d_name, &lst) >= 0){ + st = lst; + if((lst.st_mode&S_IFMT) == S_IFLNK) + stat(de->d_name, &st); + _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr); + } + p += d_reclen(de); + } + + fchdir(oldwd); + close(oldwd); + *dp = d; + return m; +} + +long +dirread(int fd, Dir **dp) +{ + char *buf; + struct stat st; + int n; + + *dp = 0; + + if(fstat(fd, &st) < 0) + return -1; + + if(st.st_blksize < 8192) + st.st_blksize = 8192; + + buf = malloc(st.st_blksize); + if(buf == nil) + return -1; + + n = mygetdents(fd, (void*)buf, st.st_blksize); + if(n < 0){ + free(buf); + return -1; + } + n = dirpackage(fd, buf, n, dp); + free(buf); + return n; +} + + +long +dirreadall(int fd, Dir **d) +{ + uchar *buf, *nbuf; + long n, ts; + struct stat st; + + if(fstat(fd, &st) < 0) + return -1; + + if(st.st_blksize < 8192) + st.st_blksize = 8192; + + buf = nil; + ts = 0; + for(;;){ + nbuf = realloc(buf, ts+st.st_blksize); + if(nbuf == nil){ + free(buf); + return -1; + } + buf = nbuf; + n = mygetdents(fd, (void*)(buf+ts), st.st_blksize); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(fd, (char*)buf, ts, d); + free(buf); + if(ts == 0 && n < 0) + return -1; + return ts; +} -- cgit v1.2.3 From 6fd4e901ce48f2e056c505c81320f786175588ff Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 17 May 2020 12:37:11 -0400 Subject: lib9: add close More preparation for opendir. --- src/lib9/open.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/lib9') diff --git a/src/lib9/open.c b/src/lib9/open.c index 44a4feee..43910694 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -129,6 +129,13 @@ p9open(char *name, int mode) return fd; } +int +p9close(int fd) +{ + return close(fd); +} + + extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); #if defined(__linux__) -- cgit v1.2.3 From 16f60479e16e3714b376e633c6b902a32e0607ea Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 17 May 2020 12:38:32 -0400 Subject: lib9: move seek into open.c More preparation for opendir. --- src/lib9/mkfile | 1 - src/lib9/open.c | 7 ++++++- src/lib9/seek.c | 8 -------- 3 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 src/lib9/seek.c (limited to 'src/lib9') diff --git a/src/lib9/mkfile b/src/lib9/mkfile index 6fb3d4a7..db267dfe 100644 --- a/src/lib9/mkfile +++ b/src/lib9/mkfile @@ -139,7 +139,6 @@ LIB9OFILES=\ readn.$O\ rfork.$O\ searchpath.$O\ - seek.$O\ sendfd.$O\ sleep.$O\ strdup.$O\ diff --git a/src/lib9/open.c b/src/lib9/open.c index 43910694..ffee7931 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -129,13 +129,18 @@ p9open(char *name, int mode) return fd; } +vlong +p9seek(int fd, vlong offset, int whence) +{ + return lseek(fd, offset, whence); +} + int p9close(int fd) { return close(fd); } - extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); #if defined(__linux__) diff --git a/src/lib9/seek.c b/src/lib9/seek.c deleted file mode 100644 index b626355f..00000000 --- a/src/lib9/seek.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -vlong -seek(int fd, vlong offset, int whence) -{ - return lseek(fd, offset, whence); -} -- cgit v1.2.3 From 8cb7308f3a24249ed091c7decf22005c64099783 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 17 May 2020 20:02:07 -0400 Subject: lib9: use opendir/readdir to read directories getdirentries(2) has been deprecated on macOS since 10.5 (ten releases ago). Using it requires disabling 64-bit inodes, but that in turn makes binaries incompatible with some dynamic libraries, most notably ASAN. At some point getdirentries(2) will actually be removed. For both these reasons, switch to opendir/readdir. A little clunky since we have to keep the DIR* hidden away to preserve the int fd interfaces, but it lets us remove a bunch of OS-specific code too. --- src/lib9/open.c | 370 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 187 insertions(+), 183 deletions(-) (limited to 'src/lib9') diff --git a/src/lib9/open.c b/src/lib9/open.c index ffee7931..65ea99ec 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -1,15 +1,76 @@ #define _GNU_SOURCE /* for Linux O_DIRECT */ #include -#define NOPLAN9DEFINES +#include +#include #include -#include -#include -#include #include -#include -#ifndef O_DIRECT -#define O_DIRECT 0 -#endif +#define NOPLAN9DEFINES +#include + +static struct { + Lock lk; + DIR **d; + int nd; +} dirs; + +static int +dirput(int fd, DIR *d) +{ + int i, nd; + DIR **dp; + + if(fd < 0) { + werrstr("invalid fd"); + return -1; + } + lock(&dirs.lk); + if(fd >= dirs.nd) { + nd = dirs.nd*2; + if(nd <= fd) + nd = fd+1; + dp = realloc(dirs.d, nd*sizeof dirs.d[0]); + if(dp == nil) { + werrstr("out of memory"); + unlock(&dirs.lk); + return -1; + } + for(i=dirs.nd; i= 0 && S_ISDIR(st.st_mode)) { + d = fdopendir(fd); + if(d == nil) { + close(fd); + return -1; + } + if(dirput(fd, d) < 0) { + closedir(d); + return -1; + } + } if(rclose) remove(name); } @@ -132,213 +206,143 @@ p9open(char *name, int mode) vlong p9seek(int fd, vlong offset, int whence) { + DIR *d; + + if((d = dirget(fd)) != nil) { + if(whence == 1 && offset == 0) + return telldir(d); + if(whence == 0) { + seekdir(d, offset); + return 0; + } + werrstr("bad seek in directory"); + return -1; + } + return lseek(fd, offset, whence); } int p9close(int fd) { + DIR *d; + + if((d = dirdel(fd)) != nil) + return closedir(d); return close(fd); } -extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); - -#if defined(__linux__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - off_t off; - int nn; - - /* This doesn't match the man page, but it works in Debian with a 2.2 kernel */ - off = p9seek(fd, 0, 1); - nn = getdirentries(fd, (void*)buf, n, &off); - return nn; -} -#elif defined(__APPLE__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - long off; - return getdirentries(fd, (void*)buf, n, &off); -} -#elif defined(__FreeBSD__) || defined(__DragonFly__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - off_t off; - return getdirentries(fd, (void*)buf, n, &off); -} -#elif defined(__sun__) || defined(__NetBSD__) || defined(__OpenBSD__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - return getdents(fd, (void*)buf, n); -} -#elif defined(__AIX__) -static int -mygetdents(int fd, struct dirent *buf, int n) -{ - return getdirent(fd, (void*)buf, n); -} -#endif +typedef struct DirBuild DirBuild; +struct DirBuild { + Dir *d; + int nd; + int md; + char *str; + char *estr; +}; -#if defined(__DragonFly__) -static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); } -#else -static inline int d_reclen(struct dirent *de) { return de->d_reclen; } -#endif +extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); static int -countde(char *p, int n) +dirbuild1(DirBuild *b, struct stat *lst, struct stat *st, char *name) { - char *e; - int m; - struct dirent *de; - - e = p+n; - m = 0; - while(p < e){ - de = (struct dirent*)p; - if(d_reclen(de) <= 4+2+2+1 || p+d_reclen(de) > e) - break; - if(de->d_name[0]=='.' && de->d_name[1]==0) - de->d_name[0] = 0; - else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) - de->d_name[0] = 0; - m++; - p += d_reclen(de); + int i, nstr; + Dir *d; + int md, mstr; + char *lo, *hi, *newlo; + + nstr = _p9dir(lst, st, name, nil, nil, nil); + if(b->md-b->nd < 1 || b->estr-b->str < nstr) { + // expand either d space or str space or both. + md = b->md; + if(b->md-b->nd < 1) { + md *= 2; + if(md < 16) + md = 16; + } + mstr = b->estr-(char*)&b->d[b->md]; + if(b->estr-b->str < nstr) { + mstr += nstr; + mstr += mstr/2; + } + if(mstr < 512) + mstr = 512; + d = realloc(b->d, md*sizeof d[0] + mstr); + if(d == nil) + return -1; + // move strings and update pointers in Dirs + lo = (char*)&b->d[b->md]; + newlo = (char*)&d[md]; + hi = b->str; + memmove(newlo, lo+((char*)d-(char*)b->d), hi-lo); + for(i=0; ind; i++) { + if(lo <= d[i].name && d[i].name < hi) + d[i].name += newlo - lo; + if(lo <= d[i].uid && d[i].uid < hi) + d[i].uid += newlo - lo; + if(lo <= d[i].gid && d[i].gid < hi) + d[i].gid += newlo - lo; + if(lo <= d[i].muid && d[i].muid < hi) + d[i].muid += newlo - lo; + } + b->d = d; + b->md = md; + b->str += newlo - lo; + b->estr = newlo + mstr; } - return m; + _p9dir(lst, st, name, &b->d[b->nd], &b->str, b->estr); + b->nd++; + return 0; } -static int -dirpackage(int fd, char *buf, int n, Dir **dp) +static long +dirreadmax(int fd, Dir **dp, int max) { - int oldwd; - char *p, *str, *estr; - int i, nstr, m; + int i; + DIR *dir; + DirBuild b; struct dirent *de; struct stat st, lst; - Dir *d; - - n = countde(buf, n); - if(n <= 0) - return n; - - if((oldwd = open(".", O_RDONLY)) < 0) - return -1; - if(fchdir(fd) < 0) - return -1; - - p = buf; - nstr = 0; - - for(i=0; id_name[0] == 0) - /* nothing */ {} - else if(lstat(de->d_name, &lst) < 0) - de->d_name[0] = 0; - else{ - st = lst; - if(S_ISLNK(lst.st_mode)) - stat(de->d_name, &st); - nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil); - } - p += d_reclen(de); - } - d = malloc(sizeof(Dir)*n+nstr); - if(d == nil){ - fchdir(oldwd); - close(oldwd); + if((dir = dirget(fd)) == nil) { + werrstr("not a directory"); return -1; } - str = (char*)&d[n]; - estr = str+nstr; - p = buf; - m = 0; - for(i=0; id_name[0] != 0 && lstat(de->d_name, &lst) >= 0){ - st = lst; - if((lst.st_mode&S_IFMT) == S_IFLNK) - stat(de->d_name, &st); - _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr); + memset(&b, 0, sizeof b); + for(i=0; max == -1 || id_name[de->d_namlen] != 0) + sysfatal("bad readdir"); + if(de->d_name[0]=='.' && de->d_name[1]==0) + continue; + if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) + continue; + if(fstatat(fd, de->d_name, &lst, AT_SYMLINK_NOFOLLOW) < 0) + continue; + st = lst; + if(S_ISLNK(lst.st_mode)) + fstatat(fd, de->d_name, &st, 0); + dirbuild1(&b, &lst, &st, de->d_name); } - - fchdir(oldwd); - close(oldwd); - *dp = d; - return m; + *dp = b.d; + return b.nd; } long dirread(int fd, Dir **dp) { - char *buf; - struct stat st; - int n; - - *dp = 0; - - if(fstat(fd, &st) < 0) - return -1; - - if(st.st_blksize < 8192) - st.st_blksize = 8192; - - buf = malloc(st.st_blksize); - if(buf == nil) - return -1; - - n = mygetdents(fd, (void*)buf, st.st_blksize); - if(n < 0){ - free(buf); - return -1; - } - n = dirpackage(fd, buf, n, dp); - free(buf); - return n; + return dirreadmax(fd, dp, 10); } - long -dirreadall(int fd, Dir **d) +dirreadall(int fd, Dir **dp) { - uchar *buf, *nbuf; - long n, ts; - struct stat st; - - if(fstat(fd, &st) < 0) - return -1; - - if(st.st_blksize < 8192) - st.st_blksize = 8192; - - buf = nil; - ts = 0; - for(;;){ - nbuf = realloc(buf, ts+st.st_blksize); - if(nbuf == nil){ - free(buf); - return -1; - } - buf = nbuf; - n = mygetdents(fd, (void*)(buf+ts), st.st_blksize); - if(n <= 0) - break; - ts += n; - } - if(ts >= 0) - ts = dirpackage(fd, (char*)buf, ts, d); - free(buf); - if(ts == 0 && n < 0) - return -1; - return ts; + return dirreadmax(fd, dp, -1); } -- cgit v1.2.3 From c53ad837a734f7570badcb3666ccb3604e7e6467 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 18 May 2020 17:03:42 -0400 Subject: lib9: avoid unportable use of d_namlen in dirread Fixes #395. --- src/lib9/open.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/lib9') diff --git a/src/lib9/open.c b/src/lib9/open.c index 65ea99ec..2354268b 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -318,8 +318,7 @@ dirreadmax(int fd, Dir **dp, int max) return -1; break; } - if(de->d_name[de->d_namlen] != 0) - sysfatal("bad readdir"); + // Note: not all systems have d_namlen. Assume NUL-terminated. if(de->d_name[0]=='.' && de->d_name[1]==0) continue; if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) -- cgit v1.2.3