9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | 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 }