|  | /* Mostly copied from Plan 9's libc. */ | 
|  |  | 
|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <fcall.h> | 
|  | #include <9pclient.h> | 
|  | #include "fsimpl.h" | 
|  |  | 
|  | static long | 
|  | dirpackage(uchar *buf, long ts, Dir **d, int dotu) | 
|  | { | 
|  | char *s; | 
|  | long ss, i, n, nn, m; | 
|  |  | 
|  | *d = nil; | 
|  | if(ts <= 0) | 
|  | return 0; | 
|  |  | 
|  | /* | 
|  | * first find number of all stats, check they look like stats, & size all associated strings | 
|  | */ | 
|  | ss = 0; | 
|  | n = 0; | 
|  | for(i = 0; i < ts; i += m){ | 
|  | m = BIT16SZ + GBIT16(&buf[i]); | 
|  | if(statchecku(&buf[i], m, dotu) < 0) | 
|  | break; | 
|  | ss += m; | 
|  | n++; | 
|  | } | 
|  |  | 
|  | if(i != ts) | 
|  | return -1; | 
|  |  | 
|  | *d = malloc(n * sizeof(Dir) + ss); | 
|  | if(*d == nil) | 
|  | return -1; | 
|  |  | 
|  | /* | 
|  | * then convert all buffers | 
|  | */ | 
|  | s = (char*)*d + n * sizeof(Dir); | 
|  | nn = 0; | 
|  | for(i = 0; i < ts; i += m){ | 
|  | m = BIT16SZ + GBIT16((uchar*)&buf[i]); | 
|  | if(nn >= n || convM2Du(&buf[i], m, *d + nn, s, dotu) != m){ | 
|  | free(*d); | 
|  | *d = nil; | 
|  | return -1; | 
|  | } | 
|  | nn++; | 
|  | s += m; | 
|  | } | 
|  |  | 
|  | return nn; | 
|  | } | 
|  |  | 
|  | long | 
|  | fsdirread(CFid *fid, Dir **d) | 
|  | { | 
|  | uchar *buf; | 
|  | long ts; | 
|  |  | 
|  | buf = malloc(DIRMAX); | 
|  | if(buf == nil) | 
|  | return -1; | 
|  | ts = fsread(fid, buf, DIRMAX); | 
|  | if(ts >= 0) | 
|  | ts = dirpackage(buf, ts, d, fid->fs->dotu); | 
|  | free(buf); | 
|  | return ts; | 
|  | } | 
|  |  | 
|  | long | 
|  | fsdirreadall(CFid *fid, Dir **d) | 
|  | { | 
|  | uchar *buf, *nbuf; | 
|  | long n, ts; | 
|  |  | 
|  | buf = nil; | 
|  | ts = 0; | 
|  | for(;;){ | 
|  | nbuf = realloc(buf, ts+DIRMAX); | 
|  | if(nbuf == nil){ | 
|  | free(buf); | 
|  | return -1; | 
|  | } | 
|  | buf = nbuf; | 
|  | n = fsread(fid, buf+ts, DIRMAX); | 
|  | if(n <= 0) | 
|  | break; | 
|  | ts += n; | 
|  | } | 
|  | if(ts >= 0){ | 
|  | ts = dirpackage(buf, ts, d, fid->fs->dotu); | 
|  | if(ts < 0) | 
|  | werrstr("malformed directory contents [dotu=%d]", fid->fs->dotu); | 
|  | } | 
|  | free(buf); | 
|  | if(ts == 0 && n < 0) | 
|  | return -1; | 
|  | return ts; | 
|  | } |