dirread.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
dirread.c (3712B) | |
--- | |
1 #include <u.h> | |
2 #define NOPLAN9DEFINES | |
3 #include <libc.h> | |
4 #include <sys/stat.h> | |
5 #include <dirent.h> | |
6 | |
7 #if defined (__linux__) | |
8 # include <sys/syscall.h> | |
9 # if defined (_LARGEFILE64_SOURCE) | |
10 # define getdents SYS_getdents64 | |
11 # else | |
12 # define getdents SYS_getdents | |
13 # endif | |
14 #endif | |
15 | |
16 extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*… | |
17 | |
18 #if defined(__linux__) | |
19 static int | |
20 mygetdents(int fd, struct dirent *buf, int n) { | |
21 return syscall (getdents, fd, (void*) buf, n); | |
22 } | |
23 #elif defined(__APPLE__) || defined(__FreeBSD__) | |
24 static int | |
25 mygetdents(int fd, struct dirent *buf, int n) | |
26 { | |
27 long off; | |
28 return getdirentries(fd, (void*)buf, n, &off); | |
29 } | |
30 #elif defined(__OpenBSD__) | |
31 #include <sys/param.h> | |
32 # if OpenBSD < 201405 /* for OpenBSD 5.4 and earlier */ | |
33 static int | |
34 mygetdents(int fd, struct dirent *buf, int n) | |
35 { | |
36 off_t off; | |
37 return getdirentries(fd, (void*)buf, n, &off); | |
38 } | |
39 # else | |
40 static int | |
41 mygetdents(int fd, struct dirent *buf, int n) | |
42 { | |
43 return getdents(fd, (void*)buf, n); | |
44 } | |
45 # endif | |
46 #elif defined(__sun__) || defined(__NetBSD__) | |
47 static int | |
48 mygetdents(int fd, struct dirent *buf, int n) | |
49 { | |
50 return getdents(fd, (void*)buf, n); | |
51 } | |
52 #elif defined(__AIX__) | |
53 static int | |
54 mygetdents(int fd, struct dirent *buf, int n) | |
55 { | |
56 return getdirent(fd, (void*)buf, n); | |
57 } | |
58 #endif | |
59 | |
60 static int | |
61 countde(char *p, int n) | |
62 { | |
63 char *e; | |
64 int m; | |
65 struct dirent *de; | |
66 | |
67 e = p+n; | |
68 m = 0; | |
69 while(p < e){ | |
70 de = (struct dirent*)p; | |
71 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e) | |
72 break; | |
73 if(de->d_name[0]=='.' && de->d_name[1]==0) | |
74 de->d_name[0] = 0; | |
75 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->… | |
76 de->d_name[0] = 0; | |
77 m++; | |
78 p += de->d_reclen; | |
79 } | |
80 return m; | |
81 } | |
82 | |
83 static int | |
84 dirpackage(int fd, char *buf, int n, Dir **dp) | |
85 { | |
86 int oldwd; | |
87 char *p, *str, *estr; | |
88 int i, nstr, m; | |
89 struct dirent *de; | |
90 struct stat st, lst; | |
91 Dir *d; | |
92 | |
93 n = countde(buf, n); | |
94 if(n <= 0) | |
95 return n; | |
96 | |
97 if((oldwd = open(".", O_RDONLY)) < 0) | |
98 return -1; | |
99 if(fchdir(fd) < 0) | |
100 return -1; | |
101 | |
102 p = buf; | |
103 nstr = 0; | |
104 | |
105 for(i=0; i<n; i++){ | |
106 de = (struct dirent*)p; | |
107 memset(&lst, 0, sizeof lst); | |
108 if(de->d_name[0] == 0) | |
109 /* nothing */ {} | |
110 else if(lstat(de->d_name, &lst) < 0) | |
111 de->d_name[0] = 0; | |
112 else{ | |
113 st = lst; | |
114 if(S_ISLNK(lst.st_mode)) | |
115 stat(de->d_name, &st); | |
116 nstr += _p9dir(&lst, &st, de->d_name, nil, nil, … | |
117 } | |
118 p += de->d_reclen; | |
119 } | |
120 | |
121 d = malloc(sizeof(Dir)*n+nstr); | |
122 if(d == nil){ | |
123 fchdir(oldwd); | |
124 close(oldwd); | |
125 return -1; | |
126 } | |
127 str = (char*)&d[n]; | |
128 estr = str+nstr; | |
129 | |
130 p = buf; | |
131 m = 0; | |
132 for(i=0; i<n; i++){ | |
133 de = (struct dirent*)p; | |
134 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){ | |
135 st = lst; | |
136 if((lst.st_mode&S_IFMT) == S_IFLNK) | |
137 stat(de->d_name, &st); | |
138 _p9dir(&lst, &st, de->d_name, &d[m++], &str, est… | |
139 } | |
140 p += de->d_reclen; | |
141 } | |
142 | |
143 fchdir(oldwd); | |
144 close(oldwd); | |
145 *dp = d; | |
146 return m; | |
147 } | |
148 | |
149 long | |
150 dirread(int fd, Dir **dp) | |
151 { | |
152 char *buf; | |
153 struct stat st; | |
154 int n; | |
155 | |
156 *dp = 0; | |
157 | |
158 if(fstat(fd, &st) < 0) | |
159 return -1; | |
160 | |
161 if(st.st_blksize < 8192) | |
162 st.st_blksize = 8192; | |
163 | |
164 buf = malloc(st.st_blksize); | |
165 if(buf == nil) | |
166 return -1; | |
167 | |
168 n = mygetdents(fd, (void*)buf, st.st_blksize); | |
169 if(n < 0){ | |
170 free(buf); | |
171 return -1; | |
172 } | |
173 n = dirpackage(fd, buf, n, dp); | |
174 free(buf); | |
175 return n; | |
176 } | |
177 | |
178 | |
179 long | |
180 dirreadall(int fd, Dir **d) | |
181 { | |
182 uchar *buf, *nbuf; | |
183 long n, ts; | |
184 struct stat st; | |
185 | |
186 if(fstat(fd, &st) < 0) | |
187 return -1; | |
188 | |
189 if(st.st_blksize < 8192) | |
190 st.st_blksize = 8192; | |
191 | |
192 buf = nil; | |
193 ts = 0; | |
194 for(;;){ | |
195 nbuf = realloc(buf, ts+st.st_blksize); | |
196 if(nbuf == nil){ | |
197 free(buf); | |
198 return -1; | |
199 } | |
200 buf = nbuf; | |
201 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize); | |
202 if(n <= 0) | |
203 break; | |
204 ts += n; | |
205 } | |
206 if(ts >= 0) | |
207 ts = dirpackage(fd, (char*)buf, ts, d); | |
208 free(buf); | |
209 if(ts == 0 && n < 0) | |
210 return -1; | |
211 return ts; | |
212 } |