Как описано здесь, используя SetFileInformationByHandle
с FILE_DISPOSITION_INFO
позволяет установить файл с открытым дескриптором для удаления при закрытии всех дескрипторов.
Однако я пытаюсь удалить файл на основе его индекса файла (идентификатор диска), полученного с помощью FILE_DISPOSITION_INFO
и
OpenFileById
, чтобы безопасно удалять файлы/каталоги в каталоге, которые отличаются только в случае.
Это безопасно в моем случае использования, как в системе NTFS, индексы файлов постоянный до удаления,
отрицая использование ReplaceFile
, которое обрабатывает текущая кодовая база.
Однако при попытке удалить дескриптор, я получаю ошибку 87 (ERROR_INVALID_PARAMETER
).
Если я удалю, используя дескриптор, созданный с помощью CreateFileW
, я не сталкиваюсь с проблемами.
Я не могу этого сделать, поскольку Windows не сможет отличить два файла/папки одного и того же случая, хотя NTFS может.
Я также знаю, что существует двусмысленность с файлами с жесткой привязкой, открытыми с помощью OpenFileById
,
поскольку файлы с жесткими ссылками имеют один и тот же идентификатор диска.
Проблема с жестко привязанными файлами может считаться неактуальной для этого сценария.
Я удалю только каталоги по идентификатору, который не может быть привязан к строчке.
Есть ли параметр или параметр, отсутствующий в моем OpenFileById
вызов?
Как-то в моем SetFileInformationByHandle
вызов?
Дополнительные методы, которые я пробовал:
- Вызов
DuplicateHandle
сOpenFileById
, предоставляяDELETE
дляdwDesiredAccess
и используя это. Тот же результатERROR_INVALID_PARAMETER
. - Используя
ReOpenFile
сOpenFileById
, предоставляяDELETE
дляdwDesiredAccess
и используя это. Тот же результатERROR_INVALID_PARAMETER
. - Используя
ReOpenFile
сOpenFileById
, предоставляяDELETE
дляdwDesiredAccess
и предоставляя флаг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 и выше. Предложения по улучшению кода также приветствуются.