Echo Lineinitial commit9fd65008 years agoHistory
621 lines · 9.2 KB · C
RawDownload
#include	"u.h"#include	<sys/types.h>#include	<sys/stat.h>#include	<dirent.h>#include	<fcntl.h>#include	<errno.h>#include	<stdio.h> /* for remove, rename */#include	<limits.h> #ifndef NAME_MAX#	define NAME_MAX 256#endif#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h"  typedef	struct Ufsinfo	Ufsinfo; enum{	NUID	= 256,	NGID	= 256,	MAXPATH	= 1024,	MAXCOMP	= 128}; struct Ufsinfo{	int	mode;	int	fd;	int	uid;	int	gid;	DIR*	dir;	vlong	offset;	QLock	oq;	char*	path;	char nextname[NAME_MAX];}; char	*base = "/"; static	Qid	fsqid(char*, struct stat *);static	char*	catpath(char*, char*);static	ulong	fsdirread(Chan*, uchar*, int, ulong);static	int	fsomode(int); static char*lastelem(char *s){	char *t; 	if((t = strrchr(s, '/')) == nil)		return s;	if(t[1] == 0)		return t;	return t+1;}	static Chan*fsattach(char *spec){	Chan *c;	struct stat stbuf;	static int devno;	Ufsinfo *uif; 	if(stat(base, &stbuf) < 0)		error(strerror(errno)); 	c = devattach('U', spec); 	uif = mallocz(sizeof(Ufsinfo), 1);	uif->mode = stbuf.st_mode;	uif->uid = stbuf.st_uid;	uif->gid = stbuf.st_gid; 	c->aux = uif;	c->dev = devno++;	c->qid.type = QTDIR;/*print("fsattach %s\n", c2name(c));*/ 	return c;} static Chan*fsclone(Chan *c, Chan *nc){	Ufsinfo *uif; 	uif = mallocz(sizeof(Ufsinfo), 1);	*uif = *(Ufsinfo*)c->aux;	nc->aux = uif; 	return nc;} static intfswalk1(Chan *c, char *name){	struct stat stbuf;	char *path;	Ufsinfo *uif; 	uif = c->aux;	path = catpath(uif->path, name); 	/*print("** fs walk '%s' -> %s\n", path, name);  */ 	if(stat(path, &stbuf) < 0) {		free(path);		return 0;	} 	uif->mode = stbuf.st_mode;	uif->uid = stbuf.st_uid;	uif->gid = stbuf.st_gid; 	c->qid = fsqid(path, &stbuf); 	free(path); 	return 1;} static Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){	int i;	Walkqid *wq; 	if(nc != nil)		panic("fswalk: nc != nil");	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	nc = devclone(c); 	fsclone(c, nc);	wq->clone = nc;	for(i=0; i<nname; i++){		if(fswalk1(nc, name[i]) == 0)			break;		wq->qid[i] = nc->qid;	}	if(i != nname){		cclose(nc);		wq->clone = nil;	}	wq->nqid = i;	return wq;}	static intfsstat(Chan *c, uchar *buf, int n){	Dir d;	struct stat stbuf;	Ufsinfo *uif; 	if(n < BIT16SZ)		error(Eshortstat); 	uif = c->aux;	if(stat(uif->path, &stbuf) < 0)		error(strerror(errno)); 	d.name = lastelem(uif->path);	d.uid = "unknown";	d.gid = "unknown";	d.muid = "unknown";	d.qid = c->qid;	d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);	d.atime = stbuf.st_atime;	d.mtime = stbuf.st_mtime;	d.length = stbuf.st_size;	d.type = 'U';	d.dev = c->dev;	return convD2M(&d, buf, n);} static Chan*fsopen(Chan *c, int mode){	char *path;	int m, isdir;	Ufsinfo *uif; /*print("fsopen %s\n", c2name(c));*/	m = mode & (OTRUNC|3);	switch(m) {	case 0:		break;	case 1:	case 1|16:		break;	case 2:		case 0|16:	case 2|16:		break;	case 3:		break;	default:		error(Ebadarg);	} 	isdir = c->qid.type & QTDIR; 	if(isdir && mode != OREAD)		error(Eperm); 	m = fsomode(m & 3);	c->mode = openmode(mode); 	uif = c->aux; 	path = uif->path;	if(isdir) {		uif->dir = opendir(path);		if(uif->dir == 0)			error(strerror(errno));	}		else {		if(mode & OTRUNC)			m |= O_TRUNC;		uif->fd = open(path, m, 0666); 		if(uif->fd < 0)			error(strerror(errno));	}	uif->offset = 0; 	c->offset = 0;	c->flag |= COPEN;	return c;} static Chan*fscreate(Chan *c, char *name, int mode, ulong perm){	int fd, m;	char *path;	struct stat stbuf;	Ufsinfo *uif; 	m = fsomode(mode&3); 	uif = c->aux;	path = catpath(uif->path, name); 	if(perm & DMDIR) {		if(m)			error(Eperm); 		if(mkdir(path, perm & 0777) < 0)			error(strerror(errno)); 		fd = open(path, 0);		if(fd >= 0) {			chmod(path, perm & 0777);			chown(path, uif->uid, uif->uid);		}		close(fd); 		uif->dir = opendir(path);		if(uif->dir == 0)			error(strerror(errno));	}	else {		fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);		if(fd >= 0) {			if(m != 1) {				close(fd);				fd = open(path, m);			}			chmod(path, perm & 0777);			chown(path, uif->uid, uif->gid);		}		if(fd < 0)			error(strerror(errno));		uif->fd = fd;	} 	if(stat(path, &stbuf) < 0)		error(strerror(errno));	c->qid = fsqid(path, &stbuf);	free(path);	c->offset = 0;	c->flag |= COPEN;	c->mode = openmode(mode); 	return c;} static voidfsclose(Chan *c){	Ufsinfo *uif; 	uif = c->aux; 	if(c->flag & COPEN) {		if(c->qid.type & QTDIR)			closedir(uif->dir);		else			close(uif->fd);	} 	free(uif);} static longfsread(Chan *c, void *va, long n, vlong offset){	int fd, r;	Ufsinfo *uif; /*print("fsread %s\n", c2name(c));*/	if(c->qid.type & QTDIR)		return fsdirread(c, va, n, offset); 	uif = c->aux;	qlock(&uif->oq);	if(waserror()) {		qunlock(&uif->oq);		nexterror();	}	fd = uif->fd;	if(uif->offset != offset) {		r = lseek(fd, offset, 0);		if(r < 0)			error(strerror(errno));		uif->offset = offset;	} 	n = read(fd, va, n);	if(n < 0)		error(strerror(errno)); 	uif->offset += n;	qunlock(&uif->oq);	poperror(); 	return n;} static longfswrite(Chan *c, void *va, long n, vlong offset){	int fd, r;	Ufsinfo *uif; 	uif = c->aux; 	qlock(&uif->oq);	if(waserror()) {		qunlock(&uif->oq);		nexterror();	}	fd = uif->fd;	if(uif->offset != offset) {		r = lseek(fd, offset, 0);		if(r < 0)			error(strerror(errno));		uif->offset = offset;	} 	n = write(fd, va, n);	if(n < 0)		error(strerror(errno)); 	uif->offset += n;	qunlock(&uif->oq);	poperror(); 	return n;} static voidfsremove(Chan *c){	int n;	char *path;	Ufsinfo *uif; 	uif = c->aux;	path = uif->path;	if(c->qid.type & QTDIR)		n = rmdir(path);	else		n = remove(path);	if(n < 0)		error(strerror(errno));} intfswstat(Chan *c, uchar *buf, int n){	Dir d;	struct stat stbuf;	char *old, new[MAXPATH];	char strs[MAXPATH*3], *p;	Ufsinfo *uif; 	if(convM2D(buf, n, &d, strs) != n)		error(Ebadstat);		uif = c->aux;	if(stat(uif->path, &stbuf) < 0)		error(strerror(errno)); 	if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {		if(chmod(uif->path, d.mode&0777) < 0)			error(strerror(errno));		uif->mode &= ~0777;		uif->mode |= d.mode&0777;	} 	if(d.name[0] && strcmp(d.name, lastelem(uif->path)) != 0) {		old = uif->path;		strcpy(new, old);		p = strrchr(new, '/');		strcpy(p+1, d.name);		if(rename(old, new) < 0)			error(strerror(errno));	} /*	p = name2pass(gid, d.gid);	if(p == 0)		error(Eunknown); 	if(p->id != stbuf.st_gid) {		if(chown(old, stbuf.st_uid, p->id) < 0)			error(strerror(errno)); 		uif->gid = p->id;	}*/	return n;} static Qidfsqid(char *p, struct stat *st){	Qid q;	int dev;	ulong h;	static int nqdev;	static uchar *qdev; 	if(qdev == 0)		qdev = mallocz(65536U, 1); 	q.type = 0;	if((st->st_mode&S_IFMT) ==  S_IFDIR)		q.type = QTDIR; 	dev = st->st_dev & 0xFFFFUL;	if(qdev[dev] == 0)		qdev[dev] = ++nqdev; 	h = 0;	while(*p != '\0')		h += *p++ * 13;		q.path = (vlong)qdev[dev]<<32;	q.path |= h;	q.vers = st->st_mtime; 	return q;} static char*catpath(char *base, char *ext){	char *path;	int n, m; 	n = strlen(base);	m = strlen(ext);	path = malloc(n+m+2);	memmove(path, base, n);	if(n > 0 && path[n-1] != '/')		path[n++] = '/';	memmove(path+n, ext, m+1);	return path;} static intisdots(char *name){	if(name[0] != '.')		return 0;	if(name[1] == '\0')		return 1;	if(name[1] != '.')		return 0;	if(name[2] == '\0')		return 1;	return 0;

Lines 1–500 of 621.