Windows блокирует доступ к файловой системе FAT32
Мне нужно дописать программу, которая уже написана под Windows на с++. Задача в том, чтобы из системы FAT32 стирать имя удаленного файла (делаю безопасное удаление, чтобы программы восстановления не давали инфы о том, что файл с таким-то названием был вообще на компьютере). Это легко получается сделать используя WinHex.
У меня есть алгоритм, вполне рабочий, но проблема в ОС, которая блокирует доступ в таблице FAT. Смех в том, что система позволяет писать что угодно от нулевого до, кажется, около 10-титысячного смещения, из-за чего раздел можно очень легко положить, но в таблицу доступа не дает, не смотря на то, что запускаюсь от имени администратора.
#include <windows.h>
#include <iostream>
#include <filesystem>
#include <iomanip>
#include <sstream>
#include <Dbt.h>
int main() {
setlocale(LC_ALL, "rus");
//Путь к диску U:, его открытие L"\\\\.\\PhysicalDrive0\\Partition2";
//Путь к разделу через физический диск
LPCSTR partitionU = "\\\\.\\U:";
//const wchar_t* partitionU = L"\\\\.\\U:";
HANDLE hDisk = CreateFileA(partitionU,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE , NULL, OPEN_EXISTING, 0, NULL);
if (hDisk == INVALID_HANDLE_VALUE) {
std::cout << GetLastError() << std::endl;
return 0;
}
else std::cout << "Success!" << std::endl;
//****************************************
if (SetFilePointer(hDisk, 4194304, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
std::cerr << "Ошибка установки указателя: ";
return GetLastError();
}
byte buffer[512*1]; //кол-во секторов *n
DWORD dwRead;
int sector_count = 0;
int row_count = 0;
int str_count = 0;
if (ReadFile(hDisk, buffer, sizeof(buffer), &dwRead, NULL)) {
std::cout << "Прочитано байт:" << dwRead << std::endl;
for (DWORD i = 0; i < dwRead; ++i) {
if (row_count != 15) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(buffer[i]) << " ";
row_count++;
}
else {
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(buffer[i]) << " "<<std::endl;
row_count = 0;
sector_count++;
}
if (sector_count == 32) {
std::cout << "-----------------------" << str_count++ << "------------------------" << std::endl;
sector_count = 0;
}
}
std::cout << std::endl;
}
else {
//std::cerr << "Ошибка при чтении: " << GetLastError() << std::endl;
DWORD error = GetLastError();
std::cerr << "Error opening disk. Error code: " << error << std::endl;
}
//*********************************
//**********Переписывание данных*********
byte* pointer = reinterpret_cast<byte*>(0);
LARGE_INTEGER largeInt;
largeInt.QuadPart = 0x400200;//reinterpret_cast<LONG_PTR>(pointer);
if (!SetFilePointerEx(hDisk, largeInt, NULL, FILE_BEGIN)) { //file_begin - от начала файла
std::cerr << "Ошибка установки указателя: ";
return GetLastError();
}
DWORD dwBytesWritten = 0;
//const char dataToWrite[] = "\xd2";
// Создаем массив из 512 значений
unsigned char byteArray[512*1];
// Заполняем массив нужными значениями, например, 0xFF
memset(byteArray, 0xFF, sizeof(byteArray));
if (WriteFile(hDisk, byteArray , sizeof(byteArray), &dwBytesWritten, NULL)) {
std::cout << "Данные успешно записаны. Байтов записано: " << dwBytesWritten << std::endl;
}
else {
std::cerr << "Ошибка при записи данных: " << GetLastError() << std::endl;
DWORD error = GetLastError();
std::cerr << "Error opening disk. Error code: " << error << std::endl;
}
//**************************************
//**************************************
CloseHandle(hDisk);
return 0;
}
Для лучшего понимания картины прикладываю скрины:
Recuva после удаления находит такой след, а его быть не должно

4.Нахожу его название в таблице (метка E5 говорит о том, что файл удалён)
5.Вношу немного чепухи и сохраняю (это WinHex)
6.И вот теперь Recuva выдаёт требуемый мне результат, которого я не могу добиться алгоритмом
Ответы (2 шт):
Так, разобрался. Для того, чтобы код заработал, нужно размонтировать образ путём: DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dwBytesWritten, 0);
сделать запись, затем снова его смонтировать (либо он сам смонтируется как только прога завершит работу):
DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, &dwBytesWritten, 0);
Так, разобрался
На мой взгляд это не полное решение проблемы, т.к. в общем случае, помимо блокировки тома, запись в служебные сектора FS диска требует соблюдения следующих правил:
Поскольку ОС активно взаимодействует с FS, операции записи должны быть асинхронными, для чего предусмотрена структура "OVERLAPPED" в параметрах
CreateFile(). Перед каждым вызовом функцийRead/WriteFile(), структуру "OVERLAPPED" нужно очищать, а в её поле "Offset" указывать новое смещение (для томов это номер сектора). Пример открытия тома:FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL.По умолчанию, для операций в/в с дисками включено кэширование, которое имеет смысл отключить. Для этого служат флаги
FILE_FLAG_NO_BUFFERING(без буфера) +FILE_FLAG_WRITE_THROUGH(сквозная запись в кэш, и сразу на диск). Их нужно скомбинировать с флагами из пункта(1).В критических случаях ОС может залочить доступ к служебной области FS, тогда придётся использовать указанный вами
DeviceIoControl()с кодом "FSCTL_LOCK_VOLUME". Детали здесь: https://learn.microsoft.com/ru-ru/windows/win32/fileio/volume-management-control-codes

