如所述here , 使用 SetFileInformationByHandle
与 FILE_DISPOSITION_INFO
允许将打开句柄的文件设置为在所有句柄关闭时删除。
但是,我正在尝试根据 FILE_DISPOSITION_INFO
检索到的文件索引(磁盘 ID)删除文件和
OpenFileById
为了安全地删除目录中仅大小写不同的文件/目录。
在我的用例中这样做是安全的,因为在 NTFS 系统上,文件索引是 persistent until deletion ,
否定当前代码库处理的 ReplaceFile
的使用。
但是,当尝试删除句柄时,出现错误 87 (ERROR_INVALID_PARAMETER
)。
如果我使用 CreateFileW
创建的句柄删除,我没有遇到任何问题。
不过,我不能这样做,因为 Windows 无法区分相同大小写的两个文件/文件夹,即使 NTFS 可以。
我也知道用 OpenFileById
打开的硬链接(hard link)文件存在歧义。 ,
因为硬链接(hard link)文件共享相同的磁盘 ID。
硬链接(hard link)文件的问题可以被认为与这种情况无关。
我只会按 ID 删除目录,不能硬链接(hard link)。
我的 OpenFileById
中是否缺少参数或设置?称呼?
不知何故,在我的SetFileInformationByHandle
打电话?
我尝试过的其他方法:
- 调用
DuplicateHandle
与OpenFileById
句柄,为dwDesiredAccess
提供DELETE
,并使用它。 相同的ERROR_INVALID_PARAMETER
结果。 - 使用
ReOpenFile
与OpenFileById
句柄,为dwDesiredAccess
提供DELETE
,并使用它。 相同的ERROR_INVALID_PARAMETER
结果。 - 使用
ReOpenFile
与OpenFileById
句柄,为dwDesiredAccess
提供DELETE
,并提供FILE_FLAG_DELETE_ON_CLOSE
标志。 没有给出错误,但文件在所有句柄关闭后仍然存在。
这是重现问题的最小但完整的示例:
#include <stdio.h>
#include <sys/stat.h>
#include <Windows.h>
DWORD getFileID(LPCWSTR path, LARGE_INTEGER *id)
{
HANDLE h = CreateFileW(path, 0, 0, 0, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT |
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_POSIX_SEMANTICS,
0);
if (h == INVALID_HANDLE_VALUE)
return GetLastError();
BY_HANDLE_FILE_INFORMATION info;
if (!GetFileInformationByHandle(h, &info))
{
DWORD err = GetLastError();
CloseHandle(h);
return err;
}
id->HighPart = info.nFileIndexHigh;
id->LowPart = info.nFileIndexLow;
CloseHandle(h);
return ERROR_SUCCESS;
}
DWORD deleteFileHandle(HANDLE fileHandle)
{
FILE_DISPOSITION_INFO info;
info.DeleteFileW = TRUE;
if (!SetFileInformationByHandle(
fileHandle, FileDispositionInfo, &info, sizeof(info)))
{
return GetLastError();
}
return ERROR_SUCCESS;
}
int wmain(DWORD argc, LPWSTR argv[])
{
if (argc != 3)
{
fwprintf(stderr, L"Arguments: <rootpath> <path>\n");
return 1;
}
DWORD err;
HANDLE rootHandle = CreateFileW(
argv[1], 0, 0, 0, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT |
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_POSIX_SEMANTICS,
0);
if (rootHandle == INVALID_HANDLE_VALUE)
{
err = GetLastError();
fwprintf(stderr,
L"Could not open root directory '%s', error code %d\n",
argv[1], err);
return err;
}
LARGE_INTEGER fileID;
err = getFileID(argv[2], &fileID);
if (err != ERROR_SUCCESS)
{
fwprintf(stderr,
L"Could not get file ID of file/directory '%s', error code %d\n",
argv[2], err);
CloseHandle(rootHandle);
return err;
}
fwprintf(stdout,
L"The file ID of '%s' is %lld\n",
argv[2], fileID.QuadPart);
FILE_ID_DESCRIPTOR idStruct;
idStruct.Type = FileIdType;
idStruct.FileId = fileID;
HANDLE fileHandle = OpenFileById(
rootHandle, &idStruct, DELETE, FILE_SHARE_DELETE, 0,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
if (fileHandle == INVALID_HANDLE_VALUE)
{
err = GetLastError();
CloseHandle(rootHandle);
fwprintf(stderr,
L"Could not open file by ID %lld, error code %d\n",
fileID.QuadPart, err);
return err;
}
err = deleteFileHandle(fileHandle);
if (err != ERROR_SUCCESS)
{
fwprintf(stderr,
L"Could not delete file by ID '%lld', error code %d\n",
fileID.QuadPart, err);
}
CloseHandle(fileHandle);
struct _stat _tmp;
fwprintf(stdout,
L"File was %ssuccessfully deleted\n",
(_wstat(argv[2], &_tmp) == 0) ? L"not " : L"");
CloseHandle(rootHandle);
return err;
}
任何解决方案都必须适用于 Vista 及更高版本。也欢迎提出代码改进建议。
最佳答案
为了使 FILE_DISPOSITION_INFO
正常工作,您需要在 CreateFile
函数中指定 DELETE 访问权限,如 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365539(v=VS.85).aspx 中所报告的那样:
You must specify appropriate access flags when creating the file handle for use with SetFileInformationByHandle. For example, if the application is using FILE_DISPOSITION_INFO with the DeleteFile member set to TRUE, the file would need DELETE access requested in the call to the CreateFile function. To see an example of this, see the Example Code section. For more information about file permissions, see File Security and Access Rights. I.e.
//...
HANDLE hFile = CreateFile( TEXT("tempfile"),
GENERIC_READ | GENERIC_WRITE | DELETE, //Specify DELETE access!
0 /* exclusive access */,
NULL,
CREATE_ALWAYS,
0,
NULL);
但似乎无法使用使用OpenFileById()
创建的句柄,因为该函数无法接受DELETE
标志。
来自 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365432(v=vs.85).aspx在 OpenFileById()
上可以读取:
dw期望
Access [in]
The access to the object. Access can be read, write, or both.
即使设置 DELETE
或 GENERIC_ALL
函数也会失败。
如果将传递给 SetFileInformationByHandle
的句柄替换为使用 CreateFile
函数创建并设置了 DELETE
标志的句柄,如以上,它有效。
关于c - 根据磁盘 ID 删除文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36217150/