shithub: ext4srv

Download patch

ref: 55ae64148184b266f33fc4fcbc6e8a5d9914b5cf
parent: 6be4348c2f5cd7f3de417d56af3644bd9ce981ad
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sat Nov 14 11:08:48 EST 2020

support wstat, fix dirfill giving wrong mode

--- a/ext4srv.c
+++ b/ext4srv.c
@@ -280,6 +280,10 @@
 	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;
@@ -383,7 +387,7 @@
 		return -1;
 	}
 
-	dir->mode = ext4_inode_get_mode(a->p->sb, &inode);
+	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);
 	t = ext4_inode_type(a->p->sb, &inode);
@@ -554,7 +558,130 @@
 static void
 rwstat(Req *r)
 {
-	respond(r, "nope");
+	int res, isdir, wrperm, isowner;
+	char *old, *new, *err, *s;
+	struct ext4_inode inode;
+	u32int uid, gid;
+	ext4_file f;
+	Aux *a, o;
+	Group *g;
+
+	a = r->fid->aux;
+	old = nil;
+	new = nil;
+	err = nil;
+
+	/* can't do anything to root, can't change the owner */
+	if(a->path[0] == 0 || (r->d.uid != nil && r->d.uid[0] != 0)){
+		err = Eperm;
+		goto error;
+	}
+
+	if((old = smprint("%M/%s", a->p, a->path)) == nil){
+		err = "memory";
+		goto error;
+	}
+	new = old;
+
+	wrperm = haveperm(a, OWRITE, &inode);
+	uid = ext4_inode_get_uid(&inode);
+	isowner = a->uid == Root || a->uid == uid;
+
+	/* permission to truncate */
+	isdir = ext4_inode_type(a->p->sb, &inode) & EXT4_INODE_MODE_DIRECTORY;
+	if(r->d.length >= 0 && (!wrperm || isdir || !ext4_inode_can_truncate(a->p->sb, &inode))){
+		err = Eperm;
+		goto error;
+	}
+
+	/* permission to rename */
+	if(r->d.name != nil && r->d.name[0] != 0){
+		if((s = strrchr(old, '/')) != nil)
+			*s = 0;
+		if((new = smprint("%M/%s%s%s", a->p, s ? old : "", s ? "/" : "", r->d.name)) == nil){
+			err = "memory";
+			goto error;
+		}
+
+		/* check parent write permission */
+		o = *a;
+		o.path = old;
+		if(!haveperm(&o, OWRITE, nil)){
+			err = Eperm;
+			goto error;
+		}
+		*s = '/';
+	}
+
+	/* permission to change mode */
+	if(r->d.mode != ~0){
+		/* has to be owner and can't change dir bit */
+		if(!isowner || (!!isdir != !!(r->d.mode & DMDIR))){
+			err = Eperm;
+			goto error;
+		}
+	}
+
+	/* permission to change mtime */
+	if(r->d.mtime != ~0 && !isowner){
+		err = Eperm;
+		goto error;
+	}
+
+	/* permission to change gid */
+	if(r->d.gid != nil && r->d.gid[0] != 0){
+		/* has to be the owner, group has to exist, must be in that group */
+		if(a->uid == Root || (!isowner || (g = findgroup(&a->p->groups, r->d.gid, &gid)) == nil || !ingroup(g, a->uid))){
+			err = Eperm;
+			goto error;
+		}
+	}
+
+	/* done checking permissions, now apply all the changes and hope it all works */
+
+	/* rename */
+	if(r->d.name != nil && r->d.name[0] != 0){
+		if((res = ext4_frename(old, new)) != 0)
+			goto ext4error;
+
+		free(old);
+		old = new;
+		new = nil;
+
+		free(a->path);
+		a->path = strdup(strchr(old+1, '/')+1);
+	}
+
+	/* truncate */
+	if(r->d.length >= 0){
+		if((res = ext4_fopen2(&f, new, toext4mode(OWRITE, 0, 0))) != 0 ||
+		   (res = ext4_ftruncate(&f, r->d.length)) != 0){
+			goto ext4error;
+		}
+		ext4_fclose(&f);
+	}
+
+	/* mode */
+	if(r->d.mode != ~0 && (res = ext4_mode_set(new, r->d.mode & 0x1ff)) != 0)
+		goto ext4error;
+
+	/* mtime */
+	if(r->d.mtime != ~0 && (res = ext4_mtime_set(new, r->d.mtime)) != 0)
+		goto ext4error;
+
+	/* gid */
+	if(r->d.gid != nil && r->d.gid[0] != 0 && (res = ext4_owner_set(new, uid, gid)) != 0)
+		goto ext4error;
+
+	goto error; /* not really an error */
+
+ext4error:
+	err = errno2s(res);
+error:
+	free(old);
+	if(new != old)
+		free(new);
+	respond(r, err);
 }
 
 static char *