簡體   English   中英

Apache commons-io 復制繼承目標權限

[英]Apache commons-io copy and inherit target permissions

在 Windows 上,當使用commons-io@2.11 FileUtils復制目錄時(例如FileUtils.copyDirectory(...) ,行為與Windows 的行為不同:com 默認復制行為

“默認情況下,object 在創建時或復制或移動到其父文件夾時從其父 object 繼承權限。此規則的唯一例外是當您將 ZA8CFDE6331BD59EB2AC96F8911C4B66 上的不同文件夾移動時卷。在這種情況下,保留原始權限。”

預期行為:

  • 復制到目標的文件繼承父權限

實際行為:

  • 復制到目標的文件不繼承父權限

這很重要的原因是 Windows 歷史上管理這些; 手動設置它們會容易出現更多潛在錯誤。 因此,在沒有繼承目標權限的能力的情況下,這種方法在 Windows 上無法達到最常用的目的。

如何在不降級commons-io庫的情況下恢復繼承目標權限的舊行為?

這似乎是行為的回歸:

版本 地位
commons-io@2.4 ✅ 繼承目的地的權限
commons-io@2.11 不繼承目的地的權限

例如,如果復制到C:\Program Files

版本 權限( icals <file>
commons-io@2.4 NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)
BUILTIN\Users:(I)(RX)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)
commons-io@2.11 NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
WIN10ARM\owner:(F)

示例代碼:

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

public class Main {
    private static final String PROGRAM_FILES = System.getenv().get("ProgramFiles");
    public static void main(String ... args) throws IOException {
        // Prepare our folder
        File folder = new File("MyApp");
        folder.mkdirs();
        File file = new File(folder, "test.txt");
        file.createNewFile();

        // Use FileUtils to copy it elsewhere
        File parent = new File(PROGRAM_FILES);
        File dest = new File(parent, "MyApp");
        System.out.println(String.format("Creating parent folder %s...", dest));
        dest.mkdirs();
        System.out.println(String.format("Copying contents %s to %s...", folder, dest));
        FileUtils.copyDirectory(folder, dest);

        // To test permissions call:
        //    icacls "%ProgramFiles%\MyApp\test.txt"
    }
}

編譯代碼:

javac -cp lib\commons-io-2.4.jar src\Main.java

運行代碼(以管理員身份打開 CMD):

java -cp lib/commons-io-2.4.jar;src Main

測試權限:

icacls "%ProgramFiles%\MyApp\test.txt"

然后手動刪除%ProgramFiles%\MyApp並重復commons-io-2.11.0.jar

以前也有人問過類似的問題,但我找不到這種行為的解釋。

有關的:

一種可能的解決方法,但要復雜得多:

使用org.apache.commons.io.FileUtils.copyFile(File, File, boolean, CopyOption...)來完全控制你想要做什么。 在幕后它最終調用java.nio.file.Files.copy(Path, Path, CopyOption...)

解決方法是:

- FileUtils.copyDirectory(folder, dest);
+ FileUtils.copyDirectory(folder, dest, false);
//                           HERE  -----^

或者交替...

- FileUtils.copyDirectory(folder, dest);
+ PathUtils.copyDirectory(folder.toPath(), dest.toPath())
//^------ HERE

引用與 Apache Commons 郵件列表的一些交流:

我認為這是有問題的行: https://github.com/apache/commons-io/blob/f22a4227401855ecbfdf8184bbe37275c3aeb5c3/src/main/java/org/apache/commons/io/FileUtils.java#L701

從我正在閱讀的內容來看,關閉preserveFileDate會在不經意間且不明顯地解決此問題,但在這一點上。 至少對於 Windows 環境,此修復程序似乎是不受歡迎的、未記錄的且易於中斷的行為。

我很好奇使用什么推理將文件的修改日期與其屬性的 rest 相關聯。 也許這是使用新 NIO API 維護修改日期的向后兼容快捷方式? 無論如何,這會引入權限更改,這些更改可能會破壞需要繼承權限的環境的標准文件復制操作,例如 Windows。

理想情況下,文件修改日期可以保留而不會破壞默認的 NIO 行為。

目前可行的解決方法是:

 FileUtils.copyDirectory(folder, dest, false /* <--- change to FALSE */);

...然而,這確實有(可能)丟失時間戳信息的缺點,這仍然是一種回歸,盡管更小。

...但是本地測試表明時間戳信息(文件,而不是文件夾)在 Windows 上默認保留(即使關閉了此標志),因此第二個問題可能不那么...以及...有關。 這種變化對 Unix 的影響還有待測試。

造成差異的原因是 commons-io 2.4 執行自己的文件復制 ( source ),而 commons-io 2.11 委托給 NIO 的Files.copy ( source )。

NIO Files.copy采用一個或多個CopyOption值。 這里相關的是CopyOption.COPY_ATTRIBUTES ,它告訴 NIO 將屬性從源文件復制到目標。

如果您將true作為preserveFileDate參數傳遞給FileUtils.copyDirectory (如果您使用兩個參數變體,這是默認設置), FileUtils會將其轉換為CopyOption.COPY_ATTRIBUTES並將其傳遞給Files.copyFile

這樣做的結果是,當您要求FileUtils保留文件日期時,它實際上會從源文件復制所有屬性,包括 ACL。

正如在其他一些答案中已經提到的那樣,解決方案是將preserveFileDate作為false傳遞,這為您提供與原始版本 2.4 相同的行為:文件是在目標目錄中創建的,具有默認屬性和 ACL。

FileUtils.copyDirectory(folder, dest, /* preserveFileDate= */ false);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM