MoveFile Внутренняя реализация и отслеживание прогресса

Рейтинг: 1Ответов: 1Опубликовано: 29.07.2023

Каким образом WINAPI функция MoveFile выполняет перемещение файлов или папок: просто меняет информацию о расположении файлов в FAT или же выполняет копирование данных и удаление оригинальных файлов с диска (иными словами вызывается CopyFile и DeleteFile)? Каким образом можно отследить прогресс операции? Есть WINAPI функция MoveFileTransacted, однако в документации настоятельно рекомендуется не использовать её, но альтернатив конкретно под эту задачу я не нашёл.

Ответы

▲ 1Принят

Если происходит перемещение на другой диск, то очевидно, что это копирование и затем удаление. Я имел ввиду ситуацию с перемещением в пределах одного диска.

Как-раз недавно пришлось исследовать структуры NTFS, и написал для этого спец.утилиту. Из стороннего софта использовал WinHex, который в удобном виде отображает все метафайлы, типа $MFT и прочие. В зарегистрированной его версии можно звать даже шаблоны структур $BOOT и "FILE_RECORD" - очень удобно. Но для начала небольшой ликбез для начинающих.

Каждый файл на диске NTFS описывается структурой "FILE_RECORD" (паспорт файла) - сколько файлов на диске, столько и записей Record (папка тоже считается файлом). Размер одной записи указывается в структуре "$BOOT", найти которую можно в секторе(0) каждого из разделов/томов. В дефолте, размер сектора 512-байт, кластера 4096 (8 секторов), а размер одной записи Record = 2 сектора, или 1КБ.

Для хранения всех записей Record используется таблица $MFT - Master File Table. У каждого раздела диска своя $MFT. Указатель на неё в кластерах прописывается в структуре $BOOT раздела. Отдельная запись "FILE_RECORD" может иметь макс.16 различных свойств, которые в доках числятся как "ATTRIBUTE" (не путать с файловыми атрибутами ОС типа "Hidden" и прочие).

Таким образом, в строках таблицы $MFT указывается имя файла (сигнатура "FILE" в начале сектора), а в 16-ти её столбцах - атрибуты. Как-правило, у записей Record всего 3..6 атрибута, из возможных 16-ти. Так выглядит картина в общих чертах.

Теперь к вопросу о перемещении файлов в пределах своего и соседнего раздела. Для этого, достаточно прочитать Record интересующего файла, и сравнить его до и после перемещения. В своём коде я вывожу на консоль сл.детали о записи Record:

  1. Основная структура "FILE_RECORD" начинается с порядкового номера записи в глобальной $MFT. Флаг "Record status" - это битовая маска: (0)запись недействительна и её можно использовать повторно, т.е. файл удалён; (1)активная запись, (2)запись описывает папку. Если папка на диске активна, то флаг принимает значение(3), если удалена(2). Для файлов он всегда равен 1 или 0.

  2. Поле с номером "Update sequency" позволяет отыскивать Record'ы одной записи, когда они размазаны по всему диску, т.е. фрагментированны. Это значение прошивается в самый конец сектора, и является уникальным.

  3. В атрибуте записи "STANDART" нас интересует поле "ChangeTime" - это время последнего изменения данной Record в таблице $MFT. NTFS изменяет поле, например, при переименовании файла. В поле "Security" хранятся такие атрибуты безопасности файла, как DACL/SACL и прочие.

  4. Атрибут "FILE_NAME" уже более информативен. Здесь имеется ссылка на Record родителя "Parent". Если запись описывает файл (см.пункт 1), то родителем всегда будет каталог верхнего уровня и т.д., пока не упрёмся в корневой дир раздела. Флаг резидента показывает, где находится текущая запись - в таблице $MFT =1, или за её пределами =0. Далее перечисляются знакомые нам атрибуты ОС типа "Скрытый, Системный, Архивный" и т.п. Функция Win GetFileAttribute() для папок возвращает значение(10h), а здесь это 1000.0000h.

Теперь что мы видим на скрине ниже? Когда файл перемещается в пределах своего раздела, то в оригинальном Record просто меняется ссылка на родителя "Parent", и сразу фиксируется время изменения данной записи. То-есть сам файл "lang_ru.ini" фактически остался на своём месте!

Но когда файл перемещается на другой том, то это реальное копирование всех данных. При этом оригинальная информация не стирается физически с диска, а лишь в основной структуре "FILE_RECORD" статус сбрасывается в нуль "Deleted". Обратите внимание, что это одна и та-же запись с номером #0000100916. Таким образом, криминалисты легко могут обнаружить все удалённые файлы, если их секторы не затёрли новые.

введите сюда описание изображения