SerCeMan / jnr-fuse

FUSE implementation in Java using Java Native Runtime (JNR)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

I can't get getxattr() working

nixn opened this issue · comments

commented

I'm developing a filesystem with jnr-fuse, which in one part should return user extended attributes with getxattr(). But I can't get it working and don't understand the problem.

This is the relevant code in my project:

class FuseImpl extends FuseStubFS
{
    private static final XATTR_USER_PREFIX = "user.";

    @Override
    public int getxattr(String path, String name, Pointer value, long size)
    {
        // check for existence of node
        Path sourcePath = basePath.resolve(path);
        if (!Files.exists(sourcePath))
            return -ErrorCodes.ENOENT();
        // check requested attribute name
        if (!name.startsWith(XATTR_USER_PREFIX))
            return -ErrorCodes.EINVAL();
        name = name.substring(XATTR_USER_PREFIX.length());
        // get user attributes of node
        UserDefinedFileAttributeView userView = Files.getFileAttributeView(sourcePath, UserDefinedFileAttributeView.class, LinkOption.NO_FOLLOW_LINKS);
        if (userView == null)
            return -ErrorCodes.EIO();
        if (!userView.list().contains(name))
            return -ErrorCodes.EINVAL();
        // requested attribute is present on file => read and return
        int attrSize = userView.size(name);
        if (size == 0) // case (1)
            return attrSize;
        else if (size < attrSize) // case (2)
            return -ErrorCodes.ERANGE();
        // case (3)
        ByteBuffer buf = ByteBuffer.allocate(attrSize);
        userView.read(name, buf);
        value.put(0, buf.array(), 0, attrSize);
        return 0; // success
    }
}

While the FS is running (mounted on /tmp/mnt), I give the following command in a shell:
getfattr -n user.myattr /tmp/mnt/test-file
This calls getxattr() twice, first time with size==0 and value==null, which activates case (1), second time with size==256 and value!=null (some real memory pointer), which activates case (3). The user attribute value (attrSize==51) is copied successfully to the Pointer value, I checked it with debugger (and debug output) multiple times. But the command result in the shell gives:

$ getfattr -n user.myattr /tmp/mnt/test-file
getfattr: Removing leading '/' from absolute path names
# file: tmp/mnt/test-file
user.myattr=""

When calling getfattr on the original file without the FuseFS in between, it works:

$ getfattr -n user.myattr /path/to/test-file
getfattr: Removing leading '/' from absolute path names
# file: path/to/test-file
user.myattr="1055792 1552639092 a4031ed34d3544daa73a1e41dcaef2e8"

The value seems to be not propagated properly, I don't know why. The only thing I found are the instructions in the libfuse documentation which state that the reply must be done with fuse_reply_xattr for case (1) and fuse_reply_buf for case (3).

Unfortunately none of the example projects or the referenced projects which use jnr-fuse are implementing xattrs.

commented

Seems like a simple return attrSize; at the end fixed the problem. Will test further.