Blob


1 #include <u.h>
2 #include <libc.h>
4 #undef asctime
5 #undef ctime
6 #undef gmtime
7 #undef localtime
9 #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 int
16 mygetdents(int fd, char *buf, int n)
17 {
18 ssize_t nn;
19 #if _GETDIRENTRIES_TAKES_LONG
20 long off;
21 #else
22 off_t off;
23 #endif
25 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 int
33 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 else
50 m++;
51 p += de->d_reclen;
52 }
53 return m;
54 }
56 static int
57 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 else
82 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;
104 fchdir(oldwd);
105 close(oldwd);
106 *dp = d;
107 return m;
110 long
111 dirread(int fd, Dir **dp)
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;
134 n = dirpackage(fd, buf, n, dp);
135 free(buf);
136 return n;
140 long
141 dirreadall(int fd, Dir **d)
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;
161 buf = nbuf;
162 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
163 if(n <= 0)
164 break;
165 ts += n;
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;