xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/opendir.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
1 #include "lib.h"
2 #include <stdlib.h>
3 #include <sys/stat.h>
4 #include <dirent.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8 #include "sys9.h"
9 #include "dir.h"
10 
11 #define DBLOCKSIZE 20
12 
13 DIR *
opendir(const char * filename)14 opendir(const char *filename)
15 {
16 	int f;
17 	DIR *d;
18 	struct stat sb;
19 	Dir *d9;
20 
21 	if((d9 = _dirstat(filename)) == nil){
22 		_syserrno();
23 		return NULL;
24 	}
25 	_dirtostat(&sb, d9, 0);
26 	free(d9);
27 	if(S_ISDIR(sb.st_mode) == 0) {
28 		errno = ENOTDIR;
29 		return NULL;
30 	}
31 
32 	f = open(filename, O_RDONLY);
33 	if(f < 0){
34 		_syserrno();
35 		return NULL;
36 	}
37 	_fdinfo[f].flags |= FD_CLOEXEC;
38 	d = (DIR *)malloc(sizeof(DIR) + DBLOCKSIZE*sizeof(struct dirent));
39 	if(!d){
40 		errno = ENOMEM;
41 		return NULL;
42 	}
43 	d->dd_buf = (char *)d + sizeof(DIR);
44 	d->dd_fd = f;
45 	d->dd_loc = 0;
46 	d->dd_size = 0;
47 	d->dirs = nil;
48 	d->dirsize = 0;
49 	d->dirloc = 0;
50 	return d;
51 }
52 
53 int
closedir(DIR * d)54 closedir(DIR *d)
55 {
56 	if(!d){
57 		errno = EBADF;
58 		return -1;
59 	}
60 	if(close(d->dd_fd) < 0)
61 		return -1;
62 	free(d->dirs);
63 	free(d);
64 	return 0;
65 }
66 
67 void
rewinddir(DIR * d)68 rewinddir(DIR *d)
69 {
70 	if(!d)
71 		return;
72 	d->dd_loc = 0;
73 	d->dd_size = 0;
74 	d->dirsize = 0;
75 	d->dirloc = 0;
76 	free(d->dirs);
77 	d->dirs = nil;
78 	if(_SEEK(d->dd_fd, 0, 0) < 0){
79 		_syserrno();
80 		return;
81 	}
82 }
83 
84 struct dirent *
readdir(DIR * d)85 readdir(DIR *d)
86 {
87 	int i;
88 	struct dirent *dr;
89 	Dir *dirs;
90 
91 	if(!d){
92 		errno = EBADF;
93 		return NULL;
94 	}
95 	if(d->dd_loc >= d->dd_size){
96 		if(d->dirloc >= d->dirsize){
97 			free(d->dirs);
98 			d->dirs = NULL;
99 			d->dirsize = _dirread(d->dd_fd, &d->dirs);
100 			d->dirloc = 0;
101 		}
102 		if(d->dirsize < 0) {	/* malloc or read failed in _dirread? */
103 			free(d->dirs);
104 			d->dirs = NULL;
105 		}
106 		if(d->dirs == NULL)
107 			return NULL;
108 
109 		dr = (struct dirent *)d->dd_buf;
110 		dirs = d->dirs;
111 		for(i=0; i<DBLOCKSIZE && d->dirloc < d->dirsize; i++){
112 			strncpy(dr[i].d_name, dirs[d->dirloc++].name, MAXNAMLEN);
113 			dr[i].d_name[MAXNAMLEN] = 0;
114 		}
115 		d->dd_loc = 0;
116 		d->dd_size = i*sizeof(struct dirent);
117 	}
118 	dr = (struct dirent*)(d->dd_buf+d->dd_loc);
119 	d->dd_loc += sizeof(struct dirent);
120 	return dr;
121 }
122