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()
。
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");
}
}
構造体の定義はfuse_operations
ここにあります。
これは、次を使用してコンパイルできます。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
私の質問は、これら 2 つのプログラム (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
は変更されていないことを示します。つまり、まだ 777 ディレクトリです。
また、すべての s をs ではなくs としてFuseTemp.java
含めるように書き直しました。ただし、動作は同じです。Callback
Callback
Pointer
ヒューズのソース コードを調べたところ、実行中の複数の時点でエラー コード 1 が返される可能性があります。ヒューズ側のどこが故障しているかを正確に特定し、ここに報告します。
現在、hello.c
通常のユーザーとして実行し、同じ権限で開始し、引数と/some/mount/point
を渡すと、プログラムは最初は出力を出力しませんが、実行を続けます。マウントポイントで実行すると、プログラムは出力します-f
/some/mount/point
stat
getattr was called
あるべきように。stat
はエラーを返しますが、それは単にhello.c
のgetattr
関数が情報を提供しないためであり、問題はありません。通常のユーザーとして実行した後fusermount -u /some/mount/point
、プログラムはリターン コード 0 で終了し、アンマウントは成功します。
root として実行し、同じパーミッション on から開始して引数and/some/mount/point
を渡すと、プログラムは最初は出力を出力しませんが、実行を続けます。マウントポイントで実行すると、root ではないため、権限エラーが発生します。ルートとして実行すると、プログラムは出力します-f
/some/mount/point
stat
stat
getattr was called
あるべきように。fusermount -u /some/mount/point
通常のユーザーとして実行する
fusermount: entry for /some/mount/point not found in /etc/mtab
root として実行fusermount
すると、プログラムはリターン コード 0 で終了し、アンマウントは成功します。