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

📄 sysfile.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h"#include	"user.h"#undef open#undef mount#undef read#undef write#undef seek#undef stat#undef wstat#undef remove#undef close#undef fstat#undef fwstat/* * The sys*() routines needn't poperror() as they return directly to syscall(). */static voidunlockfgrp(Fgrp *f){	int ex;	ex = f->exceed;	f->exceed = 0;	unlock(&f->ref.lk);	if(ex)		pprint("warning: process exceeds %d file descriptors\n", ex);}intgrowfd(Fgrp *f, int fd)	/* fd is always >= 0 */{	Chan **newfd, **oldfd;	if(fd < f->nfd)		return 0;	if(fd >= f->nfd+DELTAFD)		return -1;	/* out of range */	/*	 * Unbounded allocation is unwise; besides, there are only 16 bits	 * of fid in 9P	 */	if(f->nfd >= 5000){    Exhausted:		print("no free file descriptors\n");		return -1;	}	newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));	if(newfd == 0)		goto Exhausted;	oldfd = f->fd;	memmove(newfd, oldfd, f->nfd*sizeof(Chan*));	f->fd = newfd;	free(oldfd);	f->nfd += DELTAFD;	if(fd > f->maxfd){		if(fd/100 > f->maxfd/100)			f->exceed = (fd/100)*100;		f->maxfd = fd;	}	return 1;}/* *  this assumes that the fgrp is locked */intfindfreefd(Fgrp *f, int start){	int fd;	for(fd=start; fd<f->nfd; fd++)		if(f->fd[fd] == 0)			break;	if(fd >= f->nfd && growfd(f, fd) < 0)		return -1;	return fd;}intnewfd(Chan *c){	int fd;	Fgrp *f;	f = up->fgrp;	lock(&f->ref.lk);	fd = findfreefd(f, 0);	if(fd < 0){		unlockfgrp(f);		return -1;	}	if(fd > f->maxfd)		f->maxfd = fd;	f->fd[fd] = c;	unlockfgrp(f);	return fd;}intnewfd2(int fd[2], Chan *c[2]){	Fgrp *f;	f = up->fgrp;	lock(&f->ref.lk);	fd[0] = findfreefd(f, 0);	if(fd[0] < 0){		unlockfgrp(f);		return -1;	}	fd[1] = findfreefd(f, fd[0]+1);	if(fd[1] < 0){		unlockfgrp(f);		return -1;	}	if(fd[1] > f->maxfd)		f->maxfd = fd[1];	f->fd[fd[0]] = c[0];	f->fd[fd[1]] = c[1];	unlockfgrp(f);	return 0;}Chan*fdtochan(int fd, int mode, int chkmnt, int iref){	Chan *c;	Fgrp *f;	c = 0;	f = up->fgrp;	lock(&f->ref.lk);	if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {		unlock(&f->ref.lk);		error(Ebadfd);	}	if(iref)		incref(&c->ref);	unlock(&f->ref.lk);	if(chkmnt && (c->flag&CMSG)) {		if(iref)			cclose(c);		error(Ebadusefd);	}	if(mode<0 || c->mode==ORDWR)		return c;	if((mode&OTRUNC) && c->mode==OREAD) {		if(iref)			cclose(c);		error(Ebadusefd);	}	if((mode&~OTRUNC) != c->mode) {		if(iref)			cclose(c);		error(Ebadusefd);	}	return c;}intopenmode(ulong o){	o &= ~(OTRUNC|OCEXEC|ORCLOSE);	if(o > OEXEC)		error(Ebadarg);	if(o == OEXEC)		return OREAD;	return o;}long_sysfd2path(int fd, char *buf, uint nbuf){	Chan *c;	c = fdtochan(fd, -1, 0, 1);	if(c->name == nil)		snprint(buf, nbuf, "<null>");	else		snprint(buf, nbuf, "%s", c->name->s);	cclose(c);	return 0;}long_syspipe(int fd[2]){	Chan *c[2];	Dev *d;	static char *datastr[] = {"data", "data1"};	d = devtab[devno('|', 0)];	c[0] = namec("#|", Atodir, 0, 0);	c[1] = 0;	fd[0] = -1;	fd[1] = -1;	if(waserror()){		cclose(c[0]);		if(c[1])			cclose(c[1]);		nexterror();	}	c[1] = cclone(c[0]);	if(walk(&c[0], datastr+0, 1, 1, nil) < 0)		error(Egreg);	if(walk(&c[1], datastr+1, 1, 1, nil) < 0)		error(Egreg);	c[0] = d->open(c[0], ORDWR);	c[1] = d->open(c[1], ORDWR);	if(newfd2(fd, c) < 0)		error(Enofd);	poperror();	return 0;}long_sysdup(int fd0, int fd1){	int fd;	Chan *c, *oc;	Fgrp *f = up->fgrp;	/*	 * Close after dup'ing, so date > #d/1 works	 */	c = fdtochan(fd0, -1, 0, 1);	fd = fd1;	if(fd != -1){		lock(&f->ref.lk);		if(fd<0 || growfd(f, fd)<0) {			unlockfgrp(f);			cclose(c);			error(Ebadfd);		}		if(fd > f->maxfd)			f->maxfd = fd;		oc = f->fd[fd];		f->fd[fd] = c;		unlockfgrp(f);		if(oc)			cclose(oc);	}else{		if(waserror()) {			cclose(c);			nexterror();		}		fd = newfd(c);		if(fd < 0)			error(Enofd);		poperror();	}	return fd;}long_sysopen(char *name, int mode){	int fd;	Chan *c = 0;	openmode(mode);	/* error check only */	if(waserror()){		if(c)			cclose(c);		nexterror();	}	c = namec(name, Aopen, mode, 0);	fd = newfd(c);	if(fd < 0)		error(Enofd);	poperror();	return fd;}voidfdclose(int fd, int flag){	int i;	Chan *c;	Fgrp *f = up->fgrp;	lock(&f->ref.lk);	c = f->fd[fd];	if(c == 0){		/* can happen for users with shared fd tables */		unlock(&f->ref.lk);		return;	}	if(flag){		if(c==0 || !(c->flag&flag)){			unlock(&f->ref.lk);			return;		}	}	f->fd[fd] = 0;	if(fd == f->maxfd)		for(i=fd; --i>=0 && f->fd[i]==0; )			f->maxfd = i;	unlock(&f->ref.lk);	cclose(c);}long_sysclose(int fd){	fdtochan(fd, -1, 0, 0);	fdclose(fd, 0);	return 0;}longunionread(Chan *c, void *va, long n){	int i;	long nr;	Mhead *m;	Mount *mount;	qlock(&c->umqlock);	m = c->umh;	rlock(&m->lock);	mount = m->mount;	/* bring mount in sync with c->uri and c->umc */	for(i = 0; mount != nil && i < c->uri; i++)		mount = mount->next;	nr = 0;	while(mount != nil) {		/* Error causes component of union to be skipped */		if(mount->to && !waserror()) {			if(c->umc == nil){				c->umc = cclone(mount->to);				c->umc = devtab[c->umc->type]->open(c->umc, OREAD);			}				nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);			c->umc->offset += nr;			poperror();		}		if(nr > 0)			break;		/* Advance to next element */		c->uri++;		if(c->umc) {			cclose(c->umc);			c->umc = nil;		}		mount = mount->next;	}	runlock(&m->lock);	qunlock(&c->umqlock);	return nr;}static longkread(int fd, void *buf, long n, vlong *offp){	int dir;	Chan *c;	vlong off;	c = fdtochan(fd, OREAD, 1, 1);	if(waserror()) {		cclose(c);		nexterror();	}	dir = c->qid.type&QTDIR;	/*	 * The offset is passed through on directories, normally. sysseek complains but	 * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue.	 */	if(offp == nil)	/* use and maintain channel's offset */		off = c->offset;	else		off = *offp;	if(off < 0)		error(Enegoff);	if(dir && c->umh)		n = unionread(c, buf, n);	else		n = devtab[c->type]->read(c, buf, n, off);	if(offp == nil){		lock(&c->ref.lk);		c->offset += n;		unlock(&c->ref.lk);	}	poperror();	cclose(c);	return n;}/* name conflicts with netbsdlong_sys_read(int fd, void *buf, long n){	return kread(fd, buf, n, nil);}*/long_syspread(int fd, void *buf, long n, vlong off){	if(off == ((uvlong) ~0))		return kread(fd, buf, n, nil);	return kread(fd, buf, n, &off);}static longkwrite(int fd, void *buf, long nn, vlong *offp){	Chan *c;	long m, n;	vlong off;	n = 0;	c = fdtochan(fd, OWRITE, 1, 1);	if(waserror()) {		if(offp == nil){			lock(&c->ref.lk);			c->offset -= n;			unlock(&c->ref.lk);		}		cclose(c);		nexterror();	}	if(c->qid.type & QTDIR)		error(Eisdir);	n = nn;	if(offp == nil){	/* use and maintain channel's offset */		lock(&c->ref.lk);		off = c->offset;		c->offset += n;		unlock(&c->ref.lk);	}else		off = *offp;	if(off < 0)		error(Enegoff);	m = devtab[c->type]->write(c, buf, n, off);	if(offp == nil && m < n){		lock(&c->ref.lk);		c->offset -= n - m;		unlock(&c->ref.lk);	}	poperror();	cclose(c);	return m;}longsys_write(int fd, void *buf, long n){	return kwrite(fd, buf, n, nil);}long_syspwrite(int fd, void *buf, long n, vlong off){	if(off == ((uvlong) ~0))		return kwrite(fd, buf, n, nil);	return kwrite(fd, buf, n, &off);}static vlong_sysseek(int fd, vlong off, int whence){	Chan *c;	uchar buf[sizeof(Dir)+100];	Dir dir;	int n;	c = fdtochan(fd, -1, 1, 1);	if(waserror()){		cclose(c);		nexterror();	}	if(devtab[c->type]->dc == '|')		error(Eisstream);	switch(whence){	case 0:		if((c->qid.type & QTDIR) && off != 0)			error(Eisdir);		if(off < 0)			error(Enegoff);		c->offset = off;		break;	case 1:		if(c->qid.type & QTDIR)			error(Eisdir);		lock(&c->ref.lk);	/* lock for read/write update */		off = off + c->offset;		if(off < 0)			error(Enegoff);		c->offset = off;		unlock(&c->ref.lk);		break;	case 2:		if(c->qid.type & QTDIR)			error(Eisdir);		n = devtab[c->type]->stat(c, buf, sizeof buf);		if(convM2D(buf, n, &dir, nil) == 0)			error("internal error: stat error in seek");		off = dir.length + off;		if(off < 0)			error(Enegoff);		c->offset = off;		break;	default:		error(Ebadarg);	}	c->uri = 0;	c->dri = 0;	cclose(c);	poperror();	return off;}voidvalidstat(uchar *s, int n){	int m;	char buf[64];	if(statcheck(s, n) < 0)		error(Ebadstat);	/* verify that name entry is acceptable */	s += STATFIXLEN - 4*BIT16SZ;	/* location of first string */	/*	 * s now points at count for first string.	 * if it's too long, let the server decide; this is	 * only for his protection anyway. otherwise	 * we'd have to allocate and waserror.	 */	m = GBIT16(s);	s += BIT16SZ;	if(m+1 > sizeof buf)		return;	memmove(buf, s, m);	buf[m] = '\0';	/* name could be '/' */	if(strcmp(buf, "/") != 0)		validname(buf, 0);}long_sysfstat(int fd, void *buf, long n){	Chan *c;	uint l;	l = n;	validaddr(buf, l, 1);	c = fdtochan(fd, -1, 0, 1);	if(waserror()) {		cclose(c);		nexterror();	}	l = devtab[c->type]->stat(c, buf, l);	poperror();	cclose(c);	return l;}long_sysstat(char *name, void *buf, long n){	Chan *c;	uint l;	l = n;	validaddr(buf, l, 1);	validaddr(name, 1, 0);	c = namec(name, Aaccess, 0, 0);	if(waserror()){		cclose(c);		nexterror();	}	l = devtab[c->type]->stat(c, buf, l);	poperror();	cclose(c);	return l;}

⌨️ 快捷键说明

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