Ummm... no, not a bug.

Moreover, it's not just with "defer_permissions" that you should see
expected behavior. You should also see it with "default_permissions".
You should also see expected behavior if you *do NOT* implement the
access() method in your user-space file system.

As for how this works as you expect on Linux, well, as I keep saying:

1. Mac OS X != Linux
2. Mac VFS != Linux VFS
3. MacFUSE != Linux FUSE

The issue is with involving access(2), which returns ELOOP when used
on a self referencing symbolic link, even for F_OK.

The Mac OS X VFS has more knobs than Linux in terms of involving a
file system in decision making. MacFUSE exposes several of these knobs
to user space. Now, if a user-space file system implements the
access() method, MacFUSE will plumb things such that the vnode-level
access() call will result in calls to your file system's access(). In
your example, when you want to unlink(2), the VFS wants to authorize
that action, which eventually results in a call to your file system's
access(), which in turn (I assume) uses access(2), and gets the ELOOP
error.

Why doesn't it happen with HFS+? Because HFS+ doesn't implement its
own vnode-level access()--it relies on the kernel to make such
decisions. This is fine because the user/group/permission information
returned by HFS+ is "reliable".

Why doesn't it happen with sshfs? Because sshfs doesn't implement an
access() method.

Why does it happen with fusexmp_fh on Mac OS X? Because fusexmp_fh's
access() uses access(2) and simply returns the result. If you see the
implementation of xmp_access() in MacFUSE code (fusexmp_fh.c), I
special case ENOENT for the case of a symlink pointing to a
nonexistent target. I can similarly special case for ELOOP, and then
fusexmp_fh should work too.

Why doesn't it happen with defer_permissions or default_permissions?
Because these options configure MacFUSE to not involve the user-space
file system's access() method. default_permissions is very much like
the HFS+ case.

The bottom line is: if your user-space file system provides an
access() method, it means it doesn't trust the kernel to make
authorization decisions based on file metadata (user/group/permissions
etc.)--it wants to be involved in such decisions. The onus is then
upon you to handle the ELOOP case for F_OK (I think special casing it
in the kernel is ugly and unnecessary.)

Why doesn't it happen on Linux? Because the unlink(2) code path on
Linux doesn't have a precursor call to access().

Try something like the following in your access() implementation (not
perfect--tweak to taste):

static int
whatever_access(const char *path, int mask)
{
    int res;

    res = access(path, mask);
    if (res == -1) {
#if (__FreeBSD__ >= 10)
        if ((errno == ENOENT) || (error == ELOOP)) {
            int next_res;
            int saved_error = error;
            struct stat sb;
            next_res = lstat(path, &sb);
            if (next_res == 0 && S_ISLNK(sb.st_mode) &&
                ((sb.st_uid == getuid()) || (geteuid() == 0))) {
                /*
                 * The target of the symlink doesn't exist, but the
                 * symlink itself does. Or it points to itself.
                 *
                 * A lame cheap fix here.
                 */
                return 0;
            }
            return -saved_error;
        }
#endif
        return -errno;
    }  /* if (res == -1) */

    return 0;
}

Amit


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"macfuse-devel" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/macfuse-devel?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to