gpt4 book ai didi

java - 在 Java 中使用 FUSE 库;尝试复制 hello.c 示例

转载 作者:搜寻专家 更新时间:2023-10-30 21:30:06 25 4
gpt4 key购买 nike

我正在尝试使用 JNA 创建到 FUSE 库的绑定(bind),但我在路上遇到了障碍。我尽可能地最小化了代码,以使其在此处易于理解。

FUSE 库附带了一些用 C 编写的示例文件系统。其中最简单的是 hello.c .以下是其代码的最小化版本,只是文件系统函数中的一些打印:
hello.c :

/*
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 -o hello `pkg-config fuse --cflags --libs`
*/
#define FUSE_USE_VERSION 26

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

static int hello_getattr(const char *path, struct stat *stbuf)
{
printf("getattr was called\n");
return 0;
}

static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
printf("readdir was called\n");
return 0;
}

static int hello_open(const char *path, struct fuse_file_info *fi)
{
printf("open was called\n");
return 0;
}

static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
printf("read was called\n");
return 0;
}

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

int main(int argc, char *argv[])
{
return fuse_main_real(argc, argv, &hello_oper, sizeof(hello_oper), NULL);
}

这可以使用 gcc -Wall hello.c -o hello -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -pthread -lfuse -lrt -ldl 编译

并用 ./hello.c -f /some/mount/point 调用
-f flag 是让它保持在前景,这样你就可以看到 printf()正在工作。

所有这些都运行良好,您可以看到 printf()正在正确执行。我正在尝试使用 JNA 在 Java 中复制相同的内容。这是我想出的:
FuseTemp.java :
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;

public class FuseTemp
{
public static interface Fuse extends Library
{
int fuse_main_real(int argc, String[] argv, StructFuseOperations op, long size, Pointer user_data);
}

@SuppressWarnings("unused")
public static class StructFuseOperations extends Structure
{
public static class ByReference extends StructFuseOperations implements Structure.ByReference
{
}

public Callback getattr = new Callback()
{
public int callback(final String path, final Pointer stat)
{
System.out.println("getattr was called");
return 0;
}
};
public Callback readlink = null;
public Callback mknod = null;
public Callback mkdir = null;
public Callback unlink = null;
public Callback rmdir = null;
public Callback symlink = null;
public Callback rename = null;
public Callback link = null;
public Callback chmod = null;
public Callback chown = null;
public Callback truncate = null;
public Callback utime = null;
public Callback open = new Callback()
{
public int callback(final String path, final Pointer info)
{
System.out.println("open was called");
return 0;
}
};
public Callback read = new Callback()
{
public int callback(final String path, final Pointer buffer, final long size, final long offset, final Pointer fi)
{
System.out.println("read was called");
return 0;
}
};
public Callback write = null;
public Callback statfs = null;
public Callback flush = null;
public Callback release = null;
public Callback fsync = null;
public Callback setxattr = null;
public Callback getxattr = null;
public Callback listxattr = null;
public Callback removexattr = null;
public Callback opendir = null;
public Callback readdir = new Callback()
{
public int callback(final String path, final Pointer buffer, final Pointer filler, final long offset,
final Pointer fi)
{
System.out.println("readdir was called");
return 0;
}
};
public Callback releasedir = null;
public Callback fsyncdir = null;
public Callback init = null;
public Callback destroy = null;
public Callback access = null;
public Callback create = null;
public Callback ftruncate = null;
public Callback fgetattr = null;
public Callback lock = null;
public Callback utimens = null;
public Callback bmap = null;
public int flag_nullpath_ok;
public int flag_reserved;
public Callback ioctl = null;
public Callback poll = null;
}

public static void main(final String[] args)
{
final String[] actualArgs = { "-f", "/some/mount/point" };
final Fuse fuse = (Fuse) Native.loadLibrary("fuse", Fuse.class);
final StructFuseOperations.ByReference operations = new StructFuseOperations.ByReference();
System.out.println("Mounting");
final int result = fuse.fuse_main_real(actualArgs.length, actualArgs, operations, operations.size(), null);
System.out.println("Result: " + result);
System.out.println("Mounted");
}
}

The definition of the the fuse_operations struct can be found here .

这可以使用以下方式编译: javac -cp path/to/jna.jar FuseTemp.java
并使用 java -cp path/to/jna.jar:. FuseTemp 调用

jna.jar is available here .

出现的错误是: fusermount: failed to access mountpoint /some/mount/point: Permission denied .

我正在以对同一个挂载点文件夹具有相同权限的同一用户身份执行这两个程序,并且我在 fuse 中团体。我在用:
  • Linux 内核 3.0.0
  • fuse 2.8.4
  • OpenJDK 1.6.0_23
  • JNA 3.4.0

  • 所以我的问题是:这两个程序( hello.cFuseTemp.java )之间到底有什么不同,以及如何让它们做同样的事情?

    提前致谢。

    编辑 : 这是一些额外的信息。

    初始 stat挂载点:
      File: `/some/mount/point'
    Size: 4096 Blocks: 8 IO Block: 4096 directory
    Device: 803h/2051d Inode: 540652 Links: 2
    Access: (0777/drwxrwxrwx) Uid: ( 1000/ myusername) Gid: ( 1000/ myusername)

    我以普通用户身份运行 Java 程序得到的输出:
    Mounting
    fusermount: failed to access mountpoint /some/mount/point: Permission denied
    Result: 1
    Mounted
    (program exits with return code 0)

    在此之后,尝试执行 stat给出以下错误消息:
    stat: cannot stat/some/mount/point': 传输端点未连接`

    那是因为 Java 程序不再运行,所以 fuse 无法调用其回调。要卸载,如果我尝试 fusermount -u /some/mount/point ,我得到:
    fusermount: entry for /some/mountpoint not found in /etc/mtab

    如果我尝试 sudo fusermount -u /some/mount/point ,挂载点成功卸载, fusermount没有输出. /etc/mtab是 chmod'd 644 ( -rw-r--r-- ) 所以我的用户可以阅读它,但它不包含 /some/mount/point .成功卸载后,挂载点将恢复到其旧权限(777 目录)。

    现在,以 root 身份运行 java 程序:
    Mounting
    Result: 1
    Mounted
    (program exits with return code 0)

    之后, stat ing /some/mount/point显示它没有被修改,即它仍然是一个 777 目录。

    我也重写了 FuseTemp.java包括所有 Callback s 为 Callback s 而不是 Pointer s。但是,行为是相同的。

    我查看了 fuse 的源代码,在整个执行过程中可以在多个点返回错误代码 1。我将查明 fuse 侧究竟是哪里出现故障并在这里报告。

    现在为 hello.c : 以普通用户身份运行它,从 /some/mount/point 上以相同的权限开始并将参数传递给它 -f/some/mount/point ,程序一开始不打印任何输出,但会继续运行。运行时 stat在挂载点,程序打印
    getattr was called

    应该喜欢。 stat返回错误,但这仅仅是因为 hello.cgetattr function 没有给它任何信息,所以那里没有问题。执行后 fusermount -u /some/mount/point作为普通用户,程序退出并返回代码 0,卸载成功。

    以 root 身份运行它,在 /some/mount/point 上以相同的权限开始并将参数传递给它 -f/some/mount/point ,程序一开始不打印任何输出,但会继续运行。运行时 stat在挂载点上,我收到一个权限错误,因为我不是 root。运行时 stat以 root 身份在它上面,程序打印
    getattr was called

    应该喜欢。正在执行 fusermount -u /some/mount/point作为普通用户 yield
    fusermount: entry for /some/mount/point not found in /etc/mtab

    正在执行 fusermount作为 root,程序退出并返回代码 0,卸载成功。

    最佳答案

    找到了。虽然回想起来这个错误真的很愚蠢,但并不容易发现。

    解决方案 : fuse fuse_main_real方法的第一个参数是一个参数列表。在这个列表中,它期望参数 0 是文件系统名称,或者一些有意义的程序名称。因此,而不是

    final String[] actualArgs = { "-f", "/some/mount/point" };

    应该是
    final String[] actualArgs = { "programName", "-f", "/some/mount/point" };

    这也意味着你不能在你的 main 中使用 Java 给你的参数列表。方法,因为它也不包含程序名称。

    为什么重要 :fuse 实际上会自己解析参数并调用 /bin/mount将以下参数传递给它:
    --no-canonicalize -i -f -t fuse.(arg 0) -o (options) (mountpoints) ...

    因此,如果您提供 if -f /some/mount/point作为参数列表,fuse 将尝试运行:
    /bin/mount --no-canonicalize -i -f -t fuse.-f -o rw,nosuid,nodev /some/mount/point

    mount不喜欢“ fuse.-f”并且会提示。

    它是如何被发现的 : 加一堆 printf()在 fuse 的源代码中找出问题的确切位置:在 /lib/mount_util.c在第 82 行:
    execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
    "-f", "-t", type, "-o", opts, fsname, mnt, NULL);

    我很抱歉假设错误是由于它与 Java 相关或 JNA 相关或权限相关。我将编辑问题标题和标签以反射(reflect)这一点。 (在我的辩护中,错误 fuse 正在返回(“权限被拒绝”)当然没有帮助!)

    谢谢你的帮助ee。和技术,我再次为因为一个愚蠢的错误而占用你大量时间而道歉。

    关于java - 在 Java 中使用 FUSE 库;尝试复制 hello.c 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8872821/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com