我的问题的一些快速背景:
我正在编写一个编译器,将域类型强制规范转换为Java安全管理器代码。简而言之,DTE定义"类型"(对象),为这些类型分配路径;然后定义"域"(subject),并定义域对各种类型的权限(rwxdc)。我需要在JSM中尽可能地模仿这种行为。
目前我正在研究写权限。我已经成功地重写了JSM的checkWrite(字符串文件名)方法。列表中的下一个是checkWrite(FileDescriptor文件描述符),而这一个更为棘手。由于定义DTE的方式,我需要路径信息来确定是否允许写入操作。
-
是否可以从FileDescriptor中提取路径数据?我猜不会——我已经查看了文档和各种教程,没有发现任何迹象表明我有任何方法可以获得这些信息(不过,我很高兴被证明是错误的;这会让我的工作更容易)。
-
如果上面的答案是否定的,有人能提出一个可行的解决方案吗?例如,有没有什么方法可以让我编写本机代码来做我想做的事情,并将其绑定到我的自定义JSM类中?我可以做那种"高级"的事情,但我需要一些如何开始的想法。
-
或者我的唯一选项基本上是拒绝使用FileDescriptor的所有写入权限?我很想避免这种情况,因为这是一个糟糕的解决方案,但如果这是现实,我需要知道。
非常感谢您抽出时间。
简短的回答是否定的,因为文件独立于用于访问该文件的路径(至少在任何重要的操作系统上)。
一种可能的解决方案是使用方面框架捕获打开文件的调用,并将引用的文件描述符放入WeakHashMap<FileDescriptor,File>
中。然后,只要您需要验证写入,就可以简单地查看此映射。
希望不会被反射限制阻止,但现在你可以使用这个(代码基于另一个答案),从Android O:开始
val file = File(filesDir, "ff")
file.parentFile!!.mkdirs()
val fileOutputStream = FileOutputStream(file)
val fd = fileOutputStream.fd
val method = fd.javaClass.getMethod("getInt$")
val fdId = method.invoke(fd)
val path = Paths.get("/proc/self/fd/$fdId")
val filePath = Files.readSymbolicLink(path)
Log.d("AppLog", "filePath:$filePath")
但不确定FileChannel。它的实现文件("FileChannelImpl")应该具有;路径";(文件路径字符串类型)和";fd";是FileDescriptor,但两者都通过反射隐藏
从java:中的FileDescriptor获取路径的解决方案
工作原理:
我们知道文件描述符包含描述符id,用于定位当前进程中打开的文件。
什么是文件描述符,用简单的术语解释?
如果我们知道描述符id,那么我们可以通过以下java代码很容易地找到文件路径:
Path path = Paths.get("/proc/self/fd/"+fd_id);
System.out.println(Files.readSymbolicLink(path)); //return file path in file descriptor
此处:
fd_id文件描述符id(0,1,2…..)
/proc其a目录包含在系统中运行的所有进程
/自当前运行的java类进程id
/fd文件描述符目录
//fd_id文件描述符id
SafeFileDescriptor.java
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.nio.file.Path;
public class SafeFileDescriptor {
static {
System.load("Documents/java native interface exmples/libSafeFileDescriptor.so");
}
private native int getFDid(FileDescriptor fd);
public static void main(String[] args) throws IOException{
FileOutputStream fout = new FileOutputStream("Documents/test.txt");
FileDescriptor fd=fout.getFD();
int fd_id = new SafeFileDescriptor().getFDid(fd);
Path path = Paths.get("/proc/self/fd/"+fd_id);
System.out.println(Files.readSymbolicLink(path));
}
}
getFDid()
是一种本地方法,用于获取给定文件描述符对象的描述符id
以下代码是getFDid()
本机方法的实现
SafeFileDescriptor.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class SafeFileDescriptor */
#ifndef _Included_SafeFileDescriptor
#define _Included_SafeFileDescriptor
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: SafeFileDescriptor
* Method: getFDid
* Signature: (Ljava/io/FileDescriptor;)I
*/
JNIEXPORT jint JNICALL Java_SafeFileDescriptor_getFDid
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
从java文件SafeFileDescriptor.java 创建SafeFileDescriptor.h
javac -h dir SafeFileDescriptor.java
将"dir"替换为存储SafeFileDescriptor.h 的目录
SafeFileDescriptor.c
#include <jni.h>
#include "SafeFileDescriptor.h"
JNIEXPORT jint JNICALL Java_SafeFileDescriptor_getFDid
(JNIEnv *env, jobject this_object, jobject fdObject) {
jclass fileDescriptor = (*env)->GetObjectClass(env,fdObject);
jfieldID id_fd = (*env)->GetFieldID(env, fileDescriptor, "fd", "I");
return (*env)->GetIntField(env,fdObject,id_fd);
}
编译SafeFileDescriptor.c
gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libSafeFileDescriptor.so SafeFileDescriptor.c
将libSafeFileDescriptor.so文件添加到java类文件
System.load("Documents/java native interface exmples/libSafeFileDescriptor.so");
根据@androiddeveloper和@zakmck的回答添加了附加信息。
/对于大多数Unix变体,包括大多数Linux变体和MacOS,dev/fd是一个更好的解决方案,但并非适用于所有变体。它适用于我在CentOS 9和MacOS 12.1上使用。
fdescfdesc文件系统通常安装在/dev/fd上。它的功能类似于Linux上的/proc//fd(或简称/proc/self/fd),也就是说,它为当前运行的进程提供了所有活动文件描述符的列表。请注意,一个典型的Linux系统具有象征性地链接到/proc/self/fd的/dev/fd。
参考文献:
-
https://web.archive.org/web/20190724030849/http://osxbook.com/book/bonus/ancient/whatismacosx/arch_fs.html
-
https://en.wikipedia.org/wiki/File_descriptor
-
https://unix.stackexchange.com/questions/123602/portability-of-file-descriptor-links/123659#123659