Програма написана на мові ASM-86 з використанням команд процесора 286/386. Вона складається з головної програми, яка перевіряє параметр - файл, який потрібно відновити, знаходить цей файл, якщо він є, серед вилучених, та відновлює його.
Програма компілюється Turbo Assembler, зв’язується за допомогою TLINK.
IBM сумісний комп’ютер із мікропроцесором Intel 80386 або старшим.
Для перегляду результатів - Turbo Debugger або інший відлагоджувач.
Для запуску програми, яка дозволяє відновлювати файли, треба в командному рядку набрати UNDEL.com потім, через проміжок набрати ім'я файлу, який треба відновити на диску a, та натиснути Enter. Програма перевірить, чи є таке ім'я на диску серед вилучених файлів, і якщо є, то відновить його.
Отже, є розробленою програма, яка виконує відновлювання вилучених файлів. Також був розглянутий алгоритм відновлювання файлів, які були вилучені. По перерахованим вище кроках може показатися, що процедура відновлення файлів є досить прямолінійної. У залежності від наявних у вашому розпорядженні програмних інструментів, у дійсності однак перегляд даних на диску й запис інформації на диск може бути складним заняттям. Відзначимо тут, що кроки 6 і 7 містять застереження про можливість того, що трохи раніше стертих файлів можуть переплестися через складну послідовність розташування їхніх кластерів. Відновлення переплутаних даних зазначеним вище способом може виявитися дуже нудотним і в той же час головоломним заняттям. Але при наявності терпіння (можливо усього лише невеликого!), і, змусити себе бути методичним, ви неодмінно зможете розплутати файли.
1) “Програмування на мові Асемблера ЕС ЕВМ" З.С. Брич. В.I. Воющ Москва 1989 р. ст.166
2) “Програмування на сучасних мовах програмування. ” Москва 1990р. ст. 206
3) “Основи мови” Асемблер” В.I. Криволап. Москва 1997р. ст.309
4) “Ассемблер для початкiвцiв” М.П. Шукiн. Київ 1980р. ст.155
5) “Турбо Асемблер” Л.В. Захаров. Харків 1995 р ст.178
6) “Макро Асемблер” К.С. Кропiйко О.Д. Богатирова. Київ - “Наука” 1991р.
7) Електронний довідник BOOK.
FCB_LOC EQU 5CH; Положение FCB для удаленного файла в PSP
SWITCH_LOC EQU 81H; Положение командного рядка
CR EQU 13; ASCII возврат каретки
LF EQU 10; ASCII перевод строки
CODE_SEG SEGMENT
ASSUME CS: CODE_SEG,DS: CODE_SEG,ES: CODE_SEG
ORG 100H
ENTRY: JMP FIRST; пропуск данных
I_O_FLAG DW?; Выбор чтения или записи кластеров
START_CLUSTER DW?; Первый кластер удаленного файла
FILE_SIZE DW?; Размер файла в кластерах (1 кластер =1 сектору)
DISK_DRIVE DB 0; Диск для удаленного файла
NOT_FOUND_MSG DB 13,'File not found deleted$'; Messages
WRITTEN_OVER_MSG DB 13,'File already written over$'
DATA DB 1024 DUP (0); Место под directory и FAT
FIRST:; Начало программы
UNDEL PROC NEAR
MOV AL,CS: FCB_LOC; Получить drive specified - 0 если one given
SUB AL,1; Was it a 1 (A:) or 2 (B:)?
JNC DRIVE_KNOWN; Yes, store drive number
MOV AH, 19H; Нет, получить диск по умолчанию
INT 21H
DRIVE_KNOWN:
MOV DISK_DRIVE,AL; Запомнить диск
MOV DX,17; Директории начинаются с 19 сектора
LOOPs: ADD DX,1; Переход к следующему кластеру директории
CMP DX,33; Проверка на последний кластер директории
JB READ_DIR; Если не последний, переход на чтение
MOV AH,9; Иначе выходим с выдачей сообщения,
LEA DX,NOT_FOUND_MSG; о том, что файл не найден
INT 21H
JMP OUT1; Exit
READ_DIR:
AND I_O_FLAG,0; Выбираем чтение
CALL CLUSTER_I_O; Читаем кластер
LEA DI,DATA; Загружаем адрес проверки
MOV AL,0E5H; Символ проверки - первый символ удаленного файла E5H
MOV CX, 200H; Количество символов проверки 512
SEARCH:;
REPNE SCASB; Проверка
JCXZ LOOPs; If no match (Counter=0), get next dir cluster
MOV SI,FCB_LOC+2; Сравнение со 2 символа на совпадение имен файлов
MOV BX,11; Сравнение 11 символов
CMPLOOP: DEC BX; уменьшить количество сравниваемых символов
CMPS byte ptr [DI], [SI] ; Сравнить файлы
JZ CMPLOOP; Если совпадают, переход на следующий чимвол
CMP BX,0; Сравнение закончено, все символы проверены?
JNZ SEARCH; Нет, переход на продолжение поиска
MOV AX,CS: FCB_LOC+1; Да, получить первый символ файла
MOV [DI-12],AX; Заменить символ E5H на первыый символ файла
OR I_O_FLAG,1; Выбрать запись 1 кластера
CALL CLUSTER_I_O; Запись измененной директории
MOV AX, [DI+14] ; Получить начальный сектор в FAT
MOV START_CLUSTER,AX; Запомнить начальный сектор FAT
MOV AX, [DI+16] ; Получить размер файла (младшее слово)
TEST AX,511; MOD (size,512) =0?
JZ EVEN_K; Да, не добавлять 1 кластер после SHR
ADD AX,512; Нет, добавлять другие кластера
EVEN_K: MOV CL,9; Деление на 512 (512=размер кластера)
SHR AX,CL
MOV DX, [DI+18] ; Получить размер файла (старшее слово)
MOV CL,7; Умножение на 128 (2^16/2^9)
SHL DX,CL
ADD AX,DX; Добавить старшее слово до младшего слова
MOV FILE_SIZE,AX; Сохранить размер
MOV DX,1; Прочитать FAT
AND I_O_FLAG,0; Выбор чтения 1 кластера
CALL CLUSTER_I_O
MOV CX,FILE_SIZE; Счетчик количества кластеров
MOV AX,START_CLUSTER; Проверка на то, что первый кластер свободный
DEC AX;
CALL GET_NEXT_ZERO;
CMP DX,START_CLUSTER
JE FILL; Если свободный, переход на заполнение FAT
MOV AH,13H; Нет, файл перезаписуется
MOV DX,FCB_LOC; Удаляется сохраненная запись директории
INT 21H;
MOV AH,9; Выход с ошибкой
LEA DX,WRITTEN_OVER_MSG
INT 21H
JMP OUT1; переход на выход
FILL: MOV AX,DX; Установить старое свободное пространство в FAT на первый найденный
MOV DX,0FFFH; Указать, что это последний кластер (FFFH=End of file)
CMP CX,1; Если последняя запись? (CX=количество кластеров)
JZ LAST; Да, не надо шукать следующую свободную запись
CALL GET_NEXT_ZERO; Вызов с AX=старый 0 кластер. Возвращает DX=новый 0 кластер
LAST: CALL PUT_FAT_ENTRY; Вызов с AX=старый 0 кластер. Возвращает DX=новый 0 кластер в FAT
LOOP FILL; Обработать следующий кластер
MOV DX,1; Запись измененной 1 копии FAT
OR I_O_FLAG,1; Выбор записи кластера
CALL CLUSTER_I_O; Запись кластера
MOV DX,3; Запись измененной 1 копии FAT
CALL CLUSTER_I_O; Запись кластера
OUT1: INT 20H; Выход
UNDEL ENDP
CLUSTER_I_O PROC NEAR; Чтение кластера
; Вход: DX-начальный сектор
PUSH AX; Сохранить используемые регистры в стеке
PUSH BX; INT 25H изменяет все регистры
PUSH CX
PUSH DX
PUSH DI
MOV AL,DISK_DRIVE; Получить номер диска
MOV CX,1; 1 сектор
LEA BX,DATA; Адрес буфера
TEST I_O_FLAG,1; Проверка на чтение/запись
JNZ WRITE; переход на запись
INT 25H; Чтение секторов
JMP POPOUT; выход с процедуры
WRITE: INT 26H; запись секторов
POPOUT: POPF; убрать из стека
POP DI; восстановить регистры
POP DX
POP CX
POP BX
POP AX
RET; Выход
CLUSTER_I_O ENDP
GET_NEXT_ZERO PROC NEAR; Поиск следующей нулевой записи FAT
; Вход: AX-FAT номер записи (кластер)
; Выход: следующий ноль в DX
PUSH AX; Сохранить используемые регистры в стеке
PUSH BX
PUSH CX
CHECK_NEXT:; Поиск
INC AX; AX начало сдедующей записи
MOV BX,AX; Получить 3/2*AX для действительного смещения в FAT
SHL BX,1;
ADD BX,AX
SHR BX,1; BX - значение смещения записи FAT in AX
MOV DX,WORD PTR DATA [BX] ; в DX записеется значение записи FAT
TEST AX,1; Запись четная?
JZ EVEN_ENTRY; Да, использовать младшие 12 bits
MOV CL,4; Нет, использовать старшие 12 bits
SHR DX,CL
EVEN_ENTRY:
AND DX,0FFFH; Получить младшие 12 bits
CMP DX,0; значение FAT =0?
JNE CHECK_NEXT; Нет, переход к следующему кластеру
MOV DX,AX; Поместить значение записи из AX
POPS: POP CX; восстановить регистры
POP BX
POP AX
RET
GET_NEXT_ZERO ENDP
PUT_FAT_ENTRY PROC NEAR; Запись новой FAT записи в FAT
; Получает номер уластера FAT в AX и новую запись в DX
PUSH AX; Сохранить используемые регистры в стеке
PUSH BX
PUSH CX
PUSH DX
MOV BX,AX; Получить смещение в FAT, 3*AX/2
SHL BX,1; Умножить на 2
ADD BX,AX; Добавит AX для получения 3*AX
SHR BX,1; Деление на 2 - BX содержит значение смещения FAT
TEST AX,1; Четный номер?
JZ P_EVEN_ENTRY; Да, использовать младшие 12 bits
MOV CL,4; Нет, использовать старшие 12 bits
SHL DX,CL
P_EVEN_ENTRY:
OR WORD PTR DATA [BX],DX; Записать номер кластера в FAT
POP DX; восстановить регистры
POP CX
POP BX
POP AX
RET
PUT_FAT_ENTRY ENDP
CODE_SEG ENDS
END ENTRY