212 lines · 3.3 KB · C
RawDownload
#include <u.h>#include <mingw32.h>#include <libc.h>#include <sys/stat.h>#include <dirent.h> #include "util.h"#include "fdtab.h"#define	readdir	_wreaddir#define	dirent	_wdirent#define	DIR		_WDIR#define	stat		_stat extern int _p9dir(struct stat*, WCHAR*, Dir*, char**, char*); enum {	STRUCT_ALIGN = sizeof(int),	MAXDENTSIZE = STRUCT_ALIGN + sizeof(struct dirent),	NDIRFDS = 32,	BLKSIZE = 8192,};  static DIR*fd2dir(int fd){	Fd	*f; 	f = fdtget(fd);	if (f==nil || f->type!=Fdtypedir)		return nil; 	return f->dir;	} static intd_reclen(char *p, int *reclen){	*reclen = *(ushort *)p;	return STRUCT_ALIGN;} static intmygetdents(int fd, uchar *buf, int n){	DIR	*dir;	struct dirent	*de;	int	nn, r, len;	ushort	*reclen; 	dir = fd2dir(fd);	if (dir == nil)		return 0;		for (nn = 0; nn + MAXDENTSIZE <= n; nn += *reclen) {		de = _wreaddir(dir);		if (de == nil)			break; 		reclen = (ushort*) &buf[nn];		nn += STRUCT_ALIGN;		for (len=0; de->d_name[len]!='\0'; len++);		*reclen = offsetof(struct dirent, d_name) + 2*(len+1);		r = *reclen % STRUCT_ALIGN;		if (r)			*reclen += STRUCT_ALIGN - r; 		memcpy(&buf[nn], de, *reclen);	}	return nn;}  static intcountde(char *p, int n){	char *e;	int m;	struct dirent *de;	int reclen; 	e = p+n;	m = 0;	while(p + sizeof(ushort) <= e){		p += d_reclen(p, &reclen);		de = (struct dirent*)p;		if(p+reclen > e)			break;		if(de->d_name[0]=='.' && de->d_name[1]==0)			de->d_name[0] = 0;		else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)			de->d_name[0] = 0;		m++;		p += reclen;	}	return m;} static intdirpackage(int fd, char *buf, int n, Dir **dp){	int oldwd;	char *p, *str, *estr;	int i, nstr, m;	struct dirent *de;	int reclen;	struct stat st;	Dir *d; 	n = countde(buf, n);	if(n <= 0)		return n; 	if((oldwd = open(".", O_RDONLY)) < 0)		return -1;	if(fchdir(fd) < 0)		return -1;			p = buf;	nstr = 0; 	for(i=0; i<n; i++){		p += d_reclen(p, &reclen);		de = (struct dirent*)p;		memset(&st, 0, sizeof st);		if(de->d_name[0] == 0)			/* nothing */ {}		else if(_wstat(de->d_name, &st) < 0)			de->d_name[0] = 0;		else{			nstr += _p9dir(&st, de->d_name, nil, nil, nil);		}		p += reclen;	} 	d = malloc(sizeof(Dir)*n+nstr);	if(d == nil){		fchdir(oldwd);		close(oldwd);		return -1;	}	str = (char*)&d[n];	estr = str+nstr; 	p = buf;	m = 0;	for(i=0; i<n; i++){		p += d_reclen(p, &reclen);		de = (struct dirent*)p;		if(de->d_name[0] != 0 && _wstat(de->d_name, &st) >= 0){			winreplacews(de->d_name, 0);			_p9dir(&st, de->d_name, &d[m++], &str, estr);		}		p += reclen;	} 	fchdir(oldwd);	close(oldwd);	*dp = d;	return m;} longdirread(int fd, Dir **dp){	char *buf;	int n; 	*dp = 0; 	buf = malloc(BLKSIZE);	if(buf == nil)		return -1; 	n = mygetdents(fd, (void*)buf, BLKSIZE);	if(n < 0){		free(buf);		return -1;	}	n = dirpackage(fd, buf, n, dp);	free(buf);	return n;}  longdirreadall(int fd, Dir **d){	uchar *buf, *nbuf;	long n, ts; 	buf = nil;	ts = 0;	for(;;){		nbuf = realloc(buf, ts+BLKSIZE);		if(nbuf == nil){			free(buf);			return -1;		}		buf = nbuf;		n = mygetdents(fd, (void*)(buf+ts), BLKSIZE);		if(n <= 0)			break;		ts += n;	}	if(ts >= 0)		ts = dirpackage(fd, (char*)buf, ts, d);	free(buf);	if(ts == 0 && n < 0)		return -1;	return ts;}