⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devfs-posix.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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	"u.h"#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;	ulong	offset;	QLock	oq;	char nextname[NAME_MAX];};char	*base = "/";static	Qid	fsqid(char*, struct stat *);static	void	fspath(Chan*, char*, char*);static	ulong	fsdirread(Chan*, uchar*, int, ulong);static	int	fsomode(int);/* clumsy hack, but not worse than the Path stuff in the last one */static char*uc2name(Chan *c){	char *s;	if(c->name == nil)		return "/";	s = c2name(c);	if(s[0]=='#' && s[1]=='U')		return s+2;	return s;}static char*lastelem(Chan *c){	char *s, *t;	s = uc2name(c);	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[MAXPATH];	Ufsinfo *uif;	fspath(c, name, path);	/*print("** fs walk '%s' -> %s\n", path, name);  */	if(stat(path, &stbuf) < 0)		return 0;	uif = c->aux;	uif->mode = stbuf.st_mode;	uif->uid = stbuf.st_uid;	uif->gid = stbuf.st_gid;	c->qid = fsqid(path, &stbuf);	return 1;}extern Cname* addelem(Cname*, char*);static Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){	int i;	Cname *cname;	Walkqid *wq;	if(nc != nil)		panic("fswalk: nc != nil");	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	nc = devclone(c);	cname = c->name;	incref(&cname->ref);	fsclone(c, nc);	wq->clone = nc;	for(i=0; i<nname; i++){		nc->name = cname;		if(fswalk1(nc, name[i]) == 0)			break;		cname = addelem(cname, name[i]);		wq->qid[i] = nc->qid;	}	nc->name = nil;	cnameclose(cname);	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;	char path[MAXPATH];	if(n < BIT16SZ)		error(Eshortstat);	fspath(c, 0, path);	if(stat(path, &stbuf) < 0)		error(strerror(errno));	d.name = lastelem(c);	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[MAXPATH];	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;	fspath(c, 0, 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 voidfscreate(Chan *c, char *name, int mode, ulong perm){	int fd, m;	char path[MAXPATH];	struct stat stbuf;	Ufsinfo *uif;	m = fsomode(mode&3);	fspath(c, name, path);	uif = c->aux;	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);	c->offset = 0;	c->flag |= COPEN;	c->mode = openmode(mode);}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[MAXPATH];	fspath(c, 0, 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[MAXPATH], new[MAXPATH];	char strs[MAXPATH*3], *p;	Ufsinfo *uif;	if(convM2D(buf, n, &d, strs) != n)		error(Ebadstat);		fspath(c, 0, old);	if(stat(old, &stbuf) < 0)		error(strerror(errno));	uif = c->aux;	if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {		fspath(c, 0, old);		strcpy(new, old);		p = strrchr(new, '/');		strcpy(p+1, d.name);		if(rename(old, new) < 0)			error(strerror(errno));	}	fspath(c, 0, old);	if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {		if(chmod(old, d.mode&0777) < 0)			error(strerror(errno));		uif->mode &= ~0777;		uif->mode |= d.mode&0777;	}/*	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 voidfspath(Chan *c, char *ext, char *path){	strcpy(path, base);	strcat(path, "/");	strcat(path, uc2name(c));	if(ext){		strcat(path, "/");		strcat(path, ext);	}	cleanname(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;}static intp9readdir(char *name, Ufsinfo *uif){	struct dirent *de;		if(uif->nextname[0]){		strcpy(name, uif->nextname);		uif->nextname[0] = 0;		return 1;	}	de = readdir(uif->dir);	if(de == NULL)		return 0;			strcpy(name, de->d_name);	return 1;}static ulongfsdirread(Chan *c, uchar *va, int count, ulong offset){	int i;	Dir d;	long n;	char de[NAME_MAX];	struct stat stbuf;	char path[MAXPATH], dirpath[MAXPATH];	Ufsinfo *uif;/*print("fsdirread %s\n", c2name(c));*/	i = 0;	uif = c->aux;	errno = 0;	if(uif->offset != offset) {		if(offset != 0)			error("bad offset in fsdirread");		uif->offset = offset;  /* sync offset */		uif->nextname[0] = 0;		rewinddir(uif->dir);	}	fspath(c, 0, dirpath);	while(i+BIT16SZ < count) {		if(!p9readdir(de, uif))			break;		if(de[0]==0 || isdots(de))			continue;		d.name = de;		sprint(path, "%s/%s", dirpath, de);		memset(&stbuf, 0, sizeof stbuf);		if(stat(path, &stbuf) < 0) {			/* fprint(2, "dir: bad path %s\n", path); */			/* but continue... probably a bad symlink */		}		d.uid = "unknown";		d.gid = "unknown";		d.muid = "unknown";		d.qid = fsqid(path, &stbuf);		d.mode = (d.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;		n = convD2M(&d, (uchar*)va+i, count-i);		if(n == BIT16SZ){			strcpy(uif->nextname, de);			break;		}		i += n;	}/*print("got %d\n", i);*/	uif->offset += i;	return i;}static intfsomode(int m){	switch(m) {	case 0:			/* OREAD */	case 3:			/* OEXEC */		return 0;	case 1:			/* OWRITE */		return 1;	case 2:			/* ORDWR */		return 2;	}	error(Ebadarg);	return 0;}Dev fsdevtab = {	'U',	"fs",	devreset,	devinit,	devshutdown,	fsattach,	fswalk,	fsstat,	fsopen,	fscreate,	fsclose,	fsread,	devbread,	fswrite,	devbwrite,	fsremove,	fswstat,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -