xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/opendir.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include "lib.h"
23e12c5d1SDavid du Colombier #include <stdlib.h>
33e12c5d1SDavid du Colombier #include <sys/stat.h>
43e12c5d1SDavid du Colombier #include <dirent.h>
53e12c5d1SDavid du Colombier #include <unistd.h>
63e12c5d1SDavid du Colombier #include <errno.h>
73e12c5d1SDavid du Colombier #include <string.h>
83e12c5d1SDavid du Colombier #include "sys9.h"
93e12c5d1SDavid du Colombier #include "dir.h"
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier #define DBLOCKSIZE 20
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier DIR *
143e12c5d1SDavid du Colombier opendir(const char *filename)
153e12c5d1SDavid du Colombier {
163e12c5d1SDavid du Colombier 	int f;
173e12c5d1SDavid du Colombier 	DIR *d;
18*219b2ee8SDavid du Colombier 	struct stat sb;
19*219b2ee8SDavid du Colombier 	char cd[DIRLEN];
203e12c5d1SDavid du Colombier 
21*219b2ee8SDavid du Colombier 	if(_STAT(filename, cd) < 0){
22*219b2ee8SDavid du Colombier 		_syserrno();
23*219b2ee8SDavid du Colombier 		return NULL;
24*219b2ee8SDavid du Colombier 	}
25*219b2ee8SDavid du Colombier 	_dirtostat(&sb, cd, 0);
26*219b2ee8SDavid du Colombier 	if(S_ISDIR(sb.st_mode) == 0) {
27*219b2ee8SDavid du Colombier 		errno = ENOTDIR;
28*219b2ee8SDavid du Colombier 		return NULL;
29*219b2ee8SDavid du Colombier 	}
30*219b2ee8SDavid du Colombier 
31*219b2ee8SDavid du Colombier 	f = open(filename, O_RDONLY);
323e12c5d1SDavid du Colombier 	if(f < 0){
333e12c5d1SDavid du Colombier 		_syserrno();
343e12c5d1SDavid du Colombier 		return NULL;
353e12c5d1SDavid du Colombier 	}
363e12c5d1SDavid du Colombier 	_fdinfo[f].flags |= FD_CLOEXEC;
373e12c5d1SDavid du Colombier 	d = (DIR *)malloc(sizeof(DIR) + DBLOCKSIZE*sizeof(struct dirent));
383e12c5d1SDavid du Colombier 	if(!d){
393e12c5d1SDavid du Colombier 		errno = ENOMEM;
403e12c5d1SDavid du Colombier 		return NULL;
413e12c5d1SDavid du Colombier 	}
423e12c5d1SDavid du Colombier 	d->dd_buf = ((char *)d) + sizeof(DIR);
433e12c5d1SDavid du Colombier 	d->dd_fd = f;
443e12c5d1SDavid du Colombier 	d->dd_loc = 0;
453e12c5d1SDavid du Colombier 	d->dd_size = 0;
463e12c5d1SDavid du Colombier 	return d;
473e12c5d1SDavid du Colombier }
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier int
503e12c5d1SDavid du Colombier closedir(DIR *d)
513e12c5d1SDavid du Colombier {
523e12c5d1SDavid du Colombier 	if(!d){
533e12c5d1SDavid du Colombier 		errno = EBADF;
543e12c5d1SDavid du Colombier 		return -1;
553e12c5d1SDavid du Colombier 	}
563e12c5d1SDavid du Colombier 	if(close(d->dd_fd) < 0)
573e12c5d1SDavid du Colombier 		return -1;
583e12c5d1SDavid du Colombier 	free(d);
593e12c5d1SDavid du Colombier 	return 0;
603e12c5d1SDavid du Colombier }
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier void
633e12c5d1SDavid du Colombier rewinddir(DIR *d)
643e12c5d1SDavid du Colombier {
65*219b2ee8SDavid du Colombier 	int f;
66*219b2ee8SDavid du Colombier 	char dname[300];
67*219b2ee8SDavid du Colombier 
68*219b2ee8SDavid du Colombier 	d->dd_loc = 0;
69*219b2ee8SDavid du Colombier 	d->dd_size = 0;
703e12c5d1SDavid du Colombier 	if(!d){
713e12c5d1SDavid du Colombier 		return;
723e12c5d1SDavid du Colombier 	}
73*219b2ee8SDavid du Colombier 	/* seeks aren't allowed on directories, so reopen */
74*219b2ee8SDavid du Colombier 	strncpy(dname, _fdinfo[d->dd_fd].name, sizeof(dname));
75*219b2ee8SDavid du Colombier 	close(d->dd_fd);
76*219b2ee8SDavid du Colombier 	 f = open(dname, O_RDONLY);
77*219b2ee8SDavid du Colombier 	if (f < 0) {
78*219b2ee8SDavid du Colombier 		_syserrno();
79*219b2ee8SDavid du Colombier 		return;
80*219b2ee8SDavid du Colombier 	}
81*219b2ee8SDavid du Colombier 	_fdinfo[f].flags |= FD_CLOEXEC;
82*219b2ee8SDavid du Colombier 	d->dd_fd = f;
833e12c5d1SDavid du Colombier }
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier struct dirent *
863e12c5d1SDavid du Colombier readdir(DIR *d)
873e12c5d1SDavid du Colombier {
883e12c5d1SDavid du Colombier 	int i, n;
893e12c5d1SDavid du Colombier 	struct dirent *dr;
903e12c5d1SDavid du Colombier 	Dir dirs[DBLOCKSIZE];
913e12c5d1SDavid du Colombier 	Dir td;
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier 	if(!d){
943e12c5d1SDavid du Colombier 		errno = EBADF;
953e12c5d1SDavid du Colombier 		return NULL;
963e12c5d1SDavid du Colombier 	}
973e12c5d1SDavid du Colombier 	if(d->dd_loc >= d->dd_size){
983e12c5d1SDavid du Colombier 		n = read(d->dd_fd, (char *)dirs, sizeof dirs);
993e12c5d1SDavid du Colombier 		if(n <= 0)
1003e12c5d1SDavid du Colombier 			return NULL;
1013e12c5d1SDavid du Colombier 		n = n/sizeof(Dir);
1023e12c5d1SDavid du Colombier 		dr = (struct dirent *)(d->dd_buf);
1033e12c5d1SDavid du Colombier 		for(i=0; i<n; i++, dr++){
1043e12c5d1SDavid du Colombier 			convM2D((char *)&dirs[i], &td);
1053e12c5d1SDavid du Colombier 			strncpy(dr->d_name, td.name, MAXNAMLEN);
1063e12c5d1SDavid du Colombier 			dr->d_name[MAXNAMLEN] = 0;
1073e12c5d1SDavid du Colombier 		}
1083e12c5d1SDavid du Colombier 		d->dd_loc = 0;
1093e12c5d1SDavid du Colombier 		d->dd_size = n*sizeof(struct dirent);
1103e12c5d1SDavid du Colombier 	}
1113e12c5d1SDavid du Colombier 	dr = (struct dirent*)(d->dd_buf+d->dd_loc);
1123e12c5d1SDavid du Colombier 	d->dd_loc += sizeof(struct dirent);
1133e12c5d1SDavid du Colombier 	return dr;
1143e12c5d1SDavid du Colombier }
115