login
Header Space

 
 

Linux: need of working and simple euidaccess() syscall

May 5, 2008 - 2:14pm
Submitted by olecom on May 5, 2008 - 2:14pm.
Linux

* another bug report (thread)
http://thread.gmane.org/gmane.comp.shells.dash/36/focus=37
* another nice conversation with kernel hackers
http://thread.gmane.org/gmane.linux.file-systems/23151/focus=23160

the most simple shell `test` tool fail, yet they discuss case-insensitive renames, oh gee. Code part is raceless stripped linux-2.6/fs/open.c:sys_faccessat():

asmlinkage long sys_feuidaccessat(int dfd, const char __user *filename, int mode)
{
        struct nameidata nd;
        int res;

        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;

        res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
        if (res)
                goto out;

        res = vfs_permission(&nd, mode);
        /* SuS v2 requires we report a read only fs too */
        if(res || !(mode & S_IWOTH) ||
           special_file(nd.dentry->d_inode->i_mode))
                goto out_path_release;

        if(IS_RDONLY(nd.dentry->d_inode))
                res = -EROFS;

out_path_release:
        path_release(&nd);
out:
        return res;
}

And if we excpect non-error part to be likely, and we don't generally like goto in basic stuff, and we don't want to use unlikely_buggy(optimizing) gcc:

asmlinkage long sys_feuidaccessat(int dfd, const char __user *filename, int mode)
{
        struct nameidata nd;
        int res;

        /* where's F_OK, X_OK, W_OK, R_OK? */
        if (!(mode & ~S_IRWXO)) {
                /* here */
                res = __user_walk_fd(dfd, filename,
                                     LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
                if (!res) {
                        res = vfs_permission(&nd, mode);
                        /* SuS v2 requires we report a read only fs too */
                        if (res || !(mode & S_IWOTH) ||
                            special_file(nd.dentry->d_inode->i_mode))
                        {} else if (IS_RDONLY(nd.dentry->d_inode))
                                res = -EROFS;
                        path_release(&nd);
                }
                return res;
        }
        return -EINVAL;
}

Simple, isn't it?
____

speck-geostationary