尝试将文件复制到具有特定权限的文件夹时遇到问题。
这是我非常简单的测试程序:
#include <iostream>
#include <windows.h>
int main()
{
if(CopyFileA("D:/SOURCE/File.txt", "D:/LOCKED/dst1.txt", TRUE))
std::cout << "OK\n";
else
std::cout << "Fail\n";
if (CopyFileA("D:/SOURCE/File.txt", "D:/LOCKED/dst2.txt", TRUE))
std::cout << "OK\n";
else
std::cout << "Fail\n";
system("PAUSE");
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
Fail
OK
Run Code Online (Sandbox Code Playgroud)
我可以复制任意数量的文件。对于每次运行,第一次总是失败,后续总是成功。错误是 ERROR_ACCESS_DENIED。
这是重要的细节:我的目标文件夹具有受限的权限,只有当我删除“写入属性”或“写入扩展属性”时才会出现此行为。

我使用了 sysInternals 的进程监视器:没有其他进程正在访问源文件和目标文件。但是,目标文件上的行为并不相似。第一次尝试关闭文件并尝试重新打开它。以下是日志:
| 行动 | 地位 | 细节 |
|---|---|---|
| 失败的尝试(第一次) | —— | —— |
| 创建文件 | 成功 | 所需访问:通用读/写、删除、写 DAC、处置:创建、选项:顺序访问、非目录文件、属性:A、ShareMode:无、AllocationSize:0、OpenResult:已创建 |
| 关闭文件 | 成功 | |
| 创建文件 | 拒绝访问 | 所需访问:通用读/写、删除、写 DAC、处置:OpenIf、选项:顺序访问、同步 IO 非警报、非目录文件、属性:A、共享模式:无、分配大小:0 |
| 创建文件 | 拒绝访问 | 所需访问:通用读/写、删除、写 DAC、处置:OpenIf、选项:顺序访问、同步 IO 非警报、非目录文件、属性:A、共享模式:读、写、分配大小:0 |
| 创建文件 | 拒绝访问 | 所需访问:通用读/写、写 DAC、处置:OpenIf、选项:顺序访问、同步 IO 非警报、非目录文件、属性:A、共享模式:读、写、分配大小:0 |
| 创建文件 | 拒绝访问 | 所需访问:通用读/写,处置:OpenIf,选项:顺序访问,同步 IO 非警报,非目录文件,属性:A,共享模式:无,分配大小:0 |
| 创建文件 | 拒绝访问 | 所需访问:通用读/写,处置:OpenIf,选项:顺序访问,同步 IO 非警报,非目录文件,属性:A,共享模式:读、写,分配大小:0 |
| 成功的尝试(第二次和后续) | —— | —— |
| 创建文件 | 成功 | 所需访问:通用读/写、删除、写 DAC、处置:创建、选项:顺序访问、同步 IO 非警报、非目录文件、属性:A、ShareMode:无、AllocationSize:0、OpenResult:已创建 |
| QueryAttributeInformationVolume | 成功 | 文件系统属性:保留大小写、区分大小写、Unicode、ACL、压缩、命名流、EFS、对象 ID、重新分析点、稀疏文件、配额、事务、0x3c00600、MaximumComponentNameLength:255、FileSystemName:NTFS |
| 查询基本信息文件 | 成功 | CreationTime:19/08/2021 15:20:32,LastAccessTime:19/08/2021 15:20:32,LastWriteTime:19/08/2021 15:20:32,ChangeTime:19/08/2021 15:20: 32、FileAttributes:A |
| SetEndOfFileInformationFile | 成功 | 文件结尾:24 |
| 写文件 | 成功 | 偏移:0,长度:24,优先级:正常 |
| 读取文件 | 成功 | 偏移量:0,长度:24,I/O 标志:非缓存,分页 I/O,同步分页 I/O,优先级:正常 |
| 设置基本信息文件 | 成功 | CreationTime:01/01/1601 02:00:00,LastAccessTime:01/01/1601 02:00:00,LastWriteTime:19/08/2021 14:50:49,ChangeTime:19/08/2021 14:50: 49、FileAttributes:不适用 |
| QueryRemoteProtocolInformation | 无效的参数 | |
| 关闭文件 | 成功 |
编辑1:
这是get-acl D:\LOCKED | fl回应:
Path : Microsoft.PowerShell.Core\FileSystem::D:\LOCKED
Owner : BUILTIN\Administrators
Group : KJ-WIN10\None
Access : Everyone Allow CreateFiles, AppendData, ReadAndExecute, Synchronize
Audit :
Sddl : O:BAG:S-1-5-21-1983668899-2794625975-2151939504-513D:PAI(A;OICI;0x1200af;;;WD)
Run Code Online (Sandbox Code Playgroud)
您可以在https://github.com/KiwiJaune/CantMove/blob/master/Program.cs 上使用我的 C# 示例程序重现完整行为(文件夹创建和文件复制)。
编辑2:
以下是fltmc几台经过测试的 PC 之一的结果:
| 过滤器名称 | 数量实例 | 高度 | 框架 |
|---|---|---|---|
| 绑定 | 1 | 409800 | 0 |
| 依赖 | 12 | 407000 | 0 |
| 过滤器 | 12 | 328010 | 0 |
| 暴风雪 | 0 | 244000 | 0 |
| 西弗斯 | 4 | 189900 | 0 |
| 氟利昂 | 2 | 180451 | 0 |
| 自卫队 | 12 | 145900 | 0 |
| 文件加密 | 0 | 141100 | 0 |
| 路飞 | 1 | 135000 | 0 |
| npsvctrig | 1 | 46000 | 0 |
| 沃夫 | 8 | 40700 | 0 |
| 文件信息 | 12 | 40500 | 0 |
我发现它总是在 D:/ 或闪存驱动器上失败,但在 C:/ 上成功,无论 D: 是另一个物理磁盘还是与 C: 相同磁盘上的分区...
我在 4 台经过测试的 PC 上有相同的行为(3 台 Win10 和 1 台 Win7)
是否有 Windows 已知行为?提前感谢您的想法。
小智 2
将文件从同一驱动器上的一个位置移动到另一个位置只会导致 Windows 移动其目录位置;移动到不同驱动器上的位置会导致 Windows 将文件复制到目标,然后删除原始文件。
使用 API 复制文件时,Windows 似乎使用两种方法:
这就是您的程序中发生的情况:第一次调用“移动文件”时,Windows 使用方法 1...后续调用使用方法 2。
问题是方法1需要目录的修改权限。实际上,Windows 创建了空文件,但随后无法打开该文件来添加数据。D:\LOCKING 中创建的空文件证实了这一点:向目标目录授予“修改”权限可以解决此问题;或者,在与预期目标相同的驱动器上创建临时文件。
| 归档时间: |
|
| 查看次数: |
452 次 |
| 最近记录: |