libc: simplify access; libposix: let access lie
There are a few issues with Plan 9's `access`: - it has side effects: to test the actual access (that the file servers can allow or deny according to complex custom rules) it opens and then closes the file, allocating (and disposing) the fd - it does not work on directories, since - they cannot be opened for writing, despite the fact that to create a file in a directory you must be granted write access on that directory - they cannot be opened for execution, despite the fact that to access a file in a directory you must be granted execution access on that directory Despite the fact that `access` (even on UNIX) is a violation of the "tell, don't ask" principle (the access could be forbidden just after its successful return, making subsequent `open` fail anyway), this fact smells of a little design error in the file interface. So, right now we choose to let the libposix's `access` lie on directories: it will always return 0 on AWRITE and AEXEC for them, accepting that a successive create/mkdir may fail. However, a cleaner file API and protocol should allow a simpler `access` to be implemented for directories too.
This commit is contained in:
parent
1aaf8d3703
commit
713eb8843f
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
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)
|
||||
fd = open(name, reqmode);
|
||||
if(fd >= 0){
|
||||
close(fd);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue