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";
|
err = "/tmp does not exists";
|
||||||
else if(access("/tmp", AREAD) != 0)
|
else if(access("/tmp", AREAD) != 0)
|
||||||
err = "/tmp is not readable";
|
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)
|
else if(access("/tmp", AWRITE) != 0)
|
||||||
err = "/tmp is not writeable";
|
err = "/tmp is not writeable";
|
||||||
else if(access("/tmp", AEXEC) != 0)
|
else if(access("/tmp", AEXEC) != 0)
|
||||||
err = "/tmp is not traversable";
|
err = "/tmp is not traversable";
|
||||||
|
*/
|
||||||
if(err == nil){
|
if(err == nil){
|
||||||
print("PASS\n");
|
print("PASS\n");
|
||||||
exits("PASS");
|
exits("PASS");
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
int
|
int
|
||||||
jehanne_access(const char *name, int mode)
|
jehanne_access(const char *name, int mode)
|
||||||
{
|
{
|
||||||
int tmp, reqmode;
|
int fd, reqmode;
|
||||||
Dir *db;
|
|
||||||
char *user;
|
|
||||||
|
|
||||||
static char omode[] = {
|
static char omode[] = {
|
||||||
OSTAT,
|
OSTAT,
|
||||||
|
@ -38,35 +36,25 @@ jehanne_access(const char *name, int mode)
|
||||||
};
|
};
|
||||||
|
|
||||||
reqmode = omode[mode&AMASK];
|
reqmode = omode[mode&AMASK];
|
||||||
tmp = open(name, reqmode);
|
fd = open(name, reqmode);
|
||||||
if(tmp >= 0){
|
if(fd >= 0){
|
||||||
close(tmp);
|
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;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,25 +119,36 @@ find_seek_type(int whence)
|
||||||
int
|
int
|
||||||
POSIX_access(int *errnop, const char *path, int amode)
|
POSIX_access(int *errnop, const char *path, int amode)
|
||||||
{
|
{
|
||||||
|
Dir *d;
|
||||||
PosixError e = 0;
|
PosixError e = 0;
|
||||||
|
|
||||||
|
d = dirstat(path);
|
||||||
if(path == nil || path[0] == '\0'){
|
if(path == nil || path[0] == '\0'){
|
||||||
e = PosixENOENT;
|
e = PosixENOENT;
|
||||||
} else if(amode == __libposix_F_OK){
|
} else if(d == nil){
|
||||||
if(access(path, AEXIST) == 0)
|
|
||||||
return 0;
|
|
||||||
e = PosixENOENT;
|
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;
|
e = PosixEINVAL;
|
||||||
else if((amode & __libposix_R_OK) && access(path, AREAD) != 0)
|
} else if((amode & __libposix_R_OK) && access(path, AREAD) != 0){
|
||||||
e = PosixEACCES;
|
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;
|
e = PosixEACCES;
|
||||||
else if((amode & __libposix_X_OK) && access(path, AEXEC) != 0)
|
} else if((amode & __libposix_X_OK) && access(path, AEXEC) != 0){
|
||||||
e = PosixEACCES;
|
e = PosixEACCES;
|
||||||
else
|
}else{
|
||||||
|
AccessDone:
|
||||||
|
free(d);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(d);
|
||||||
*errnop = __libposix_get_errno(e);
|
*errnop = __libposix_get_errno(e);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue