xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/opendir.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
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 *
opendir(const char * filename)143e12c5d1SDavid du Colombier opendir(const char *filename)
153e12c5d1SDavid du Colombier {
163e12c5d1SDavid du Colombier 	int f;
173e12c5d1SDavid du Colombier 	DIR *d;
18219b2ee8SDavid du Colombier 	struct stat sb;
199a747e4fSDavid du Colombier 	Dir *d9;
203e12c5d1SDavid du Colombier 
219a747e4fSDavid du Colombier 	if((d9 = _dirstat(filename)) == nil){
22219b2ee8SDavid du Colombier 		_syserrno();
23219b2ee8SDavid du Colombier 		return NULL;
24219b2ee8SDavid du Colombier 	}
259a747e4fSDavid du Colombier 	_dirtostat(&sb, d9, 0);
269a747e4fSDavid du Colombier 	free(d9);
27219b2ee8SDavid du Colombier 	if(S_ISDIR(sb.st_mode) == 0) {
28219b2ee8SDavid du Colombier 		errno = ENOTDIR;
29219b2ee8SDavid du Colombier 		return NULL;
30219b2ee8SDavid du Colombier 	}
31219b2ee8SDavid du Colombier 
32219b2ee8SDavid du Colombier 	f = open(filename, O_RDONLY);
333e12c5d1SDavid du Colombier 	if(f < 0){
343e12c5d1SDavid du Colombier 		_syserrno();
353e12c5d1SDavid du Colombier 		return NULL;
363e12c5d1SDavid du Colombier 	}
373e12c5d1SDavid du Colombier 	_fdinfo[f].flags |= FD_CLOEXEC;
383e12c5d1SDavid du Colombier 	d = (DIR *)malloc(sizeof(DIR) + DBLOCKSIZE*sizeof(struct dirent));
393e12c5d1SDavid du Colombier 	if(!d){
403e12c5d1SDavid du Colombier 		errno = ENOMEM;
413e12c5d1SDavid du Colombier 		return NULL;
423e12c5d1SDavid du Colombier 	}
4325fc6993SDavid du Colombier 	d->dd_buf = (char *)d + sizeof(DIR);
443e12c5d1SDavid du Colombier 	d->dd_fd = f;
453e12c5d1SDavid du Colombier 	d->dd_loc = 0;
463e12c5d1SDavid du Colombier 	d->dd_size = 0;
479a747e4fSDavid du Colombier 	d->dirs = nil;
489a747e4fSDavid du Colombier 	d->dirsize = 0;
499a747e4fSDavid du Colombier 	d->dirloc = 0;
503e12c5d1SDavid du Colombier 	return d;
513e12c5d1SDavid du Colombier }
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier int
closedir(DIR * d)543e12c5d1SDavid du Colombier closedir(DIR *d)
553e12c5d1SDavid du Colombier {
563e12c5d1SDavid du Colombier 	if(!d){
573e12c5d1SDavid du Colombier 		errno = EBADF;
583e12c5d1SDavid du Colombier 		return -1;
593e12c5d1SDavid du Colombier 	}
603e12c5d1SDavid du Colombier 	if(close(d->dd_fd) < 0)
613e12c5d1SDavid du Colombier 		return -1;
629a747e4fSDavid du Colombier 	free(d->dirs);
633e12c5d1SDavid du Colombier 	free(d);
643e12c5d1SDavid du Colombier 	return 0;
653e12c5d1SDavid du Colombier }
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier void
rewinddir(DIR * d)683e12c5d1SDavid du Colombier rewinddir(DIR *d)
693e12c5d1SDavid du Colombier {
7025fc6993SDavid du Colombier 	if(!d)
7125fc6993SDavid du Colombier 		return;
72219b2ee8SDavid du Colombier 	d->dd_loc = 0;
73219b2ee8SDavid du Colombier 	d->dd_size = 0;
749a747e4fSDavid du Colombier 	d->dirsize = 0;
759a747e4fSDavid du Colombier 	d->dirloc = 0;
769a747e4fSDavid du Colombier 	free(d->dirs);
779a747e4fSDavid du Colombier 	d->dirs = nil;
789a747e4fSDavid du Colombier 	if(_SEEK(d->dd_fd, 0, 0) < 0){
79219b2ee8SDavid du Colombier 		_syserrno();
80219b2ee8SDavid du Colombier 		return;
81219b2ee8SDavid du Colombier 	}
823e12c5d1SDavid du Colombier }
833e12c5d1SDavid du Colombier 
843e12c5d1SDavid du Colombier struct dirent *
readdir(DIR * d)853e12c5d1SDavid du Colombier readdir(DIR *d)
863e12c5d1SDavid du Colombier {
87*781103c4SDavid du Colombier 	int i;
883e12c5d1SDavid du Colombier 	struct dirent *dr;
899a747e4fSDavid du Colombier 	Dir *dirs;
903e12c5d1SDavid du Colombier 
913e12c5d1SDavid du Colombier 	if(!d){
923e12c5d1SDavid du Colombier 		errno = EBADF;
933e12c5d1SDavid du Colombier 		return NULL;
943e12c5d1SDavid du Colombier 	}
953e12c5d1SDavid du Colombier 	if(d->dd_loc >= d->dd_size){
969a747e4fSDavid du Colombier 		if(d->dirloc >= d->dirsize){
979a747e4fSDavid du Colombier 			free(d->dirs);
9825fc6993SDavid du Colombier 			d->dirs = NULL;
999a747e4fSDavid du Colombier 			d->dirsize = _dirread(d->dd_fd, &d->dirs);
1009a747e4fSDavid du Colombier 			d->dirloc = 0;
1019a747e4fSDavid du Colombier 		}
10225fc6993SDavid du Colombier 		if(d->dirsize < 0) {	/* malloc or read failed in _dirread? */
10325fc6993SDavid du Colombier 			free(d->dirs);
10425fc6993SDavid du Colombier 			d->dirs = NULL;
10525fc6993SDavid du Colombier 		}
1069a747e4fSDavid du Colombier 		if(d->dirs == NULL)
1073e12c5d1SDavid du Colombier 			return NULL;
10825fc6993SDavid du Colombier 
10925fc6993SDavid du Colombier 		dr = (struct dirent *)d->dd_buf;
1109a747e4fSDavid du Colombier 		dirs = d->dirs;
1119a747e4fSDavid du Colombier 		for(i=0; i<DBLOCKSIZE && d->dirloc < d->dirsize; i++){
1129a747e4fSDavid du Colombier 			strncpy(dr[i].d_name, dirs[d->dirloc++].name, MAXNAMLEN);
1139a747e4fSDavid du Colombier 			dr[i].d_name[MAXNAMLEN] = 0;
1143e12c5d1SDavid du Colombier 		}
1153e12c5d1SDavid du Colombier 		d->dd_loc = 0;
1169a747e4fSDavid du Colombier 		d->dd_size = i*sizeof(struct dirent);
1173e12c5d1SDavid du Colombier 	}
1183e12c5d1SDavid du Colombier 	dr = (struct dirent*)(d->dd_buf+d->dd_loc);
1193e12c5d1SDavid du Colombier 	d->dd_loc += sizeof(struct dirent);
1203e12c5d1SDavid du Colombier 	return dr;
1213e12c5d1SDavid du Colombier }
122