diff options
Diffstat (limited to 'src/lib9')
-rw-r--r-- | src/lib9/create.c | 75 | ||||
-rw-r--r-- | src/lib9/dirread.c | 207 | ||||
-rw-r--r-- | src/lib9/fmt/fmt.c | 21 | ||||
-rw-r--r-- | src/lib9/mkfile | 3 | ||||
-rw-r--r-- | src/lib9/open.c | 293 | ||||
-rw-r--r-- | src/lib9/readcons.c | 2 | ||||
-rw-r--r-- | src/lib9/seek.c | 8 |
7 files changed, 312 insertions, 297 deletions
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 <u.h> -#define NOPLAN9DEFINES -#include <sys/file.h> -#include <unistd.h> -#include <fcntl.h> -#include <libc.h> -#include <sys/stat.h> -#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 <u.h> -#define NOPLAN9DEFINES -#include <libc.h> -#include <sys/stat.h> -#include <dirent.h> - -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; i<n; i++){ - de = (struct dirent*)p; - memset(&lst, 0, sizeof lst); - if(de->d_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; i<n; i++){ - de = (struct dirent*)p; - if(de->d_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/fmt/fmt.c b/src/lib9/fmt/fmt.c index a86482c3..47b186a4 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 <stdarg.h> #include <string.h> + +/* + * 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.9). + * AIX is using its own IBM compiler (XL C). + */ +#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)) +#define atomic_store(x, y) (*(x)=(y)) +#define ATOMIC_VAR_INIT(x) (x) +#else #include <stdatomic.h> +#endif + #include "plan9.h" #include "fmt.h" #include "fmtdef.h" diff --git a/src/lib9/mkfile b/src/lib9/mkfile index 7c37de42..db267dfe 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\ @@ -141,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 a0573ae7..2354268b 100644 --- a/src/lib9/open.c +++ b/src/lib9/open.c @@ -1,11 +1,140 @@ #define _GNU_SOURCE /* for Linux O_DIRECT */ #include <u.h> -#define NOPLAN9DEFINES +#include <dirent.h> +#include <errno.h> #include <sys/file.h> +#include <sys/stat.h> +#define NOPLAN9DEFINES #include <libc.h> -#ifndef O_DIRECT -#define O_DIRECT 0 -#endif + +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<nd; i++) + dp[i] = nil; + dirs.d = dp; + dirs.nd = nd; + } + dirs.d[fd] = d; + unlock(&dirs.lk); + return 0; +} + +static DIR* +dirget(int fd) +{ + DIR *d; + + lock(&dirs.lk); + d = nil; + if(0 <= fd && fd < dirs.nd) + d = dirs.d[fd]; + unlock(&dirs.lk); + return d; +} + +static DIR* +dirdel(int fd) +{ + DIR *d; + + lock(&dirs.lk); + d = nil; + if(0 <= fd && fd < dirs.nd) { + d = dirs.d[fd]; + dirs.d[fd] = nil; + } + unlock(&dirs.lk); + return d; +} + +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) @@ -13,6 +142,8 @@ p9open(char *name, int mode) int cexec, rclose; int fd, umode, lock, rdwr; struct flock fl; + struct stat st; + DIR *d; rdwr = mode&3; umode = rdwr; @@ -55,8 +186,162 @@ p9open(char *name, int mode) } if(cexec) fcntl(fd, F_SETFL, FD_CLOEXEC); + if(fstat(fd, &st) >= 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); } return fd; } + +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); +} + +typedef struct DirBuild DirBuild; +struct DirBuild { + Dir *d; + int nd; + int md; + char *str; + char *estr; +}; + +extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); + +static int +dirbuild1(DirBuild *b, struct stat *lst, struct stat *st, char *name) +{ + 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; i<b->nd; 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; + } + _p9dir(lst, st, name, &b->d[b->nd], &b->str, b->estr); + b->nd++; + return 0; +} + +static long +dirreadmax(int fd, Dir **dp, int max) +{ + int i; + DIR *dir; + DirBuild b; + struct dirent *de; + struct stat st, lst; + + if((dir = dirget(fd)) == nil) { + werrstr("not a directory"); + return -1; + } + + memset(&b, 0, sizeof b); + for(i=0; max == -1 || i<max; i++) { // max = not too many, not too few + errno = 0; + de = readdir(dir); + if(de == nil) { + if(b.nd == 0 && errno != 0) + return -1; + break; + } + // 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) + 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); + } + *dp = b.d; + return b.nd; +} + +long +dirread(int fd, Dir **dp) +{ + return dirreadmax(fd, dp, 10); +} + +long +dirreadall(int fd, Dir **dp) +{ + return dirreadmax(fd, dp, -1); +} 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 <libc.h> #include <termios.h> +#ifdef HAS_SYS_TERMIOS #include <sys/termios.h> +#endif static int rawx(int fd, int echoing) 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 <u.h> -#include <libc.h> - -vlong -seek(int fd, vlong offset, int whence) -{ - return lseek(fd, offset, whence); -} |