macos-fuse-t / fuse-t

Other
920 stars 7 forks source link

`getxattr` does not work if `listxattr` is not implemented #62

Closed vvolkl closed 3 months ago

vvolkl commented 3 months ago

Hi!

As stated in the title, this works fine for both libfuse on linux and OSXFuse, but not with fuse-t - I think it's a bug, as it's not necessary to have to list an xattr in order to get it, and applications may want to hide xattrs in the listing for various reasons.

Possibly also related to #57

Tested with fuse-t 1.038 on an m1 mini, macos v 12.4

Below is a simple reproducer, extended from the libfuse2 hello world example. Expected behavior (seen with libfuse and OSXFuse):

./hello /Users/Shared/cvmfs/test/
xattr -p abc /Users/Shared/cvmfs/test/hello
abcd

With fuse-t:

./hello /Users/Shared/cvmfs/test/
xattr -p abc /Users/Shared/cvmfs/test/hello
xattr: /Users/Shared/cvmfs/test/hello: No such xattr: abc
/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.

  gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello
*/

#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";

static int hello_getattr(const char *path, struct stat *stbuf)
{
        int res = 0;

        memset(stbuf, 0, sizeof(struct stat));
        if (strcmp(path, "/") == 0) {
                stbuf->st_mode = S_IFDIR | 0755;
                stbuf->st_nlink = 2;
        } else if (strcmp(path, hello_path) == 0) {
                stbuf->st_mode = S_IFREG | 0444;
                stbuf->st_nlink = 1;
                stbuf->st_size = strlen(hello_str);
        } else
                res = -ENOENT;

        return res;
}

static int hello_getxattr(const char *path, const char *name, char* value, size_t size, uint32_t position) {
 if (size == 0) {
   return 4;
 }
  char source[] = "abcd";
 strcpy(value, source);
 return 4;
}

static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                         off_t offset, struct fuse_file_info *fi)
{
        (void) offset;
        (void) fi;

        if (strcmp(path, "/") != 0)
                return -ENOENT;

        filler(buf, ".", NULL, 0);
        filler(buf, "..", NULL, 0);
        filler(buf, hello_path + 1, NULL, 0);

        return 0;
}

static int hello_open(const char *path, struct fuse_file_info *fi)
{
        if (strcmp(path, hello_path) != 0)
                return -ENOENT;

        if ((fi->flags & 3) != O_RDONLY)
                return -EACCES;

        return 0;
}

static int hello_read(const char *path, char *buf, size_t size, off_t offset,
                      struct fuse_file_info *fi)
{
        size_t len;
        (void) fi;
        if(strcmp(path, hello_path) != 0)
                return -ENOENT;

        len = strlen(hello_str);
        if (offset < len) {
                if (offset + size > len)
                        size = len - offset;
                memcpy(buf, hello_str + offset, size);
        } else
                size = 0;

        return size;
}

static struct fuse_operations hello_oper = {
        .getattr        = hello_getattr,
        .getxattr       = hello_getxattr,
        .readdir        = hello_readdir,
        .open           = hello_open,
        .read           = hello_read,
};

int main(int argc, char *argv[])
{
        return fuse_main(argc, argv, &hello_oper, NULL);
}
macos-fuse-t commented 3 months ago

What you're saying is correct in theory but in practice both NFS and SMB macOS clients would perform listxattr operation prior to getxattr therefore due to this limitation you'll have to implement the listxattr operation as well.

vvolkl commented 3 months ago

Fair enough. If that's a NFS limitation it'll indeed be hard to fix. I'd suggest updating the Readme though and adding this to "Possible Issues", or to the Unsupported Features page on the wiki.