Sigrid Solveig Haflínudóttirupdate for newest c9c66e91c2 years agoHistory
1106 lines · 21.7 KB · C
RawDownload
#ifdef __linux__#define _GNU_SOURCE#else#define _DEFAULT_SOURCE#endif#define _FILE_OFFSET_BITS 64#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <grp.h>#include <inttypes.h>#include <pwd.h>#include <signal.h>#include <stdarg.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/select.h>#include <sys/stat.h>#include <sys/time.h>#include <unistd.h>#if defined(__APPLE__) || defined(__NetBSD__)#define st_atim st_atimespec#define st_ctim st_ctimespec#endif#include "c9/proto.h"#include "parg.h" #define max(a,b) ((a)>(b)?(a):(b))#define used(x) ((void)(x))#define nelem(x) (int)(sizeof(x)/sizeof((x)[0])) uint32_t crc32(const void *data, int len); typedef struct Fid Fid;typedef struct Id Id;typedef struct Tag Tag; enum{	Canrd = 1<<0,	Canwr = 1<<1,}; struct Fid{	char *path; /* full path */	char *name; /* base name */ 	DIR *dir; /* set when it's an opened directory */	uint64_t diroffset; /* to read dirs correctly */ 	C9qid qid;	C9fid fid;	C9mode mode; /* mode in which the file was opened */	uint32_t iounit; 	int fd; /* set when it's an opened file */}; struct Tag{	C9tag tag;}; struct Id{	char *name;	uint32_t id;}; static char *t2s[] ={	[Tversion-Tversion] = "Tversion",	[Tauth-Tversion] = "Tauth",	[Tattach-Tversion] = "Tattach",	[Tflush-Tversion] = "Tflush",	[Twalk-Tversion] = "Twalk",	[Topen-Tversion] = "Topen",	[Tcreate-Tversion] = "Tcreate",	[Tread-Tversion] = "Tread",	[Twrite-Tversion] = "Twrite",	[Tclunk-Tversion] = "Tclunk",	[Tremove-Tversion] = "Tremove",	[Tstat-Tversion] = "Tstat",	[Twstat-Tversion] = "Twstat",}; static char *modes[] ={	"read", "write", "rdwr", "exec",}; static char *Enoauth = "authentication not required";static char *Eunknownfid = "unknown fid";static char *Enowstat = "wstat prohibited";static char *Eperm = "permission denied";static char *Enowrite = "write prohibited";static char *Enomem = "out of memory";static char *Edupfid = "duplicate fid";static char *Ewalknodir = "walk in non-directory";static char *Enotfound = "file not found";static char *Eduptag = "duplicate tag";static char *Ebotch = "9P protocol botch";static char *Enocreate = "create prohibited";static char *Eisdir = "is a directory";static char *Ebadoffset = "bad offset"; static int in, out, eof;static C9ctx ctx;static int debug, rootescape, anon;static Fid **fids;static int numfids;static Tag **tags;static int numtags;static char *rootpath;static size_t rootlen;static C9qid walkqids[C9maxpathel];static uint8_t *rdbuf;static uint8_t *wrbuf;static uint32_t wroff, wrend, wrbufsz;static Id *uids, *gids;static int numuids, numgids; __attribute__((format(printf, 1, 2)))static voidtrace(const char *fmt, ...){	va_list ap; 	if(debug == 0)		return; 	va_start(ap, fmt);	vfprintf(stderr, fmt, ap);	va_end(ap);} static intcanrw(int rdonly, int block){	struct timeval t;	fd_set r, w, e;	int fl; 	FD_ZERO(&r);	FD_SET(in, &r);	FD_ZERO(&w);	if(rdonly == 0)		FD_SET(out, &w);	FD_ZERO(&e);	FD_SET(in, &e);	FD_SET(out, &e);	memset(&t, 0, sizeof(t));	t.tv_usec = 1000;	for(;;){		errno = 0;		if(select(max(in, out) + 1, &r, &w, &e, block ? NULL : &t) < 0 ||		   FD_ISSET(in, &e) || FD_ISSET(out, &e)){			if(errno == EINTR)				continue;			return -1;		}		break;	} 	fl = 0;	if(FD_ISSET(in, &r))		fl |= Canrd;	if(FD_ISSET(out, &w))		fl |= Canwr; 	return fl;} static intwrsend(void){	uint32_t n;	int w; 	if(wrend == 0)		return 0;	for(n = 0; n < wrend; n += w){		errno = 0;		if((w = write(out, wrbuf+n, wrend-n)) <= 0){			if(errno == EINTR)				continue;			if(errno != EPIPE) /* remote end closed */				perror("write");			return -1;		}	}	if(debug >= 2)		trace("<- %d bytes, %d left\n", wrend, wroff-wrend);	memmove(wrbuf, wrbuf+wrend, wroff-wrend);	wroff = wroff - wrend; 	return 0;} static inthastag(C9tag tag){	int i; 	for(i = 0; i < numtags; i++){		if(tags[i] != NULL && tags[i]->tag == tag)			return 1;	} 	return 0;} static intstatpath(char *path, struct stat *st, char **err){	if(stat(path, st) == 0)		return 0; 	if(errno == EACCES)		*err = Eperm;	else if(errno == ENOMEM)		*err = Enomem;	else if(errno == ENOTDIR)		*err = Ewalknodir;	else if(errno == ENOENT)		*err = Enotfound;	else		*err = strerror(errno); 	return -1;} #define copyadvance(p, data, size) do{ memmove(p, data, size); p += size; }while(0) static voidstat2qid(struct stat *st, C9qid *qid, uint32_t *iounit){	uint8_t b[sizeof(st->st_ctim) + sizeof(st->st_size) + sizeof(st->st_dev) + sizeof(st->st_ino)], *p;	int fmt; 	qid->path = st->st_ino;	qid->type = C9qtfile; 	p = b;	copyadvance(p, &st->st_ctime, sizeof(st->st_ctim));	copyadvance(p, &st->st_size, sizeof(st->st_size));	copyadvance(p, &st->st_dev, sizeof(st->st_dev));	copyadvance(p, &st->st_ino, sizeof(st->st_ino));	qid->version = crc32(b, p-b); 	fmt = st->st_mode & S_IFMT;	if(fmt == S_IFDIR)		qid->type |= C9qtdir;	if((st->st_mode & 0222) != 0 &&	   (fmt == S_IFCHR || fmt == S_IFCHR || fmt == S_IFSOCK || fmt == S_IFIFO))		qid->type |= C9qtappend;	if(iounit != NULL)		*iounit = 0;} static Fid *newfid(C9fid fid, char *path, char **err){	Fid *f, **newfids;	struct stat st;	int i; 	for(i = 0; i < numfids; i++){		if(fids[i] != NULL && fids[i]->fid == fid){			*err = Edupfid;			return NULL;		}	} 	if(statpath(path, &st, err) != 0)		return NULL; 	if((f = calloc(1, sizeof(*f))) == NULL || (f->path = strdup(path)) == NULL){nomem:		if(f != NULL){			free(f->path);			free(f);		}		*err = Enomem;		return NULL;	}	f->fd = -1;	f->name = strrchr(f->path, '/');	if(f->name == NULL)		f->name = f->path;	else		f->name++;	if(f->name[0] == 0)		fprintf(stderr, "%s -> empty file name\n", f->path); 	for(i = 0; i < numfids; i++){		if(fids[i] == NULL){			fids[i] = f;			break;		}	}	if(i >= numfids){		if((newfids = realloc(fids, (numfids+1)*sizeof(*fids))) == NULL)			goto nomem;		fids = newfids;		fids[numfids++] = f;	} 	f->fid = fid;	stat2qid(&st, &f->qid, &f->iounit); 	return f;} static Fid *findfid(C9fid fid, char **err){	int i; 	for(i = 0; i < numfids; i++){		if(fids[i] != NULL && fids[i]->fid == fid){			return fids[i];		}	} 	*err = Eunknownfid; 	return NULL;} static intdelfid(C9fid fid, char **err){	Fid *f;	int i; 	for(i = 0; i < numfids; i++){		f = fids[i];		if(f != NULL && f->fid == fid){			if(f->dir != NULL)				closedir(f->dir);			else if(f->fd >= 0)				close(f->fd);			free(f->path);			free(f);			fids[i] = NULL;			return 0;		}	} 	*err = Eunknownfid; 	return -1;} static inthasperm(struct stat *st, C9mode mode, char **err){	int m, stm, fmt; 	m = mode & 0xf;	stm = st->st_mode & 0777;	*err = Eperm;	if(((stm & 0111) == 0 || (stm & 0444) == 0) && m == C9exec) /* executing needs rx */		return 0;	if((stm & 0222) == 0 && (m == C9write || m == C9rdwr)) /* writing needs w */		return 0;	if((stm & 0444) == 0 && m != C9write) /* reading needs r */		return 0;	fmt = st->st_mode & S_IFMT;	if(fmt == S_IFDIR && ((stm & 0111) == 0 || (stm & 0444) == 0)) /* dirs need rx */		return 0;	*err = NULL; 	return 1;} static Fid *walk(C9fid fid, C9fid nfid, char *el[], C9qid *qids[], char **err){	Fid *f;	char *path, *real, *p;	struct stat st;	int i, plen, ellen; 	if((f = findfid(fid, err)) == NULL)		return NULL; 	if(el[0] == NULL){ /* nwname = 0 */		qids[0] = NULL;		if(fid == nfid)			return f;		return newfid(nfid, f->path, err);	} 	if((f->qid.type & C9qtdir) == 0){ /* has to be a dir */		*err = Ewalknodir;		return NULL;	} 	p = strdup(f->path);	f = NULL;	for(i = 0; el[i] != NULL; i++){		plen = strlen(p);		ellen = strlen(el[i]);		path = malloc(plen + 1 + ellen + 1);		memmove(path, p, plen);		path[plen] = '/';		memmove(path+plen+1, el[i], ellen);		path[plen+1+ellen] = 0; 		if(!rootescape){			real = realpath(path, NULL);			free(path);			if(real == NULL)				break;			if(strlen(real) < rootlen){ /* don't escape root */				free(real);				real = strdup(rootpath);			}		}else{			real = path;		} 		free(p);		p = real; 		if(statpath(p, &st, err) != 0)			break;		if(el[i+1] != NULL && !hasperm(&st, C9read, err))			break; 		qids[i] = &walkqids[i];		stat2qid(&st, qids[i], NULL);	} 	qids[i] = NULL;	if(el[i] == NULL){ /* could walk all the way */		f = newfid(nfid, p, err);		if(f != NULL && f->name[0] == '/' && f->name[1] == 0) /* root */			f->name = "/";	}else if(i != 0){ /* didn't fail on the first one */		*err = NULL;	}	free(p); 	return f;} static intmode2unix(C9mode mode, int qidtype){	int omode; 	omode = O_NOFOLLOW;	if((mode & 3) == C9read)		omode |= O_RDONLY;	else if((mode & 3) == C9write)		omode |= O_WRONLY;	else if((mode & 3) == C9rdwr)		omode |= O_RDWR;	if(mode & C9trunc)		omode |= O_TRUNC;#ifdef __linux__	if(mode & C9rclose)		omode |= O_TMPFILE;#endif	if((qidtype & C9qtappend) != 0)		omode |= O_APPEND; 	return omode;} static intopenfid(Fid *f, C9mode mode, char **err){	struct stat st;	int omode; 	if(stat(f->path, &st) != 0 || !hasperm(&st, mode, err))		goto error;	stat2qid(&st, &f->qid, &f->iounit); 	if((f->qid.type & C9qtdir) != 0){		if((f->dir = opendir(f->path)) == NULL){			*err = strerror(errno);			return -1;		}		f->fd = dirfd(f->dir);	}else{		omode = mode2unix(mode, f->qid.type);		f->fd = open(f->path, omode);	} 	if(f->fd < 0)		goto error;	f->mode = mode;

Lines 1–500 of 1106.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t