diff options
author | rsc <devnull@localhost> | 2003-11-23 18:12:54 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-11-23 18:12:54 +0000 |
commit | fd04aacee17b348da206c13a550dc1029669805f (patch) | |
tree | 9bdd35a25ff6e3d6e9a0171b06240a76723f922c /src/lib9/dirread.c | |
parent | 74f990ad84deb1591ddb91be4fc8152ec0c46222 (diff) | |
download | plan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.gz plan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.bz2 plan9port-fd04aacee17b348da206c13a550dc1029669805f.zip |
Various additions and fixes.
Diffstat (limited to 'src/lib9/dirread.c')
-rw-r--r-- | src/lib9/dirread.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c new file mode 100644 index 00000000..f4610f68 --- /dev/null +++ b/src/lib9/dirread.c @@ -0,0 +1,155 @@ +#include <u.h> +#include <libc.h> + +#undef asctime +#undef ctime +#undef gmtime +#undef localtime + +#include <sys/stat.h> +#include <dirent.h> + +extern int _p9dir(struct stat*, char*, Dir*, char**, char*); + +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(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e) + break; + if(de->d_namlen == 1 && de->d_name[0]=='.') + de->d_namlen = 0; + else if(de->d_namlen == 2 && de->d_name[0]=='.' && de->d_name[1]=='.') + de->d_namlen = 0; + else + m++; + p += de->d_reclen; + } + 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; + 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; + if(stat(de->d_name, &st) < 0) + de->d_namlen = 0; + else + nstr += _p9dir(&st, de->d_name, nil, nil, nil); + p += de->d_reclen; + } + + 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_namlen != 0 && stat(de->d_name, &st) >= 0) + _p9dir(&st, de->d_name, &d[m++], &str, estr); + p += de->d_reclen; + } + + 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 = getdents(fd, 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 = getdents(fd, buf+ts, st.st_blksize); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(fd, buf, ts, d); + free(buf); + if(ts == 0 && n < 0) + return -1; + return ts; +} |