xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/opendir.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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 *
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
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
68 rewinddir(DIR *d)
69 {
70 	int f;
71 	char dname[300];
72 
73 	d->dd_loc = 0;
74 	d->dd_size = 0;
75 	d->dirsize = 0;
76 	d->dirloc = 0;
77 	free(d->dirs);
78 	d->dirs = nil;
79 	if(!d){
80 		return;
81 	}
82 	if(_SEEK(d->dd_fd, 0, 0) < 0){
83 		_syserrno();
84 		return;
85 	}
86 }
87 
88 struct dirent *
89 readdir(DIR *d)
90 {
91 	int i, n;
92 	struct dirent *dr;
93 	Dir *dirs;
94 
95 	if(!d){
96 		errno = EBADF;
97 		return NULL;
98 	}
99 	if(d->dd_loc >= d->dd_size){
100 		if(d->dirloc >= d->dirsize){
101 			free(d->dirs);
102 			d->dirsize = _dirread(d->dd_fd, &d->dirs);
103 			d->dirloc = 0;
104 		}
105 		if(d->dirs == NULL)
106 			return NULL;
107 		dr = (struct dirent *)(d->dd_buf);
108 		dirs = d->dirs;
109 		for(i=0; i<DBLOCKSIZE && d->dirloc < d->dirsize; i++){
110 			strncpy(dr[i].d_name, dirs[d->dirloc++].name, MAXNAMLEN);
111 			dr[i].d_name[MAXNAMLEN] = 0;
112 		}
113 		d->dd_loc = 0;
114 		d->dd_size = i*sizeof(struct dirent);
115 	}
116 	dr = (struct dirent*)(d->dd_buf+d->dd_loc);
117 	d->dd_loc += sizeof(struct dirent);
118 	return dr;
119 }
120