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(__DragonFly__)
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__) || defined(__OpenBSD__)
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 #if defined(__DragonFly__)
50 static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); }
51 #else
52 static inline int d_reclen(struct dirent *de) { return de->d_reclen; }
53 #endif
55 static int
56 countde(char *p, int n)
57 {
58 char *e;
59 int m;
60 struct dirent *de;
62 e = p+n;
63 m = 0;
64 while(p < e){
65 de = (struct dirent*)p;
66 if(d_reclen(de) <= 4+2+2+1 || p+d_reclen(de) > e)
67 break;
68 if(de->d_name[0]=='.' && de->d_name[1]==0)
69 de->d_name[0] = 0;
70 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
71 de->d_name[0] = 0;
72 m++;
73 p += d_reclen(de);
74 }
75 return m;
76 }
78 static int
79 dirpackage(int fd, char *buf, int n, Dir **dp)
80 {
81 int oldwd;
82 char *p, *str, *estr;
83 int i, nstr, m;
84 struct dirent *de;
85 struct stat st, lst;
86 Dir *d;
88 n = countde(buf, n);
89 if(n <= 0)
90 return n;
92 if((oldwd = open(".", O_RDONLY)) < 0)
93 return -1;
94 if(fchdir(fd) < 0)
95 return -1;
97 p = buf;
98 nstr = 0;
100 for(i=0; i<n; i++){
101 de = (struct dirent*)p;
102 memset(&lst, 0, sizeof lst);
103 if(de->d_name[0] == 0)
104 /* nothing */ {}
105 else if(lstat(de->d_name, &lst) < 0)
106 de->d_name[0] = 0;
107 else{
108 st = lst;
109 if(S_ISLNK(lst.st_mode))
110 stat(de->d_name, &st);
111 nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
113 p += d_reclen(de);
116 d = malloc(sizeof(Dir)*n+nstr);
117 if(d == nil){
118 fchdir(oldwd);
119 close(oldwd);
120 return -1;
122 str = (char*)&d[n];
123 estr = str+nstr;
125 p = buf;
126 m = 0;
127 for(i=0; i<n; i++){
128 de = (struct dirent*)p;
129 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
130 st = lst;
131 if((lst.st_mode&S_IFMT) == S_IFLNK)
132 stat(de->d_name, &st);
133 _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
135 p += d_reclen(de);
138 fchdir(oldwd);
139 close(oldwd);
140 *dp = d;
141 return m;
144 long
145 dirread(int fd, Dir **dp)
147 char *buf;
148 struct stat st;
149 int n;
151 *dp = 0;
153 if(fstat(fd, &st) < 0)
154 return -1;
156 if(st.st_blksize < 8192)
157 st.st_blksize = 8192;
159 buf = malloc(st.st_blksize);
160 if(buf == nil)
161 return -1;
163 n = mygetdents(fd, (void*)buf, st.st_blksize);
164 if(n < 0){
165 free(buf);
166 return -1;
168 n = dirpackage(fd, buf, n, dp);
169 free(buf);
170 return n;
174 long
175 dirreadall(int fd, Dir **d)
177 uchar *buf, *nbuf;
178 long n, ts;
179 struct stat st;
181 if(fstat(fd, &st) < 0)
182 return -1;
184 if(st.st_blksize < 8192)
185 st.st_blksize = 8192;
187 buf = nil;
188 ts = 0;
189 for(;;){
190 nbuf = realloc(buf, ts+st.st_blksize);
191 if(nbuf == nil){
192 free(buf);
193 return -1;
195 buf = nbuf;
196 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
197 if(n <= 0)
198 break;
199 ts += n;
201 if(ts >= 0)
202 ts = dirpackage(fd, (char*)buf, ts, d);
203 free(buf);
204 if(ts == 0 && n < 0)
205 return -1;
206 return ts;