dirread.c (3712B)
1 #include <u.h> 2 #define NOPLAN9DEFINES 3 #include <libc.h> 4 #include <sys/stat.h> 5 #include <dirent.h> 6 7 #if defined (__linux__) 8 # include <sys/syscall.h> 9 # if defined (_LARGEFILE64_SOURCE) 10 # define getdents SYS_getdents64 11 # else 12 # define getdents SYS_getdents 13 # endif 14 #endif 15 16 extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); 17 18 #if defined(__linux__) 19 static int 20 mygetdents(int fd, struct dirent *buf, int n) { 21 return syscall (getdents, fd, (void*) buf, n); 22 } 23 #elif defined(__APPLE__) || defined(__FreeBSD__) 24 static int 25 mygetdents(int fd, struct dirent *buf, int n) 26 { 27 long off; 28 return getdirentries(fd, (void*)buf, n, &off); 29 } 30 #elif defined(__OpenBSD__) 31 #include <sys/param.h> 32 # if OpenBSD < 201405 /* for OpenBSD 5.4 and earlier */ 33 static int 34 mygetdents(int fd, struct dirent *buf, int n) 35 { 36 off_t off; 37 return getdirentries(fd, (void*)buf, n, &off); 38 } 39 # else 40 static int 41 mygetdents(int fd, struct dirent *buf, int n) 42 { 43 return getdents(fd, (void*)buf, n); 44 } 45 # endif 46 #elif defined(__sun__) || defined(__NetBSD__) 47 static int 48 mygetdents(int fd, struct dirent *buf, int n) 49 { 50 return getdents(fd, (void*)buf, n); 51 } 52 #elif defined(__AIX__) 53 static int 54 mygetdents(int fd, struct dirent *buf, int n) 55 { 56 return getdirent(fd, (void*)buf, n); 57 } 58 #endif 59 60 static int 61 countde(char *p, int n) 62 { 63 char *e; 64 int m; 65 struct dirent *de; 66 67 e = p+n; 68 m = 0; 69 while(p < e){ 70 de = (struct dirent*)p; 71 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e) 72 break; 73 if(de->d_name[0]=='.' && de->d_name[1]==0) 74 de->d_name[0] = 0; 75 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0) 76 de->d_name[0] = 0; 77 m++; 78 p += de->d_reclen; 79 } 80 return m; 81 } 82 83 static int 84 dirpackage(int fd, char *buf, int n, Dir **dp) 85 { 86 int oldwd; 87 char *p, *str, *estr; 88 int i, nstr, m; 89 struct dirent *de; 90 struct stat st, lst; 91 Dir *d; 92 93 n = countde(buf, n); 94 if(n <= 0) 95 return n; 96 97 if((oldwd = open(".", O_RDONLY)) < 0) 98 return -1; 99 if(fchdir(fd) < 0) 100 return -1; 101 102 p = buf; 103 nstr = 0; 104 105 for(i=0; i<n; i++){ 106 de = (struct dirent*)p; 107 memset(&lst, 0, sizeof lst); 108 if(de->d_name[0] == 0) 109 /* nothing */ {} 110 else if(lstat(de->d_name, &lst) < 0) 111 de->d_name[0] = 0; 112 else{ 113 st = lst; 114 if(S_ISLNK(lst.st_mode)) 115 stat(de->d_name, &st); 116 nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil); 117 } 118 p += de->d_reclen; 119 } 120 121 d = malloc(sizeof(Dir)*n+nstr); 122 if(d == nil){ 123 fchdir(oldwd); 124 close(oldwd); 125 return -1; 126 } 127 str = (char*)&d[n]; 128 estr = str+nstr; 129 130 p = buf; 131 m = 0; 132 for(i=0; i<n; i++){ 133 de = (struct dirent*)p; 134 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){ 135 st = lst; 136 if((lst.st_mode&S_IFMT) == S_IFLNK) 137 stat(de->d_name, &st); 138 _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr); 139 } 140 p += de->d_reclen; 141 } 142 143 fchdir(oldwd); 144 close(oldwd); 145 *dp = d; 146 return m; 147 } 148 149 long 150 dirread(int fd, Dir **dp) 151 { 152 char *buf; 153 struct stat st; 154 int n; 155 156 *dp = 0; 157 158 if(fstat(fd, &st) < 0) 159 return -1; 160 161 if(st.st_blksize < 8192) 162 st.st_blksize = 8192; 163 164 buf = malloc(st.st_blksize); 165 if(buf == nil) 166 return -1; 167 168 n = mygetdents(fd, (void*)buf, st.st_blksize); 169 if(n < 0){ 170 free(buf); 171 return -1; 172 } 173 n = dirpackage(fd, buf, n, dp); 174 free(buf); 175 return n; 176 } 177 178 179 long 180 dirreadall(int fd, Dir **d) 181 { 182 uchar *buf, *nbuf; 183 long n, ts; 184 struct stat st; 185 186 if(fstat(fd, &st) < 0) 187 return -1; 188 189 if(st.st_blksize < 8192) 190 st.st_blksize = 8192; 191 192 buf = nil; 193 ts = 0; 194 for(;;){ 195 nbuf = realloc(buf, ts+st.st_blksize); 196 if(nbuf == nil){ 197 free(buf); 198 return -1; 199 } 200 buf = nbuf; 201 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize); 202 if(n <= 0) 203 break; 204 ts += n; 205 } 206 if(ts >= 0) 207 ts = dirpackage(fd, (char*)buf, ts, d); 208 free(buf); 209 if(ts == 0 && n < 0) 210 return -1; 211 return ts; 212 }