Sigrid Haflínudóttir9gc: ctxread: print the errorc7a2f586 years agoHistory
1000 lines · 20.2 KB · C
RawDownload
#define _DEFAULT_SOURCE#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>#include "c9.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); enum{	Canrd = 1<<0,	Canwr = 1<<1,}; typedef struct{	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 */}Fid; typedef struct{	C9tag tag;}Tag; typedef struct{	char *name;	uint32_t id;}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;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 n, 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 ((n = 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;} static voidstat2qid(struct stat *st, C9qid *qid, uint32_t *iounit){	int fmt; 	qid->path = st->st_ino;	qid->version = crc32(&st->st_ctim, sizeof(st->st_ctime));	qid->type = C9qtfile;	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 = st->st_blksize;} 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) {		*err = Enomem;		return NULL;	}	f->fd = -1;	f->path = strdup(path);	f->name = strrchr(f->path, '/');	if (f->name == NULL)		f->name = f->path;	else		f->name++; 	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) {			*err = Enomem;			return NULL;		}		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 ((real = realpath(path, NULL)) == NULL)			break;		free(path);		if (strlen(real) < rootlen) { /* don't escape root */			free(real);			real = strdup(rootpath);		}		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 intopenfid(Fid *f, C9mode mode, char **err){	struct stat st;	int omode; 	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 = O_RDONLY;		if ((f->qid.type & C9qtappend) != 0)			omode |= O_APPEND;		f->fd = open(f->path, omode);	} 	if (f->fd < 0 || fstat(f->fd, &st) != 0 || !hasperm(&st, mode, err)) {		if (*err == NULL)			*err = strerror(errno); 		if (f->dir != NULL)			closedir(f->dir);		else if (f->fd >= 0)			close(f->fd); 		f->dir = NULL;		f->fd = -1;		return -1;	}	stat2qid(&st, &f->qid, &f->iounit);	f->mode = mode; 	return 0;} static char *uid2str(uid_t uid, char **err){	struct passwd *p;	Id *newuids;	int i; 	for (i = 0; i < numuids; i++) {		if (uids[i].id == uid)			return uids[i].name;	}	if ((p = getpwuid(uid)) == NULL) {		*err = strerror(errno);		return NULL;	}	if ((newuids = realloc(uids, sizeof(*uids)*(numuids+1))) == NULL) {		*err = Enomem;		return NULL;	}	uids = newuids;	uids[numuids].id = uid;	uids[numuids].name = strdup(p->pw_name); 	return uids[numuids++].name;} static char *gid2str(gid_t gid, char **err){	struct group *g;	Id *newgids;	int i; 	for (i = 0; i < numgids; i++) {		if (gids[i].id == gid)			return gids[i].name;	}	if ((g = getgrgid(gid)) == NULL) {		*err = strerror(errno);		return NULL;	}	if ((newgids = realloc(gids, sizeof(*gids)*(numgids+1))) == NULL) {		*err = Enomem;		return NULL;	}	gids = newgids;

Lines 1–500 of 1000.

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