У меня проблема с дефрагментацией файлов на системном томе Windows XP, FAT32. Я не пишу дефрагментатор, но вместо этого часть решения требует, чтобы определенный набор файлов был постоянно выложен на диск. Чтобы гарантировать это, я использую FSCTL_MOVE_FILE ioctl для перемещения экстентов файлов в один экстент свободного пространства достаточного размера на томе. Процесс происходит следующим образом:
1) Создайте файл:
return m_file.Create(path,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
CREATE_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH |
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
NULL);
2) Заполнить файл нулями.
3) Убедитесь, что файл фрагментирован, если это так, получите растровое изображение тома с помощью FSCTL_GET_VOLUME_BITMAP, найдите свободную цепочку кластеров достаточного размера.
4) Используйте FSCTL_MOVE_FILE для дефрагментации файла в найденный экстент как таковой:
MOVE_FILE_DATA input;
input.FileHandle = fileHandle;
input.StartingVcn.QuadPart = 0;
input.StartingLcn.QuadPart = freeExtent.lcn;
input.ClusterCount = totalFileClusters;
DWORD bytesReturned = 0; // unused
::DeviceIoControl(
volumeHandle,
FSCTL_MOVE_FILE,
&input,
sizeof(input),
NULL,
0,
&bytesReturned,
NULL);
Этот последний вызов отлично работает в системе NTFS и на обычных томах. Несистемные тома в XP также не представляют проблемы. Однако на системных томах FAT32 на XP я почти всегда получаю сообщение об ошибке INVALID_ARGUMENT (87). Файлы довольно большие, около 700 МБ. Том имеет около 10 ГБ свободного места. После сбоя fsctl видно, что часть файла была фактически перемещена до возникновения ошибки. Я пробовал несколько попыток, но пока все 50 из них не увенчались успехом. Я знаю, что перемещение большого файла таким образом может завершиться неудачей из-за того, что ранее свободный кластер, находящийся дальше по дороге, будет занят чем-то другим на томе, особенно если том имеет большую активность (как это обычно бывает с системными томами). Но я понятия не имею, как смягчить это, учитывая, что у меня нет ядра. Что я делаю неправильно и/или как я могу сделать лучше?