我正在尝试使用JNA创建与 FUSE 库的绑定,但我在路上遇到了障碍。我已经尽可能地最小化了代码,以便在这里可以消化。
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
标志是让它留在前台,这样你就可以看到' printf()
s 的工作。
所有这些都运行良好,您可以看到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");
}
}
这可以使用以下方法编译:javac -cp path/to/jna.jar FuseTemp.java
并使用java -cp path/to/jna.jar:. FuseTemp
出现的错误是:fusermount: failed to access mountpoint /some/mount/point: Permission denied
。
我在同一个挂载点文件夹上以具有相同权限的同一个用户身份执行这两个程序,并且我在该fuse
组中。我在用:
- Linux 内核 3.0.0
- 保险丝 2.8.4
- OpenJDK 1.6.0_23
- JNA 3.4.0
所以我的问题是:这两个程序(hello.c
和FuseTemp.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
显示is没有被修改,即仍然是777目录。
我还重写FuseTemp.java
了将所有Callback
s 包含为Callback
s 而不是Pointer
s。但是,行为是相同的。
我查看了 fuse 的源代码,错误代码 1 可以在整个执行过程中的多个点返回。我将查明保险丝端究竟在哪里发生故障并在这里报告。
现在对于hello.c
: 以普通用户身份运行它,从相同的权限开始/some/mount/point
并传递参数-f
and /some/mount/point
,程序一开始不会打印任何输出,但会继续运行。在挂载点上运行stat
时,程序会打印
getattr was called
应该的。stat
返回一个错误,但这仅仅是因为hello.c
'getattr
函数没有给它任何信息,所以那里没有问题。以普通用户身份执行后fusermount -u /some/mount/point
,程序以返回码 0 退出,卸载成功。
以 root 身份运行它,以相同的权限开始/some/mount/point
并传递参数-f
and /some/mount/point
,程序一开始不会打印任何输出,但会继续运行。在挂载点上运行stat
时,我收到权限错误,因为我不是 root。当stat
以 root 身份运行时,程序会打印
getattr was called
应该的。以普通用户身份执行fusermount -u /some/mount/point
产生
fusermount: entry for /some/mount/point not found in /etc/mtab
以root身份执行fusermount
,程序退出,返回码0,卸载成功。