close

Вход

Забыли?

вход по аккаунту

?

Курсовая ОСи (2)

код для вставкиСкачать
Министерство образования и науки РФ
Рязанский государственный радиотехнический университет
Кафедра ЭВМ
К защите
Руководитель проекта
__________________________
дата, подпись
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА
К КУРСОВОМУ ПРЕКТУ
по дисциплине
"Операционные системы"
Тема:
"Разработка, отладка и тестирование вспомогательной системной программы в среде программирования Delphi с использованием средств Windows API"
Выполнила студентка группы 042
Перец Татьяна Александровна _____________________________
дата сдачи на проверку, подпись
Руководитель
Засорин Сергей Валентинович _____________ _____________________________
оценка дата защиты, подпись
Рязань 2013
ОГЛАВЛЕНИЕ
1 ВВЕДЕНИЕ4
2 ТЕХНИЧЕСКОЕ ЗАДАНИЕ5
2.1 Основание для разработки программы5
2.2 Назначение разработки5
2.3 Требования к приложению5
2.4 Требования к надежности5
2.5 Требования к программной документации5
2.6 Текст задания на разработку5
3 ОПИСАНИЕ РАЗРАБОТАННОЙ ПРОГРАММЫ6
3.1 Общие сведения6
3.2 Функциональное назначение6
3.3 Описание логической структуры6
3.4 Используемые технические средства18
3.5 Вызов и загрузка19
3.6 Входные данные19
3.7 Выходные данные19
4 ПРОГРАММА И МЕТОДИКА ИСПЫТАНИЙ19
4.1 Объект испытаний19
4.2 Цель испытаний19
4.3 Требования к программе19
4.4 Требования к программной документации20
4.5 Средства и порядок испытаний20
4.5.1 Тестирование методом "черного ящика"20
4.5.2 Тестирование методом "белого ящика"20
5 ЭКСПЛУАТАЦИОННЫЕ ДОКУМЕНТЫ27
5.1 Руководство программиста27
5.1.1 Общие сведения о программе27
5.1.2 Структура программы27
5.1.3 Настройка программы27
5.1.4 Проверка программы27
5.1.5 Дополнительные возможности программы28
5.1.6 Сообщения системному программисту28
5.2 Руководство оператора (пользователя)31
5.2.1 Назначение и условия применения программы31
5.2.2 Обращение к программе для запуска31
5.2.3 Входные и выходные данные31
5.2.4 Сообщения оператору31
6 ПРИЛОЖЕНИЕ31
7 СПИСОК ЛИТЕРАТУРЫ67
1 ВВЕДЕНИЕ
В данном курсовом проекте ставится задача разработки, отладки и тестирования вспомогательной системной программы (многопоточного приложения) в системе программирования Delphi с использованием средств Windows API. Данное приложение разработано на персональном компьютере модели IBM PC в операционной системе Windows 7 c использованием системы программирования Delphi.
Программа называется "восстановление и копирование". Она проста в использовании и рассчитана на средний уровень квалификации пользователя.
2 ТЕХНИЧЕСКОЕ ЗАДАНИЕ
2.1 Основание для разработки программы
Основанием для разработки данной программы служит учебный план РГРТУ для специальности "Компьютерная безопасность", а также документ задание к курсовому проекту, соответствующее 14 варианту.
2.2 Назначение разработки
Данное приложение разработано для выполнения восстановления удаленных файлов на логических дисках, а также копирования файла с одновременным переименованием с одного логического диска на другой.
2.3 Требования к приложению
Приложение должно выполнять следующие функции:
* предусматривать выбор логического диска (для восстановления) и исходного файла (для копирования);
* сканировать выбранный логический диск на предмет удаленных файлов и выводить их в список;
* обеспечивать возможность восстановления файла из списка в выбранную директорию;
* предоставлять возможность переименования копируемого файла;
* при сохранении копируемого файла в новую директорию оставлять его содержимое без изменений.
2.4 Требования к надежности
При правильных действиях пользователя (соблюдении условий эксплуатации вычислительной системы, системного и прикладного программного обеспечения) программа должна обеспечивать безошибочное функционирование, то есть при работе с программой не должно возникать сообщений об ошибках, которые в программе не предусмотрены. 2.5 Требования к программной документации
Документация к программе представлена, согласно требованиям, следующими разделами:
1. Введение
2. Техническое задание (ГОСТ 19.201-78)
3. Описание разработанной программы (ГОСТ 19.402-78)
4. Программа и методика испытаний (ГОСТ 19.301-79)
5. Эксплуатационные документы
5.1. Руководство программиста (ГОСТ 19.504-79)
5.2. Руководство оператора (ГОСТ 19.505-79)
6. Приложение
7. Список литературы
2.6 Текст задания на разработку
Разработать многопоточное приложение, выполняющее следующие операции:
1. Восстановление удаленных файлов на логических дисках.
2. Копирование файла с одновременным переименованием с одного логического диска на другой.
Исходные данные:
1. Для первого пункта задания:
* имя логического диска, содержащего удаленные файлы;
* удаленный файл.
2. Для второго пункта задания:
* полное имя исходного файла;
* полное имя файла для копирования на новый диск.
3 ОПИСАНИЕ РАЗРАБОТАННОЙ ПРОГРАММЫ
3.1 Общие сведения
Программа носит название "Восстановление и копирование" и является многопоточным приложением, которое предназначено для выполнения восстановления удаленный файлов на логических дисках и копирования с одновременным переименованием файла с одного логического диска на другой.
Программа позволяет пользователю вводить данные через программный интерфейс.
Программа проста в использовании и рассчитана на средний уровень квалификации пользователя.
Программа разработана в среде программирования Delphi 7. Для корректного функционирования программы требуется ОС Windows XP/Vista/7.
3.2 Функциональное назначение
Программа должна реализовывать следующие функции:
1. Восстановление удаленных файлов на логических дисках.
2. Копирование с одновременным переименованием файла с одного логического диска на другой.
3.3 Описание логической структуры
Вся программа представлена пятью взаимодействующими модулями:
1. Main.pas - основной модуль программы, содержащий главную форму и все процедуры, необходимые для выполнения основных функций программы;
2. FileDetails.pas - модуль, отвечающий за вывод окна информации восстанавливаемого файла;
3. Scan.pas - модуль, отвечающий за процесс сканирования логического диска на предмет удаленных файлов;
4. Restore.pas - модуль, отвечающий за восстановление удаленного файла;
5. Copy.pas - модуль, отвечающий за копирование с одновременным переименованием файла с одного логического диска на другой.
Программа представлена следующими файлами:
* Восстановление и копирование.exe - исполняемый файл программы после установки;
* Help.chm - скомпилированный файл справки в формате html.
В программе функционирует три потока потока:
1. Сканирования логического диска на предмет удаленных файлов.
2. Восстановление удаленного файла.
3. Копирование с одновременным переименованием файла с одного логического диска на другой.
В программе предусмотрено ведение "журнала", то есть вывод в текстовое поле "лог" информации о работе программы.
* Рассмотрим блок-схему алгоритма процедуры анализа содержимого последовательности обновлений, представленную на рисунке 1:
Рисунок 1 - Блок-схема процедуры анализа содержимого последовательности обновлений
Остановимся подробнее. Основное назначение последовательностей обновления (fix-up' ов) - защита от "обрыва записи". При каждой перезаписи сектора update sequence увеличивается на единицу и потому, если произошел обрыв записи, значение последовательности обновления, находящейся в заголовке ФЗ не будет совпадать с последовательностью обновления, расположенной в конце сектора. Данную схему и реализует представленная процедура. Получает смещение и номер последовательности обновлений, сравнивает номер с содержимым двух последних байт этого и следующего секторов. Происходит анализ расхождений. Если расхождения есть, то выдается сообщение об ошибке. Иначе - переходим по смещению массива последовательности обновлений, получаем два слова по этому смещению, записываем полученные слова в конец первого и последнего секторов.
* Рассмотрим блок-схему алгоритма процедуры получения атрибутов файла, представленную на рисунке 2:
Рисунок 2 - Процедура получения атрибутов файла Остановимся подробнее. Поэтапно анализируем ФЗ, разбивая ее на атрибуты. Анализируем каждый полученный атрибут. Если он не равен FFFFFFFF и этот атрибут - не тот, что нам необходим - переходим к следующему. Если атрибут искомый - записываем данные, полученные из этого атрибута. * Рассмотрим блок-схему алгоритма анализа возможности восстановления удаленного файла, представленную на рисунке 3:
Рисунок 3 - Предварительный анализ
Остановимся подробнее. Выбираем нужный для анализа и восстановления диск. Происходит попытка установления соединения между программой и устройством. Если Handle диска в результате не будет получен происходит вывод сообщения об ошибке. Иначе - считывается загрузочная запись и происходит анализ файловой системы. Если тип файловой системы корректен (иначе - сообщение об ошибке), то происходят некоторые вычисления (конкретно вычисляются: байт/сектор, сектор/кластер, байт/кластер), далее считывается таблица размещения файлов. Потом происходит обращение к процедуре, представленной на рисунке 1. Затем, происходит анализ флагов: таблица фрагментирована, зашифрована или сжата? Да - вывод ошибки. Нет - продолжение работы, а именно: вычисляем размеры таблицы размещения файлов, пропускаем системные файлы и переходим к основному циклу, представленному на следующей блок-схеме (рисунок 4).
* Рассмотрим блок-схему алгоритма основного цикла, представленную на рисунке 4:
Рисунок 4 - Основной цикл
Остановимся подробнее. Просматриваем подряд все ФЗ таблицы размещения файлов, начиная с 16. Файл помечен, как удаленный? Да - получаем атрибуты стандартной информации, нет - переходим к следующей ФЗ. Далее получаем необходимую информацию о файле.
Рассмотрим блок-схему алгоритма процедуры восстановления файла, представленную на рисунках 5 - 6:
Рисунок 5 - Восстановление файла
Рисунок 6 - Восстановление файла
Остановимся подробнее. Получаем адрес восстанавливаемого файла и handle устройства. Анализируем ФЗ. Она цела? Если да, то проверяем, является ли выбранный файл все еще удаленным. Затем пытаемся получить необходимую о файле информацию. Если не удалось получить информацию по дате и имени устанавливаем их по умолчанию. Проверяем файл. Он резидентный? Если да, то считываем данные, выводим окно информации и восстанавливаем файл. Если же файл нерезидентный, то необходимо "собрать его кусочки". Эти "кусочки" называются отрезками, а информация о них списком отрезков. Получив данные обо всех отрезках, выводим окно информации и восстанавливаем файл. Рассмотрим блок-схему алгоритма процедуры "чистки" имени файла, представленную на рисунке 7:
Рисунок 7 - Процедура "чистки" нового имени файла
Остановимся подробнее. Пользователь, задавая новое имя файла, может ввести символы, не позволяющие записать файл по заданному имени. Поэтому в программе была предусмотрена процедура "чистки" имени от подобных символов. Логически она проста. Просматриваем каждый символ имени. Если он совпадает с массивом некорректных символов - удаляем символ из имени.
* Рассмотрим блок-схему алгоритма процедуры копирования файла, представленную на рисунке 8:
Рисунок 8 - Процедура копирования
Остановимся подробнее. Проверяем выбор исходного файла. Если файл не выбран - выводим сообщение об ошибке. Иначе - проверяем задание имени нового файла. Имя не задано - ошибка. Задано - "чистим" имя от некорректных символов и записываем файл по указанному адресу. Предусмотрена ошибка совпадения директорий. То есть если такой файл по новому адрес уже существует. 3.4 Используемые технические средства
Для работы программы необходим персональный компьютер на базе процессора Intel с установленной ОС Windows XP/Vista/7, монитор, манипулятор типа "мышь", клавиатуру.
3.5 Вызов и загрузка
Программа устанавливается на компьютер запуском файла установки Восстановление и копирование.exe. После инсталляции программы ее можно запустить с помощью исполняемого файла "Восстановление и копирование".
3.6 Входные данные
1. Для восстановления удаленных файлов на логических дисках в качестве входных данных используются: * имя логического диска, содержащего удаленные файлы;
* удаленный файл.
2. Для копирования с одновременным переименованием с одного логического диска на другой в качестве входных данных используются:
* полное имя исходного файла;
* полное имя файла для копирования на новый диск.
3.7 Выходные данные
Выходными данными в программе являются результаты работы, выводимые на экран, а именно: таблица удаленных файлов, информация о восстанавливаемом файле, информация о восстановлении файла, вывод ошибок восстановления, информация о результате копирования файла, вывод ошибок копирования файла. Кроме того все действия программы отражаются в текстовом поле "Журнал".
4 ПРОГРАММА И МЕТОДИКА ИСПЫТАНИЙ
4.1 Объект испытаний
Объектом испытаний является программа, служащая для выполнения восстановления удаленных файлов на логических дисках, а также копирования с одновременным переименованием файла с одного логического диска на другой.
4.2 Цель испытаний
Целью испытаний является выявление возможных функциональных ошибок и сбоев, возникающих при работе данной программы, обеспечение их устойчивого функционирования в процессе эксплуатации и подтверждение работоспособности.
4.3 Требования к программе
В ходе тестирования необходимо проверить:
* правильность восстановления удаленного файла на логическом диске;
* правильность копирования с одновременным переименованием выбранного файла с одного логического диска на другой.
Программа должна:
* функционировать на любой ЭВМ, отвечающей техническим требованиям;
* восстанавливать удаленный файл на логическом диске с корректной для работы приложения файловой системой заданного диска;
* копировать выбранный файл с одного логического диска на другой (с обеспечением одновременного переименования);
* иметь файл справки.
В программе предусмотрен вывод следующих ошибок:
1) невозможность установления соединения между программой и диском;
2) неподдерживаемый тип файловой системы;
3) невозможность получения необходимых данных о файловой записи;
4) отсутствие удаленных файлов на выбранном диске;
5) отсутствие выбранного файла в списке удаленных;
6) отсутствие исходного для копирования файла;
7) отсутствие нового имени файла;
8) файл, выбранный для копирования, уже находится в выбранной директории.
4.4 Требования к программной документации
В программной документации должны присутствовать следующие разделы:
1. Введение
2. Техническое задание
3. Описание разработанной программы
4. Программа и методика испытаний
5. Эксплуатационные документы
6. Приложение (листинг программы с комментариями)
7. Список литературы
4.5 Средства и порядок испытаний
В процессе проведения испытаний использовалась конфигурация аппаратных средств, соответствующая разделу 3.4. На момент проведения испытаний использовалась следующая конфигурация аппаратных средств:
* ПК с процессором Intel(R) Pentium(r) CPU P6000 @ 1.87 GHz;
* объем ОЗУ - 3 Гб;
* видеоадаптер ATI Mobility Radeon HD 5470 Series 512 Мб;
* монитор Sony 15.5" TFT Зеркальный (Glare);
* клавиатура, мышь.
Из программных средств используется 64-разрядная операционная система Windows 7, полностью совместимая с указанной конфигурацией, система программирования Borland Delphi 7.
4.5.1 Тестирование методом "черного ящика"
Тестирование процедуры копирования файла будет проведено методом "черного ящика" с использованием способа разбиения по эквивалентности. Входными данными являются. Выделим следующие классы эквивалентности:
1. Попытка копирования не заданного файла (имя и путь исходного файла не выбраны).
2. Попытка копирования файла без задания его нового имени и полного пути.
3. Попытка копирования файла в директорию, уже содержащую файл с таким именем.
4. Попытка копирования файла в директорию, не содержащую файл с таким именем. Результаты тестирования методом "черного ящика" приведены в таблице 1:
Таблица 1. Тестирование методом "черного ящика"
№ те-стаКласс экви-валентнос-тиИсходные данныеОжидаемые результатыПолученные результаты11Попытка копирования не заданного файла (имя и путь исходного файла не выбраны).
Сообщение об ошибке.
Вывод ошибки в Журнал.
22Попытка копирования файла без задания его нового имени и полного пути.
Сообщение об ошибке.
Вывод ошибки в Журнал.
33Попытка копирования файла в директорию, уже содержащую файл с таким именем.
Сообщение об ошибке.
Вывод ошибки в Журнал.
44Попытка копирования файла в директорию, не содержащую файл с таким именем. Информационное сообщение об успешном копировании.
Вывод результатов корректной работы программы в Журнал.
Как видно из таблицы приведенных результатов, процедура восстановления удаленных файлов функционирует правильно. Все ожидаемые результаты совпали с полученными.
4.5.2 Тестирование методом "белого ящика"
Методом "белого ящика" будет проводиться тестирование процедуры копирования файла. Ниже приводится текст процедуры:
procedure TMainForm.Button3Click(Sender: TObject);
var
result: boolean;
FromFile, FileName,ToFile: string;
Ext, ExtName: string;
begin //выбран ли исходный файл
1. FromFile:=EditCopyFileName.Text;
ExtName:=ExtractFileName(EditPasteFileName.Text);
2. if FromFile='' then
begin
3. Log('Ошибка открытия исходного файла. Файл не выбран.', clred);
MessageBoxA(Handle,
Pchar('Файл не выбран!'+#13#10+'Выберите исходный файл.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end
else
begin
4. If (EditPasteFileName.Text='') or (ExtName='') then
begin
5. Log('Ошибка копирования. Не задано новое имя файла.', clred);
MessageBoxA(Handle,
Pchar('Не задано имя файла!'+#13#10+'Выберите новое имя файла.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST)
end
else
Begin
6. if pos('.',EditPasteFileName.Text)=0 then
begin
7. Ext:=ExtractFileExt(FromFile);
8. EditPasteFileName.Text:=(EditPasteFileName.Text+Ext);
FileName:=EditPasteFileName.Text;
9. FileName:=SanitizeString(FileName); //"чистка" имени
end;
10. ToFile:=EditPasteFileName.Text;
ToFile:=SanitizeString(ToFile);
11. result:=CopyFile(PChar(FromFile), PChar(ToFile), true);
12. If not result then begin
13. Log('Ошибка копирования файла. Такой файл уже существует.', clred);
MessageBoxA(Handle,
Pchar('Такой файл уже существует.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end
else
begin
14. Log('Файл скопирован.', clgreen);
Log('Имя исходного файла : '+FromFile, clBlue);
Log('Новое имя файла : '+ToFile, clBlue);
MessageBoxA(Handle,
Pchar('Файл скопирован!'),
Pchar('Информация'),
MB_ICONINFORMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
end;
end;
15. end;
Потоковый граф приведен на рисунке 9:
Рисунок 9 - Потоковый граф
Цикломатическая сложность графа может быть вычислена тремя способами:
1) V(G)=Число регионов потокового графа =4; 2) V(G)=E-N+2=17-15+2=4, где E - число дуг графа, N - количество его узлов; 3) V(G)=P+1=4+1=4, где Р - число предикатных узлов потокового графа.
Базовое множество путей графа приведено в таблице 2:
Таблица 2. Базовое множество путей графа
№ путиПуть11-2-3-1521-2-4-5-1531-2-4-6-7-8-9-10-11-12-13-1541-2-4-6-7-8-9-10-11-12-14-15Тестирование базового множества путей графа:
1) 1-2-3-15
Исходные данные: не задан исходный файл.
Ожидаемые результаты: сообщение об ошибке, вывод ошибки в Журнал.
Полученные результаты: сообщение об ошибке (рисунок 10), вывод ошибки в Журнал (рисунок 11).
Рисунок 10 - Ошибка выбора файла.
Рисунок 11 - Вывод в Журнал
2) 1-2-4-5-15
Исходные данные: исходный файл задан, не задано имя нового файла.
Ожидаемые результаты: сообщение об ошибке, вывод ошибки в Журнал.
Полученные результаты: сообщение об ошибке (рисунок 12), вывод ошибки в Журнал (рисунок 13).
Рисунок 12 - Ошибка
Рисунок 13 - Вывод ошибки в Журнал
3) 1-2-4-6-7-8-9-10-11-12-13-15
Исходные данные: выбран исходный файл, задано новое имя файла, новое имя файла является полным именем уже существующего файла.
Ожидаемые результаты: Сообщение об ошибки, вывод ошибки в Журнал.
Полученные результаты: Сообщение об ошибке (рисунок 14), вывод ошибки в Журнал (рисунок 15).
Рисунок 14 - Ошибка совпадения директорий
Рисунок 15 - Вывод ошибки в Журнал
4) 1-2-4-6-7-8-9-10-11-12-14-15
Исходные данные: выбран исходный файл, задано новое имя файла, новое имя файла не является полным именем уже существующего файла.
Ожидаемые результаты: Корректная работа программы. Вывод в Журнал результатов копирования.
Полученные результаты: Корректная работа программы (рисунок 16). Вывод в Журнал результатов копирования (рисунок 17).
Рисунок 16 - Корректная работа программы
Рисунок 17 - Вывод в Журнал результатов работы
5 ЭКСПЛУАТАЦИОННЫЕ ДОКУМЕНТЫ
5.1 Руководство программиста
5.1.1 Общие сведения о программе
Программа называется "Восстановление и копирование" и является многопоточным приложением, которое предназначено для выполнения восстановления удаленных файлов с логического диска, а также копирования с одновременным переименованием файла с одного логического диска на другой.
Программа позволяет пользователю вводить данные через программный интерфейс. Программа проста в использовании и рассчитана на средний уровень квалификации пользователя.
Программа разработана в среде программирования Delphi 7. Для корректного выполнения программы требуется ОС Windows XP/Vista/7.
5.1.2 Структура программы
Данная программа содержит пять модулей. Основным модулем является модуль Main, содержащий главную форму и все процедуры, необходимые для выполнения основных функций программы, модули Scan, Restore и Copy отвечают за сканирование диска на предмет удаленных файлов, восстановления удаленного файла и копирование выбранного файла на другой логический диск соответственно. Модуль FileDetails отвечает за вывод окна информации о восстанавливаемом файле. 5.1.3 Настройка программы
После установки программа требует для корректной работы запуска от имени администратора.
5.1.4 Проверка программы
Результаты тестирования программы приведены в разделе 4.5. При проведении дополнительных тестирований следует опираться на результаты этого раздела.
5.1.5 Дополнительные возможности программы
В качестве дополнительных возможностей программы стоит отметить, что она осуществляет копирование файлов не только с одного логического диска на другой, но и на другой физический диск. Восстановление файлов также возможно и на логических и на физических дисках с корректной для работы программы типом файловой системы. Вызов справки осуществляется при нажатии клавиши F1.
5.1.6 Сообщения системному программисту
В случае ошибки работы программы будет выдано одно из следующих сообщений.
Сообщение следующего типа (рисунок 18) выводится в случае, если не удалось установить соединение между программой и диском.
Рисунок 18 - Ошибка доступа к диску
При появлении такой ошибки (рисунок 18) необходимо выбрать другой диск.
Сообщение следующего типа (рисунок 19) выводится в случае, если выбранный диск имеет некорректный для работы программы тип файловой системы.
Рисунок 19 - Ошибка корректности типа файловой системы
При появлении такой ошибки (рисунок 19) необходимо выбрать другой диск с корректной файловой системой либо переформатировать выбранный диск.
Сообщение следующего типа (рисунок 20) выводится в случае, если на выбранном диске не было обнаружено удаленных файлов.
Рисунок 20 - Информационное сообщение
Появление такого сообщения (рисунок 21) означает, что на выбранном диске при сканировании диска программой не было обнаружено ни одного удаленного файла. Значит, для дальнейшей работы по восстановлению необходимо выбрать другой диск, либо завершить работу программы.
Сообщение следующего типа (рисунок 21) выводится в случае, если выбранный на восстановление файл больше не является удаленным.
Рисунок 21 - Ошибка восстановления файла
Появление такой ошибки (рисунок 21) означает, что файл, выбранный в списке удаленных, удаленным больше не является. Это может быть связано со следующей ситуацией: дважды было вызвано приложение на работу и просканирован один и тот же диск. В одном активном окне приложения этот файл был восстановлен. Таким образом, при попытке восстановления этого же файла в другом активном окне приложения, программа проверит, действительно ли он удален. В нашем случае, нет, а значит будет выдано такое информационное сообщение. Ответными действиями могут быть: выбор нового файла либо завершение работы приложения. Сообщение следующего типа (рисунок 22) выводится в случае, если при попытке копирования пользователем не был выбран исходный файл.
Рисунок 22 - Ошибка выбора исходного файла
При появлении такой ошибки (рисунок 22) необходимо задать полное имя исходного файла. Это можно сделать вручную или воспользоваться кнопкой выбора, расположенной рядом с полем ввода имени исходного файла.
Сообщение следующего типа (рисунок 23) выводится в случае, если при попытке копирования пользователем не было задано новое имя файла.
Рисунок 23 - Ошибка задания нового имени файла
При появлении такой ошибки (рисунок 23) необходимо задать полное имя нового файла (переименовать исходный с указанием конечной директории расположения). Это можно сделать вручную или воспользоваться кнопкой выбора, расположенной рядом с полем ввода имени исходного файла.
Сообщение следующего типа (рисунок 24) выводится в случае, если производится попытка скопировать файл в директорию, в которой такой файл уже существует.
Рисунок 24 - Ошибка совпадения директорий
При появлении такой ошибки (рисунок 24) необходимо выбрать новую конечную директорию для копирования файла либо указать ему другое имя.
5.2 Руководство оператора (пользователя)
5.2.1 Назначение и условия применения программы
Программа реализовывает следующие функции:
1. Восстановление удаленных файлов на логических дисках;
2. Копирование с одновременным переименованием заданного файла с одного логического диска на другой.
Также в программе предусмотрено ведение "журнала", то есть вывод в текстовое поле "Журнал" информации о работе программы.
Для полноценной работы программы необходим персональный компьютер на базе процессора Intel с установленной ОС Windows XP/Vista/7, монитор, манипулятор типа "мышь", клавиатуру.
5.2.2 Обращение к программе для запуска
Для установки программы следует запустить файл Восстановление и копирование.exe. После установки программу можно запустить вызовом соответствующего исполняемого файла "Восстановление и копирование" либо из меню Пуск -> Все программы -> Восстановление и копирование. 5.2.3 Входные и выходные данные
Для восстановления удаленных файлов на логических дисках в качестве входных данных используются: * имя логического диска, содержащего удаленные файлы;
* удаленный файл.
Для копирования с одновременным переименованием с одного логического диска на другой в качестве входных данных используются:
* полное имя исходного файла;
* полное имя файла для копирования на новый диск.
Выходными данными в программе являются результаты работы, выводимые на экран, а именно: таблица удаленных файлов, информация о восстанавливаемом файле, информация о восстановлении файла, вывод ошибок восстановления, информация о результате копирования файла, вывод ошибок копирования файла. Кроме того все действия программы отражаются в текстовом поле "Журнал".
5.2.4 Сообщения оператору
В случае ошибки работы программы будет выдано одно из следующих сообщений.
Сообщение следующего типа (рисунок 25) выводится в случае, если не удалось установить соединение между программой и диском.
Рисунок 25 - Ошибка доступа к диску
При появлении такой ошибки (рисунок 25) необходимо выбрать другой диск.
Сообщение следующего типа (рисунок 26) выводится в случае, если выбранный диск имеет некорректный для работы программы тип файловой системы.
Рисунок 26 - Ошибка корректности типа файловой системы
При появлении такой ошибки (рисунок 26) необходимо выбрать другой диск с корректной файловой системой либо переформатировать выбранный диск.
Сообщение следующего типа (рисунок 27) выводится в случае, если на выбранном диске не было обнаружено удаленных файлов.
Рисунок 27 - Информационное сообщение
Появление такого сообщения (рисунок 27) означает, что на выбранном диске при сканировании диска программой не было обнаружено ни одного удаленного файла. Значит, для дальнейшей работы по восстановлению необходимо выбрать другой диск, либо завершить работу программы.
Сообщение следующего типа (рисунок 28) выводится в случае, если выбранный на восстановление файл больше не является удаленным.
Рисунок 28 - Ошибка восстановления файла
Появление такой ошибки (рисунок 28) означает, что файл, выбранный в списке удаленных, удаленным больше не является. Это может быть связано со следующей ситуацией: дважды было вызвано приложение на работу и просканирован один и тот же диск. В одном активном окне приложения этот файл был восстановлен. Таким образом, при попытке восстановления этого же файла в другом активном окне приложения, программа проверит, действительно ли он удален. В нашем случае, нет, а значит будет выдано такое информационное сообщение. Ответными действиями могут быть: выбор нового файла либо завершение работы приложения. Сообщение следующего типа (рисунок 29) выводится в случае, если при попытке копирования пользователем не был выбран исходный файл.
Рисунок 29 - Ошибка выбора исходного файла
При появлении такой ошибки (рисунок 29) необходимо задать полное имя исходного файла. Это можно сделать вручную или воспользоваться кнопкой выбора, расположенной рядом с полем ввода имени исходного файла.
Сообщение следующего типа (рисунок 30) выводится в случае, если при попытке копирования пользователем не было задано новое имя файла.
Рисунок 30 - Ошибка задания нового имени файла
При появлении такой ошибки (рисунок 30) необходимо задать полное имя нового файла (переименовать исходный с указанием конечной директории расположения). Это можно сделать вручную или воспользоваться кнопкой выбора, расположенной рядом с полем ввода имени исходного файла.
Сообщение следующего типа (рисунок 30) выводится в случае, если производится попытка скопировать файл в директорию, в которой такой файл уже существует.
Рисунок 30 - Ошибка совпадения директорий
При появлении такой ошибки (рисунок 30) необходимо выбрать новую конечную директорию для копирования файла либо указать ему другое имя.
6 ПРИЛОЖЕНИЕ
В данном разделе приведены исходные тексты всех модулей программы.
Листинг основного модуля программы Main:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileDetails, XPMan, ComCtrls, Grids, ValEdit, ExtCtrls, Buttons,
Copy, Restore, Scan;
type
TDynamicCharArray = array of Char;
type // структура данных отвечающая за последовательность загрузки диска
TBOOT_SEQUENCE = packed record
_jmpcode : array[1..3] of Byte;
cOEMID: array[1..8] of Char;
wBytesPerSector: Word;
bSectorsPerCluster: Byte;
wSectorsReservedAtBegin: Word;
Mbz1: Byte;
Mbz2: Word;
Reserved1: Word;
bMediaDescriptor: Byte;
Mbz3: Word;
wSectorsPerTrack: Word;
wSides: Word;
dwSpecialHiddenSectors: DWord;
Reserved2: DWord;
Reserved3: DWord;
TotalSectors: Int64;
MftStartLcn: Int64;
Mft2StartLcn: Int64;
ClustersPerFileRecord: DWord;
ClustersPerIndexBlock: DWord;
VolumeSerialNumber: Int64;
_loadercode: array[1..430] of Byte;
wSignature: Word;
end;
type
TNTFS_RECORD_HEADER = packed record
Identifier: array[1..4] of Char;
UsaOffset : Word;
UsaCount : Word;
LSN : Int64;
end;
type
TFILE_RECORD = packed record
Header: TNTFS_RECORD_HEADER;
SequenceNumber : Word;
ReferenceCount : Word;
AttributesOffset : Word;
Flags : Word; // $0000 = удалено, $0001 = неиспользовано, $0002 = каталог
BytesInUse : DWord;
BytesAllocated : DWord;
BaseFileRecord : Int64;
NextAttributeID : Word;
end;
type
TRECORD_ATTRIBUTE = packed record //атрибуты записи
AttributeType : DWord;
Length : DWord;
NonResident : Byte;
NameLength : Byte;
NameOffset : Word;
Flags : Word;
AttributeNumber : Word;
end;
type
TRESIDENT_ATTRIBUTE = packed record
Attribute : TRECORD_ATTRIBUTE;
ValueLength : DWord;
ValueOffset : Word;
Flags : Word;
end;
type
TNONRESIDENT_ATTRIBUTE = packed record
Attribute: TRECORD_ATTRIBUTE;
LowVCN: Int64;
HighVCN: Int64;
RunArrayOffset : Word;
CompressionUnit : Byte;
Padding : array[1..5] of Byte;
AllocatedSize: Int64;
DataSize: Int64;
InitializedSize: Int64;
CompressedSize: Int64;
end;
type
TFILENAME_ATTRIBUTE = packed record //атрибуты имени файла
Attribute: TRESIDENT_ATTRIBUTE;
DirectoryFileReferenceNumber: Int64;
CreationTime: Int64;
ChangeTime: Int64;
LastWriteTime: Int64;
LastAccessTime: Int64;
AllocatedSize: Int64;
DataSize: Int64;
FileAttributes: DWord;
AlignmentOrReserved: DWord;
NameLength: Byte;
NameType: Byte;
Name: Word;
end;
type
TSTANDARD_INFORMATION = packed record //общая информация
Attribute: TRESIDENT_ATTRIBUTE;
CreationTime: Int64;
ChangeTime: Int64;
LastWriteTime: Int64;
LastAccessTime: Int64;
FileAttributes: DWord;
Alignment: array[1..3] of DWord;
QuotaID: DWord;
SecurityID: DWord;
QuotaCharge: Int64;
USN: Int64;
end;
{интерфейс}
type
TMainForm = class(TForm)
DriveComboBox: TComboBox;
LogLbl: TLabel;
LogMemo: TRichEdit;
WaitMsg: TPanel;
FoundFilesStringGrid: TStringGrid;
SaveDialog: TSaveDialog;
Drive_Background: TShape;
Drive_Title: TLabel;
Drive_SerialLbl: TLabel;
Drive_SizeLbl: TLabel;
Drive_NameLbl: TLabel;
Drive_BackgroundSeparator: TShape;
ScannedFiles_BackgroundSeparator: TShape;
RecoverBtn: TBitBtn;
Shape1: TShape;
Label1: TLabel;
EditCopyFileName: TEdit;
Label2: TLabel;
EditPasteFileName: TEdit;
Label3: TLabel;
Button1: TButton;
Button3: TButton;
OpenDialog1: TOpenDialog;
Button2: TButton;
SaveDialog1: TSaveDialog;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
ScanBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure ChangeUIEnableStatus(EnableControls: boolean; MaskList: boolean=false);
procedure DriveComboBoxChange(Sender: TObject);
procedure Log(Item: string; ItemColor: TColor=clBlack);
procedure LogChange(Sender: TObject);
procedure SortStringGrid(var GenStrGrid: TStringGrid; ThatCol: Integer);
function FindAttributeByType(RecordData: TDynamicCharArray; AttributeType: DWord;
FindSpecificFileNameSpaceValue: boolean=false) : TDynamicCharArray;
procedure FixupUpdateSequence(var RecordData: TDynamicCharArray);
procedure RecoverBtnClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FoundFilesStringGridClick(Sender: TObject);
function SanitizeString(str:string):string;
procedure Button2Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure ScanBtnClick(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
public
ThreadCopy: TThreadCopy;
ThreadRestore: TThreadRestore;
ThreadScan: TThreadScan;
end;
{глобальные переменные и константы}
const
atAttributeStandardInformation = $10;
atAttributeFileName = $30;
atAttributeData = $80;
var
MainForm: TMainForm;
BytesPerFileRecord: Word;
BytesPerCluster: Word;
BytesPerSector: Word;
SectorsPerCluster: Word;
CURRENT_DRIVE: string; // Выбранное устройство
MASTER_FILE_TABLE_LOCATION : Int64;
MASTER_FILE_TABLE_END : Int64;
MASTER_FILE_TABLE_SIZE : Int64;
MASTER_FILE_TABLE_RECORD_COUNT : integer;
DEBUG_FOLDER_LOCATION : string;
SEARCHING_FLAG : boolean;
implementation
{$R *.dfm}
{инициализируем компоненты формы и глобальные переменные}
procedure TMainForm.FormCreate(Sender: TObject);
var
i: integer;
Bits: set of 0..25;
ValidDrives: TStrings;
tmpStr: string;
begin
DEBUG_FOLDER_LOCATION := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName))+'Debug\';
ForceDirectories(DEBUG_FOLDER_LOCATION); // Обновление устройств в ComboBox
ValidDrives := TStringList.Create; // Создаем список
try
integer(Bits) := GetLogicalDrives; // Получаем логические диски
for i := 0 to 25 do begin
tmpStr := Char(i+Ord('A'))+':'; // пробегаем все буквы алфавита
if (i in Bits) and (((GetDriveType(Pchar(tmpStr+'\'))=DRIVE_FIXED) or (GetDriveType(Pchar(tmpstr+'\'))=DRIVE_REMOVABLE))) then ValidDrives.Append(tmpStr);
end; // Получаем типы логическов дисков
DriveComboBox.Items.Assign(ValidDrives); // Связка диска с перемнной
if DriveComboBox.Items.Count<>0 then DriveComboBox.ItemIndex := 0;
Log('Список дисков обновлен', clGreen); //вывод в Журнал
finally
FreeAndNil(ValidDrives); //освобождаем переменную
end;
// стилизуем StringGrid
with FoundFilesStringGrid do begin
RowCount := 1;
Rows[0].Text := ('Положение записи'+#13#10+'Имя файла'+#13#10+
'Размер (Байт)'+#13#10+'Дата создания'+#13#10+'Дата последнего изменения');
end;
// предотвращаем повторный поиск
SEARCHING_FLAG := false; // Флаг поиска
end;
procedure TMainForm.FoundFilesStringGridClick(Sender: TObject);
begin
end;
// Получение информации об устройствах
function GetVolumeLabel(Drive: Char): string;
var
unused, flags: DWord;
buffer: array [0..MAX_PATH] of Char;
begin
buffer[0] := #$00;
if GetVolumeInformation(PChar(Drive + ':\'), buffer, DWord(sizeof(buffer)),nil,unused,flags,nil,0) then
SetString(result, buffer, StrLen(buffer))
else result := '';
end;
// Конвертер времени
function Int64TimeToDateTime(aFileTime: Int64): TDateTime;
var
UTCTime, LocalTime: TSystemTime;
begin
FileTimeToSystemTime( TFileTime(aFileTime), UTCTime);
SystemTimeToTzSpecificLocalTime(nil, UTCTime, LocalTime);
result := SystemTimeToDateTime(LocalTime);
end;
// Графический интерфейс и все что с ним связано
procedure TMainForm.ChangeUIEnableStatus(EnableControls, MaskList: boolean); //доступность кнопок
begin
ScanBtn.Enabled := EnableControls;
DriveComboBox.Enabled := EnableControls;
RecoverBtn.Enabled := EnableControls;
FoundFilesStringGrid.Enabled := EnableControls;
FoundFilesStringGrid.Visible := (not MaskList);
if EnableControls then LogLbl.Caption := '';
SEARCHING_FLAG := not EnableControls;
end;
procedure TMainForm.DriveComboBoxChange(Sender: TObject);
var
VolumeLabel: string;
begin
VolumeLabel := DriveComboBox.Text;
VolumeLabel := GetVolumeLabel(VolumeLabel[1]);
if VolumeLabel <> '' then Drive_NameLbl.Caption := 'Метка : '+VolumeLabel
else Drive_NameLbl.Caption := 'Метка : неизвестна';
Drive_SerialLbl.Caption := 'Серия : неизвестна';
Drive_SizeLbl.Caption := 'Размер : неизвестен';
FoundFilesStringGrid.RowCount := 1;
end;
// Вывод в Журнал
procedure TMainForm.Log(Item: string; ItemColor:TColor=clBlack);
var
i1, i2, i3 : integer;
Date : string;
begin
i1 := Length(LogMemo.Lines.Text);
Date := DateTimeToStr(now)+' | ';
i2 := i1 + Length(Date);
LogMemo.Lines.Add(Date+Item);
i3 := Length(LogMemo.Lines.Text);
LogMemo.SelStart := i1;
LogMemo.SelLength := i2-i1;
LogMemo.SelAttributes.Color := clblack;
LogMemo.SelStart := i2;
LogMemo.SelLength := i3-i2;
LogMemo.SelAttributes.Color := ItemColor;
LogMemo.SelStart := i3;
SendMessage(LogMemo.Handle,WM_VScroll,SB_LINEDOWN,0); // Посылает сообщения для взаимодействия с ОС
end;
procedure TMainForm.LogChange(Sender: TObject);
begin
LogMemo.Lines.SaveToFile(DEBUG_FOLDER_LOCATION+'LOG.RTF');
end;
// Сортировки
procedure TMainForm.SortStringGrid(var GenStrGrid: TStringGrid; ThatCol: Integer);
const
SeparatorChar = '@'; //разделитель
var
CountItem, i, j, k, PositionIndex: integer;
TmpList: TStringList;
TmpStr1, TmpStr2: string;
begin
CountItem := GenStrGrid.RowCount; // Получить число строк
TmpList := TStringList.Create;
TmpList.Sorted := False;
try
begin
for i := 1 to (CountItem - 1) do
TmpList.Add(GenStrGrid.Rows[i].Strings[ThatCol] + SeparatorChar + GenStrGrid.Rows[i].Text); //формируем временный список для сортировки
TmpList.Sort; //сортируем временный список
for k := 1 to TmpList.Count do
begin
TmpStr1 := TmpList.Strings[(k - 1)];
PositionIndex := Pos(SeparatorChar, TmpStr1);
TmpStr2 := '';
TmpStr2 := Copy(TmpStr1, (PositionIndex + 1), Length(TmpStr1));
TmpList.Strings[(k - 1)] := '';
TmpList.Strings[(k - 1)] := TmpStr2;
end;
for j := 1 to (CountItem - 1) do
GenStrGrid.Rows[j].Text := TmpList.Strings[(j - 1)]; //заносим отсортированный список обратно в таблицу
end;
finally
TmpList.Free;
end;
end;
function TMainForm.FindAttributeByType(RecordData: TDynamicCharArray; AttributeType: DWord;
FindSpecificFileNameSpaceValue: boolean=false) : TDynamicCharArray; // функция поиска атрибутов по типу атрибутов
var
pFileRecord: ^TFILE_RECORD;
pRecordAttribute: ^TRECORD_ATTRIBUTE;
NextAttributeOffset: Word;
TmpRecordData: TDynamicCharArray;
TotalBytes: Word;
begin
New(pFileRecord);
ZeroMemory(pFileRecord, SizeOf(TFILE_RECORD));
CopyMemory(pFileRecord, RecordData, SizeOf(TFILE_RECORD));
if pFileRecord.Header.Identifier[1] + pFileRecord.Header.Identifier[2]
+ pFileRecord.Header.Identifier[3] + pFileRecord.Header.Identifier[4]<>'FILE' then begin
NextAttributeOffset := 0;
end else begin
NextAttributeOffset := pFileRecord^.AttributesOffset; end;
TotalBytes := Length(RecordData);
Dispose(pFileRecord);
New(pRecordAttribute);
ZeroMemory(pRecordAttribute, SizeOf(TRECORD_ATTRIBUTE));
SetLength(TmpRecordData,TotalBytes-(NextAttributeOffset-1));
TmpRecordData := Copy(RecordData,NextAttributeOffset,TotalBytes-(NextAttributeOffset-1));
CopyMemory(pRecordAttribute, TmpRecordData, SizeOf(TRECORD_ATTRIBUTE));
while (pRecordAttribute^.AttributeType <> $FFFFFFFF) and
(pRecordAttribute^.AttributeType <> AttributeType) do begin
NextAttributeOffset := NextAttributeOffset + pRecordAttribute^.Length;
SetLength(TmpRecordData,TotalBytes-(NextAttributeOffset-1));
TmpRecordData := Copy(RecordData,NextAttributeOffset,TotalBytes-(NextAttributeOffset-1));
CopyMemory(pRecordAttribute, TmpRecordData, SizeOf(TRECORD_ATTRIBUTE));
end;
if pRecordAttribute^.AttributeType = AttributeType then begin
if (FindSpecificFileNameSpaceValue) and (AttributeType=atAttributeFileName) then begin
if (TmpRecordData[$59]=Char($0)) {POSIX} or (TmpRecordData[$59]=Char($1)) {Win32}
or (TmpRecordData[$59]=Char($3)) {Win32&DOS} then begin
SetLength(result,pRecordAttribute^.Length);
result := Copy(TmpRecordData,0,pRecordAttribute^.Length);
end else begin
NextAttributeOffset := NextAttributeOffset + pRecordAttribute^.Length;
SetLength(TmpRecordData,TotalBytes-(NextAttributeOffset-1));
TmpRecordData := Copy(RecordData,NextAttributeOffset,TotalBytes-(NextAttributeOffset-1));
result := FindAttributeByType(TmpRecordData,AttributeType,true);
end;
end else begin
SetLength(result,pRecordAttribute^.Length);
result := Copy(TmpRecordData,0,pRecordAttribute^.Length);
end;
end else begin
result := nil;
end;
Dispose(pRecordAttribute);
end;
//процедура проверки возможности "обрыва записи"
procedure TMainForm.FixupUpdateSequence(var RecordData: TDynamicCharArray);
var
pFileRecord: ^TFILE_RECORD;
UpdateSequenceOffset, UpdateSequenceCount: Word;
UpdateSequenceNumber: array[1..2] of Char;
i: integer;
begin
New(pFileRecord);
ZeroMemory(pFileRecord, SizeOf(TFILE_RECORD));
CopyMemory(pFileRecord, RecordData, SizeOf(TFILE_RECORD));
with pFileRecord^.Header do begin
if Identifier[1]+Identifier[2]+Identifier[3]+Identifier[4] <> 'FILE' then begin
Dispose(pFileRecord);
end;
end;
UpdateSequenceOffset := pFileRecord^.Header.UsaOffset;
UpdateSequenceCount := pFileRecord^.Header.UsaCount;
Dispose(pFileRecord);
UpdateSequenceNumber[1] := RecordData[UpdateSequenceOffset];
UpdateSequenceNumber[2] := RecordData[UpdateSequenceOffset+1];
for i:=1 to UpdateSequenceCount-1 do begin
if (RecordData[i*BytesPerSector-2] <> UpdateSequenceNumber[1])
and (RecordData[i*BytesPerSector-1] <> UpdateSequenceNumber[2]) then begin
Log('Предупреждение: Некорректные данные записи: Сектор №'+IntToStr(i)+' может быть поврежден!', clMaroon);
MessageBoxA(Handle,
Pchar('Предупреждение : Некорректные данные записи: Сектор №'+IntToStr(i)+' может быть поврежден!'+
#13#10+'Процесс не будет заверщен.'),
Pchar('Предупреждение'),
MB_ICONEXCLAMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
RecordData[i*BytesPerSector-2] := RecordData[UpdateSequenceOffset+2*i];
RecordData[i*BytesPerSector-1] := RecordData[UpdateSequenceOffset+1+2*i];
end;
end;
// Восстанавливаем файл согласно его расположению в таблице размещения файлов
procedure TMainForm.RecoverBtnClick(Sender: TObject);
begin
ThreadRestore:=TThreadRestore.create(false);
ThreadRestore.Priority:=tpLowest;
end;
procedure TMainForm.Button1Click(Sender: TObject);
begin
OpenDialog1.Execute;
EditCopyFileName.Text := OpenDialog1.FileName;
end;
function TMainForm.SanitizeString(str:string) : string; //функция "чистки" имени
var
InvalidCharacters : array[0..5] of char;
i: integer;
ch: char;
S: string;
Flags: TReplaceFlags;
begin
InvalidCharacters[0]:='*';
InvalidCharacters[1]:='?';
InvalidCharacters[2]:='"';
InvalidCharacters[3]:='<';
InvalidCharacters[4]:='>';
InvalidCharacters[5]:='|';
Flags:= [ rfReplaceAll, rfIgnoreCase ];
S:= str;
for i:= 0 to (Length(InvalidCharacters)-1) do
begin
ch:=InvalidCharacters[i];
S:= StringReplace( S, ch, '', Flags);
end;
Result:=S;
end;
procedure TMainForm.Button3Click(Sender: TObject);
begin
ThreadCopy:=TThreadCopy.create(false);
ThreadCopy.Priority:=tpLowest;
end;
procedure TMainForm.Button2Click(Sender: TObject);
begin
SaveDialog1.Execute;
EditPasteFileName.Text := SaveDialog1.FileName;
end;
procedure TMainForm.Button8Click(Sender: TObject);
begin
close;
end;
procedure TMainForm.ScanBtnClick(Sender: TObject);
begin
ThreadScan:=TThreadScan.create(false);
ThreadScan.Priority:=tpLowest;
end;
procedure TMainForm.Button5Click(Sender: TObject);
begin
try
ThreadScan.Suspend;
finally
end;
end;
procedure TMainForm.Button6Click(Sender: TObject);
begin
try
ThreadScan.Resume;
finally
end;
end;
end.
Листинг модуля Scan:
Unit Scan;
interface
uses
Classes, Windows, Messages, SysUtils, Variants, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileDetails, XPMan, ComCtrls, Grids, ValEdit, ExtCtrls, Buttons;
type
TThreadScan = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
uses
Main;
function Int64TimeToDateTime(aFileTime: Int64): TDateTime;
var
UTCTime, LocalTime: TSystemTime;
begin
FileTimeToSystemTime( TFileTime(aFileTime), UTCTime);
SystemTimeToTzSpecificLocalTime(nil, UTCTime, LocalTime);
result := SystemTimeToDateTime(LocalTime);
end;
function GetVolumeLabel(Drive: Char): string;
var
unused, flags: DWord;
buffer: array [0..MAX_PATH] of Char;
begin
buffer[0] := #$00;
if GetVolumeInformation(PChar(Drive + ':\'), buffer, DWord(sizeof(buffer)),nil,unused,flags,nil,0) then
SetString(result, buffer, StrLen(buffer))
else result := '';
end;
procedure TThreadScan.Execute;
var
hDevice, hDest : THandle;
BootData: array[1..512] of Char;
MFTData: TDynamicCharArray;
MFTAttributeData: TDynamicCharArray;
StandardInformationAttributeData: TDynamicCharArray;
FileNameAttributeData: TDynamicCharArray;
DataAttributeHeader: TDynamicCharArray;
dwread: LongWord;
dwwritten: LongWord;
pBootSequence: ^TBOOT_SEQUENCE;
pFileRecord: ^TFILE_RECORD;
pMFTNonResidentAttribute : ^TNONRESIDENT_ATTRIBUTE;
pStandardInformationAttribute : ^TSTANDARD_INFORMATION;
pFileNameAttribute : ^TFILENAME_ATTRIBUTE;
pDataAttributeHeader: ^TRECORD_ATTRIBUTE;
CurrentRecordCounter: integer; //счетчик записи
CurrentRecordLocator: Int64; //адрес записи
FileName: WideString;
FileCreationTime, FileChangeTime: TDateTime;
FileParentDirectoryRecordNumber: Int64;
FileSize: Int64;
FileSizeArray : TDynamicCharArray;
i: integer;
begin
// обновляем текущий диск
CURRENT_DRIVE := MainForm.DriveComboBox.Text;
if CURRENT_DRIVE = '' then begin
MessageBoxA(Handle,
Pchar('Диск не обнаружен!'+#13#10+'Продолжение невозможно.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
exit;
end else begin
MainForm.Log('Сбор информации о диске '+CURRENT_DRIVE+'\ ...'); // вывод в Журнал
MainForm.LogLbl.Caption := 'Сбор информации о диске '+CURRENT_DRIVE+'\ ...';
end;
// Изменение доступности кнопок
MainForm.ChangeUIEnableStatus(false,true);
// установление соединения между приложением и диском
hDevice := CreateFile( PChar('\\.\'+CURRENT_DRIVE), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hDevice = INVALID_HANDLE_VALUE) then begin
MainForm.Log('Ошибка доступа к диску : ошибка '+IntToStr(GetLastError()), clred);
MessageBoxA(Handle,
Pchar('Ошибка доступа к диску '+#13#10+' Ошибка '+IntToStr(GetLastError())),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Closehandle(hDevice);
MainForm.ChangeUIEnableStatus(true); //кнопки доступны
exit;
end else begin
MainForm.Log('Диск '+CURRENT_DRIVE+'\ успешно открыт', clgreen);
end;
//считываем загрузочную запись
New(PBootSequence);
ZeroMemory(PBootSequence, SizeOf(TBOOT_SEQUENCE)); // освобождение памяти
SetFilePointer(hDevice, 0, nil, FILE_BEGIN);
ReadFile(hDevice,PBootSequence^, 512,dwread,nil);
// Обновляем "свойства диска"
MainForm.Drive_NameLbl.Caption := 'Метка : '+GetVolumeLabel(CURRENT_DRIVE[1]);
MainForm.Drive_SerialLbl.Caption := 'Серия : '+IntToHex(PBootSequence.VolumeSerialNumber,8);
MainForm.Log('Прочитаны данные из загрузочной записи : '+IntToStr(dwread)+' Байт', clblue);
// Проверка типа файловой системы
with PBootSequence^ do begin
if (cOEMID[1]+cOEMID[2]+cOEMID[3]+cOEMID[4] <> 'NTFS') then begin
MessageBoxA(Handle,
Pchar('Некорректный тип файловой системы!'+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
MainForm.Log('Ошибка : некорретный тип файловой системы !', clred);
Dispose(PBootSequence);
Closehandle(hDevice);
MainForm.ChangeUIEnableStatus(true);
exit;
end else begin
MainForm.Log('Тип файловой системы корректен.', clGreen);
end;
end;
// Вычисление соотношений
BytesPerSector := PBootSequence^.wBytesPerSector;
SectorsPerCluster := PBootSequence^.bSectorsPerCluster;
BytesPerCluster := SectorsPerCluster * BytesPerSector;
MainForm.Log('Байт на сектор : '+IntToStr(BytesPerSector));
MainForm.Log('Секторов на кластер : '+IntToStr(SectorsPerCluster));
MainForm.Log('Байт на кластер : '+IntToStr(BytesPerCluster));
// Обновляем "свойства диска"
MainForm.Drive_SizeLbl.Caption := 'Размер : '+IntToStr(PBootSequence.TotalSectors*BytesPerSector)+' байт';
if (PBootSequence^.ClustersPerFileRecord < $80) then
BytesPerFileRecord := PBootSequence^.ClustersPerFileRecord * BytesPerCluster
else
BytesPerFileRecord := 1 shl ($100 - PBootSequence^.ClustersPerFileRecord);
MainForm.Log('Байт на файловую запись : '+IntToStr(BytesPerFileRecord));
MASTER_FILE_TABLE_LOCATION := PBootSequence^.MftStartLcn * PBootSequence^.wBytesPerSector
* PBootSequence^.bSectorsPerCluster;
MainForm.Log('Адрес таблицы размещения файлов : $'+IntToHex(MASTER_FILE_TABLE_LOCATION,2));
// Обновляем "свойства диска"
SetLength(MFTData,BytesPerFileRecord);
SetFilePointer(hDevice, Int64Rec(MASTER_FILE_TABLE_LOCATION).Lo,
@Int64Rec(MASTER_FILE_TABLE_LOCATION).Hi, FILE_BEGIN);
Readfile(hDevice, PChar(MFTData)^, BytesPerFileRecord, dwread, nil);
MainForm.Log('Таблица размещения файлов считана : '+IntToStr(dwread)+' Байт', clBlue);
try
MainForm.FixupUpdateSequence(MFTData);
except on E: Exception do begin
MainForm.Log('Ошибка : '+E.Message, clred);
MessageBoxA(Handle,
Pchar(E.Message+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Closehandle(hDevice);
MainForm.ChangeUIEnableStatus(true);
exit;
end;
end;
//Log('MFT Data FixedUp');
MFTAttributeData := MainForm.FindAttributeByType(MFTData,atAttributeData);
New(pMFTNonResidentAttribute);
ZeroMemory(pMFTNonResidentAttribute, SizeOf(TNONRESIDENT_ATTRIBUTE));
CopyMemory(pMFTNonResidentAttribute, MFTAttributeData, SizeOf(TNONRESIDENT_ATTRIBUTE));
if (pMFTNonResidentAttribute^.Attribute.Flags = $8000)
or (pMFTNonResidentAttribute^.Attribute.Flags = $4000)
or (pMFTNonResidentAttribute^.Attribute.Flags = $0001) then begin
MessageBoxA(Handle,
Pchar('Таблица размещения файлов фрагментирована, зашифрована или сжата.'+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
MainForm.Log('Ошибка : Таблица размещения файлов фрагментирована : Невозможно продолжить.', clRed);
Dispose(pMFTNonResidentAttribute);
MainForm.ChangeUIEnableStatus(true);
exit;
end;
MASTER_FILE_TABLE_SIZE := pMFTNonResidentAttribute^.HighVCN - pMFTNonResidentAttribute^.LowVCN; //вычисление размеров таблицы расположения файлов
Dispose(pMFTNonResidentAttribute);
MASTER_FILE_TABLE_END := MASTER_FILE_TABLE_LOCATION + MASTER_FILE_TABLE_SIZE;
MASTER_FILE_TABLE_RECORD_COUNT := (MASTER_FILE_TABLE_SIZE * BytesPerCluster) div BytesPerFileRecord;
MainForm.Log('Размер таблицы размещения файлов : '+IntToStr(MASTER_FILE_TABLE_SIZE)+' Кластеров');
MainForm.Log('Количество записей : '+IntToStr(MASTER_FILE_TABLE_RECORD_COUNT));
MainForm.Log('Сканирование удаленных файлов, пожалуйста подождите...');
// Пропускаем записи системных файлов
MainForm.LogLbl.Caption := 'Анализ файловой записи '+IntToStr(MASTER_FILE_TABLE_RECORD_COUNT);
Application.ProcessMessages;
// Очищаем список найденных файлов
MainForm.FoundFilesStringGrid.RowCount := 1;
//Основной цикл
for CurrentRecordCounter := 16 to MASTER_FILE_TABLE_RECORD_COUNT-1 do begin
if (CurrentRecordCounter mod 512) = 0 then begin // Обновляем счетчик каждые 512 записей
MainForm.LogLbl.Caption := 'Анализируем файловую запись '+IntToStr(CurrentRecordCounter)+' из '
+IntToStr(MASTER_FILE_TABLE_RECORD_COUNT);
Application.ProcessMessages;
end;
CurrentRecordLocator := MASTER_FILE_TABLE_LOCATION + CurrentRecordCounter*BytesPerFileRecord;
// Распределение памяти. Подготавливаем буферной структуру, содержащую каждую файловую запись
SetLength(MFTData,BytesPerFileRecord);
SetFilePointer(hDevice, Int64Rec(CurrentRecordLocator).Lo,
@Int64Rec(CurrentRecordLocator).Hi, FILE_BEGIN);
Readfile(hDevice, PChar(MFTData)^, BytesPerFileRecord, dwread, nil);
try
MainForm.FixupUpdateSequence(MFTData);
except on E: Exception do begin
MainForm.Log('Предупреждение : файловая запись '+IntToStr(CurrentRecordCounter)+' из '
+IntToStr(MASTER_FILE_TABLE_RECORD_COUNT-1)+' : '+E.Message, clMaroon);
continue;
end;
end;
New(pFileRecord);
ZeroMemory(pFileRecord, SizeOf(TFILE_RECORD));
CopyMemory(pFileRecord, MFTData, SizeOf(TFILE_RECORD));
if pFileRecord^.Flags=$0 then begin // Если файл помечен как удаленный
StandardInformationAttributeData := MainForm.FindAttributeByType(MFTData, atAttributeStandardInformation);
if StandardInformationAttributeData<>nil then begin
New(pStandardInformationAttribute);
ZeroMemory(pStandardInformationAttribute, SizeOf(TSTANDARD_INFORMATION));
CopyMemory(pStandardInformationAttribute, StandardInformationAttributeData,
SizeOf(TSTANDARD_INFORMATION));
// Задаем переменные времени создания и последнего изменения файла
FileCreationTime := Int64TimeToDateTime(pStandardInformationAttribute^.CreationTime);
FileChangeTime := Int64TimeToDateTime(pStandardInformationAttribute^.ChangeTime);
Dispose(pStandardInformationAttribute);
end else begin
continue;
end;
FileNameAttributeData := MainForm.FindAttributeByType(MFTData, atAttributeFileName, true);
if FileNameAttributeData<>nil then begin
New(pFileNameAttribute);
ZeroMemory(pFileNameAttribute, SizeOf(TFILENAME_ATTRIBUTE));
CopyMemory(pFileNameAttribute, FileNameAttributeData, SizeOf(TFILENAME_ATTRIBUTE));
// Получаем имя файла, которое начинается со смещения $5A
FileName := WideString(Copy(FileNameAttributeData, $5A, pFileNameAttribute^.NameLength*2));
Dispose(pFileNameAttribute);
end else begin
continue;
end;
DataAttributeHeader := MainForm.FindAttributeByType(MFTData, atAttributeData);
if DataAttributeHeader<>nil then begin
New(pDataAttributeHeader);
ZeroMemory(pDataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
CopyMemory(pDataAttributeHeader, DataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
FileSizeArray := Copy(DataAttributeHeader, $10+(pDataAttributeHeader^.NonResident)*$20,
(pDataAttributeHeader^.NonResident+$1)*$4 );
FileSize := 0;
for i:=Length(FileSizeArray)-1 downto 0 do FileSize := (FileSize shl 8)+Ord(FileSizeArray[i]);
Dispose(pDataAttributeHeader);
end else begin
continue;
end;
MainForm.FoundFilesStringGrid.RowCount := MainForm.FoundFilesStringGrid.RowCount + 1;
MainForm.FoundFilesStringGrid.Rows[MainForm.FoundFilesStringGrid.RowCount-1].Text :=
('$'+IntToHex(CurrentRecordLocator,2)+#13#10
+FileName+#13#10
+IntToStr(FileSize)+#13#10
+FormatDateTime('c',FileCreationTime)+#13#10
+FormatDateTime('c',FileChangeTime));
end;
Dispose(pFileRecord);
end;
MainForm.Log('Все файловые записи проанализированы ('+IntToStr(MASTER_FILE_TABLE_RECORD_COUNT)+')',clGreen);
Application.ProcessMessages;
If MainForm.FoundFilesStringGrid.RowCount > 1 then
MainForm.FoundFilesStringGrid.FixedRows := 1;
MainForm.ChangeUIEnableStatus(true);
Dispose(PBootSequence);
Closehandle(hDevice);
end;
end.
Листинг модуля Restore:
unit Restore;
interface
uses
Classes, Windows, Messages, SysUtils, Variants, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileDetails, XPMan, ComCtrls, Grids, ValEdit, ExtCtrls, Buttons;
type
TThreadRestore = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure Log(Item: string; ItemColor: TColor=clBlack);
end;
implementation
uses
Main;
procedure TThreadRestore.Log(Item: string; ItemColor: TColor=clBlack);
begin
MainForm.Log(Item, ItemColor);
end;
function Int64TimeToDateTime(aFileTime: Int64): TDateTime;
var
UTCTime, LocalTime: TSystemTime;
begin
FileTimeToSystemTime( TFileTime(aFileTime), UTCTime);
SystemTimeToTzSpecificLocalTime(nil, UTCTime, LocalTime);
result := SystemTimeToDateTime(LocalTime);
end;
procedure TThreadRestore.Execute;
var
RecordLocator: Int64;
hDevice, hDest : THandle;
MFTFileRecord: TDynamicCharArray;
StandardInformationAttributeData: TDynamicCharArray;
FileNameAttributeData: TDynamicCharArray;
DataAttributeHeader: TDynamicCharArray;
ResidentDataAttributeData: TDynamicCharArray;
NonResidentDataAttributeData: TDynamicCharArray;
pFileRecord: ^TFILE_RECORD;
pStandardInformationAttribute : ^TSTANDARD_INFORMATION;
pFileNameAttribute : ^TFILENAME_ATTRIBUTE;
pDataAttributeHeader : ^TRECORD_ATTRIBUTE;
pResidentDataAttribute : ^TRESIDENT_ATTRIBUTE;
pNonResidentDataAttribute : ^TNONRESIDENT_ATTRIBUTE;
dwread: LongWord;
dwwritten: LongWord;
FileName: WideString;
FileCreationTime, FileChangeTime: TDateTime;
NonResidentFlag : boolean;
DataAttributeSize: DWord;
NonRes_OffsetToDataRuns: Word;
NonRes_DataSize: Int64;
NonRes_DataRuns: TDynamicCharArray;
NonRes_DataRunsIndex: integer;
NonRes_DataOffset: Int64;
NonRes_DataOffset_inBytes: Int64;
NonRes_CurrentLength: Int64;
NonRes_CurrentOffset: Int64;
NonRes_CurrentLengthSize: Byte;
NonRes_CurrentOffsetSize: Byte;
NonRes_CurrentData: TDynamicCharArray;
NonRes_PreviousFileDataLength: Int64;
Res_OffsetToData: Word;
Res_DataSize: Int64;
FileData: TDynamicCharArray;
FileType: string;
i : integer;
i64 : Int64;
begin
if (MainForm.FoundFilesStringGrid.Row<1) or (MainForm.FoundFilesStringGrid.Rows[1].Strings[0]='')
or (MainForm.FoundFilesStringGrid.Rows[1].Strings[0]=' ') then
begin
Log('Удаленные файлы на диске не найдены');
MessageBoxA(Handle,
Pchar('Удаленных файлов на диске нет'),
Pchar('Информация'),
MB_ICONINFORMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
// Получаем адрес восстанавливаемого файла
RecordLocator := StrToInt64(MainForm.FoundFilesStringGrid.Rows[MainForm.FoundFilesStringGrid.Row].Strings[0]);
Log('Пытаемся восстановить запись по адресу $'+IntToHex(RecordLocator,2));
// Устанавливаем соединение между программой и диском
hDevice := CreateFile( PChar('\\.\'+CURRENT_DRIVE), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hDevice = INVALID_HANDLE_VALUE) then begin
Log('Некорректное значение дескриптора : Ошибка '+IntToStr(GetLastError()), clred);
MessageBoxA(Handle,
Pchar('Некорректное значение дескриптора'+#13#10+'Ошибка '+IntToStr(GetLastError())),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Closehandle(hDevice);
exit;
end else begin
Log('Диск '+CURRENT_DRIVE+'\ Успешно открыт', clGreen);
end;
SetFilePointer(hDevice, 0, nil, FILE_BEGIN);
SetLength(MFTFileRecord,BytesPerFileRecord);
SetFilePointer(hDevice, Int64Rec(RecordLocator).Lo, @Int64Rec(RecordLocator).Hi, FILE_BEGIN);
Readfile(hDevice, PChar(MFTFileRecord)^, BytesPerFileRecord, dwread, nil);
try
MainForm.FixupUpdateSequence(MFTFileRecord);
except on E: Exception do begin
Log('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)+') : '
+E.Message, clred);
MessageBoxA(Handle,
Pchar('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)+')'
+#13#10+E.Message+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Closehandle(hDevice);
exit;
end;
end;
New(pFileRecord);
ZeroMemory(pFileRecord, SizeOf(TFILE_RECORD));
CopyMemory(pFileRecord, MFTFileRecord, SizeOf(TFILE_RECORD));
// проверяем, действительно ли файл находится в списке удаленных
if pFileRecord^.Flags<>0 then begin
Log('Ошибка : Файл больше не является удаленным.', clred);
MessageBoxA(Handle,
Pchar('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)+')'
+#13#10'Файл больше не является удаленным.'+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Dispose(pFileRecord);
Closehandle(hDevice);
exit;
end;
// Получение информации StandardInformationAttributeData := MainForm.FindAttributeByType(MFTFileRecord, atAttributeStandardInformation);
if StandardInformationAttributeData<>nil then begin
New(pStandardInformationAttribute);
ZeroMemory(pStandardInformationAttribute, SizeOf(TSTANDARD_INFORMATION));
CopyMemory(pStandardInformationAttribute, StandardInformationAttributeData,
SizeOf(TSTANDARD_INFORMATION));
Log('Дата создания : '+IntToStr(pStandardInformationAttribute^.CreationTime), clBlue);
Log('Дата изменения : '+IntToStr(pStandardInformationAttribute^.ChangeTime), clBlue);
FileCreationTime := Int64TimeToDateTime(pStandardInformationAttribute^.CreationTime);
FileChangeTime := Int64TimeToDateTime(pStandardInformationAttribute^.ChangeTime);
Dispose(pStandardInformationAttribute);
Log('Информация по датам получена', clGreen);
end else begin
FileCreationTime := now;
FileChangeTime := now;
Log('Предупреждение : Невозможно получить информацию по датам.', clMaroon);
Log('Информация по времени установлена в текущую дату', clMaroon);
MessageBoxA(Handle,
Pchar('Предупреждение восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)
+')'+#13#10+'Невозможно получить информацию по датам.'
+#13#10+'Информация по времени установлена в текущую дату.'),
Pchar('Предупреждение'),
MB_ICONEXCLAMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
// Получение информации об имени файла
FileNameAttributeData := MainForm.FindAttributeByType(MFTFileRecord, atAttributeFileName, true);
if FileNameAttributeData<>nil then begin
New(pFileNameAttribute);
ZeroMemory(pFileNameAttribute, SizeOf(TFILENAME_ATTRIBUTE));
CopyMemory(pFileNameAttribute, FileNameAttributeData, SizeOf(TFILENAME_ATTRIBUTE));
FileName := WideString(Copy(FileNameAttributeData, $5A, pFileNameAttribute^.NameLength*2));
Log('Имя файла : '+FileName, clBlue);
Dispose(pFileNameAttribute);
Log('Информация об имени файла получена', clGreen);
end else begin
FileName := 'UntitledFile.xxx';
Log('Предупреждение : Невозможно получить информацию об имени файла.', clMaroon);
Log('Имя файла установлено в UntitledFile.xxx', clMaroon);
MessageBoxA(Handle,
Pchar('Предупреждение восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)
+')'+#13#10+'Невозможно получить информацию об имени файла.'
+#13#10+'Имя файла установлено в UntitledFile.xxx.'),
Pchar('Предупреждение'),
MB_ICONEXCLAMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
// Получение информации о типе данных файла
DataAttributeHeader := MainForm.FindAttributeByType(MFTFileRecord, atAttributeData);
if DataAttributeHeader<>nil then begin
New(pDataAttributeHeader);
ZeroMemory(pDataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
CopyMemory(pDataAttributeHeader, DataAttributeHeader, SizeOf(TRECORD_ATTRIBUTE));
NonResidentFlag := pDataAttributeHeader^.NonResident=1;
DataAttributeSize := pDataAttributeHeader^.Length;
Dispose(pDataAttributeHeader);
end else begin
Log('Ошибка : Невозможно получить информацию о типе данных', clred);
MessageBoxA(Handle,
Pchar('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)+')'
+#13#10+'Невозможно получить информацию о типе данных.'+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Dispose(pFileRecord);
Closehandle(hDevice);
exit;
end;
// Собираем данные
if NonResidentFlag then begin
Log('Атрибут данных - нерезидентный.');
NonResidentDataAttributeData := MainForm.FindAttributeByType(MFTFileRecord, atAttributeData);
if NonResidentDataAttributeData<>nil then begin
New(pNonResidentDataAttribute);
ZeroMemory(pNonResidentDataAttribute, SizeOf(TNONRESIDENT_ATTRIBUTE));
CopyMemory(pNonResidentDataAttribute,NonResidentDataAttributeData, SizeOf(TNONRESIDENT_ATTRIBUTE));
NonRes_OffsetToDataRuns := pNonResidentDataAttribute^.RunArrayOffset;
NonRes_DataSize := pNonResidentDataAttribute^.DataSize;
Log('Начальное смещение : $'+IntToHex(NonRes_OffsetToDataRuns,2), clBlue);
Log('Размер данных : $'+IntToHex(NonRes_DataSize,2), clBlue);
Dispose(pNonResidentDataAttribute);
SetLength(NonRes_DataRuns, DataAttributeSize-(NonRes_OffsetToDataRuns-1));
NonRes_DataRuns := Copy(NonResidentDataAttributeData,NonRes_OffsetToDataRuns,
DataAttributeSize-(NonRes_OffsetToDataRuns-1));
end else begin
Log('Ошибка : Невозможно получить информацию.', clred);
MessageBoxA(Handle,
Pchar('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)
+')'+#13#10+'Невозможно получить информацию.'
+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Dispose(pFileRecord);
Closehandle(hDevice);
exit;
end;
// Получение списков отрезков
try
SetLength(FileData, 0);
NonRes_DataRunsIndex := 0;
NonRes_DataOffset := 0;
while NonRes_DataRuns[NonRes_DataRunsIndex] <> Char($00) do begin
NonRes_CurrentLengthSize := Ord(NonRes_DataRuns[NonRes_DataRunsIndex]) and $F;
NonRes_CurrentOffsetSize := (Ord(NonRes_DataRuns[NonRes_DataRunsIndex]) shr 4) and $F;
NonRes_CurrentLength := 0;
NonRes_CurrentOffset := 0;
// Получаем размер и смещение для текущего отрезка
for i := NonRes_CurrentLengthSize-1 downto 0 do
NonRes_CurrentLength := (Ord(NonRes_CurrentLength) shl 8)
+ Ord(NonRes_DataRuns[1+i+NonRes_DataRunsIndex]);
for i := NonRes_CurrentLengthSize+NonRes_CurrentOffsetSize-1 downto NonRes_CurrentLengthSize do
NonRes_CurrentOffset := (Ord(NonRes_CurrentOffset) shl 8)
+ Ord(NonRes_DataRuns[1+i+NonRes_DataRunsIndex]);
if (NonRes_CurrentOffset > ($80 shl ((8*NonRes_CurrentOffsetSize)-1)))
and (NonRes_DataRunsIndex<>0) then // This is a signed value (first one excepted!!!)
NonRes_DataOffset := NonRes_DataOffset
- ( ($100 shl ((8*NonRes_CurrentOffsetSize)-1) ) - NonRes_CurrentOffset)
else /
NonRes_DataOffset := NonRes_DataOffset + NonRes_CurrentOffset;
// читаем содержимое диска, соответствующее текущему отрезку
SetLength(NonRes_CurrentData, NonRes_CurrentLength*BytesPerCluster);
NonRes_DataOffset_inBytes := NonRes_DataOffset*BytesPerCluster;
SetFilePointer(hDevice, Int64Rec(NonRes_DataOffset_inBytes).Lo,
@Int64Rec(NonRes_DataOffset_inBytes).Hi, FILE_BEGIN);
Readfile(hDevice, PChar(NonRes_CurrentData)^, NonRes_CurrentLength*BytesPerCluster, dwread, nil);
NonRes_PreviousFileDataLength := Length(FileData);
SetLength(FileData, NonRes_PreviousFileDataLength + (NonRes_CurrentLength*BytesPerCluster));
if NonRes_CurrentOffset=0 then begin // Sparse File
// заполняем с "$00"
i64 := NonRes_PreviousFileDataLength;
while i64 <= Length(FileData)-1 do begin
FileData[i64] := Char($00);
inc(i64);
end;
end else begin
// Копируем содержимое данных, соответствующее текущему отрезку
i64 := NonRes_PreviousFileDataLength;
while i64 <= Length(FileData)-1 do begin
FileData[i64] := NonRes_CurrentData[i64-NonRes_PreviousFileDataLength];
inc(i64);
end;
end;
// переходим к следующему отрезку
NonRes_DataRunsIndex := NonRes_DataRunsIndex+NonRes_CurrentLengthSize+NonRes_CurrentOffsetSize+1;
end;
SetLength(FileData, NonRes_DataSize);
Log('Data Runs processed : Data Recovered', clGreen);
except
Log('Ошибка : Unable to compute correctly the DataRuns information.', clred);
MessageBoxA(Handle,
Pchar('Error during File Recovery (File Record Address : $'+IntToHex(RecordLocator,2)
+')'+#13#10+'Unable to compute correctly the DataRuns information.'
+#13#10+'Unable to continue.'),
Pchar('Error'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Dispose(pFileRecord);
Closehandle(hDevice);
exit;
end;
end else begin
Log('Резидентный атрибут данных.');
ResidentDataAttributeData := MainForm.FindAttributeByType(MFTFileRecord, atAttributeData);
if ResidentDataAttributeData<>nil then begin
New(pResidentDataAttribute);
ZeroMemory(pResidentDataAttribute, SizeOf(TRESIDENT_ATTRIBUTE));
CopyMemory(pResidentDataAttribute, ResidentDataAttributeData, SizeOf(TRESIDENT_ATTRIBUTE));
Res_OffsetToData := pResidentDataAttribute^.ValueOffset;
Res_DataSize := pResidentDataAttribute^.ValueLength;
Log('Смещение данных : $'+IntToHex(Res_OffsetToData,2), clBlue);
Log('Размер данных : $'+IntToHex(Res_DataSize,2), clBlue);
Dispose(pResidentDataAttribute);
SetLength(FileData, Res_DataSize);
FileData := Copy(ResidentDataAttributeData,Res_OffsetToData,Res_DataSize);
Log('Данные восстановлены', clGreen);
end else begin
Log('Ошибка : Невозможно прочитать информацию.', clred);
MessageBoxA(Handle,
Pchar('Ошибка восстановления файла (Файловая запись : $'+IntToHex(RecordLocator,2)
+')'+#13#10'Невозможно прочитать информацию.'
+#13#10+'Невозможно продолжить.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
Dispose(pFileRecord);
Closehandle(hDevice);
exit;
end;
end;
// Заполнение и вывод окна информации о файле
FileDetailsForm.FileNameLbl.Caption := FileName;
//FileDetailsForm.
FileDetailsForm.SizeLbl.Caption := IntToStr(Length(FileData))+' Байт';
FileDetailsForm.CreationTimeLbl.Caption := 'Дата создания : '+FormatDateTime('c', FileCreationTime);
FileDetailsForm.ChangeTimeLbl.Caption := 'Дата изменения : '+FormatDateTime('c', FileChangeTime);;
FileDetailsForm.SysIco.GetIcon(FileDetailsForm.GetIconIndex(ExtractFileExt(FileName), 0, FileType),
FileDetailsForm.IconImg.Picture.Icon.Create);
FileDetailsForm.FileTypeLbl.Caption := FileType;
// Сохрание файла
if (FileDetailsForm.ShowModal = mrOK) then begin
MainForm.SaveDialog.FileName := FileName;
if MainForm.SaveDialog.Execute then begin
hDest:= CreateFile(PChar(MainForm.SaveDialog.FileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
WriteFile(hDest, PChar(FileData)^, Length(FileData), dwwritten, nil);
Closehandle(hDest);
Log('Восстановленный файл сохранен : '+ExtractFileName(MainForm.SaveDialog.FileName)+' ('
+IntToStr(dwwritten)+' Байт)', clBlue);
Log('Файл восстановлен', clGreen);
MessageBoxA(Handle,
Pchar('Файл восстановлен и сохранен :'+#13#10+MainForm.SaveDialog.FileName),
Pchar('Информация'),
MB_ICONINFORMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
end;
Dispose(pFileRecord);
Closehandle(hDevice);
end;
end.
Листинг модуля Copy:
unit Copy;
interface
uses
Classes, Windows, Messages, SysUtils, Variants, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileDetails, XPMan, ComCtrls, Grids, ValEdit, ExtCtrls, Buttons;
type
TThreadCopy = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
uses
Main;
procedure TThreadCopy.Execute;
var
result: boolean;
FromFile, FileName,ToFile: string;
Ext, ExtName: string;
begin //выбран ли исходный файл
FromFile:=MainForm.EditCopyFileName.Text;
ExtName:=ExtractFileName(MainForm.EditPasteFileName.Text);
if FromFile='' then
begin
MainForm.Log('Ошибка открытия исходного файла. Файл не выбран.', clred);
MessageBoxA(Handle,
Pchar('Файл не выбран!'+#13#10+'Выберите исходный файл.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end
else
begin
If (MainForm.EditPasteFileName.Text='') or (ExtName='') then
begin
MainForm.Log('Ошибка копирования. Не задано новое имя файла.', clred);
MessageBoxA(Handle,
Pchar('Не задано имя файла!'+#13#10+'Выберите новое имя файла.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST)
end
else
Begin
if pos('.',MainForm.EditPasteFileName.Text)=0 then
begin
Ext:=ExtractFileExt(FromFile);
MainForm.EditPasteFileName.Text:=(MainForm.EditPasteFileName.Text+Ext);
FileName:=MainForm.EditPasteFileName.Text;
FileName:=MainForm.SanitizeString(FileName); //"чистка" имени
end;
ToFile:=MainForm.EditPasteFileName.Text;
ToFile:=MainForm.SanitizeString(ToFile);
result:=CopyFile(PChar(FromFile), PChar(ToFile), true);
If not result then begin
MainForm.Log('Ошибка копирования файла. Такой файл уже существует.', clred);
MessageBoxA(Handle,
Pchar('Такой файл уже существует.'),
Pchar('Ошибка'),
MB_ICONSTOP + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end
else
begin
MainForm.Log('Файл скопирован.', clgreen);
MainForm.Log('Имя исходного файла : '+FromFile, clBlue);
MainForm.Log('Новое имя файла : '+ToFile, clBlue);
MessageBoxA(Handle,
Pchar('Файл скопирован!'),
Pchar('Информация'),
MB_ICONINFORMATION + MB_SYSTEMMODAL + MB_SETFOREGROUND + MB_TOPMOST);
end;
end;
end;
end;
end.
Листинг модуля FileDetails:
unit FileDetails;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ShellAPI, ImgList;
type
TFileDetailsForm = class(TForm)
CancelBtn: TButton;
RecoverBtn: TButton;
IconImg: TImage;
FileNameLbl: TLabel;
CreationTimeLbl: TLabel;
ChangeTimeLbl: TLabel;
SizeLbl: TLabel;
SysIco: TImageList;
FileTypeLbl: TLabel;
procedure FormCreate(Sender: TObject);
function GetIconIndex(Extension: String; Attributes: DWORD; var FileType :string):Integer;
private
public
end;
var
FileDetailsForm: TFileDetailsForm;
implementation
{$R *.dfm}
function TFileDetailsForm.GetIconIndex(Extension: String; Attributes: DWORD; var FileType :string):Integer;
var SHFileInfo: TSHFileInfo;
begin
if Extension[1] <> '.' then Extension := '.' + Extension;
SHGetFileInfo(PChar(Extension), Attributes, SHFileInfo, SizeOf(TSHFileInfo),
SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES or SHGFI_TYPENAME);
FileType := SHFileInfo.szTypeName;
Result := SHFileInfo.iIcon; end;
procedure TFileDetailsForm.FormCreate(Sender: TObject);
var
SHFileInfo :TSHFileINfo;
begin
SysIco.Handle := SHGetFileInfo('', 0, SHFileInfo, SizeOF(SHFileInfo), SHGFI_SYSICONINDEX or SHGFI_LARGEICON);
end;
end.
7 СПИСОК ЛИТЕРАТУРЫ
1. MSDN - Library, http://msdn.microsoft.com/ru-ru/library/
2. Методические указания к курсовому проекту по курсу "операционные системы", Рязань, 2002, 15 с. 3. Методические указания к лабораторной работе №4 "Исследование структуры тома NTFS".
4. Засорин С. В., Конкин Ю. В. "Объектно-ориентированное программирование. Лабораторный практикум: Учебное пособие". - : Рязань 2012. - 355 с.; ил.
5. http://www.insidepro.com/kk/044/044r.shtml
6. http://www.insidepro.com/kk/032/032r.shtml
2
Документ
Категория
Рефераты
Просмотров
56
Размер файла
575 Кб
Теги
оси, курсовая
1/--страниц
Пожаловаться на содержимое документа