lib9: merge create, open, dirread into open.c

Preparation for using opendir.
This commit is contained in:
Russ Cox 2020-05-17 12:35:03 -04:00
parent bd6f12068b
commit 58fdc083ad
5 changed files with 273 additions and 292 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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\

View file

@ -2,11 +2,79 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <sys/file.h>
#include <unistd.h>
#include <fcntl.h>
#include <libc.h>
#include <sys/stat.h>
#include <dirent.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;
}
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; 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;
}

View file

@ -20,14 +20,12 @@ echo cd `pwd`
9c convM2D.c
9c convM2S.c
9c convS2M.c
9c create.c
9c crypt.c
9c ctime.c
9c dial.c
9c dirfstat.c
9c dirfwstat.c
9c dirmodefmt.c
9c dirread.c
9c dirstat.c
9c dirwstat.c
9c dup.c
@ -109,6 +107,7 @@ echo cd `pwd`
9c -Ifmt fmt/fmtstr.c
9c -Ifmt fmt/fmtvprint.c
9c -Ifmt fmt/fprint.c
9c frexp.c
9c -Ifmt fmt/nan64.c
9c -Ifmt fmt/print.c
9c -Ifmt fmt/runefmtstr.c
@ -150,7 +149,7 @@ echo cd `pwd`
9c utf/utfrrune.c
9c utf/utfrune.c
9c utf/utfutf.c
9ar rsc $PLAN9/lib/lib9.a _exits.o _p9dialparse.o _p9dir.o announce.o argv0.o atexit.o atoi.o atol.o atoll.o atnotify.o await.o cistrcmp.o cistrncmp.o cistrstr.o cleanname.o convD2M.o 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 encodefmt.o errstr.o exec.o execl.o exitcode.o fcallfmt.o frand.o get9root.o getcallerpc.o getenv.o getfields.o getnetconn.o getns.o getuser.o getwd.o jmp.o lrand.o lnrand.o main.o malloc.o malloctag.o mallocz.o nan.o needsrcquote.o needstack.o netcrypt.o netmkaddr.o notify.o nrand.o nulldir.o open.o opentemp.o pin.o pipe.o post9p.o postnote.o qlock.o quote.o rand.o read9pmsg.o readcons.o readn.o rfork.o searchpath.o seek.o sendfd.o sleep.o strdup.o strecpy.o sysfatal.o syslog.o sysname.o time.o tm2sec.o tokenize.o truerand.o u16.o u32.o u64.o unsharp.o wait.o waitpid.o write.o zoneinfo.o dofmt.o fltfmt.o fmt.o fmtfd.o fmtfdflush.o fmtlocale.o fmtlock2.o fmtnull.o fmtprint.o fmtquote.o fmtrune.o fmtstr.o fmtvprint.o fprint.o nan64.o print.o runefmtstr.o runeseprint.o runesmprint.o runesnprint.o runesprint.o runevseprint.o runevsmprint.o runevsnprint.o seprint.o smprint.o snprint.o sprint.o strtod.o vfprint.o vseprint.o vsmprint.o vsnprint.o charstod.o pow10.o rune.o runestrcat.o runestrchr.o runestrcmp.o runestrcpy.o runestrdup.o runestrlen.o runestrecpy.o runestrncat.o runestrncmp.o runestrncpy.o runestrrchr.o runestrstr.o runetype.o utfecpy.o utflen.o utfnlen.o utfrrune.o utfrune.o utfutf.o
9ar rsc $PLAN9/lib/lib9.a _exits.o _p9dialparse.o _p9dir.o announce.o argv0.o atexit.o atoi.o atol.o atoll.o atnotify.o await.o cistrcmp.o cistrncmp.o cistrstr.o cleanname.o convD2M.o convM2D.o convM2S.o convS2M.o crypt.o ctime.o dial.o dirfstat.o dirfwstat.o dirmodefmt.o dirstat.o dirwstat.o dup.o encodefmt.o errstr.o exec.o execl.o exitcode.o fcallfmt.o frand.o get9root.o getcallerpc.o getenv.o getfields.o getnetconn.o getns.o getuser.o getwd.o jmp.o lrand.o lnrand.o main.o malloc.o malloctag.o mallocz.o nan.o needsrcquote.o needstack.o netcrypt.o netmkaddr.o notify.o nrand.o nulldir.o open.o opentemp.o pin.o pipe.o post9p.o postnote.o qlock.o quote.o rand.o read9pmsg.o readcons.o readn.o rfork.o searchpath.o seek.o sendfd.o sleep.o strdup.o strecpy.o sysfatal.o syslog.o sysname.o time.o tm2sec.o tokenize.o truerand.o u16.o u32.o u64.o unsharp.o wait.o waitpid.o write.o zoneinfo.o dofmt.o fltfmt.o fmt.o fmtfd.o fmtfdflush.o fmtlocale.o fmtlock2.o fmtnull.o fmtprint.o fmtquote.o fmtrune.o fmtstr.o fmtvprint.o fprint.o frexp.o nan64.o print.o runefmtstr.o runeseprint.o runesmprint.o runesnprint.o runesprint.o runevseprint.o runevsmprint.o runevsnprint.o seprint.o smprint.o snprint.o sprint.o strtod.o vfprint.o vseprint.o vsmprint.o vsnprint.o charstod.o pow10.o rune.o runestrcat.o runestrchr.o runestrcmp.o runestrcpy.o runestrdup.o runestrlen.o runestrecpy.o runestrncat.o runestrncmp.o runestrncpy.o runestrrchr.o runestrstr.o runetype.o utfecpy.o utflen.o utfnlen.o utfrrune.o utfrune.o utfutf.o
cd ..
cd libbio
echo cd `pwd`
@ -211,9 +210,5 @@ echo cd `pwd`
9c word.c
9c unix.c
9l -o o.mk arc.o archive.o bufblock.o env.o file.o graph.o job.o lex.o main.o match.o mk.o parse.o recipe.o rc.o rule.o run.o sh.o shell.o shprint.o symtab.o var.o varsub.o word.o unix.o
if [ `uname` = AIX ]; then
installbsd o.mk $PLAN9/bin/mk
else
install o.mk $PLAN9/bin/mk
fi
install o.mk $PLAN9/bin/mk
cd ..