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 *