当有效ID与文件不匹配时,在Java中设置文件修改时间

时间:2018-12-22 09:46:26

标签: java

我有一个Java进程,需要更新它不拥有的文件的修改时间。我尝试了下面看似正确的程序,但它失败了,并显示为Operation Not Permitted

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;

public class Touch {
    public static void main(String args[]) {
        for (String filename : args) {
            try {
                Path path = new File(filename).toPath();
                FileTime time = FileTime.fromMillis(System.currentTimeMillis());
                Files.setLastModifiedTime(path, time);
            } catch (IOException e) {
                System.err.println("Failed to touch: " + filename);
                e.printStackTrace();
            }
        }
    }
}

在给定root拥有的现有文件asdfasdf的情况下,这是程序的输出,但是我具有通过组(0660权限)对其进行写访问的权限。

$ strace -f -o mtime.log java -cp . Touch asdfasdf
Failed to touch: asdfasdf
java.nio.file.FileSystemException: asdfasdf: Operation not permitted
        at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
        at sun.nio.fs.UnixFileAttributeViews$Basic.setTimes(UnixFileAttributeViews.java:109)
        at java.nio.file.Files.setLastModifiedTime(Files.java:2306)
        at Touch.main(Touch.java:15)

strace的相关部分如下:

13414 openat(AT_FDCWD, "asdfasdf", O_RDONLY) = 4
13414 fstat(4, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
13414 utimensat(4, NULL, [{tv_sec=1545468214, tv_nsec=0} /* 2018-12-22T03:43:34-0500 */, {tv_sec=1545470858, tv_nsec=462000000} /* 2018-12-22T04:27:38.462000000-0500 */], 0) = -1 EPERM (Operation not permitted)

/usr/bin/touch可以满足我的要求,所以我也做到了:

$ strace -f -o mtime.log touch asdfasdf

这是strace的相关部分:

13483 openat(AT_FDCWD, "asdfasdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3
13483 dup2(3, 0)                        = 0
13483 close(3)                          = 0
13483 utimensat(0, NULL, NULL, 0)       = 0

查看utimensat手册页后发现,由于Java使用times!= NULL进行调用,因此该进程必须是所有者。

Java API中是否存在另一种方法,它将使用正确的参数调用utimensat(),所以我不会遇到EPERM / Operation Not Permitted错误?

进一步挖掘Java 8的Files.setLastModifiedTime显示UnixFileAttributeViews使用futimes,然后使用先前找到的utimensat调用。

0 个答案:

没有答案