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*, 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__)
29 static int
30 mygetdents(int fd, struct dirent *buf, int n)
31 {
32 return getdents(fd, (void*)buf, n);
33 }
34 #endif
36 static int
37 countde(char *p, int n)
38 {
39 char *e;
40 int m;
41 struct dirent *de;
43 e = p+n;
44 m = 0;
45 while(p < e){
46 de = (struct dirent*)p;
47 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
48 break;
49 if(de->d_name[0]=='.' && de->d_name[1]==0)
50 de->d_name[0] = 0;
51 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
52 de->d_name[0] = 0;
53 m++;
54 p += de->d_reclen;
55 }
56 return m;
57 }
59 static int
60 dirpackage(int fd, char *buf, int n, Dir **dp)
61 {
62 int oldwd;
63 char *p, *str, *estr;
64 int i, nstr, m;
65 struct dirent *de;
66 struct stat st;
67 Dir *d;
69 n = countde(buf, n);
70 if(n <= 0)
71 return n;
73 if((oldwd = open(".", O_RDONLY)) < 0)
74 return -1;
75 if(fchdir(fd) < 0)
76 return -1;
78 p = buf;
79 nstr = 0;
81 for(i=0; i<n; i++){
82 de = (struct dirent*)p;
83 if(de->d_name[0] == 0)
84 /* nothing */ {}
85 else if(stat(de->d_name, &st) < 0)
86 de->d_name[0] = 0;
87 else
88 nstr += _p9dir(&st, de->d_name, nil, nil, nil);
89 p += de->d_reclen;
90 }
92 d = malloc(sizeof(Dir)*n+nstr);
93 if(d == nil){
94 fchdir(oldwd);
95 close(oldwd);
96 return -1;
97 }
98 str = (char*)&d[n];
99 estr = str+nstr;
101 p = buf;
102 m = 0;
103 for(i=0; i<n; i++){
104 de = (struct dirent*)p;
105 if(de->d_name[0] != 0 && stat(de->d_name, &st) >= 0)
106 _p9dir(&st, de->d_name, &d[m++], &str, estr);
107 p += de->d_reclen;
110 fchdir(oldwd);
111 close(oldwd);
112 *dp = d;
113 return m;
116 long
117 dirread(int fd, Dir **dp)
119 char *buf;
120 struct stat st;
121 int n;
123 *dp = 0;
125 if(fstat(fd, &st) < 0)
126 return -1;
128 if(st.st_blksize < 8192)
129 st.st_blksize = 8192;
131 buf = malloc(st.st_blksize);
132 if(buf == nil)
133 return -1;
135 n = mygetdents(fd, (void*)buf, st.st_blksize);
136 if(n < 0){
137 free(buf);
138 return -1;
140 n = dirpackage(fd, buf, n, dp);
141 free(buf);
142 return n;
146 long
147 dirreadall(int fd, Dir **d)
149 uchar *buf, *nbuf;
150 long n, ts;
151 struct stat st;
153 if(fstat(fd, &st) < 0)
154 return -1;
156 if(st.st_blksize < 8192)
157 st.st_blksize = 8192;
159 buf = nil;
160 ts = 0;
161 for(;;){
162 nbuf = realloc(buf, ts+st.st_blksize);
163 if(nbuf == nil){
164 free(buf);
165 return -1;
167 buf = nbuf;
168 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
169 if(n <= 0)
170 break;
171 ts += n;
173 if(ts >= 0)
174 ts = dirpackage(fd, (char*)buf, ts, d);
175 free(buf);
176 if(ts == 0 && n < 0)
177 return -1;
178 return ts;