Blob


1 #include <u.h>
2 #define NOPLAN9DEFINES
3 #include <libc.h>
4 #include <sys/stat.h>
5 #include <dirent.h>
7 extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
9 #if defined(__linux__)
10 static int
11 mygetdents(int fd, struct dirent *buf, int n)
12 {
13 off_t off;
14 int nn;
16 /* This doesn't match the man page, but it works in Debian with a 2.2 kernel */
17 off = p9seek(fd, 0, 1);
18 nn = getdirentries(fd, (void*)buf, n, &off);
19 return nn;
20 }
21 #elif defined(__APPLE__)
22 static int
23 mygetdents(int fd, struct dirent *buf, int n)
24 {
25 long off;
26 return getdirentries(fd, (void*)buf, n, &off);
27 }
28 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
29 static int
30 mygetdents(int fd, struct dirent *buf, int n)
31 {
32 off_t off;
33 return getdirentries(fd, (void*)buf, n, &off);
34 }
35 #elif defined(__sun__) || defined(__NetBSD__)
36 static int
37 mygetdents(int fd, struct dirent *buf, int n)
38 {
39 return getdents(fd, (void*)buf, n);
40 }
41 #elif defined(__AIX__)
42 static int
43 mygetdents(int fd, struct dirent *buf, int n)
44 {
45 return getdirent(fd, (void*)buf, n);
46 }
47 #endif
49 static int
50 countde(char *p, int n)
51 {
52 char *e;
53 int m;
54 struct dirent *de;
56 e = p+n;
57 m = 0;
58 while(p < e){
59 de = (struct dirent*)p;
60 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
61 break;
62 if(de->d_name[0]=='.' && de->d_name[1]==0)
63 de->d_name[0] = 0;
64 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
65 de->d_name[0] = 0;
66 m++;
67 p += de->d_reclen;
68 }
69 return m;
70 }
72 static int
73 dirpackage(int fd, char *buf, int n, Dir **dp)
74 {
75 int oldwd;
76 char *p, *str, *estr;
77 int i, nstr, m;
78 struct dirent *de;
79 struct stat st, lst;
80 Dir *d;
82 n = countde(buf, n);
83 if(n <= 0)
84 return n;
86 if((oldwd = open(".", O_RDONLY)) < 0)
87 return -1;
88 if(fchdir(fd) < 0)
89 return -1;
91 p = buf;
92 nstr = 0;
94 for(i=0; i<n; i++){
95 de = (struct dirent*)p;
96 memset(&lst, 0, sizeof lst);
97 if(de->d_name[0] == 0)
98 /* nothing */ {}
99 else if(lstat(de->d_name, &lst) < 0)
100 de->d_name[0] = 0;
101 else{
102 st = lst;
103 if(S_ISLNK(lst.st_mode))
104 stat(de->d_name, &st);
105 nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
107 p += de->d_reclen;
110 d = malloc(sizeof(Dir)*n+nstr);
111 if(d == nil){
112 fchdir(oldwd);
113 close(oldwd);
114 return -1;
116 str = (char*)&d[n];
117 estr = str+nstr;
119 p = buf;
120 m = 0;
121 for(i=0; i<n; i++){
122 de = (struct dirent*)p;
123 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
124 st = lst;
125 if((lst.st_mode&S_IFMT) == S_IFLNK)
126 stat(de->d_name, &st);
127 _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
129 p += de->d_reclen;
132 fchdir(oldwd);
133 close(oldwd);
134 *dp = d;
135 return m;
138 long
139 dirread(int fd, Dir **dp)
141 char *buf;
142 struct stat st;
143 int n;
145 *dp = 0;
147 if(fstat(fd, &st) < 0)
148 return -1;
150 if(st.st_blksize < 8192)
151 st.st_blksize = 8192;
153 buf = malloc(st.st_blksize);
154 if(buf == nil)
155 return -1;
157 n = mygetdents(fd, (void*)buf, st.st_blksize);
158 if(n < 0){
159 free(buf);
160 return -1;
162 n = dirpackage(fd, buf, n, dp);
163 free(buf);
164 return n;
168 long
169 dirreadall(int fd, Dir **d)
171 uchar *buf, *nbuf;
172 long n, ts;
173 struct stat st;
175 if(fstat(fd, &st) < 0)
176 return -1;
178 if(st.st_blksize < 8192)
179 st.st_blksize = 8192;
181 buf = nil;
182 ts = 0;
183 for(;;){
184 nbuf = realloc(buf, ts+st.st_blksize);
185 if(nbuf == nil){
186 free(buf);
187 return -1;
189 buf = nbuf;
190 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
191 if(n <= 0)
192 break;
193 ts += n;
195 if(ts >= 0)
196 ts = dirpackage(fd, (char*)buf, ts, d);
197 free(buf);
198 if(ts == 0 && n < 0)
199 return -1;
200 return ts;