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__) || defined(__FreeBSD__) || defined(__OpenBSD__)
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(__sun__) || defined(__NetBSD__)
29 static int
30 mygetdents(int fd, struct dirent *buf, int n)
31 {
32 return getdents(fd, (void*)buf, n);
33 }
34 #elif defined(__AIX__)
35 static int
36 mygetdents(int fd, struct dirent *buf, int n)
37 {
38 return getdirent(fd, (void*)buf, n);
39 }
40 #endif
42 static int
43 countde(char *p, int n)
44 {
45 char *e;
46 int m;
47 struct dirent *de;
49 e = p+n;
50 m = 0;
51 while(p < e){
52 de = (struct dirent*)p;
53 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
54 break;
55 if(de->d_name[0]=='.' && de->d_name[1]==0)
56 de->d_name[0] = 0;
57 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
58 de->d_name[0] = 0;
59 m++;
60 p += de->d_reclen;
61 }
62 return m;
63 }
65 static int
66 dirpackage(int fd, char *buf, int n, Dir **dp)
67 {
68 int oldwd;
69 char *p, *str, *estr;
70 int i, nstr, m;
71 struct dirent *de;
72 struct stat st, lst;
73 Dir *d;
75 n = countde(buf, n);
76 if(n <= 0)
77 return n;
79 if((oldwd = open(".", O_RDONLY)) < 0)
80 return -1;
81 if(fchdir(fd) < 0)
82 return -1;
84 p = buf;
85 nstr = 0;
87 for(i=0; i<n; i++){
88 de = (struct dirent*)p;
89 memset(&lst, 0, sizeof lst);
90 if(de->d_name[0] == 0)
91 /* nothing */ {}
92 else if(lstat(de->d_name, &lst) < 0)
93 de->d_name[0] = 0;
94 else{
95 st = lst;
96 if(S_ISLNK(lst.st_mode))
97 stat(de->d_name, &st);
98 nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
99 }
100 p += de->d_reclen;
103 d = malloc(sizeof(Dir)*n+nstr);
104 if(d == nil){
105 fchdir(oldwd);
106 close(oldwd);
107 return -1;
109 str = (char*)&d[n];
110 estr = str+nstr;
112 p = buf;
113 m = 0;
114 for(i=0; i<n; i++){
115 de = (struct dirent*)p;
116 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
117 st = lst;
118 if((lst.st_mode&S_IFMT) == S_IFLNK)
119 stat(de->d_name, &st);
120 _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
122 p += de->d_reclen;
125 fchdir(oldwd);
126 close(oldwd);
127 *dp = d;
128 return m;
131 long
132 dirread(int fd, Dir **dp)
134 char *buf;
135 struct stat st;
136 int n;
138 *dp = 0;
140 if(fstat(fd, &st) < 0)
141 return -1;
143 if(st.st_blksize < 8192)
144 st.st_blksize = 8192;
146 buf = malloc(st.st_blksize);
147 if(buf == nil)
148 return -1;
150 n = mygetdents(fd, (void*)buf, st.st_blksize);
151 if(n < 0){
152 free(buf);
153 return -1;
155 n = dirpackage(fd, buf, n, dp);
156 free(buf);
157 return n;
161 long
162 dirreadall(int fd, Dir **d)
164 uchar *buf, *nbuf;
165 long n, ts;
166 struct stat st;
168 if(fstat(fd, &st) < 0)
169 return -1;
171 if(st.st_blksize < 8192)
172 st.st_blksize = 8192;
174 buf = nil;
175 ts = 0;
176 for(;;){
177 nbuf = realloc(buf, ts+st.st_blksize);
178 if(nbuf == nil){
179 free(buf);
180 return -1;
182 buf = nbuf;
183 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
184 if(n <= 0)
185 break;
186 ts += n;
188 if(ts >= 0)
189 ts = dirpackage(fd, (char*)buf, ts, d);
190 free(buf);
191 if(ts == 0 && n < 0)
192 return -1;
193 return ts;