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

📄 chan.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h"int chandebug=0;		/* toggled by sysr1 */QLock chanprint;		/* probably asking for trouble (deadlocks) -rsc */int domount(Chan**, Mhead**);voiddumpmount(void)		/* DEBUGGING */{	Pgrp *pg;	Mount *t;	Mhead **h, **he, *f;	if(up == nil){		print("no process for dumpmount\n");		return;	}	pg = up->pgrp;	if(pg == nil){		print("no pgrp for dumpmount\n");		return;	}	rlock(&pg->ns);	if(waserror()) {		runlock(&pg->ns);		nexterror();	}	he = &pg->mnthash[MNTHASH];	for(h = pg->mnthash; h < he; h++) {		for(f = *h; f; f = f->hash) {			print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f,				f->from->name->s, f->from->qid.path,				f->from->qid.vers, devtab[f->from->type]->dc,				f->from->dev);			for(t = f->mount; t; t = t->next)				print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);		}	}	poperror();	runlock(&pg->ns);}char*c2name(Chan *c)		/* DEBUGGING */{	if(c == nil)		return "<nil chan>";	if(c->name == nil)		return "<nil name>";	if(c->name->s == nil)		return "<nil name.s>";	return c->name->s;}enum{	CNAMESLOP	= 20};struct{	Lock lk;	int	fid;	Chan	*free;	Chan	*list;}chanalloc;typedef struct Elemlist Elemlist;struct Elemlist{	char	*name;	/* copy of name, so '/' can be overwritten */	int	nelems;	char	**elems;	int	*off;	int	mustbedir;};#define SEP(c) ((c) == 0 || (c) == '/')void cleancname(Cname*);intisdotdot(char *p){	return p[0]=='.' && p[1]=='.' && p[2]=='\0';}intincref(Ref *r){	int x;	lock(&r->lk);	x = ++r->ref;	unlock(&r->lk);	return x;}intdecref(Ref *r){	int x;	lock(&r->lk);	x = --r->ref;	unlock(&r->lk);	if(x < 0)		panic("decref, pc=0x%p", getcallerpc(&r));	return x;}/* * Rather than strncpy, which zeros the rest of the buffer, kstrcpy * truncates if necessary, always zero terminates, does not zero fill, * and puts ... at the end of the string if it's too long.  Usually used to * save a string in up->genbuf; */voidkstrcpy(char *s, char *t, int ns){	int nt;	nt = strlen(t);	if(nt+1 <= ns){		memmove(s, t, nt+1);		return;	}	/* too long */	if(ns < 4){		/* but very short! */		strncpy(s, t, ns);		return;	}	/* truncate with ... at character boundary (very rare case) */	memmove(s, t, ns-4);	ns -= 4;	s[ns] = '\0';	/* look for first byte of UTF-8 sequence by skipping continuation bytes */	while(ns>0 && (s[--ns]&0xC0)==0x80)		;	strcpy(s+ns, "...");}intemptystr(char *s){	if(s == nil)		return 1;	if(s[0] == '\0')		return 1;	return 0;}/* * Atomically replace *p with copy of s */voidkstrdup(char **p, char *s){	int n;	char *t, *prev;	n = strlen(s)+1;	/* if it's a user, we can wait for memory; if not, something's very wrong */	if(up){		t = smalloc(n);		setmalloctag(t, getcallerpc(&p));	}else{		t = malloc(n);		if(t == nil)			panic("kstrdup: no memory");	}	memmove(t, s, n);	prev = *p;	*p = t;	free(prev);}voidchandevreset(void){	int i;	for(i=0; devtab[i] != nil; i++)		devtab[i]->reset();}voidchandevinit(void){	int i;	for(i=0; devtab[i] != nil; i++)		devtab[i]->init();}voidchandevshutdown(void){	int i;		/* shutdown in reverse order */	for(i=0; devtab[i] != nil; i++)		;	for(i--; i >= 0; i--)		devtab[i]->shutdown();}Chan*newchan(void){	Chan *c;	lock(&chanalloc.lk);	c = chanalloc.free;	if(c != 0)		chanalloc.free = c->next;	unlock(&chanalloc.lk);	if(c == nil) {		c = smalloc(sizeof(Chan));		lock(&chanalloc.lk);		c->fid = ++chanalloc.fid;		c->link = chanalloc.list;		chanalloc.list = c;		unlock(&chanalloc.lk);	}	/* if you get an error before associating with a dev,	   close calls rootclose, a nop */	c->type = 0;	c->flag = 0;	c->ref.ref = 1;	c->dev = 0;	c->offset = 0;	c->iounit = 0;	c->umh = 0;	c->uri = 0;	c->dri = 0;	c->aux = 0;	c->mchan = 0;	c->mcp = 0;	c->mux = 0;	memset(&c->mqid, 0, sizeof(c->mqid));	c->name = 0;	return c;}static Ref ncname;Cname*newcname(char *s){	Cname *n;	int i;	n = smalloc(sizeof(Cname));	i = strlen(s);	n->len = i;	n->alen = i+CNAMESLOP;	n->s = smalloc(n->alen);	memmove(n->s, s, i+1);	n->ref.ref = 1;	incref(&ncname);	return n;}voidcnameclose(Cname *n){	if(n == nil)		return;	if(decref(&n->ref))		return;	decref(&ncname);	free(n->s);	free(n);}Cname*addelem(Cname *n, char *s){	int i, a;	char *t;	Cname *new;	if(s[0]=='.' && s[1]=='\0')		return n;	if(n->ref.ref > 1){		/* copy on write */		new = newcname(n->s);		cnameclose(n);		n = new;	}	i = strlen(s);	if(n->len+1+i+1 > n->alen){		a = n->len+1+i+1 + CNAMESLOP;		t = smalloc(a);		memmove(t, n->s, n->len+1);		free(n->s);		n->s = t;		n->alen = a;	}	if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')	/* don't insert extra slash if one is present */		n->s[n->len++] = '/';	memmove(n->s+n->len, s, i+1);	n->len += i;	if(isdotdot(s))		cleancname(n);	return n;}voidchanfree(Chan *c){	c->flag = CFREE;	if(c->umh != nil){		putmhead(c->umh);		c->umh = nil;	}	if(c->umc != nil){		cclose(c->umc);		c->umc = nil;	}	if(c->mux != nil){		muxclose(c->mux);		c->mux = nil;	}	if(c->mchan != nil){		cclose(c->mchan);		c->mchan = nil;	}	cnameclose(c->name);	lock(&chanalloc.lk);	c->next = chanalloc.free;	chanalloc.free = c;	unlock(&chanalloc.lk);}voidcclose(Chan *c){	if(c->flag&CFREE)		panic("cclose %p", getcallerpc(&c));	if(decref(&c->ref))		return;	if(!waserror()){		devtab[c->type]->close(c);		poperror();	}	chanfree(c);}/* * Make sure we have the only copy of c.  (Copy on write.) */Chan*cunique(Chan *c){	Chan *nc;	if(c->ref.ref != 1) {		nc = cclone(c);		cclose(c);		c = nc;	}	return c;}inteqqid(Qid a, Qid b){	return a.path==b.path && a.vers==b.vers;}inteqchan(Chan *a, Chan *b, int pathonly){	if(a->qid.path != b->qid.path)		return 0;	if(!pathonly && a->qid.vers!=b->qid.vers)		return 0;	if(a->type != b->type)		return 0;	if(a->dev != b->dev)		return 0;	return 1;}inteqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly){	if(a->qid.path != qid.path)		return 0;	if(!pathonly && a->qid.vers!=qid.vers)		return 0;	if(a->type != type)		return 0;	if(a->dev != dev)		return 0;	return 1;}Mhead*newmhead(Chan *from){	Mhead *mh;	mh = smalloc(sizeof(Mhead));	mh->ref.ref = 1;	mh->from = from;	incref(&from->ref);/*	n = from->name->len;	if(n >= sizeof(mh->fromname))		n = sizeof(mh->fromname)-1;	memmove(mh->fromname, from->name->s, n);	mh->fromname[n] = 0;*/	return mh;}intcmount(Chan **newp, Chan *old, int flag, char *spec){	Pgrp *pg;	int order, flg;	Mhead *m, **l, *mh;	Mount *nm, *f, *um, **h;	Chan *new;	if(QTDIR & (old->qid.type^(*newp)->qid.type))		error(Emount);if(old->umh)print("cmount old extra umh\n");	order = flag&MORDER;	if((old->qid.type&QTDIR)==0 && order != MREPL)		error(Emount);	new = *newp;	mh = new->umh;	/*	 * Not allowed to bind when the old directory	 * is itself a union.  (Maybe it should be allowed, but I don't see	 * what the semantics would be.)	 *	 * We need to check mh->mount->next to tell unions apart from	 * simple mount points, so that things like	 *	mount -c fd /root	 *	bind -c /root /	 * work.  The check of mount->mflag catches things like	 *	mount fd /root	 *	bind -c /root /	 * 	 * This is far more complicated than it should be, but I don't	 * see an easier way at the moment.		-rsc	 */	if((flag&MCREATE) && mh && mh->mount	&& (mh->mount->next || !(mh->mount->mflag&MCREATE)))		error(Emount);	pg = up->pgrp;	wlock(&pg->ns);	l = &MOUNTH(pg, old->qid);	for(m = *l; m; m = m->hash) {		if(eqchan(m->from, old, 1))			break;		l = &m->hash;	}	if(m == nil) {		/*		 *  nothing mounted here yet.  create a mount		 *  head and add to the hash table.		 */		m = newmhead(old);		*l = m;		/*		 *  if this is a union mount, add the old		 *  node to the mount chain.		 */		if(order != MREPL)			m->mount = newmount(m, old, 0, 0);	}	wlock(&m->lock);	if(waserror()){		wunlock(&m->lock);		nexterror();	}	wunlock(&pg->ns);	nm = newmount(m, new, flag, spec);	if(mh != nil && mh->mount != nil) {		/*		 *  copy a union when binding it onto a directory		 */		flg = order;		if(order == MREPL)			flg = MAFTER;		h = &nm->next;		um = mh->mount;		for(um = um->next; um; um = um->next) {			f = newmount(m, um->to, flg, um->spec);			*h = f;			h = &f->next;		}	}	if(m->mount && order == MREPL) {		mountfree(m->mount);		m->mount = 0;	}	if(flag & MCREATE)		nm->mflag |= MCREATE;	if(m->mount && order == MAFTER) {		for(f = m->mount; f->next; f = f->next)			;		f->next = nm;	}	else {		for(f = nm; f->next; f = f->next)			;		f->next = m->mount;		m->mount = nm;	}	wunlock(&m->lock);	poperror();	return nm->mountid;}voidcunmount(Chan *mnt, Chan *mounted){	Pgrp *pg;	Mhead *m, **l;	Mount *f, **p;	if(mnt->umh)	/* should not happen */		print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);	/*	 * It _can_ happen that mounted->umh is non-nil, 	 * because mounted is the result of namec(Aopen)	 * (see sysfile.c:/^sysunmount).	 * If we open a union directory, it will have a umh.	 * Although surprising, this is okay, since the	 * cclose will take care of freeing the umh.	 */	pg = up->pgrp;	wlock(&pg->ns);	l = &MOUNTH(pg, mnt->qid);	for(m = *l; m; m = m->hash) {		if(eqchan(m->from, mnt, 1))			break;		l = &m->hash;	}	if(m == 0) {		wunlock(&pg->ns);		error(Eunmount);	}	wlock(&m->lock);	if(mounted == 0) {		*l = m->hash;		wunlock(&pg->ns);		mountfree(m->mount);		m->mount = nil;		cclose(m->from);		wunlock(&m->lock);		putmhead(m);		return;	}	p = &m->mount;	for(f = *p; f; f = f->next) {		/* BUG: Needs to be 2 pass */		if(eqchan(f->to, mounted, 1) ||		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) {			*p = f->next;			f->next = 0;			mountfree(f);			if(m->mount == nil) {				*l = m->hash;				cclose(m->from);				wunlock(&m->lock);				wunlock(&pg->ns);				putmhead(m);				return;			}			wunlock(&m->lock);			wunlock(&pg->ns);			return;		}		p = &f->next;	}	wunlock(&m->lock);	wunlock(&pg->ns);	error(Eunion);}Chan*cclone(Chan *c){	Chan *nc;	Walkqid *wq;	wq = devtab[c->type]->walk(c, nil, nil, 0);	if(wq == nil)		error("clone failed");	nc = wq->clone;	free(wq);	nc->name = c->name;	if(c->name)		incref(&c->name->ref);	return nc;}intfindmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid){	Pgrp *pg;	Mhead *m;	pg = up->pgrp;	rlock(&pg->ns);	for(m = MOUNTH(pg, qid); m; m = m->hash){		rlock(&m->lock);if(m->from == nil){	print("m %p m->from 0\n", m);	runlock(&m->lock);	continue;}		if(eqchantdqid(m->from, type, dev, qid, 1)) {			runlock(&pg->ns);			if(mp != nil){				incref(&m->ref);				if(*mp != nil)					putmhead(*mp);				*mp = m;			}			if(*cp != nil)				cclose(*cp);			incref(&m->mount->to->ref);			*cp = m->mount->to;			runlock(&m->lock);			return 1;		}		runlock(&m->lock);	}	runlock(&pg->ns);	return 0;}intdomount(Chan **cp, Mhead **mp){	return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);}Chan*undomount(Chan *c, Cname *name){	Chan *nc;	Pgrp *pg;	Mount *t;	Mhead **h, **he, *f;	pg = up->pgrp;	rlock(&pg->ns);	if(waserror()) {		runlock(&pg->ns);		nexterror();	}	he = &pg->mnthash[MNTHASH];	for(h = pg->mnthash; h < he; h++) {		for(f = *h; f; f = f->hash) {			if(strcmp(f->from->name->s, name->s) != 0)				continue;			for(t = f->mount; t; t = t->next) {				if(eqchan(c, t->to, 1)) {					/*					 * We want to come out on the left hand side of the mount					 * point using the element of the union that we entered on.					 * To do this, find the element that has a from name of					 * c->name->s.					 */					if(strcmp(t->head->from->name->s, name->s) != 0)						continue;					nc = t->head->from;					incref(&nc->ref);					cclose(c);					c = nc;					break;				}			}		}	}	poperror();	runlock(&pg->ns);	return c;}/* * Either walks all the way or not at all.  No partial results in *cp. * *nerror is the number of names to display in an error message. */static char Edoesnotexist[] = "does not exist";intwalk(Chan **cp, char **names, int nnames, int nomount, int *nerror){	int dev, dotdot, i, n, nhave, ntry, type;	Chan *c, *nc;	Cname *cname;	Mount *f;	Mhead *mh, *nmh;	Walkqid *wq;	c = *cp;

⌨️ 快捷键说明

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