1523 lines · 25.3 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <bio.h> typedef struct Args Args; struct Args {	int	argc;	char	**argv;}; typedef struct Dfile Dfile;typedef struct Fid Fid;typedef struct File File;typedef struct Fs Fs;typedef struct Request Request;typedef struct Symbol Symbol;typedef struct Tardir Tardir; extern int threadrforkflag = RFNAMEG; enum{	Nstat = 1024,	/* plenty for this application */	MAXSIZE = 8192+IOHDRSZ,}; int messagesize = MAXSIZE; voidfatal(char *fmt, ...){	va_list arg;	char buf[1024]; 	write(2, "depend: ", 8);	va_start(arg, fmt);	vseprint(buf, buf+1024, fmt, arg);	va_end(arg);	write(2, buf, strlen(buf));	write(2, "\n", 1);	threadexitsall(fmt);} enum{	Nfidhash=	64,	Ndfhash=	128,}; struct Symbol{	Symbol	*next;		/* hash list chaining */	char	*sym;	int	fno;		/* file symbol is defined in */}; /* source file */struct File{	QLock; 	char	*name;	Symbol	*ref;	uchar	*refvec;	/* files resolving the references */	uint	len;		/* length of file */	uint	tarlen;		/* length of tar file */	uint	mode;	uint	mtime; 	int	use;	int	fd;}; /* .depend file */struct Dfile{	Lock;	int	use;		/* use count */	int	old;		/* true if this is an superceded dfile */ 	File	*file;		/* files */	int	nfile;		/* number of files */	int	flen;		/* length of file table */ 	Symbol	**dhash;	/* hash table of symbols */	int	hlen;		/* length of hash table */ 	Dfile	*next;		/* hash chain */	char	*path;		/* path name of dependency file */	Qid	qid;		/* qid of the dependency file */}; struct Fid{	Fid	*next;	int	fid;	int	ref; 	int	attached;	int	open;	Qid	qid;	char	*path;	Dfile	*df;	Symbol	*dp;	int	fd;	Dir	*dir;	int	ndir;	int	dirindex;}; struct Request{	Request	*next;	Fid	*fid;	Fcall	f;	uchar	buf[1];}; enum{	Tblocksize=	512,	/* tar block size */	Tnamesize=	100,	/* tar name size */}; struct Tardir{	char	name[Tnamesize];	char	mode[8];	char	uid[8];	char	gid[8];	char	size[12];	char	mtime[12];	char	chksum[8];	char	linkflag;	char	linkname[Tnamesize];}; struct Fs{	Lock; 	int	fd;		/* to kernel mount point */	Fid	*hash[Nfidhash];	char	*root;	Qid	rootqid; }; struct Fsarg{	Fs	*fs;	int	fd;	char *root;};  extern	void	fsrun(void*);extern	Fid*	fsgetfid(Fs*, int);extern	void	fsputfid(Fs*, Fid*);extern	void	fsreply(Fs*, Request*, char*);extern	void	fsversion(Fs*, Request*, Fid*);extern	void	fsauth(Fs*, Request*, Fid*);extern	void	fsflush(Fs*, Request*, Fid*);extern	void	fsattach(Fs*, Request*, Fid*);extern	void	fswalk(Fs*, Request*, Fid*);extern	void	fsopen(Fs*, Request*, Fid*);extern	void	fscreate(Fs*, Request*, Fid*);extern	void	fsread(Fs*, Request*, Fid*);extern	void	fswrite(Fs*, Request*, Fid*);extern	void	fsclunk(Fs*, Request*, Fid*);extern	void	fsremove(Fs*, Request*, Fid*);extern	void	fsstat(Fs*, Request*, Fid*);extern	void	fswstat(Fs*, Request*, Fid*); void 	(*fcall[])(Fs*, Request*, Fid*) ={	[Tflush]	fsflush,	[Tversion]	fsversion,	[Tauth]	fsauth,	[Tattach]	fsattach,	[Twalk]		fswalk,	[Topen]		fsopen,	[Tcreate]	fscreate,	[Tread]		fsread,	[Twrite]	fswrite,	[Tclunk]	fsclunk,	[Tremove]	fsremove,	[Tstat]		fsstat,	[Twstat]	fswstat}; char Eperm[]   = "permission denied";char Eexist[]  = "file does not exist";char Enotdir[] = "not a directory";char Eisopen[] = "file already open";char Enofid[] = "no such fid";char mallocerr[]	= "malloc: %r";char Etoolong[]	= "name too long"; char *dependlog = "depend"; int debug;Dfile *dfhash[Ndfhash];		/* dependency file hash */QLock dfhlock[Ndfhash];QLock iolock; Request*	allocreq(int);Dfile*	getdf(char*);void	releasedf(Dfile*);Symbol*	dfsearch(Dfile*, char*);void	dfresolve(Dfile*, int);char*	mkpath(char*, char*);int	mktar(Dfile*, Symbol*, uchar*, uint, int);void	closetar(Dfile*, Symbol*); void*emalloc(uint n){	void *p; 	p = malloc(n);	if(p == nil)		fatal(mallocerr);	memset(p, 0, n);	return p;} void *erealloc(void *ReallocP, int ReallocN){	if(ReallocN == 0)		ReallocN = 1;	if(!ReallocP)		ReallocP = emalloc(ReallocN);	else if(!(ReallocP = realloc(ReallocP, ReallocN)))		fatal("unable to allocate %d bytes",ReallocN);	return(ReallocP);} char*estrdup(char *s){	char *d, *d0; 	if(!s)		return 0;	d = d0 = emalloc(strlen(s)+1);	while(*d++ = *s++)		;	return d0;} /* *  mount the user interface and start one request processor *  per CPU */voidrealmain(void *a){	Fs *fs;	int pfd[2];	int srv;	char service[128];	struct Fsarg fsarg;	Args *args;	int argc;	char **argv; 	args = a;	argc = args->argc;	argv = args->argv; 	fmtinstall('F', fcallfmt); 	ARGBEGIN{		case 'd':			debug++;			break;	}ARGEND	if(argc != 2){		fprint(2, "usage: %s [-d] svc-name directory\n", argv0);		exits("usage");	}	snprint(service, sizeof service, "#s/%s", argv[0]);	if(argv[1][0] != '/')		fatal("directory must be rooted"); 	if(pipe(pfd) < 0)		fatal("opening pipe: %r"); 	/* Typically mounted before /srv exists */	srv = create(service, OWRITE, 0666);	if(srv < 0)		fatal("post: %r");	fprint(srv, "%d", pfd[1]);	close(srv);	close(pfd[1]); 	time(nil);	/* open fd for time before losing / */	if(bind(argv[1], "/", MREPL) == 0)		fatal("can't bind %s to /", argv[1]); 	fs = emalloc(sizeof(Fs));	fsarg.fs = fs;	fsarg.fd = pfd[0];	fsarg.root = argv[1];	proccreate(fsrun, &fsarg, 16*1024);	proccreate(fsrun, &fsarg, 16*1024);	fsrun(&fsarg);	exits(nil);} voidthreadmain(int argc, char *argv[]){	static Args args; 	args.argc = argc;	args.argv = argv;	rfork(RFNAMEG);	proccreate(realmain, &args, 16*1024);} char*mkpath(char *dir, char *file){	int len;	char *path; 	len = strlen(dir) + 1;	if(file != nil)		len += strlen(file) + 1;	path = emalloc(len);	if(file != nil)		sprint(path, "%s/%s", dir, file);	else		sprint(path, "%s", dir);	return path;} voidfsrun(void *a){	struct Fsarg *fsarg;	Fs* fs;	char *root;	int n, t;	Request *r;	Fid *f;	Dir *d; 	fsarg = a;	fs = fsarg->fs;	fs->fd = fsarg->fd;	root = fsarg->root;	d = dirstat("/");	if(d == nil)		fatal("root %s inaccessible: %r", root);	fs->rootqid = d->qid;	free(d); 	for(;;){		r = allocreq(messagesize);		qlock(&iolock);		n = read9pmsg(fs->fd, r->buf, messagesize);		qunlock(&iolock);		if(n <= 0)			fatal("read9pmsg error: %r"); 		if(convM2S(r->buf, n, &r->f) == 0){			fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],				r->buf[1], r->buf[2]);			free(r);			continue;		} 		f = fsgetfid(fs, r->f.fid);		r->fid = f;		if(debug)			fprint(2, "%F path %llux\n", &r->f, f->qid.path); 		t = r->f.type;		r->f.type++;		(*fcall[t])(fs, r, f);		fsputfid(fs, f);	} } /* *  any request that can get queued for a delayed reply */Request*allocreq(int bufsize){	Request *r; 	r = emalloc(sizeof(Request)+bufsize);	r->next = nil;	return r;} Fid*fsgetfid(Fs *fs, int fid){	Fid *f, *nf; 	lock(fs);	for(f = fs->hash[fid%Nfidhash]; f; f = f->next){		if(f->fid == fid){			f->ref++;			unlock(fs);			return f;		}	} 	nf = emalloc(sizeof(Fid));	nf->next = fs->hash[fid%Nfidhash];	fs->hash[fid%Nfidhash] = nf;	nf->fid = fid;	nf->ref = 1;	nf->fd = -1;	unlock(fs);	return nf;} voidfsputfid(Fs *fs, Fid *f){	Fid **l, *nf; 	lock(fs);	if(--f->ref > 0){		unlock(fs);		return;	}	for(l = &fs->hash[f->fid%Nfidhash]; nf = *l; l = &nf->next)		if(nf == f){			*l = f->next;			break;		}	unlock(fs);	free(f);} voidfsreply(Fs *fs, Request *r, char *err){	int n;	uchar buf[MAXSIZE]; 	if(err){		r->f.type = Rerror;		r->f.ename = err;	}	if(debug)		fprint(2, "%F path %llux\n", &r->f, r->fid->qid.path);	n = convS2M(&r->f, buf, messagesize);	if(n == 0)		fatal("bad convS2M");	if(write(fs->fd, buf, n) != n)		fatal("unmounted");	free(r);} voidfsversion(Fs *fs, Request *r, Fid*){	if(r->f.msize < 256){		fsreply(fs, r, "version: bad message size");		return;	}	if(messagesize > r->f.msize)		messagesize = r->f.msize;	r->f.msize = messagesize;	r->f.version = "9P2000";	fsreply(fs, r, nil);} voidfsauth(Fs *fs, Request *r, Fid*){	fsreply(fs, r, "depend: authentication not required");} voidfsflush(Fs*, Request*, Fid*){} voidfsattach(Fs *fs, Request *r, Fid *f){	f->qid = fs->rootqid;	f->path = strdup("/");	f->df = getdf(mkpath(f->path, ".depend")); 

Lines 1–500 of 1523.