| /* 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) |
| { |
| 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(statcheck(&buf[i], m) < 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 || convM2D(&buf[i], m, *d + nn, s) != 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); |
| 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); |
| if(ts < 0) |
| werrstr("malformed directory contents"); |
| } |
| free(buf); |
| if(ts == 0 && n < 0) |
| return -1; |
| return ts; |
| } |