Sigrid Solveig Haflínudóttiradd -d BITMASK option to enable debugging messagesc63712c2 years agoHistory
1060 lines · 19.4 KB · C
RawDownload
#include <ext4.h>#include <ext4_inode.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <bio.h>#include "group.h"#include "common.h" #define MIN(a,b) ((a)<(b)?(a):(b)) int mainstacksize = 65536; typedef struct Aux Aux; struct Aux {	Part *p;	u32int uid;	char *path;	int doff;	union {		ext4_file *file;		ext4_dir *dir;	};	int type;}; enum {	Adir,	Afile,}; static Opts opts = {	.group = nil,	.cachewb = 0,	.asroot = 0,	.linkmode = Lhide, 	.fstype = -1,	.blksz = 1024,	.label = "",	.inodesz = 256,	.ninode = 0,};static u32int Root;static u8int zero[65536];static char Eperm[] = "permission denied";static char *srvname; static char *linkresolve(Aux *a, char *s, char **value){	char *q, buf[4096+1];	usize sz;	int res; 	res = 0;	if(opts.linkmode == Lresolve && (res = ext4_readlink(s, buf, sizeof(buf), &sz)) == 0){		if(sz == sizeof(buf)){			werrstr("readlink: %s: path too long", s);			free(s);			return nil;		} 		buf[sz] = 0;		if(value != nil)			*value = strdup(buf);		cleanname(buf);		if(buf[0] == '/'){			free(s);			s = smprint("%M%s", a->p, buf);		}else{			q = strrchr(s, '/');			*q = 0;			q = s;			s = smprint("%s/%s", q, buf);			free(q);			cleanname(strchr(s+1, '/'));		}	}else{		if(res != 0)			werrstr("readlink: %s: %s", s, errno2s(res));		if(value != nil)			*value = nil;	} 	return s;} static char *fullpath(Aux *a){	return linkresolve(a, smprint("%M/%s", a->p, a->path), nil);} static inthaveperm(Aux *a, int p, struct ext4_inode *inodeout){	struct ext4_inode inode;	u32int ino, id;	int m, fm, r;	Group *g;	char *s; 	switch(p & 3){	case OREAD:		p = AREAD;			break;	case OWRITE:		p = AWRITE;		break;	case ORDWR:		p = AREAD|AWRITE;		break;	case OEXEC:		p = AEXEC;			break;	default:		return 0;	}	if(p & OTRUNC)		p |= AWRITE; 	if((s = fullpath(a)) == nil)		return -1;	if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0){		werrstr("%s: %s", s, errno2s(r));		free(s);		return -1;	}	free(s); 	if(inodeout != nil)		memmove(inodeout, &inode, sizeof(inode)); 	fm = ext4_inode_get_mode(a->p->sb, &inode); 	/* other */	m = fm & 7;	if((p & m) == p)		return 1; 	/* owner */	id = ext4_inode_get_uid(&inode);	if(a->uid == Root || ((g = findgroupid(&a->p->groups, id)) != nil && ingroup(g, a->uid))){		m |= (fm >> 6) & 7;		if((p & m) == p)			return 1;	} 	/* group */	id = ext4_inode_get_gid(&inode);	if(a->uid == Root || ((g = findgroupid(&a->p->groups, id)) != nil && ingroup(g, a->uid))){		m |= (fm >> 3) & 7;		if((p & m) == p)			return 1;	} 	return 0;} static voidrattach(Req *r){	char err[ERRMAX];	Aux *a; 	if((a = calloc(1, sizeof(*a))) == nil)		respond(r, "memory");	else if((a->p = openpart(r->ifcall.aname, &opts)) == nil){		free(a);		rerrstr(err, sizeof(err));		respond(r, err);	}else{		if(opts.asroot || findgroup(&a->p->groups, r->ifcall.uname, &a->uid) == nil)			a->uid = Root; 		incref(a->p);		a->type = Adir;		a->path = strdup("");		r->ofcall.qid = a->p->qidmask;		r->fid->qid = a->p->qidmask;		r->fid->aux = a;		respond(r, nil);	}} static u32inttoext4mode(u32int mode, u32int perm, int creat){	u32int e; 	e = 0;	mode &= ~OCEXEC; 	if(mode & OTRUNC)		e |= O_TRUNC; 	mode &= 3;	if(mode == OWRITE)		e |= O_WRONLY;	else if(mode == ORDWR)		e |= O_RDWR; 	if(creat)		e |= O_CREAT; 	if(perm & DMEXCL)		e |= O_EXCL;	if(perm & DMAPPEND)		e |= O_APPEND; 	return e;} static voidropen(Req *r){	char *path;	int res;	Aux *a; 	a = r->fid->aux;	switch(a->type){	case Adir:		if(r->ifcall.mode != OREAD || !haveperm(a, r->ifcall.mode, nil)){			respond(r, Eperm);			return;		}		if(a->dir != nil){			respond(r, "double open");			return;		}		if((a->dir = malloc(sizeof(*a->dir))) == nil)			goto Nomem;		if((path = smprint("%M/%s", a->p, a->path)) == nil){			free(a->dir);			a->dir = nil;			goto Nomem;		}		res = ext4_dir_open(a->dir, path);		free(path);		if(res != 0){			free(a->dir);			a->dir = nil;			respond(r, errno2s(res));			return;		}		break; 	case Afile:		if(!haveperm(a, r->ifcall.mode, nil)){			respond(r, Eperm);			return;		}		if(a->file != nil){			respond(r, "double open");			return;		}		if((a->file = malloc(sizeof(*a->file))) == nil)			goto Nomem;		if((path = smprint("%M/%s", a->p, a->path)) == nil){			free(a->file);			a->file = nil;			goto Nomem;		}		res = ext4_fopen2(a->file, path, toext4mode(r->ifcall.mode, 0, 0));		free(path);		if(res != 0){			free(a->file);			a->file = nil;			respond(r, errno2s(res));			return;		}		break; Nomem:		respond(r, "memory");		return;	} 	r->ofcall.iounit = 0; 	respond(r, nil);} static voidrcreate(Req *r){	u32int perm, dirperm, t;	struct ext4_inode inode;	char *s, *err, *q;	int mkdir, res;	long tm;	Aux *a; 	a = r->fid->aux;	err = nil;	s = nil; 	if(a->file != nil || a->dir != nil){		err = "double create";		goto error;	}	if(!haveperm(a, OWRITE, &inode)){		err = Eperm;		goto error;	} 	/* first make sure this is a directory */	t = ext4_inode_type(a->p->sb, &inode);	if(t != EXT4_INODE_MODE_DIRECTORY){		err = "create in non-directory";		goto error;	} 	if((s = fullpath(a)) == nil)		goto error;	ext4_mode_get(s, &dirperm); 	/* check if the entry already exists */	if((q = smprint("%s/%s", s, r->ifcall.name)) == nil){Nomem:		err = "memory";		goto error;	}	free(s);	s = q;	cleanname(s);	if(ext4_inode_exist(s, EXT4_DE_UNKNOWN) == 0){		err = "already exists";		goto error;	} 	mkdir = r->ifcall.perm & DMDIR;	perm = mkdir ? 0666 : 0777;	perm = r->ifcall.perm & (~perm | (dirperm & perm)); 	if(mkdir){		a->type = Adir;		if((res = ext4_dir_mk(s)) != 0)			goto ext4error;		if((a->dir = malloc(sizeof(*a->dir))) == nil)			goto Nomem;		if((res = ext4_dir_open(a->dir, s)) != 0){			free(a->dir);			a->dir = nil;			goto ext4errorrm;		}	}else{		a->type = Afile;		if((a->file = malloc(sizeof(*a->file))) == nil)			goto Nomem;		if((res = ext4_fopen2(a->file, s, toext4mode(r->ifcall.mode, perm, 1))) != 0){			free(a->file);			a->file = nil;			goto ext4error;		}	} 	if((res = ext4_mode_set(s, perm)) != 0)		goto ext4errorrm;	ext4_owner_set(s, a->uid, a->uid);	tm = time(nil);	ext4_mtime_set(s, tm);	ext4_ctime_set(s, tm); 	r->fid->qid.path = a->p->qidmask.path | a->file->inode;	r->fid->qid.vers = 0;	r->fid->qid.type = 0;	r->ofcall.qid = r->fid->qid; 	free(a->path);	a->path = strdup(strchr(s+1, '/')+1);	free(s);	r->ofcall.iounit = 0;	respond(r, nil);	return; ext4errorrm:	if(mkdir)		ext4_dir_rm(s);	else		ext4_fremove(s);ext4error:	err = errno2s(res);error:	free(s);	respond(r, err);} static intdirfill(Dir *dir, Aux *a, char *path){	struct ext4_inode inode;	u32int t, ino, id;	char tmp[16];	char *s, *q;	Group *g;	int r; 	memset(dir, 0, sizeof(*dir)); 	if(path == nil){		path = a->path;		s = smprint("%M/%s", a->p, a->path);	}else{		if(*a->path == 0 && *path == 0)			path = "/";		s = smprint("%M%s%s/%s", a->p, *a->path ? "/" : "", a->path, path);	}	if((s = linkresolve(a, s, nil)) == nil)		return -1;	if((r = ext4_raw_inode_fill(s, &ino, &inode)) != 0){		werrstr("inode: %s: %s", s, errno2s(r));		free(s);		return -1;	} 	t = ext4_inode_type(a->p->sb, &inode);	if(opts.linkmode == Lhide && t == EXT4_INODE_MODE_SOFTLINK){		free(s);		return -1;	} 	dir->mode = ext4_inode_get_mode(a->p->sb, &inode) & 0x1ff;	dir->qid.path = a->p->qidmask.path | ino;	dir->qid.vers = ext4_inode_get_generation(&inode);	dir->qid.type = 0;	if(t == EXT4_INODE_MODE_DIRECTORY){		dir->qid.type |= QTDIR;		dir->mode |= DMDIR;	}else		dir->length = ext4_inode_get_size(a->p->sb, &inode);	if(ext4_inode_get_flags(&inode) & EXT4_INODE_FLAG_APPEND){		dir->qid.type |= QTAPPEND;		dir->mode |= DMAPPEND;	} 	if((q = strrchr(path, '/')) != nil)		path = q+1;	dir->name = estrdup9p(path);	dir->atime = ext4_inode_get_access_time(&inode);	dir->mtime = ext4_inode_get_modif_time(&inode); 	sprint(tmp, "%ud", id = ext4_inode_get_uid(&inode));	dir->uid = estrdup9p((g = findgroupid(&a->p->groups, id)) != nil ? g->name : tmp); 	sprint(tmp, "%ud", id = ext4_inode_get_gid(&inode));	dir->gid = estrdup9p((g = findgroupid(&a->p->groups, id)) != nil ? g->name : tmp); 	free(s); 	return 0;} static intdirgen(int n, Dir *dir, void *aux){	const ext4_direntry *e;	Aux *a; 	a = aux;	if(n == 0 || n != a->doff){		ext4_dir_entry_rewind(a->dir);		a->doff = 0;	} 	for(;;){		do{			if((e = ext4_dir_entry_next(a->dir)) == nil)				return -1;		}while(e->name == nil || strcmp((char*)e->name, ".") == 0 || strcmp((char*)e->name, "..") == 0); 		if(opts.linkmode == Lhide && e->inode_type == EXT4_DE_SYMLINK)			continue; 		if(a->doff++ != n)			continue; 		if(dirfill(dir, a, (char*)e->name) == 0)			return 0; 		a->doff--;	}} static voidrread(Req *r){	usize n;	int res;	Aux *a; 	a = r->fid->aux;	if(a->type == Adir && a->dir != nil){		dirread9p(r, dirgen, a);	}else if(a->type == Afile && a->file != nil){		if(ext4_fseek(a->file, r->ifcall.offset, SEEK_SET) != 0)			n = 0;

Lines 1–500 of 1060.

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