Blob
1 #include <u.h>2 #include <libc.h>4 #undef asctime5 #undef ctime6 #undef gmtime7 #undef localtime9 #include <sys/stat.h>10 #include <dirent.h>12 extern int _p9dir(struct stat*, char*, Dir*, char**, char*);14 /* everyone has getdirentries, just use that */15 static int16 mygetdents(int fd, char *buf, int n)17 {18 ssize_t nn;19 #if _GETDIRENTRIES_TAKES_LONG20 long off;21 #else22 off_t off;23 #endif25 off = seek(fd, 0, 1);26 nn = getdirentries(fd, buf, n, &off);27 if(nn > 0)28 seek(fd, off, 0);29 return nn;30 }32 static int33 countde(char *p, int n)34 {35 char *e;36 int m;37 struct dirent *de;39 e = p+n;40 m = 0;41 while(p < e){42 de = (struct dirent*)p;43 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)44 break;45 if(de->d_name[0]=='.' && de->d_name[1]==0)46 de->d_name[0] = 0;47 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)48 de->d_name[0] = 0;49 else50 m++;51 p += de->d_reclen;52 }53 return m;54 }56 static int57 dirpackage(int fd, char *buf, int n, Dir **dp)58 {59 int oldwd;60 char *p, *str, *estr;61 int i, nstr, m;62 struct dirent *de;63 struct stat st;64 Dir *d;66 n = countde(buf, n);67 if(n <= 0)68 return n;70 if((oldwd = open(".", O_RDONLY)) < 0)71 return -1;72 if(fchdir(fd) < 0)73 return -1;75 p = buf;76 nstr = 0;77 for(i=0; i<n; i++){78 de = (struct dirent*)p;79 if(stat(de->d_name, &st) < 0)80 de->d_name[0] = 0;81 else82 nstr += _p9dir(&st, de->d_name, nil, nil, nil);83 p += de->d_reclen;84 }86 d = malloc(sizeof(Dir)*n+nstr);87 if(d == nil){88 fchdir(oldwd);89 close(oldwd);90 return -1;91 }92 str = (char*)&d[n];93 estr = str+nstr;95 p = buf;96 m = 0;97 for(i=0; i<n; i++){98 de = (struct dirent*)p;99 if(de->d_name[0] != 0 && stat(de->d_name, &st) >= 0)100 _p9dir(&st, de->d_name, &d[m++], &str, estr);101 p += de->d_reclen;102 }104 fchdir(oldwd);105 close(oldwd);106 *dp = d;107 return m;108 }110 long111 dirread(int fd, Dir **dp)112 {113 char *buf;114 struct stat st;115 int n;117 *dp = 0;119 if(fstat(fd, &st) < 0)120 return -1;122 if(st.st_blksize < 8192)123 st.st_blksize = 8192;125 buf = malloc(st.st_blksize);126 if(buf == nil)127 return -1;129 n = mygetdents(fd, (void*)buf, st.st_blksize);130 if(n < 0){131 free(buf);132 return -1;133 }134 n = dirpackage(fd, buf, n, dp);135 free(buf);136 return n;137 }140 long141 dirreadall(int fd, Dir **d)142 {143 uchar *buf, *nbuf;144 long n, ts;145 struct stat st;147 if(fstat(fd, &st) < 0)148 return -1;150 if(st.st_blksize < 8192)151 st.st_blksize = 8192;153 buf = nil;154 ts = 0;155 for(;;){156 nbuf = realloc(buf, ts+st.st_blksize);157 if(nbuf == nil){158 free(buf);159 return -1;160 }161 buf = nbuf;162 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);163 if(n <= 0)164 break;165 ts += n;166 }167 if(ts >= 0)168 ts = dirpackage(fd, buf, ts, d);169 free(buf);170 if(ts == 0 && n < 0)171 return -1;172 return ts;173 }