[英]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 郵件列表的一些交流:
從我正在閱讀的內容來看,關閉
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.