dirread.c - 9base - revived minimalist port of Plan 9 userland to Unix
(HTM) git clone git://git.suckless.org/9base
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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->d_name[2]==0)
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, 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, estr);
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 }