diff --git a/qa/lib/c/access.c b/qa/lib/c/access.c index bec8557..3965bc3 100644 --- a/qa/lib/c/access.c +++ b/qa/lib/c/access.c @@ -26,10 +26,15 @@ main(void) err = "/tmp does not exists"; else if(access("/tmp", AREAD) != 0) err = "/tmp is not readable"; +/* NOTE: + * In Plan 9 access(AWRITE) and access(AEXEC) in directories + * fail despite the actual permission of the directory. + * else if(access("/tmp", AWRITE) != 0) err = "/tmp is not writeable"; else if(access("/tmp", AEXEC) != 0) err = "/tmp is not traversable"; +*/ if(err == nil){ print("PASS\n"); exits("PASS"); diff --git a/sys/src/lib/c/9sys/access.c b/sys/src/lib/c/9sys/access.c index b27e574..d71f476 100644 --- a/sys/src/lib/c/9sys/access.c +++ b/sys/src/lib/c/9sys/access.c @@ -22,9 +22,7 @@ int jehanne_access(const char *name, int mode) { - int tmp, reqmode; - Dir *db; - char *user; + int fd, reqmode; static char omode[] = { OSTAT, @@ -38,35 +36,25 @@ jehanne_access(const char *name, int mode) }; reqmode = omode[mode&AMASK]; - tmp = open(name, reqmode); - if(tmp >= 0){ - close(tmp); + fd = open(name, reqmode); + if(fd >= 0){ + close(fd); return 0; } - db = jehanne_dirstat(name); - if(db != nil){ - if(db->mode & DMDIR){ - /* check other first */ - tmp = db->mode & reqmode; - if(tmp != reqmode){ - /* TODO: make something better */ - user = jehanne_getuser(); - if(jehanne_strcmp(user, db->gid) == 0){ - /* check group */ - tmp |= (db->mode & (reqmode << 3)) >> 3; - if(tmp != reqmode && jehanne_strcmp(user, db->uid)== 0){ - /* check user */ - tmp |= (db->mode & (reqmode << 6)) >> 6; - } - } else if (jehanne_strcmp(user, db->uid)== 0){ - /* check user */ - tmp |= (db->mode & (reqmode << 6)) >> 6; - } - } - } - jehanne_free(db); - if(tmp == reqmode) - return 0; - } + + /* WARNING: + * + * In Plan 9 access(AWRITE) and access(AEXEC) in directories + * fail despite the actual permission of the directory. + * + * This is well understood in Plan 9, but it's counter intuitive. + * + * In Plan 9, to create a file in a directory you need write + * permission in the directory. Still you don't need to (and you + * cannot) open the directory for writing before calling create. + * + * To my eyes this is a UNIX inheritance that could be "fixed" + * but there are some trade off. + */ return -1; } diff --git a/sys/src/lib/posix/files.c b/sys/src/lib/posix/files.c index 9afab27..c2bdf6f 100644 --- a/sys/src/lib/posix/files.c +++ b/sys/src/lib/posix/files.c @@ -119,25 +119,36 @@ find_seek_type(int whence) int POSIX_access(int *errnop, const char *path, int amode) { + Dir *d; PosixError e = 0; + d = dirstat(path); if(path == nil || path[0] == '\0'){ e = PosixENOENT; - } else if(amode == __libposix_F_OK){ - if(access(path, AEXIST) == 0) - return 0; + } else if(d == nil){ e = PosixENOENT; - } else if(amode & ~(__libposix_R_OK|__libposix_W_OK|__libposix_X_OK)) + } else if(amode == __libposix_F_OK){ + goto AccessDone; + } else if(amode & ~(__libposix_R_OK|__libposix_W_OK|__libposix_X_OK)){ e = PosixEINVAL; - else if((amode & __libposix_R_OK) && access(path, AREAD) != 0) + } else if((amode & __libposix_R_OK) && access(path, AREAD) != 0){ e = PosixEACCES; - else if((amode & __libposix_W_OK) && access(path, AWRITE) != 0) + } else if((d->mode & DMDIR) != 0){ + /* we lie, but on Plan 9 access(AWRITE) and access(AEXEC) + * will always fail on directories. + */ + goto AccessDone; + } else if((amode & __libposix_W_OK) && access(path, AWRITE) != 0){ e = PosixEACCES; - else if((amode & __libposix_X_OK) && access(path, AEXEC) != 0) + } else if((amode & __libposix_X_OK) && access(path, AEXEC) != 0){ e = PosixEACCES; - else + }else{ +AccessDone: + free(d); return 0; + } + free(d); *errnop = __libposix_get_errno(e); return -1; }