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

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
		pos += m;	}	return n;}intreadmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen){	Dir d;	int n, m;	long pos;	Message *msg;	n = 0;	if(f->mb->ctl){		mkstat(&d, f->mb, nil, Qmboxctl);		m = convD2M(&d, &buf[n], blen);		if(off == 0){			if(m <= BIT16SZ || m > cnt){				f->fptr = nil;				return 0;			}			n += m;			cnt -= m;		} else			off -= m;	}	// to avoid n**2 reads of the directory, use a saved finger pointer	if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){		msg = f->fptr;		pos = f->foff;	} else {		msg = f->mb->root->part;		pos = 0;	} 	for(; cnt > 0 && msg != nil; msg = msg->next){		// act like deleted files aren't there		if(msg->deleted)			continue;		mkstat(&d, f->mb, msg, Qdir);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				break;			n += m;			cnt -= m;		}		pos += m;	}	// save a finger pointer for next read of the mbox directory	f->foff = pos;	f->fptr = msg;	f->fvers = f->mb->vers;	return n;}intreadmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen){	Dir d;	int i, n, m;	long pos;	Message *msg;	n = 0;	pos = 0;	for(i = 0; i < Qmax; i++){		mkstat(&d, f->mb, f->m, i);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				return n;			n += m;			cnt -= m;		}		pos += m;	}	for(msg = f->m->part; msg != nil; msg = msg->next){		mkstat(&d, f->mb, msg, Qdir);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				break;			n += m;			cnt -= m;		}		pos += m;	}	return n;}char*rread(Fid *f){	long off;	int t, i, n, cnt;	char *p;	rhdr.count = 0;	off = thdr.offset;	cnt = thdr.count;	if(cnt > messagesize - IOHDRSZ)		cnt = messagesize - IOHDRSZ;	rhdr.data = (char*)mbuf;	t = FILE(f->qid.path);	if(f->qid.type & QTDIR){		if(t == Qtop) {			qlock(&mbllock);			n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);			qunlock(&mbllock);		} else if(t == Qmbox) {			qlock(f->mb);			if(off == 0)				syncmbox(f->mb, 1);			n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);			qunlock(f->mb);		} else if(t == Qmboxctl) {			n = 0;		} else {			n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);		}		rhdr.count = n;		return nil;	}	if(FILE(f->qid.path) == Qheader){		rhdr.count = readheader(f->m, (char*)mbuf, off, cnt);		return nil;	}	if(FILE(f->qid.path) == Qinfo){		rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt);		return nil;	}	i = fileinfo(f->m, FILE(f->qid.path), &p);	if(off < i){		if((off + cnt) > i)			cnt = i - off;		memmove(mbuf, p + off, cnt);		rhdr.count = cnt;	}	return nil;}char*rwrite(Fid *f){	char *err;	char *token[1024];	int t, n;	String *file;	t = FILE(f->qid.path);	rhdr.count = thdr.count;	switch(t){	case Qctl:		if(thdr.count == 0)			return Ebadctl;		if(thdr.data[thdr.count-1] == '\n')			thdr.data[thdr.count-1] = 0;		else			thdr.data[thdr.count] = 0;		n = tokenize(thdr.data, token, nelem(token));		if(n == 0)			return Ebadctl;		if(strcmp(token[0], "open") == 0){			file = s_new();			switch(n){			case 1:				err = Ebadctl;				break;			case 2:				mboxpath(token[1], getlog(), file, 0);				err = newmbox(s_to_c(file), nil, 0);				break;			default:				mboxpath(token[1], getlog(), file, 0);				if(strchr(token[2], '/') != nil)					err = "/ not allowed in mailbox name";				else					err = newmbox(s_to_c(file), token[2], 0);				break;			}			s_free(file);			return err;		}		if(strcmp(token[0], "close") == 0){			if(n < 2)				return nil;			freembox(token[1]);			return nil;		}		if(strcmp(token[0], "delete") == 0){			if(n < 3)				return nil;			delmessages(n-1, &token[1]);			return nil;		}		return Ebadctl;	case Qmboxctl:		if(f->mb && f->mb->ctl){			if(thdr.count == 0)				return Ebadctl;			if(thdr.data[thdr.count-1] == '\n')				thdr.data[thdr.count-1] = 0;			else				thdr.data[thdr.count] = 0;			n = tokenize(thdr.data, token, nelem(token));			if(n == 0)				return Ebadctl;			return (*f->mb->ctl)(f->mb, n, token);		}	}	return Eperm;}char *rclunk(Fid *f){	Mailbox *mb;	f->busy = 0;	f->open = 0;	if(f->mtop != nil){		qlock(f->mb);		msgdecref(f->mb, f->mtop);		qunlock(f->mb);	}	f->m = f->mtop = nil;	mb = f->mb;	if(mb != nil){		f->mb = nil;		assert(mb->refs > 0);		qlock(&mbllock);		mboxdecref(mb);		qunlock(&mbllock);	}	f->fid = -1;	return 0;}char *rremove(Fid *f){	if(f->m != nil){		if(f->m->deleted == 0)			mailplumb(f->mb, f->m, 1);		f->m->deleted = 1;	}	return rclunk(f);}char *rstat(Fid *f){	Dir d;	if(FILE(f->qid.path) == Qmbox){		qlock(f->mb);		syncmbox(f->mb, 1);		qunlock(f->mb);	}	mkstat(&d, f->mb, f->m, FILE(f->qid.path));	rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);	rhdr.stat = mbuf;	return 0;}char *rwstat(Fid*){	return Eperm;}Fid *newfid(int fid){	Fid *f, *ff;	ff = 0;	for(f = fids; f; f = f->next)		if(f->fid == fid)			return f;		else if(!ff && !f->busy)			ff = f;	if(ff){		ff->fid = fid;		ff->fptr = nil;		return ff;	}	f = emalloc(sizeof *f);	f->fid = fid;	f->fptr = nil;	f->next = fids;	fids = f;	return f;}intfidmboxrefs(Mailbox *mb){	Fid *f;	int refs = 0;	for(f = fids; f; f = f->next){		if(f->mb == mb)			refs++;	}	return refs;}voidio(void){	char *err;	int n;	/* start a process to watch the mailboxes*/	if(plumbing){		switch(rfork(RFPROC|RFMEM)){		case -1:			/* oh well */			break;		case 0:			reader();			exits(nil);		default:			break;		}	}	for(;;){		/*		 * reading from a pipe or a network device		 * will give an error after a few eof reads		 * however, we cannot tell the difference		 * between a zero-length read and an interrupt		 * on the processes writing to us,		 * so we wait for the error		 */		checkmboxrefs();		n = read9pmsg(mfd[0], mdata, messagesize);		if(n == 0)			continue;		if(n < 0)			return;		if(convM2S(mdata, n, &thdr) == 0)			continue;		if(debug)			fprint(2, "%s:<-%F\n", argv0, &thdr);		rhdr.data = (char*)mdata + messagesize;		if(!fcalls[thdr.type])			err = "bad fcall type";		else			err = (*fcalls[thdr.type])(newfid(thdr.fid));		if(err){			rhdr.type = Rerror;			rhdr.ename = err;		}else{			rhdr.type = thdr.type + 1;			rhdr.fid = thdr.fid;		}		rhdr.tag = thdr.tag;		if(debug)			fprint(2, "%s:->%F\n", argv0, &rhdr);/**/		n = convS2M(&rhdr, mdata, messagesize);		if(write(mfd[1], mdata, n) != n)			error("mount write");	}}voidreader(void){	ulong t;	Dir *d;	Mailbox *mb;	sleep(15*1000);	for(;;){		t = time(0);		qlock(&mbllock);		for(mb = mbl; mb != nil; mb = mb->next){			assert(mb->refs > 0);			if(mb->waketime != 0 && t > mb->waketime){				qlock(mb);				mb->waketime = 0;				break;			}			d = dirstat(mb->path);			if(d == nil)				continue;			qlock(mb);			if(mb->d)			if(d->qid.path != mb->d->qid.path			   || d->qid.vers != mb->d->qid.vers){				free(d);				break;			}			qunlock(mb);			free(d);		}		qunlock(&mbllock);		if(mb != nil){			syncmbox(mb, 1);			qunlock(mb);		} else			sleep(15*1000);	}}intnewid(void){	int rv;	static int id;	static Lock idlock;	lock(&idlock);	rv = ++id;	unlock(&idlock);	return rv;}voiderror(char *s){	postnote(PNGROUP, getpid(), "die yankee pig dog");	fprint(2, "%s: %s: %r\n", argv0, s);	exits(s);}typedef struct Ignorance Ignorance;struct Ignorance{	Ignorance *next;	char	*str;		/* string */	int	partial;	/* true if not exact match */};Ignorance *ignorance;/* *  read the file of headers to ignore  */voidreadignore(void){	char *p;	Ignorance *i;	Biobuf *b;	if(ignorance != nil)		return;	b = Bopen("/mail/lib/ignore", OREAD);	if(b == 0)		return;	while(p = Brdline(b, '\n')){		p[Blinelen(b)-1] = 0;		while(*p && (*p == ' ' || *p == '\t'))			p++;		if(*p == '#')			continue;		i = malloc(sizeof(Ignorance));		if(i == 0)			break;		i->partial = strlen(p);		i->str = strdup(p);		if(i->str == 0){			free(i);			break;		}		i->next = ignorance;		ignorance = i;	}	Bterm(b);}intignore(char *p){	Ignorance *i;	readignore();	for(i = ignorance; i != nil; i = i->next)		if(cistrncmp(i->str, p, i->partial) == 0)			return 1;	return 0;}inthdrlen(char *p, char *e){	char *ep;	ep = p;	do {		ep = strchr(ep, '\n');		if(ep == nil){			ep = e;			break;		}		ep++;		if(ep >= e){			ep = e;			break;		}	} while(*ep == ' ' || *ep == '\t');	return ep - p;}// rfc2047 non-ascii: =?charset?q?encoded-text?=intrfc2047convert(String *s, char *token, int len){	char charset[100], decoded[1024], *e, *x;	int l;	if(len == 0)		return -1;	e = token+len-2;	token += 2;	x = memchr(token, '?', e-token);	if(x == nil || (l=x-token) >= sizeof charset)		return -1;	memmove(charset, token, l);	charset[l] = 0;	token = x+1;	// bail if it doesn't fit 	if(e-token > sizeof(decoded)-1)		return -1;	// bail if we don't understand the encoding	if(cistrncmp(token, "b?", 2) == 0){		token += 2;		len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);		decoded[len] = 0;	} else if(cistrncmp(token, "q?", 2) == 0){		token += 2;		len = decquoted(decoded, token, e, 1);		if(len > 0 && decoded[len-1] == '\n')			len--;		decoded[len] = 0;	} else		return -1;	if(xtoutf(charset, &x, decoded, decoded+len) <= 0)		s_append(s, decoded);	else {		s_append(s, x);		free(x);	}	return 0;}char*rfc2047start(char *start, char *end){	int quests;	if(*--end != '=')		return nil;	if(*--end != '?')		return nil;	quests = 0;	for(end--; end >= start; end--){		switch(*end){		case '=':			if(quests == 3 && *(end+1) == '?')				return end;			break;		case '?':			++quests;			break;		case ' ':		case '\t':		case '\n':		case '\r':			/* can't have white space in a token */			return nil;		}	}	return nil;}// convert a header lineString*stringconvert(String *s, char *uneaten, int len){	char *token, *p, *e;	s = s_reset(s);	p = uneaten;	for(e = p+len; p < e; ){		while(*p++ == '=' && (token = rfc2047start(uneaten, p))){			s_nappend(s, uneaten, token-uneaten);			if(rfc2047convert(s, token, p - token) < 0)				s_nappend(s, token, p - token);			uneaten = p;			for(; p<e && isspace(*p);)				p++;			if(p+2 < e && p[0] == '=' && p[1] == '?')				uneaten = p;	// paste		}	}	if(p > uneaten)		s_nappend(s, uneaten, p-uneaten);	return s;}intreadheader(Message *m, char *buf, int off, int cnt){	char *p, *e;	int n, ns;	char *to = buf;	String *s;	p = m->header;	e = m->hend;	s = nil;	// copy in good headers	while(cnt > 0 && p < e){		n = hdrlen(p, e);		if(ignore(p)){			p += n;			continue;		}		// rfc2047 processing		s = stringconvert(s, p, n);		ns = s_len(s);		if(off > 0){			if(ns <= off){				off -= ns;				p += n;				continue;			}			ns -= off;		}		if(ns > cnt)			ns = cnt;		memmove(to, s_to_c(s)+off, ns);		to += ns;		p += n;		cnt -= ns;		off = 0;	}	s_free(s);	return to - buf;}intheaderlen(Message *m){	char buf[1024];	int i, n;	if(m->hlen >= 0)		return m->hlen;	for(n = 0; ; n += i){		i = readheader(m, buf, n, sizeof(buf));		if(i <= 0)			break;	}	m->hlen = n;	return n;}QLock hashlock;uinthash(ulong ppath, char *name){	uchar *p;	uint h;	h = 0;	for(p = (uchar*)name; *p; p++)		h = h*7 + *p;	h += ppath;	return h % Hsize;}Hash*hlook(ulong ppath, char *name){	int h;	Hash *hp;	qlock(&hashlock);	h = hash(ppath, name);	for(hp = htab[h]; hp != nil; hp = hp->next)		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){			qunlock(&hashlock);			return hp;		}	qunlock(&hashlock);	return nil;}voidhenter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb){	int h;	Hash *hp, **l;	qlock(&hashlock);	h = hash(ppath, name);	for(l = &htab[h]; *l != nil; l = &(*l)->next){		hp = *l;		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){			hp->m = m;			hp->mb = mb;			hp->qid = qid;			qunlock(&hashlock);			return;		}	}	*l = hp = emalloc(sizeof(*hp));	hp->m = m;	hp->mb = mb;	hp->qid = qid;	hp->name = name;	hp->ppath = ppath;	qunlock(&hashlock);}voidhfree(ulong ppath, char *name){	int h;	Hash *hp, **l;	qlock(&hashlock);	h = hash(ppath, name);	for(l = &htab[h]; *l != nil; l = &(*l)->next){		hp = *l;		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){			hp->mb = nil;			*l = hp->next;			free(hp);			break;		}	}	qunlock(&hashlock);}inthashmboxrefs(Mailbox *mb){	int h;	Hash *hp;	int refs = 0;	qlock(&hashlock);	for(h = 0; h < Hsize; h++){		for(hp = htab[h]; hp != nil; hp = hp->next)			if(hp->mb == mb)				refs++;	}	qunlock(&hashlock);	return refs;}voidcheckmboxrefs(void){	int f, refs;	Mailbox *mb;	qlock(&mbllock);	for(mb=mbl; mb; mb=mb->next){		qlock(mb);		refs = (f=fidmboxrefs(mb))+1;		if(refs != mb->refs){			fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);			abort();		}		qunlock(mb);	}	qunlock(&mbllock);}voidpost(char *name, char *envname, int srvfd){	int fd;	char buf[32];	fd = create(name, OWRITE, 0600);	if(fd < 0)		error("post failed");	sprint(buf, "%d",srvfd);	if(write(fd, buf, strlen(buf)) != strlen(buf))		error("srv write");	close(fd);	putenv(envname, name);}

⌨️ 快捷键说明

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