Я экспериментирую с FSCTL_MOVE_FILE
.В основном все работает как положено.Однако иногда, если я пытаюсь перечитать (через FSCTL_GET_NTFS_FILE_RECORD
) запись Mft, которую я только что переместил, я получаю некоторые некорректные данные.
В частности, если запись файла говорит, что атрибут $ ATTRIBUTE_LIST не является-резидент и я использую свой дескриптор тома для чтения данных с диска, я обнаружил, что данные там внутренне несовместимы (длина записи больше, чем фактическая длина данных).
Как только я увидел этослучилось, причина была довольно ясна: я читаю запись до того, как драйвер Ntfs закончит ее писать.Отладка поддерживает эту теорию.Но знание этого не помогает мне решить это.Я использую синхронный метод для вызова FSCTL_MOVE_FILE
, но, очевидно, файловая система все еще может обновлять данные в фоновом режиме.Хм.
В обычном файле я бы подумал LockFileEx
с общей блокировкой (так как я просто читаю).Но я не уверен, что имеет какое-то значение для ручек громкости?И я даже менее уверен, что Ntfs использует этот механизм внутри для обеспечения согласованности.
Тем не менее, это, похоже, место для начала.Но мой LockFileEx
вызов с дескриптором громкости возвращает ERROR_INVALID_PARAMETER
.Я не вижу, какой параметр может быть ошибочным, если это не сам дескриптор тома.Возможно, они просто не поддерживают блокировки?Или, может быть, есть некоторые специальные флаги, которые я должен установить в CreateFile
при открытии ручки громкости?Я попытался включить SE_BACKUP_NAME
и FILE_FLAG_BACKUP_SEMANTICS
, но ошибка остается неизменной.
Двигаясь вперед, я вижу несколько альтернатив здесь:
- Выясните, как заблокироватьразделы, использующие дескриптор громкости (и надеюсь, что драйвер Ntfs делает то же самое).На данный момент кажется сомнительным.
- Выясните, как очистить метаданные для файла, который я только что переместил (nb: FlushFileBuffers для MOVE_FILE_DATA.FileHandle не помогло. Может быть, очистка дескриптора тома?).
- Существуют ли какие-либо «официальные» средства для чтения нерезидентных данных, которые не включают
ReadFile
для дескриптора тома?Я не нашел ни одного, но, возможно, я пропустил его. - Подождите немного после перемещения данных, чтобы драйвер завершил обновление всего.Тьфу.
FWIW, вот некоторый тестовый код для выполнения LockFileEx с дескриптором тома.Обратите внимание, что вы должны работать от имени администратора, чтобы заблокировать дескрипторы томов.Я использую J:
, так как это моя флешка.50000 было выбрано случайным образом, но должно быть меньше, чем размер флэш-накопителя.
void Lock()
{
WCHAR path[] = L"\\\\.\\j:";
HANDLE hRootHandle = CreateFile(path,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
OVERLAPPED olap;
memset(&olap, 0, sizeof(olap));
olap.Offset = 50000;
// Lock 1k of data at offset 50000
BOOL b = LockFileEx(hRootHandle, 1, 0, 1024, 0, &olap);
DWORD j = GetLastError();
CloseHandle(hRootHandle);
}
Код для просмотра неверных данных ... довольно сложный.Однако это легко воспроизводимо.Когда это терпит неудачу, я заканчиваю тем, что пытаюсь прочитать записи переменной длины $ ATTRIBUTE_LIST, которые имеют длину '0', что приводит к бесконечному циклу, так как похоже, что я никогда не заканчивал читать весь буфер.Я работаю над этим путем выхода, если длина равна нулю, но я беспокоюсь о «остатке мусора» в буфере вместо хороших чистых нулей.Обнаружить это было бы невозможно, поэтому я надеюсь на лучшее решение.
Не удивительно, что по этому поводу не так много информации.Так что, если у кого-то здесь есть некоторый опыт, я мог бы использовать некоторое понимание.
Редактировать 1:
Другие вещи, которые не совсем работают:
- Все еще не повезло на LockFileEx.
- Я попытался очистить ручку громкости (как предложил Пол).И хотя это работает, это более чем удваивает мое время выполнения.И, строго говоря, это все еще не решает проблему.До сих пор нет гарантии, что Ntfs не собирается что-то менять между FlushFileBuffers и FSCTL_GET_NTFS_FILE_RECORD / ReadFile.
- Мне было интересно узнать о метке времени 'RecordChanged' атрибута $ STANDARD_INFORMATION.Однако он не изменяется из-за этих изменений в ATTRIBUTE_LIST.
- Фрагментация файла в конечном итоге приводит к добавлению ATTRIBUTE_LIST, и, поскольку фрагментация продолжает увеличиваться, в этот список будет добавлено больше записей DATA.Когда добавляется запись DATA, UpdateSequenceNumber (не тот, который является частью MFT_SEGMENT_REFERENCE, а другой) обновляется.К сожалению, есть последовательность событий, чтобы выполнить это обновление.И очевидно, что длина буфера ATTRIBUTE_LIST обновляется до «UpdateSequenceNumber».Поэтому проверка, изменился ли «UpdateSequenceNumber», не помогает избежать прочтения (потенциально) неверной информации.
Моя следующая лучшая мысль - посмотреть, всегда ли Ntfs обнуляет новые байты перед обновлением длины записи.(или, может быть, всякий раз, когда длина записи уменьшается?).Если я могу зависеть от того, что длина записи равна нулю (вместо того, чтобы оставшиеся данные могли занимать эти байты), я могу притвориться, что это фиксировано.