



                       ЧАСТЬ III.   ВОССТAHОВЛЕНИЕ


              Глава 11. СТРУКТУРА ДИСКА И ВОССТAHОВЛЕНИЕ ФАЙЛОВ


              Основные принципы восстановления файлов
              Обзор процедур восстановления
              Восстановление разрушенных файлов при помощи утилит
              CHKDSK и RECOVER
              Восстановление стертых файлов
              Заключение


              Если вы уже некоторое время поработали с операционной систе-
         мой  MS-DOS,  вам,  вероятно,  доводилось случайно стирать или по
         ошибке терять файл, который мог бы в дальнейшем вам понадобиться.
         Команда  ERASE  (или  DEL) в операционной системе MS-DOS является
         часто используемой и мощной, а по своей природе - это разрушающая
         команда. Разрушительная сила, конечно, требуется этой команде для
         выполнения ею своих функций, но если вы проявите беспечность, эта
         команда станет губительной, чего вы вряд ли желаете.
              Единственная предусмотренная защита от  случайного  удаления
         файлов  командами ERASE или DEL появляется на экране тогда, когда
         вы собираетесь удалить все файлы на диске  и  указываете  команду
         стирания в виде "erase *.*". Только в этом случае на экране появ-
         ляется вопрос о том,  действительно ли вы хотите выполнить  такую
         операцию. Если в качестве ответа вы введете символ "n" (нет), вы-
         полнение команды будет прекращено. В тех же случаях, когда вы ис-
         пользуете  указанные команды удаления для стирания отдельных фай-
         лов  или  групп  файлов,  единой  защитой  вам  может   послужить
         самоконтроль:  сделайте паузу прежде, чем нажать клавишу "Return"
         (или "Enter"), и внимательно еще раз проверьте набранную вами ко-
         манду для удаления файлов. Даже тогда (и это не зависит от степе-
         ни вашей уверенности в правильности указания  файла  или  файлов,
         подлежащих  удалению)  среди удаленных вами файлов могут быть та-
         кие,  которые удалять не следовало. Что ж, все мы люди и когда-то
         совершаем ошибки! Поскольку компьютеры устроены так, что мгновен-
         но подчиняются вашим командам,  запрос на удаление  файлов  будет
         выполнен  немедленно  после  нажатия  вами  клавиши "Return" (или
         "Enter") в конце командной последовательности.
              Файл может  быть  также стерт выполняющейся в текущий момент
         программой.  Текстовые редакторы и другие программы, обеспечиваю-
         щие средства управления файлами, могут содержать команды (в явной
         или неявной форме) по удалению файлов.  Кроме того,  файлы  могут
         оказаться стертыми в результате сбоев оборудования, сбоев в пода-
         че питания или в результате каких-то запутанных переходов в самой
         программе.
              Итак, что нужно делать,  если непродублированный нигде  файл
         был  по  ошибке удален?  К счастью,  файловая система MS-DOS была
         разработана так,  что в некоторых  случаях  восстановить  стертый
         файл  не составляет труда:  существует несколько специальных ути-
         лит, предназначенных для восстановления стертых файлов. Некоторые
         из  этих  утилит  поставляются  в  основном комплекте программных
         средств. Другие можно приобрести отдельно. Из отдельно приобрета-

                                      - 11-2 -
         емых  средств  наиболее распространенными являются "Norton-утили-
         ты" и "Mace-утилиты".  Аналогичный указанным программный  продукт
         под названием "Ultra-утилиты" состоит из набора утилит, имеющего-
         ся в "свободной торговле"*.  В настоящее время его можно  достать
         через  многочисленные  общедоступные каналы распространения прог-
         раммного обеспечения.

             В настоящей главе мы обсудим процедуры восстановления стертых
         файлов  и использование утилит CHKDSK и RECOVER операционной сис-
         темы MS-DOS для восстановления разрушенных или потерянных файлов.
         Мы  будем также обсуждать применение других способов восстановле-
         ния файлов, включающих в себя коммерческие программы "Norton-ути-
         лит" и поддерживаемые пользователем программы "Ultra-утилит".
              Для того,  чтобы понять работу указанных  выше  средств,  вы
         должны  понимать  работу  всей файловой системы MS-DOS,  тогда вы
         сможете понять и ограничения,  которые имеют утилиты восстановле-
         ния файлов. Отметим, что и "Norton-утилиты" и "Ultra-утилиты" ра-
         ботают только в персональных компьютерах фирмы "IBM" или  совмес-
         тимых с ними персональных компьютерах.  "Norton-утилиты", начиная
         с версии 2.01, осуществляют также восстановление файлов, располо-
         женных на  жестких  дисках (имеются в виду 10-Мегабайтные жесткие
         диски в персональных компьютерах типа IBM-PC или в  совместимых с
         ними  средах),  а "Norton-утилиты",  начиная с версии 3.0,  имеют
         поддержку как 20-Мегабайтных жестких дисков модели IBM PC-AT, так
         и  гибких дисков большой емкости (работающих под управлением опе-
         рационной системы MS-DOS версии 3.0 или  более  поздних).  Версия
         4.0  "Norton-утилит"  включает  в себя возможность работы с любым
         носителем дискового типа, работающим под управлением операционной
         системы MS-DOS при условии,  что дисковый носитель отформатирован
         согласно стандартным соглашениям по операционной  системе MS-DOS.
              Несмотря на  то,  что  пакеты  утилит  восстановления файлов
         чрезвычайно полезны при работах в средах,  для которых  они  были
         разработаны,  может так случиться, что они не будут работать над-
         лежащим образом в среде конкретной операционной системе MS-DOS, и
         особенно  тогда,  когда  вашей  системой не является персональный
         компьютер IBM-PC или в достаточной  степени  совместимый  с  ними
         персональный  компьютер.  По этой причине в данную главу включено
         описание программы, которую вы можете попробовать запустить в том
         случае,  когда другие утилиты не работают или,  когда вы решаете,
         что они не подходят для вашей машины.  Программа RESCUE проста по
         конструкции  и  может  быть  расширена  и приспособлена под новые
         свойства.  Программа RESCUE предназначена для  работы  с  дисками
         (сменными и постоянными) при условии, что формат дисков соответс-
         твует стандартных соглашениям  по  операционной  системы  MS-DOS.
         Прежде  чем  мы  продемонстрируем вам использование "Norton -ути-
         лит", "Ultra-утилит" и альтернативной им программы RESCUE, давай-
         те  изучим основные принципы системы дисковой памяти MS-DOS и ос-
         новные принципы восстановления файлов.
         ────────────────────────────
             * Способ коммерческого распространения программного  обеспече-
         ния,  при  котором любой пользователь может свободно скопировать и
         использовать программу;  если пользователь  находит  использование
         программы полезным,  он может послать разработчику указанную в до-
         кументации сумму,  после  чего  он  считается  "зарегистрированным
         пользователем"  и  имеет  право  на  получение  информации о новых
         версиях. (Примечание переводчика.)


                                     - 11-3 -

                     Основные принципы восстановления файлов

              Вероятно вам будет небезинтересно узнать,  как можно восста-
         новить стертый файл.  Интуитивно кажется, что если уж файл стерт,
         он должен быть совершенно удален с  поверхности  диска  навсегда.
         Это предположение частично верно,  поскольку после того, как файл
         был стерт он больше не виден и к нему нет доступа при помощи  ни-
         каких стандартных команд MS-DOS.
              Каждый файл,  сохраняемый операционной  системой  MS-DOS  на
         диске, состоит из следующих трех частей:
              - элемента в каталоге, описывающего файл;
              - определенного места для файла;
              - секторов данных,  содержащих сами данные файла.
              При стирании файла затрагиваются только первые  два элемента
         файла:  относящийся к нему элемент в каталоге и пространство,  им
         занятое.  Эти две части выступают в роли  контрольных  точек  для
         операционной  системы MS-DOS для обращения к секторам данных фай-
         ла.  Сектора данных файла,  однако,  не стираются, что и является
         причиной возможности восстановления файла в том случае,  когда вы
         знаете хоть что-то о первых двух частях файла.  Подробнее о расп-
         ределении  памяти  для  файла  и о разделах каталога мы поговорим
         чуть позже,  но сначала мы рассмотрим структуру  дисков,  которые
         форматировались  разными  способами  под управлением операционной
         системы MS-DOS.
              Ниже в разделах описываются форматы стандартных гибких  дис-
         ков и жестких (постоянных) дисков.  Отметим, что в некоторых сис-
         темах все 40-трековые форматы, поддерживаемые операционной систе-
         мой  MS-DOS ,  также могут использоваться с 3,5-дюймовыми гибкими
         дисками. В таких системах дисковод для 3,5-дюймового гибкого дис-
         ка  должен  рассматриваться аппаратурой системы,  как 40-трековый
         дисковод для 5,25-дюймовых гибких дисков,  что  часто  случается,
         когда дисководы 3,5-дюймовых гибких дисков подсоединены к сущест-
         вующим в системах IBM PC, IBM PC-XT и IBM PC-AT контроллерам гиб-
         ких дисков. 80-трековые форматы, поддерживаемые операционной сис-
         темой  MS-DOS  ,  однако,  обычно  не  являются  заменяемыми  для
         3,5-дюймовых и 5,25-дюймовых гибких дисков.


                Структура 40-трековых, односторонних, 5,25-дюймовых
                                   гибких дисков

              На рис. 11-1 представлен вид структуры 40-трековых, односто-
         ронних, 5,25-дюймовых гибких дисков. Здесь показаны треки (дорож-
         ки) и сектора.  Приведен пример расположения данных файла на дис-
         ке.  В  первой  части  иллюстрации  показана   структура   диска,
         отформатированного  по  восемь  секторов на один трек.  Во второй
         части иллюстрации показана только правая часть формата  - отличие
         трека 0 для диска,  отформатированного по девять секторов на один
         трек.
              В первой  части  рисунка  11-1 представлен простейший формат
         диска,  работающего под управлением операционной системы  MS-DOS.
         Поскольку  все  стандартные дисковые форматы операционной системы
         MS-DOS поддерживают размер сектора в 512 байтов,  мы можем  легко
         проверить информацию, подсчитав общую емкость диска следующим об-
         разом:

                                      - 11-4 -

                     40 треков х 8 секторов х 512 байтов =
                =  163840 байтов ( = 160 Кбайт общей емкости)

              Общую емкость диска можно проверить, сравнив с результатами,
         выводимыми на экран при использовании команд FORMAT и CHKDSK.

                  Формат  расположения восьми секторов на треке
               ┌──────────────────────────────────────────────────┐
               │ \   Трек                                         │
               │   \               1         2         3        3 │
               │     \   0123456789012345678901234567890123456789 │
               │Cектор ┌──────────────────────────────────────────┤
               │   1   │ BXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   2   │ FXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   3   │ FXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   4   │ DXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   5   │ DXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   6   │ DXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEE │
               │   7   │ DXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEEE │
               │   8   │ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEEEE │
               └───────┴──────────────────────────────────────────┘

                  Формат расположения девяти секторов на треке
          ┌──────────────────────────┐
          │ \    Трек                │
          │   \            ...     3 │    B = запись начальной загрузки
          │     \   01     ...     9 │    D = элемент каталога
          │Cектор ┌──────────────────┤    F = таблица  размещения файла
          │   1   │ BX     ...     E │
          │   2   │ FX     ...     E │     Только для целей данного
          │   3   │ FX     ...     E │          примера:
          │   4   │ FX     ...     E │    X = секторы, содержащие
          │   5   │ FX     ...     E │        данные файла
          │   6   │ DX     ...     E │    E = пустые секторы
          │   7   │ DX     ...     E │
          │   8   │ DX     ...     E │
          │   9   │ DX     ...     E │
          └───────┴──────────────────┘
              Рис. 11-1. Схема расположения информации на 40-трековых,
         односторонних, 5,25-дюймовых гибких дисках

              Диск, отформатированный по девять секторов на дорожку (толь-
         ко для операционной системы MS-DOS версий 2.0 и выше),  похож  на
         диск,  отформатированный  по восемь секторов на дорожку.  Разница
         заключается в добавленном девятом секторе в конце  каждого трека,
         что меняет общую емкость диска. Проверить это можно тоже, получив
         общую емкость диска по представленной ниже формуле  и  сравнив  с
         результатами, выводимыми на экран при использовании команд FORMAT
         и CHKDSK.

                     40 треков х 9 секторов х 512 байтов ={F10}
               =  184320 байтов ( = 180 Кбайт общей емкости)

              Другое различие  между  восьми-секторными и девятисекторными
         форматами дисков заключается в количестве секторов  FAT  (таблицы
         размещения  файлов).  Несмотря на то,  что оба формата имеют один

                                      - 11-5 -
         сектор начальной загрузки и четыре сектора  каталога,  количество
         секторов  таблицы FAT больше в девятисекторовом формате.  Диски с
         форматом по восемь секторов на трек имеют два сектора FAT (секто-
         ры 2 и 3 дорожки 0).  Диски с форматом по десять секторов на трек
         имеют четыре сектора FAT (секторы со 2 по 5 дорожки 0). Необходи-
         мость  в дополнительном количестве секторов FAT на десяти-сектор-
         ных дисках возникает вследствие наличия дополнительного файлового
         пространства,  образованного 40 дополнительными секторами (по од-
         ному сектору на треке).

                Структура 40-трековых, двухсторонних, 5,25-дюймовых
                                   гибких дисков

              Двухсторонние 40-трековые  гибкие  диски,  отформатированные
         под управление операционной системой MS-DOS ,  имеют то же  коли-
         чество секторов FAT (пропорциональное),  что и односторонние гиб-
         кие диски, но большее количество секторов каталога, что позволяет
         увеличить  общее  число файлов,  расположенных на диске.  В обоих
         форматах двухсторонних дисков (в восьми- и в девяти-трековом) под
         каталоговые   сектора  распределяется  семь  секторов.  Структура
         двухсторонних 40-трековых дисковых форматов,  поддерживаемых опе-
         рационной системой MS-DOS,  представлены на рисунке 11-2. В левой
         части рисунка показан восьми-секторный формат. В правой части ри-
         сунка показан десяти-секторный формат.
              Структура диска,  представленная на рис.11-2 очень похожа на
         структуру диска, представленную на рис.11-1. Отметим, что на всех
         двухсторонних гибких дисках,  отформатированных  под  управлением
         операционной  системы  MS-DOS,  сохраняемая  на  треке информация
         всегда начинается со стороны 0 сектора 1 и далее располагается до
         последнего  сектора  на  этом треке.  Потом происходит переход на
         сторону 1 и информация продолжает располагаться с первого по пос-
         ледний сектор трека.  Далее снова происходит возврат на сторону 0
         и информация начинает помещаться  с  первого  сектора  следующего
         трека  и  так далее вплоть до последнего сектора последнего трека
         стороны 1.  Отметим также,  что расположение секторов каталога  и
         секторов  таблицы  FAT  отличаются  от односторонних дисков.  Оба
         двухсторонних формата имеют по одному треку начальной  загрузки и
         пропорциональное количество таких же секторов таблицы FAT,  как и
         односторонние диски.  Число секторов каталога,  однако, для обоих
         форматов двухсторонних дисков возрастает до семи.  И снова, срав-
         нивая результаты представленных ниже двух расчетных формул с  ре-
         зультатами выполнения программы CHKDSK,  мы можем проверить общую
         емкость двух форматов 40-трековых двухсторонних гибких дисков:
                 40 треков х 8 секторов х 512 байтов х 2 стороны =
                  = 327680 байтов ( = 320 Кбайт общей емкости)

                 40 треков х 9 секторов х 512 байтов х 2 стороны =
                  =  368640 байтов ( = 360 Кбайт общей емкости)


                Структура 80-трековых, двухсторонних, 5,25-дюймовых
                                   гибких дисков

              Операционная система MS-DOS версии 3.0 позволила использова-
         ние нового формата 5,25-дюймовых гибких дисков, известного обычно

                                      - 11-6 -
         под названием формат "повышенной емкости". Этот формат предостав-
         ляет возможность хранения данных общим  объемом  в  1,2  миллиона
         байтов  и  требует использования специального дисковода 80-треко-
         вых,  5,25-дюймовых гибких дисков. Этот формат повышенной емкости
         невозможен с 3,5-дюймовыми гибкими дисками.
              Структура описываемого  формата  очень  похожа  на  прежние,
         только что рассмотренные форматы.  Увеличение емкости формата за-
         висит от использования гибких дисков с удвоенным количеством тре-
         ков  (80(  и  форматирование большего количества секторов (15) на
         одном треке. На рисунке 11-3 представлена структура этого формата
         и  сделан  акцент  на старших номерах секторов каталога и таблицы
         FAT, которые обеспечивают увеличение емкости.

           Формат  расположения восьми     Формат  расположения девяти
               секторов на треке               секторов на треке
         ┌────────────────────────────┐   ┌────────────────────────────┐
         │       \   Трек             │   │       \   Трек             │
         │         \         ...    3 │   │         \         ...    3 │
         │           \   012 ... 6789 │   │           \   012 ...    9 │
         │      Cектор ┌──────────────┤   │      Cектор ┌──────────────┤
         │         1   │ BXX ... XXXX │   │         1   │ BXX ...      │
         │         2   │ FXX ... XXXX │   │         2   │ FXX ...      │
         │         3   │ FXX ... XXXX │   │         3   │ FXX ...      │
         │Сторона  4   │ DXX ... XXXX │   │Сторона  4   │ FXX ...      │
         │   0     5   │ DXX ... XXXX │   │   0     5   │ FXX ...      │
         │         6   │ DXX ... XXXX │   │         6   │ DXX ...      │
         │         7   │ DXX ... XXXX │   │         7   │ DXX ...      │
         │ ________8   │ DXX ... XXXX │   │         8   │ DXX ...      │
         │         1   │ DXX ... XEEE │   │ ________9   │ DXX ...      │
         │         2   │ DXX ... XEEE │   │         1   │ DXX ...      │
         │         3   │ XXX ... XEEE │   │         2   │ DXX ...      │
         │Сторона  4   │ XXX ... XEEE │   │         3   │ DXX ...      │
         │   1     5   │ XXX ... XEEE │   │Сторона  4   │ XXX ...      │
         │         6   │ XXX ... XEEE │   │   1     5   │ XXX ...      │
         │         7   │ XXX ... EEEE │   │         6   │ XXX ...      │
         │         8   │ XXX ... EEEE │   │         7   │ XXX ...      │
         └─────────────┴──────────────┘   │         8   │ XXX ...      │
                                          │         9   │ XXX ...      │
                                          └─────────────┴──────────────┘
         B = запись начальной загрузки      Только для целей данного
         D = элемент каталога                       примера:
         F = таблица  размещения файла      X = секторы, содержащие
                                                данные файла
                                            E = пустые секторы

              Рис. 11-2.  Схема расположения  информации  на  40-трековых,
         двухсторонних, 5,25-дюймовых гибких дисках
              Ниже приведена расчетная формула, которую можно использовать
         для  проверки результатов,  выводимых на экран программой CHKDSK,
         когда она обрабатывает 80-трековый, 5,25-дюймовый гибкий диск:

             80 треков х 15 секторов х 512 байтов х 2 стороны =
         = 1228800 байтов (= 1200 Кбайт или 1,2 Мбайт общей емкости)

              Операционная система  MS-DOS версии 3.0 обеспечила поддержку
         3,5-дюймовых гибких дискет.  3,5-дюймовые дискеты могут тоже фор-
         матироваться в такие же односторонние или двухсторонние форматы с

                                      - 11-7 -
         восемью или девятью секторами на одном треке, как это было в слу-
         чае использования 40-трековых,  5,25-дюймовых дискет при условии,
         что физическое имя дисковода будет задано командой FORMAT. Двухс-
         торонний, 80-трековый формат с 9 секторами на трек для 3,5-дюймо-
         вых дискет был также впервые введен основной операционной  систе-
         мой MS-DOS версии 3.0.  На рис. 11-3 представлена структура диска
         в этом формате. Этот формат предоставляет возможность использова-
         ния общей емкости памяти в 720 Кбайт:

                 80 треков х 9 секторов х 512 байтов х 2 стороны =
                  =  737280 байтов ( = 720 Кбайт общей емкости)

              3,5-дюймовые дискеты форматируются в формат 720  Кбайт путем
         задания  имени логического дисковода командой FORMAT без парамет-
         ров, определяющих формат. Используемый логический дисковод, кото-
         рый  был специально создан для форматирования 720 Кбайтных гибких
         дискет,  создается во время начальной загрузки, если представлен-
         ная ниже строка включена в файл CONFIG.SYS:
                         DEVICE = DRIVER.SYS/D:х

         где х представляет собой физический номер дисковода для 80-треко-
         вых,  3,5-дюймовых  дискет  (0=A:,  1=B:  и  так   далее).   Файл
         DRIVER.SYS представляет собой драйвер,  поставляемый операционной
         системой MS-DOS версий 3.2 и старше.  При начальной загрузке сис-
         темы файл DRIVER.SYS создает логический дисковод,  используя сле-
         дующую имеющуюся букву,  обозначающую дисковод, и приписывает эту
         букву заданному физическому дисководу.  После того,  как диск был
         отформатирован в формат 720 Кбайт,  его можно считывать и на него
         можно производить запись, используя имя физического дисковода или
         соответствующее имя логического дисковода.
             Операционная система MS-DOS версии  3.30  внедрила  еще  один
         формат повышенной емкости для 3,5-дюймовых дискет,  содержащих по
         80 треков,  каждый из которых отформатирован на 18 секторов  (см.
         рисунок 11-3).  Этот формат предоставляет общую емкость дискеты в
         1,44 Мбайта при использовании дисков, протестированных на 2 Мбай-
         та.  Специальные дисководы, предназначенные для 3,5-дюймовых дис-
         кет, впервые введенные в персональных компьютерах типа IBM  PS/2,
         требуются для поддержания этого формата.  1,44-Мегабайтные диско-
         воды поддерживают также формат 720-Кбайтных дисков:
                 80 треков х 18 секторов х 512 байтов х 2 стороны =
                  = 1474560 байтов ( = 1,44 Мбайта общей емкости)



                                      - 11-8 -











             Формат расположения пятнадцати     Формат  расположения девяти
                   секторов на треке                 секторов на треке
               (5,25-дюймовые  дискеты)            (3,5-дюймовые дискеты)
             ┌───────────────────────────┐   ┌────────────────────────────┐
             │       \   Трек            │   │       \   Трек             │
             │         \         ...   7 │   │         \         ...    7 │
             │           \   012 ... 789 │   │           \   012 ...   89 │
             │      Cектор ┌─────────────┤   │      Cектор ┌──────────────┤
             │         1   │ BXX ... XEE │   │         1   │ BXX ...   XX │
             │         2   │ FXX ... XEE │   │         2   │ FXX ...   XX │
             │         3   │ FXX ... XEE │   │         3   │ FXX ...   XX │
             │         4   │ FXX ... XEE │   │Сторона  4   │ FXX ...   XX │
             │         5   │ FXX ... XEE │   │   0     5   │ FXX ...   XX │
             │         6   │ FXX ... XEE │   │         6   │ FXX ...   XX │
             │Сторона  7   │ FXX ... EEE │   │         7   │ FXX ...   XX │
             │   0     8   │ FXX ... EEE │   │         8   │ DXX ...   XX │
             │         9   │ FXX ... EEE │   │ ________9   │ DXX ...   XX │
             │        10   │ FXX ... EEE │   │         1   │ DXX ...   XX │
             │        11   │ FXX ... EEE │   │         2   │ DXX ...   XX │
             │        12   │ FXX ... EEE │   │         3   │ DXX ...   XX │
             │        13   │ FXX ... EEE │   │Сторона  4   │ DXX ...   XX │
             │        14   │ FXX ... EEE │   │   1     5   │ DXX ...   XX │
             │ _______15   │ FXX ... EEE │   │         6   │ XXX ...   XX │
             │         1   │ DXX ... EEE │   │         7   │ XXX ...   XX │
             │         2   │ DXX ... EEE │   │         8   │ XXX ...   XX │
             │         3   │ DXX ... EEE │   │         9   │ XXX ...   XX │
             │         4   │ DXX ... EEE │   └─────────────┴──────────────┘
             │         5   │ DXX ... EEE │
             │         6   │ DXX ... EEE │
             │Сторона  7   │ DXX ... EEE │
             │   1     8   │ DXX ... EEE │
             │         9   │ DXX ... EEE │
             │        10   │ DXX ... EEE │
             │        11   │ DXX ... EEE │
             │        12   │ DXX ... EEE │
             │        13   │ DXX ... EEE │
             │        14   │ DXX ... EEE │
             │        15   │ XXX ... EEE │
             └─────────────┴─────────────┘










                                      - 11-9 -
                Формат  расположения восемнадцати секторов на треке
                              (3,5-дюймовые дискеты)
                      ┌──────────────────────────────┐
                      │       \   Трек               │
                      │         \           ...    7 │
                      │           \   012   ...   89 │
                      │      Cектор ┌────────────────┤
                      │         1   │ BXX   ...   XX │
                      │         2   │ FXX   ...   XX │
                      │         3   │ FXX   ...   XX │
                      │         4   │ FXX   ...   XX │
                      │         5   │ FXX   ...   XX │
                      │         6   │ FXX   ...   XX │
                      │         7   │ FXX   ...   XX │
                      │         8   │ DXX   ...   XX │
                      │Сторона  9   │ DXX   ...   XX │
                      │   0    10   │ DXX   ...   XX │
                      │        11   │ DXX   ...   XX │
                      │        12   │ DXX   ...   XX │
                      │        13   │ DXX   ...   XX │
                      │        14   │ DXX   ...   XX │
                      │        15   │ DXX   ...   XX │
                      │        16   │ FXX   ...   XX │
                      │        17   │ FXX   ...   XX │
                      │ _______18   │ FXX   ...   XX │
                      │         1   │ FXX   ...   XX │
                      │         2   │ FXX   ...   XX │
                      │         3   │ FXX   ...   XX │
                      │         4   │ FXX   ...   XX │
                      │         5   │ FXX   ...   XX │
                      │         6   │ FXX   ...   XX │
                      │         7   │ FXX   ...   XX │
                      │         8   │ FXX   ...   XX │
                      │Сторона  9   │ FXX   ...   XX │
                      │   1    10   │ FXX   ...   XX │
                      │        11   │ FXX   ...   XX │
                      │        12   │ FXX   ...   XX │
                      │        13   │ FXX   ...   XX │
                      │        14   │ FXX   ...   XX │
                      │        15   │ FXX   ...   XX │
                      │        16   │ XXX   ...   XX │
                      │        17   │ XXX   ...   XX │
                      │        18   │ XXX   ...   XX │
                      └─────────────┴────────────────┘
         B = запись начальной загрузки      Только для целей данного
         D = элемент каталога                       примера:
         F = таблица  размещения файла      X = секторы, содержащие
                                                данные файла
                                            E = пустые секторы

              Рис. 11-3.  Схема расположения  информации  на  80-трековых,
         двухсторонних,  5,25-дюймовых  и 3,5-дюймовых гибких дисках повы-
         шенной плотности


                             Сектор начальной загрузки

              Самый первый сектор на диске, отформатированном под управле-
         нием операционной системы MS-DOS,  всегда определяется,  как "за-

                                      - 11-10 -
         пись начальной загрузки". Эта запись содержит короткую программу,
         которая автоматически загружается в память,  когда диск использу-
         ется  для загрузки операционной системы MS-DOS после подачи пита-
         ния в систему или после сброса системы. Далее эта программа гово-
         рит   компьютеру  где  ему  искать  на  диске  файлы,  содержащие
         программы операционной системы MS-DOS. После нахождения этих фай-
         лов  программа  начальной загрузки загружает эти файлы в память и
         передает управление операционной системе MS-DOS.  Поскольку коли-
         чество  файлов операционной системы MS-DOS и способ,  которым они
         сохраняются, могут быть различными в зависимости от типа реализа-
         ции   (например,   для   персональных   компьютеров   типа   "IBM
         PC","COMPAQ" или "CompuPro"), содержимое записи начальной загруз-
         ки тоже может варьироваться.
              В целях сохранения логичности сектор начальной загрузки все-
         гда задается первым на отформатированном диске, независимо от то-
         го, собираетесь ли вы сделать этот диск "диском начальной загруз-
         ки" или "диском, содержащим одни только данные".
              Первые три байта записи начальной загрузки  всегда  содержат
         команду перехода.  При начальной загрузке команда перехода прика-
         зывает системе обойти первую часть этой записи и перейти к  прог-
         рамме начальной загрузки. По описанию операционной системы MS-DOS
         версии 2.00 27 байтов записи  начальной  загрузки,  расположенные
         между  начальной командой перехода и программой начальной загруз-
         ки,  содержат информацию о формате диска. Обращаясь к этой группе
         данных, программы могут получить почти всю информацию по формати-
         рованию,  необходимую для диска.  В таблице 11-1 представлено со-
         держимое  блока информации о форматировании находящегося в записи
         начальной загрузки.
              Информация о  форматировании в записи начальной загрузки мо-
         жет оказаться очень нужной при определении формата  диска. Запись
         начальной  загрузки  исходно создается,  когда диск форматируется
         командой FORMAT (для гибких дисков) или командой FDISK (для жест-
         ких дисков). Часть информации о форматировании в записи начальной
         загрузки под названием  "OEM  and  Version"  ("Фирма-изготовитель
         комплектующего  оборудования  и  версия")  обычно содержит номера
         версии и реализации использовавшейся операционной  системы MS-DOS
         для создания записи начальной загрузки.  Если ,  например, версия
         3.3 операционной системы IBM-DOS использовалась для  форматирова-
         ния диска это поле будет содержать информацию "IBM 3.3".  Осталь-
         ные элементы информации по  форматированию  из  записи  начальной
         загрузки  представляют  собой набор (надмножество) из блока пара-
         метров BIOS (блок ВРВ) (см.  главу 6), поскольку он уже существо-
         вал, во время форматирования диска.
              Последние три элемента информации  о  форматировании  (коли-
         чество  секторов на треке,  количество головок и количество скры-
         тых) секторов определяются расчетным путем и эти данные  вставля-
         ются в запись начальной загрузки в процессе форматирования диска.
              Программа READFMT,  представленная листингом 11-1,  содержит
         описание способа, при помощи которого информация о форматировании
         из записи начальной загрузки считывается с диска  и  отображается
         на экране дисплея.  Кроме элементов форматирования,  которые при-
         сутствуют в записи начальной загрузки,  программа  READFMT  также
         осуществляет  расчет  нескольких других элементов,  относящихся к
         форматированию,  таких как общая системная память,  общая  память
         данных и общая емкость дисков. Программа READFMT отображает полу-
         ченные результаты на экране дисплея.


                                     - 11-11 -
                                                        Таблица 11-1
                    Информация по форматированию, содержащаяся в
                            записи начальной загрузки
         ──────────────────────────────────────────────────────────────
         Смещение  Смещение
         (деся-   (шестнадца-   Размер     Содержание  поля
         тичное)   тиричное)
         ──────────────────────────────────────────────────────────────
           0         00       3 байта  Ближний переход к программе
                                       начальной загрузки
         ─────────────────────────────────────────────────────────────┐
           3         03       8 байтов Название фирмы-изготовителя    │
                                       оборудования и его версия   И  │
         ───────────────────────────────────────────────────────┐  Н  │
          11         0B       1 слово  Количество байтов    Б   │  Ф  │
                                       в секторе            Л   │  О Ф│
          13         0D       1 байт   Количество секторов  О   │  Р О│
                                       в кластере           К   │  М Р│
          14         0E       1 слово  Число зарезервиро-      B│  А М│
                                       ванных секторов      П  I│  Ц А│
          16         10       1 байт   Количество таблиц    А  O│  И Т│
                                       FAT                  Р  S│  Я И│
          17         11       1 слово  Количество элементов А   │    Р│
                                       в каталоге           М   │  П О│
          19         14       1 слово  Количество логичес-  Е   │  О В│
                                       ких секторов         Т   │    А│
          21         15       1 байт   Байт описателя среды Р   │    Н│
          22         16       1 слово  Количество секторов  О   │    И│
                                       таблицы FAT          В   │    Ю│
         ───────────────────────────────────────────────────────┘     │
          24         18       1 слово  Количество секторов в треке    │
          26         1A       1 слово  Количество  головок            │
          28         1С       1 слово  Количество  скрытых  секторов  │
         ─────────────────────────────────────────────────────────────┤
          30         1E     416 байтов Программа начальной загрузки   │
         446         1BE     16 байтов Информация о разделении        │
                                       памяти                         │
         462         1CE     50 байтов Остальная часть программы      │
                                        начальной загрузки            │
         ─────────────────────────────────────────────────────────────┘


              * Для операционной системы МS-DOS версий 2.Х = 3  байто-
         вый переход
                Для операционной системы МS-DOS версий 2.Х  =  2  байтовый
         короткий переход плюс операция NOP.
              ** Общее количество элементов в корневом каталоге.
              *** Бай ты описателя среды не всегда являются действительны-
         ми, как для операционной системы MS-DOS версии 2.0
              **** Относится только к жестким дискам,  содержащим  таблицы
         начальной загрузки; эта область не используется на гибких дисках.




                                     - 11-12 -
                    Листинг 11-1. Программа READFMT
         ────────────────────────────────────────────────────────────
            PAGE          50,132
            TITLE         READFMT.ASM/.EXE
           .SALL          ; подавить выдачу макрорасширений в программе
           .8086          ; пользоваться  только командами
                          ; микропроцессоров 8086/8088
         ;*************************************************************
         ;**  Программа READFMT  Версии 1.00
         ;**     Настоящая  программа считывает сектор начальной заг-
         ;** рузки с любого диска, расшифровывает обнаруженный в  за-
         ;** писи  начальной загрузки блок параметров BIOS(BPB),и вы-
         ;** водит на экран дисплея эту информацию и некоторую другую
         ;** расчетную информацию.
         ;**
         ;**     Примечание: во время создания этой программы  перек-
         ;** лючатель  LINK  "/СР:1"  должен использоваться для того,
         ;** чтобы во время загрузки программы, ей распределялось  бы
         ;** действительно  нужное  количество  памяти.  По умолчанию
         ;** максимальным объемом распределяемой памяти в том случае,
         ;** когда "/СР:1" не задан, является вся память  выше  точки
         ;** загрузки  программы, что вызывает завершение программы с
         ;** выдачей сообщения об ошибке, потому что она не в состоя-
         ;** нии сделать дополнительное  перераспределение памяти  во
         ;** время своей работы.
         ;*************************************************************
         ;
         ;   СОСТАВ:
         INCLUDE       stdequ.inc  ; включить стандартный файл равенств
         INCLUDE       stdmac.inc  ; включить стандартный файл макросов
         INCLUDELIB    stdlib.lib  ; включить  стандартную библиотеку
                                   ; STDLIB.LIB во временное редакти-
                                   ; рования
                                   ;
         ; Заявки на программы обращения к внешним  библиотекам,
         ; находящиеся в STDLIB.LIB
         EXTRN  dosv2con:NEAR      ; получить и вывести на экран текущую
                                   ; версию DOS
         EXTRN  dosver:NEAR        ; дать текущую версию  DOS
         EXTRN  bin2dec2:NEAR      ; вывести на экран дисплея DX:AX в
                                   ; десятичных цифрах кода ASCII
                                   ; (если  регистр  DX=),  регистр AX
                                   ; считается беззнаковым
         ;
         ; - - - - - -  ИНИЦИАЛИЗАЦИЯ - - - - - - - - - - - - - - - - - -
         ;
         .MODEL   SMALL            ; малая модель
         .STACK  2048              ; создать 2 Кбайтовый  стек
         ;
         ;*************************************************************
         ;  ГЛАBHАЯ  ПРОГРАММА
         ;
         .DATA
         ;
         ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ;      Cсылки и обращения к компонентам записи начальной заг-
         ; рузки,  считанной  с диска и помещенный в блок памяти, осу-

                                     - 11-13 -
         ; ществляются при помощи ES.  Обращения  производятся  только
         . компонентам  блока  "Блок параметров BIOS"(BPB); первые три
         ; байта и все данные расположенные после  области  блока  ВРВ
         ; записи начальной загрузки, игнорируются.
         ;
         bootrecord     STRUC
         BootJump       db     3 DUP (?) ; исходная команда перехода
         OEMstring      db     8 DUP (?) ; фирма-изготовитель и версия
                                         ; операционной системы MS-DOS
         SectorBytes    dw     ?         ; количество байтов в секторе
         ClusterSec     db     ?         ; количество секторов в кластере
         ReservedSec    dw     ?         ; зарезервированные сектора
         FATcopies      db     ?         ; количество копий таблицы FAT
         DirEntries     dw     ?         ; количество элементов в
                                         ; корневом каталоге
         TotalSectors   dw     ?         ; общее количество  секторов
                                         ; диска (100% диска)
         MediaDescrip   db     ?         ; описатель среды
         FATsectors     dw     ?         ; количество секторов, занятых
                                         ; одной таблицей FAT
         TrackSectors   dw     ?         ; количество секторов в треке
         Heads          dw     ?         ; количество головок
         HiddenSectors  dw     ?         ; количество скрытых секторов
         bootrecord     ENDS
         ;
         .CODE
         ;
         ; Cохранение локальных данных (храните эти определения
         ; в сегменте  программы)
         ;
         DSsave         dw    seg DGROUP ; память для регистра DS
         ;
         .DATA
         PSPseg         dw     ?         ; сегмент PSP (Префикс про-
                                         ; граммного сегмента)
         .CODE
         main     PROC NEAR              ; начало основного процесса
         ;
         ;***********************************************************
         ; ЗАПУСК ПРОГРАММЫ
         ;***********************************************************
              mov   ds,DSsave           ; инициализация DS
              mov   ax,es               ; получить адрес сегмента PSP
              mov   word ptr PSPseg,ax  ; ....... и сохранить его
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Bывести на экран дисплея сообщение о запуске
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

               @DisStr Start1_Msg       ; вывести на экран дисплея
                                        ; сообщение о запуске
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Получить номер/имя дисковода
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  mov   di,80h                  ; командная строка
                  cmp   byte ptr es:[di],0      ; есть ли параметры?
                  je    get_default_drive       ; нет, получить дисковод

                                     - 11-14 -
                                                ; по умолчанию
                  cmp   byte ptr es:[di+3],':'  ; присутствует ли двое-
                                                ; точие?
                  jne   get_default_drive       ; нет, получить дисковод
                                                ; по умолчанию
         get_disk_drive:                        ; получить дисковод в
                                                ; командной строке
                  xor   ah,ah                   ; очистить AH
                  mov   al,byte ptr es:[di+2]   ; получить заданный
                                                ; дисковод
                  cmp   al,">"                  ; использовалась ли
                                                ; переадресовка?
                  je    get_default_drive       ; да, получить дисковод
                                                ; по умолчанию
                  cmp   al,61h                  ; дисковод задан буквами
                                                ; верхнего регистра?
                  jge   convert_upper           ; да, выполнить преобра-
                                                ; зование из символов
                                                ; ASCII верхнего регистра
                  sub   al,40h                  ; иначе  выполнить  из
                                                ; символов ASCII  нижнего
                                                ; регистра
                  jmp   short test_drive        ; и продолжить
         convert_upper:
                  sub   al,60h                  ; преобразование символов
                                                ; ASCII верхнего регистра
         test_drive:
                  cmp   al,1                    ; число меньше единицы?
                  jl    bad_drive               ; да, выйти на сообщение
                                                ; об ошибке
                  dec   al                      ; иначе выполнить А:=0,
                                                ; ...... В: = 1  и т.д.
                  cmp   al,25                   ; результат предыдущeй
                                                ; команды > 25 (>Z:)?
                  jg    bad_drive               ; да, выйти на сообщение
                                                ; об ошибке
                  jmp   short drive_used        ; иначе  сохранить
                                                ; указанный дисковод
         get_default_drive:
                  mov   ah,19h                  ; получить дисковод
                                                ; по умолчанию
                  @DosCall
         drive_used:
                  mov   byte ptr DiskDrive,al   ; сохранить дисковод
                  jmp   short drive_end         ; и продолжить
         bad_drive:
                  @DisStr BadDrive_Msg          ; иначе вывести на экран
                                                ; сообщение об ошибке
                                                ;(синтаксической ошибке)
                  jmp   terminate               ; и выйти в DOS
         drive_end:
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Cчитывание в память информации сектора начальной загрузки.
         ; После возвращения ES:DI(ES:0) указывает на  блок  памяти,
         ; содержащий  запись  начальной загрузки.
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                                      - 11-15 -
         .DATA
         BootSeg   dw    ?                      ; сохранение адреса
                                                ; сегмента блока памя-
                                                ; ти содержащего копию
                                                ; записи начальной
                                                ; загрузки
         .CODE
                   mov   bx,40h                 ; распределить 1024 байта
                   call  memalloc               ; распределить  блок
                   jnc   read_boot              ; продолжить, если не
                                                ; было ошибок
                   call  mem_err_handler        ; иначе обработать ошибку
                   jmp   terminate              ; и выйти в DOS
                                                ;
         ;                                      ;
         read_boot:
                   mov   word ptr BootSeg,ax    ; сохранить адрес сег-
                                                ; мента
                   push  ax                     ; и  сохранить  его
                   mov   al,byte ptr DiskDrive  ; получить  дисковод
                                                ; для считывания
                   xor   ah,ah                  ; очистить AH
                   pop   ds                     ; получить адрес сег-
                                                ; мента нового блока
                   mov   dx,0                   ; считать логический
                                                ; сектор 0
                   mov   cx,1                   ; считать в один сектор
                   mov   bx,0                   ; поместить данные в DS:0
                   jnt   25h                    ; считать диск
                   jc    read_boot_error        ; выйти, если произошла
                                                ; ошибка
                   popf                         ; очистить флаги, про-
                                                ; толкнутые в стек во
                                                ; время прерывания
                                                ; "int 25h"
                   mov   ds,DSsave              ; повторная инициали-
                                                ; зация области DS
                   mov   ax,word ptr BootSeg    ; получить адрес сегмен-
                                                ; та начальной загрузки
                   mov   es,ax                  ; и инициализировать в
                                                ; него ES
                   xor   di,di                  ; со смещением 0
                   jmp   end_read_boot           ; и продолжить
         ;
         read_boot_error:
                   popf                         ; очистить флаги, про-
                                                ; толкнутые в стек во
                                                ; время прерывания
                                                ; "int 25h"
                   mov   ds,DSsave              ; повторная инициали-
                                                ; зация области DS
                   @DisStr ReadError_Msg       ; выйти с выдачей
                   jmp   terminate              ; сообщения об ошибке
         ;
         end_read_boot:
         ;

                                     - 11-16 -
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ;     Проверить,  чтобы  считанная  запись начальной загрузки
         ; содержала  нужную  нам  информацию.  Если  диском  является
         ; 160-Кбайтный или 320-Кбайтный гибкий диск, запись начальной
         ; загрузки  будет  содержать  нужную нам информацию блока ВРВ
         ; (это может оказаться правильным также для некоторых нестан-
         ; дартных форматов дисков , в случае чего таблица FAT  должна
         ; считываться  с  целью  получения  байта идентификатора (ID)
         ; формата. Этот байт требуется для определения формата  диска
         ; (является  ли  диск  160-Кбайтным  для -версии операционной
         ; системы DOS 1.0 или; 360-Кбайтным для  версии  операционной
         ; системы DOS 1.1.
         ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ;

                   mov    bx,20h              ; распределить 512 бай-
                                              ; ... тов (32 параграфа)
                   call   memalloc            ; распределить блок памяти
                   jnc    read_fat            ; продолжить,  если ошибок
                                              ; не было
                   call   mem_er_handler      ; иначе перейти на про-
                                              ; грамму обработки ошибок
                   jmp    terminate           ; и выйти в DOS
         ;
         read_fat:
         .DATA
         FATSeg    dw     ?                     ; адрес  сегмента  из
                                                ; таблицы  FAT
         .CODE
                   mov    word ptr FATseg,ax    ; сохранить адрес сег-
                                                ; мента FAT
                   push   ax                    ; и сохранить его
                   mov    al,byte ptr DiskDrive ; получить дисковод для
                                                ; считывания
                   xor    ah,ah                 ; очистить  AH
                   pop    ds                    ; получить адрес сег-
                                                ; мента нового блока
                   mov    dx,1                  ; очистить логический
                                                ; сектор 1
                   mov    cx,1                  ; считать в один сектор
                   mov    bx,0                  ; сохранить данные в DS:0
                   jnt    25h                   ; читать диск
                   jnc    process_FAT           ; продолжить, если ошибок
                                                ; не было
                   popf                         ; иначе, сбросить флаги
                   mov    ds,DSsave             ; повторная инициализа-
                                                ; ция области DS
                   @DisStr ReadError_Msg        ; выйти с сообщением об
                                                ; ошибке
                   mov    ax,word ptr FATSeg    ; получить адрес сегмента
                                                ; начальной  загрузки
                   call   memfree               ; освободить блок
                   jnc    end_fat_err           ; выйти, если не было
                                                ; ошибок
                   call   mem_err_handler       ; иначе, вывести на
                                                ; экран дисплея сообще-
                                                ; ние об  ошибке

                                     - 11-17 -
         end_fat_err:
                   jmp    terminate             ; выйти в DOS
         ;
         process_FAT:
                   popf                         ; очистить флаги, про-
                                                ; толкнутые в стек во
                                                ; время прерывания
                                                ; "int 25h"
                   mov    ds,DSsave             ; повторная инициализа-
                                                ; ция области DS
                   mov    ax,word ptr FATSeg    ; получить адрес сегмента
                                                ; начальной  загрузки
                   mov    es,ax                 ; и инициализировать ES
                   xor    di,di                 ; в него со смещением 0
         .DATA
         FAT_ID    db     ?                     ; байт идентификации
                                                ; (ID) из таблицы FAT
         .CODE

                   mov    al,byte ptr es:[di]   ; получить элемент О
                                                ; таблицы FAT
                   mov    byte ptr FAT_ID,at    ; и сохранить его как байт
                   call   memfree               ; освободить сегмент
                                                ; таблицы FAT
                                                ; (адрес находится в ES)
                   jnc    comp_byte_id          ; продолжить, если не
                                                ; было ошибок
                   call   mem_err_handler       ; иначе вывести на экран
                                                ; сообщение  об ошибке
                   jmp    terminate             ; выход в операционную
         ;                                      ; систему DOS
         comp_byte_id:
                   mov    ax,word ptr BootSeg   ; указать на сегмент
                                                ; начальной загрузки
                   mov    es,ax                 ; ES:0 указать на
                   xor    di,di                 ; запись  начальной
                                                ; загрузки
                   mov    al,byte ptr FAT_ID    ; получить идентифика-
                                                ; тор (ID) таблицы FAT
                   cmp    al,byte ptr es:[di].MediaDescrip ; и сравнить
                                                ; с битом ID
                                                ; в записи  начальной
                                                ; загрузки
                   jne    chk_dos1_fmt          ; если иначе, то решить
                   jmp    end_read_fat          ; иначе, продолжить
         chk_dos1_fmt:
                   cmp    al,0FEh               ; это  160-Кбайтный
                                                ; гибкий диск?
                   je     init_dos1_fmt         ; да, инициализировать
                                                ; запись начальной
                                                ; загрузки
                   cmp    al,0FFh               ; иначе, это 320-Кбайт-
                                                ; ный  гибкий  диск?
                   je     init_dos1_fmt         ; да, инициализировать
                                                ; запись начальной
                                                ; загрузки

                                     - 11-18 -
         .DATA
         UnknownMedia db "Невозможно определить формат диска."
                      db  "Возможно, это диск не "
                      db  "операционной системы MS-DOS.",CR,LF,"$"
         .CODE
                   @DisStr UnknownMedia        ; вывести на экран
                                               ; сообщение об ошибке
                   jmp     terminate           ; выход в операционную
                                               ; систему DOS
         init_dos1_fmt:
                ; Инициализировать элементы  формата, которые одинаковы
                ; для 160-Кбайтных и 320-Кбайтных форматов дисков:
                   mov     word ptr es:[di+3],"D"   ; передать по буквам
                                                    ; "DOS  1.X"
                   mov     word ptr es:[di+4],"O"   ; в поле ОЕМ и
                   mov     word ptr es:[di+5],"S"   ; версии DOS записи
                   mov     word ptr es:[di+6]," "   ; начальной загрузки
                   mov     word ptr es:[di+7],"1"
                   mov     word ptr es:[di+8],"."
                   mov     word ptr es:[[b]di].SectorBytes,512 ; коли-
                                              ; чество байтов в секторе
                   mov     word ptr es:[di].ReservedSec,1   ; зарезер-
                                                  ; вированные секторы
                   mov     word ptr es:[di[.FATcopies,2     ; количест-
                                                  ; во копий таблицы FAT
                   mov     word ptr es:[di].FATsectors,1    ; количество
                                                  ; секторов таблицы  FAT
                   mov     word ptr es:[di].TrackSectors,8  ; количество
                                                  ; секторов в треке
                   mov     word ptr es:[di].HiddenSectors,0 ; количество
                                                  ; скрытых секторов
                   cmp     al,0FEh      ; это гибкий 160-Кбайтный диск?
                   je      init_160K    ; да, инициализировать запись
                                        ; начальной загрузки
                   cmp     al,0FFh      ; иначе, это гибкий 320-Кбайтный
                                        ; диск?
                   je      init_320K    ; да, инициализировать запись
                                        ; начальной загрузки
         ;
         init_160K:
                   mov word ptr es:[di.9],"0"          ; это версия
                                                       ; "DOS 1.0"?
                   mov     word ptr es:[di.10],"?"          ;
                   mov     byte ptr es:[di].ClusterSec,1    ; количество
                                                            ; секторов в
                                                            ; кластере
                   mov     word ptr es:[di].DirEntries,64   ; количество
                                                            ; элементов
                                                            ; в каталоге
                   mov     word ptr es:[di].TotalSektors,320 ; общее ко-
                                                             ; личество
                                                             ; секторов
                                                             ; на диске
                   mov     byte ptr es:[di].MediaDescrip,0FEh ; описатель
                                                              ; носителя
                   mov     word ptr es:[di].Heads,1  ; количество головок
                   jmp          end_read_fat

                                     - 11-19 -
         ;
         init_320K:
                   mov     word ptr es:[di.9],"1"      ; это версия
                                                       ; "DOS 1.1"?
                   mov     word ptr es:[di.10],"?"
                   mov     byte ptr es:[di].ClusterSec,2    ; количество
                                                            ; секторов в
                                                            ; кластере
                   mov     word ptr es:[di].DirEntries,112  ; количество
                                                            ; элементов
                                                            ; в каталоге
                   mov     word ptr es:[di].TotalSektors,640 ; общее ко-
                                                             ; личество
                                                             ; секторов
                                                             ; на диске
                   mov     byte ptr es:[di].MediaDescrip,0FFh ; описатель
                                                              ; носителя
                   mov     word ptr es:[di].Heads,2  ; количество головок
                   jmp          end_read_fat
         ;
         end_read_FAT:
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ;      Вычислить величины, отсутствующие в  блоке  параметров
         ; BIOS.  Примечание:  ES:DI  (смещение 0) должен указывать на
         ; начало записи начальной загрузки, считанной в  память.  Все
         ; расчетные значения сохраняются в сегменте данных.
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         get_new_values:
                    xor    di,di    ; очистить DI
         ;
         ; Рассчитать общее количество секторов, используемых для всех
         ; копий таблицы  FAT.
                xor    ah,ah                          ; очистить AH
                mov    al,byte ptr es:[di].FATcopies  ; получить копии
                                                      ; таблицы FAT
                xor    dx,dx                          ; очистить DX
                mov  bx,word ptr es:[di].FATsectors   ; получить число
                                                      ; секторов таблицы
                                                      ; FAT
                mul    bx                             ; умножить на
                                                      ; это число
                mov    word ptr TotalFATSec,ax      ; сохранить ре-
                                                    ; зультат в 1 слове
         ;
         ; Рассчитать общее  количество  секторов,  используемых всеми
         ; элементами  каталога
                mov    ax,word ptr es:[di].DirEntries ; получить общее
                                                      ; количество эле-
                                                      ; ментов корневого
                                                      ; каталога

                    mov    bx,word ptr DirEntBytes    ; получить размер
                                                      ; в байтах эле-
                                                      ; ментов каталога
                    xor    dx,dx                      ; очистить  DX
                    mul    bx                         ; умножить

                                     - 11-20 -
                    mov    bx,word ptr                ;
         es:[di].SectorBytes     ; получить количество байтов в секторе
                    xor    dx,dx                      ; очистить  DX
                    div    bx                         ; разделить
                    mov    word ptr DirSectors,ax     ; сохранить ре-
                                                      ; зультат в 1 слове
         ;
         ; Вычислить  общее  количество цилиндров
               mov    ax,word ptr es:[di].TotalSectors  ; получить общее
                                                   ; количество секторов
               mov    bx,word ptr es:[di].TrackSectors   ; получить ко-
                                            ; личество секторов в  треке
               xor    dx,dx                          ; очистить  DX
               div    bx                           ; и разделить на него
               mov    bx,word ptr es:[di].Heads ; получить число головок
               xor    dx,dx                        ; очистить  DX
               div    bx                           ; и разделить на него
               cmp    word ptr es:[di].HiddenSectors ; скрытые сектора?
               je     store_cyl                      ; нет, теперь мы
                                     ; имеем общее количество цилиндров
               mov    cx,word ptr es:[di].HiddenSectors ; иначе, скрытые
                                                         ; сектора = 1
               cmp    cx,word ptr es:[di].TrackSectors    ; цилиндр?
               je     add_cyl              ; да
               mov    ax,0                 ; иначе, произошла ошибка
               jmp    short store_cyl      ;
         add_cyk:
                     add   ax,1     ; добавить дополнительный цилиндр
         store_cyl:
                     mov   word ptr Cylinders,ax ; сохранить результат
         ;
         ; Получить  общее количество байтов на всем (100%) диске
                     mov   ax,word ptr es:[di].TotalSectors ; получить
                                           ; общее количество секторов
                     xor   dx,dx                          ; очистить DX
                     mov   bx,word ptr es:[di].SectorBytes  ; получить
                                         ; количество байтов в секторе
                     mul   bx                      ; и умножить на него
                     mov   word ptr TotalBytes,ax  ; и сохранить резуль-
                                          ; тат, состоящий из двух слов
                     mov   word ptr TotalBytes.2,dx ; из AX и DX
         ;
         ; Получить общее количество секторов данных (в которых могут
         ; сохраняться файлы)
                     mov   ax,word ptr es:[di].TotalSectors ; получить
                                           ; общее количество секторов
         xor   dx,dx                                    ; очистить  DX
                    sub   ax,word ptr es:[di].ReservedSec ; вычесть
                                           ; зарезервированные секторы
                    sub   ax,word ptr TotalFATSec  ; вычесть общее
                                     ; количество секторов таблицы FAT
                                             ; (все копии таблицы FAT)
                sub   ax,word ptr DirSectors    ; вычесть  секторы
                                                ; корневого каталога
                mov   word    ptr DataSectors,ax ; и сохранить результат
         ;
         ; Получить количество байтов в кластере

                                     - 11-21 -
                 xor   ah,ah                           ; очистить AH
                 mov   al,byte ptr es:[di].ClusterSec  ; получить секторы
                                                       ; кластера
                 xor   dx,dx                           ; очистить DX
                 mov   bx,word ptr es:[di].SectorBytes ; получить байты
                                                       ; сектора
                 mul   bx                      ; и умножить на это число
                 mov   word ptr ClusterBytes,ax  ; и сохранить результат
         ;
         ; Получить общее количество секторов
                 mov   ax,word ptr DataSectors ; получить секторы данных
                 xor   bh,bh                      ; очистить BH
                 mov   bl,byte ptr es:[di].ClusterSec ; получить секторы
                                                      ; кластера
                 xor   dx,dx                     ; очистить DX
                 div   bx             ; разделить на количество секторов
                 mov   word ptr TotalClusters,aх ; и сохранить результат
                                                 ; в слове
         ;
         ; Получить количество битов в элементе таблицы FAT.
         ; Всегда 12 битов, если общее количество кластеров = 4,085 или
         ; меньше.
         ; Всегда 16 битов, если общее количество кластеров больше
         ; 4,085.
                 cmp   word ptr TotalClusters,4085       ; общее коли-
                                       ; чество кластеров больше 4085?
                 jle   got_entry_size  ; нет используйте 12-битовое
                                       ; значение по умолчанию
                 mov   al,16           ; иначе - 16-битовое значение
                 mov   byte ptr FATentryBits,al ; и сохранить значение
         got_entry_size:
         ;
         ; Получить общее количество байтов данных (используемых байтов)
                 mov   ax,word ptr DataSectors   ; получить общее коли-
                                                 ; чество секторов
                 xor   dx,dx,                    ; очистить DX
                 mov   bx,word ptr es:[di].SectorBytes ; получить байты
                                                 ; сектора
                 mul   bx                     ; и умножить на это число
                 mov   word ptr DataBytes,ax  ; и  сохранить результат
                                              ; в 2 словах
                 mov   word ptr DataBytes,2,dx   ; из AX и DX
         ;
         ; Вычислить регистр  диска  в  килобайтах или мегабайтах
                 mov   ax,word ptr TotalBytes    ; получить общее коли-
                                               ; чество байтов на диске
                 mov   dx,word ptr TotalBytes.2  ; ... (двойное слово)
                 mov   cx,1024                   ; установить делитель
                 div   cx           ; и получить значение в килобайтах
                 mov   word ptr KBytes,ax        ; сохранить значение
                 cmp   ax,1000              ; вычислить в Мегабайтах?
                 jl    dis_info             ; нет,  мы  закончили
                 mov   bx,1000              ; иначе установить делитель
                 xor   dx,dx                ; очистить регистр DX
                 div   bx                   ; и получить мегабайты
                 mov   word ptr Mbytes,ax   ; сохранить главное значение
                 mov   word ptr Mbytes2,dx  ; и сохранить часть, если

                                      - 11-22 -
                                            ; таковая имеется
                 cmp   dx,0                 ; есть ли часть?
                 je    megabytes_end        ; нет,  мы  закончили
                 mov   ax,dx                ; иначе установить делимое
                 mov   bx,10                ; установить  делитель
                 xor   dx,dx                ; очистить регистр DX
         ;
         ; Цикл удаления хвостовых нулей
         compress_loop:
                     div   bx               ; разделить регистр AX на 10
                     cmp   dx,0                ; есть ли остаток?
                     jne   megabytes_end       ; да, мы закончили
                     mov   word ptr Mbytes2,ax ; иначе сохранить новое
                                               ; сжатое значение
                     jmp   short compress_loop ; и снова  повторить
         megabytes_end:
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Отобразить на экране дисплея информацию о диске
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         dis_info:
                   @DisStr Start2_Msg ; отобразить на экране дисплея
                               ; первую часть сообщения о  дисководе
                   xor   ah,ah                 ; очистить регистр AH
                   mov   al,byte ptr DiskDrive ; и вывести на экран
                                               ; имя дисковода
                   inc   al         ; дать ему используемый номер
                   add   al,40h     ; преобразовать его  в  буквы
         ;                          ; ... ASCII верхнего регистра
                   @DisChr al       ; и вывести его на экран
                   @DisChr ':'      ; после него поставить двоеточие
                   @Newline
         ;
                   @DisStr OEM_Msg ; вывести на экран сообщение OЕМ
                                   ; (о фирме-производителя и версии)
                   push  di                     ; сохранить DI
                   mov   di,bootrecord.OEMstring ; указать строку ОЕМ
                   mov   cx,8          ; установить счетчик  символов
         more_char:                       ; ввести дисплейный цикл
                   mov   al,byte ptr es:[di]    ; получить символ
                   @DisChr al   ; отобразить символ на экране дисплея
                   inc   di            ; указать на следующий символ
                   dec   cx            ; счетчик десятичных символов
                   cmp   cx,0          ; все сделаны ?
                   jg    more_char     ; нет, вывести следующий символ
                   @NewLine            ; иначе, мы закончили
                   pop   di                     ; восстановить DI
         ;
                   @DisStr  MeliaDescrip_Msg  ; отобразить на экране
                                              ; описатель  носителя
                   xor   ah,ah,               ; очистить регистр AH
                   mov   al,byte ptr es:[di].MediaDecrip ; считать
                                              ; байтовое значение
                   @DisNum ax,16,2            ; отобразить две шест-
                                              ; надцатиричные цифры
                   cmp   byte ptr es:[di].MediaDescrip,0F8h ;жесткий диск?
                   je fixed_disk   ; да, отобразить на экране сообщение

                                      - 11-23 -

                   @DisStr RemovableMedia_Msg ; иначе - сменный диск
                   jmp   short media_size     ; и теперь сделать размер
                                              ; в Kb/Mb
         fixed_disk:
                      @DisStr FixedMedia_Msg     ; отобразить на экране
                                         ; сообщение о жестком носителе
         media_size:
                      cmp   word ptr Mbytes,0  ; показывать в Мегабайтах
                      je    show_kilobytes     ; нет, в Килобайтах
                      mov   ax,word ptr Mbytes ; да, задать в Мегабайтах
                      @DisNum ax,10,1,0        ; вывод десятичного числа
                                               ; без знака
                      cmp   word ptr Mbytes2,0


         ; есть ли часть?
                      je    done_mbytes        ; нет, мы закончили
                      @DisChr '.'              ; иначе, вывести на
                                               ; экран десятичную точку
                      mov   ax,word ptr Mbytes2 ; задать часть в Мбайтах
                      @DisNum  ax,10,1,0       ; вывод десятичного числа
                                               ; без знака
         done_mbytes:
                      @DisChr 'M'                ; вывести на экран сим-
                                                 ; вол "М"  (Мегабайт)
                      jmp   short done_media     ; и мы закончили
         show_Kilobytes:
                      mov  ax,word  ptr Kbytes   ; получить значение в
                                                 ; Килобайтах
                      @DisNum ax,10,1,0          ; вывод десятичного
                                                 ; числа без знака
                      @DisChr 'K' ; вывести на экран символ "К" (Кбайт)

         done_media:
                      @DisStr Media_Msg        ; вывести на экран конец
                                               ; сообщения
                      @NewLine
         ;
                      @DisStr Cylinders_Msg     ; отобразить на экране
                           ; дисплея общее количество цилиндров (треков)
                      cmp   word ptr Cylinders,0   ; была ли ошибка?
                      jne   show_cyl        ; нет, отобразить на экране
                                   ; дисплея общее количество цилиндров
                      @DisChr '?'  ; иначе, вывести на экран символ
                                   ; "знак вопроса"
                      jmp   short end_cyl         ; и закончить
         show_cyl:
                      mov   ax,word ptr Cylinders ; получить значение
                      @DisNum ax,10,1,0           ; и отобразить его на
                                                  ; экране дисплея
         end_cyl:
                @NewLine
         ;
                @DisStr Heads_Msg         ; отобразить на экране
                                          ; количество головок
                mov   ax,word ptr es:[id].Heads ; получить значение слова

                                      - 11-24 -
                @DisNum ax,10,1,0    ; вывод десятичного числа без знака
                @NewLine
         ;
                @DisStr TrackSectors_Msg   ; отобразить на экране
                            ; дисплея количество секторов в треке
                mov   ax,word ptr es:[di].TrackSector  ; получить
                                                 ; значение слова
                @DisNum ax,10,1,0  ; вывод десятичного числа без знака
                @NewLine
         ;
                @DisStr SectorBytes_Msg          ; отобразить на экране
                                 ; дисплея  количество байтов в секторе
                mov   ax,word ptr es:[id].SectorBytes ; получить значе-
                                                      ; ние слова
                @DisNum ax,10,1,0   ; вывод десятичного числа без знака
                @NewLine
         ;
                @DisStr НiddenSectors_Msg ; отобразить на экране
                           ; дисплея количество скрытых секторов
                mov ax,word ptr es:[di].HiddenSectors ; получить зна-
                                                        ; чение слова
                @DisNum ax,10,1,0   ; вывод десятичного числа без знака
                cmp  word ptr es:[di].HiddenSectors,0 ; есть ли
                                           ; скрытые  сектора?
                je    hidden_done          ; нет, мы закончили
                @DisStr PartitionInfo_Msg  ; иначе, дать инфор-
                                           ; мацию о разделении
         hidden_done:
               @NewLine
         ;
               @DisStr TotalSectors_Msg     ; отобразить на экране
                      ; дисплея общее  количество  секторов  диска
               mov   ax,word ptr es:[di].TotalSectors   ; получить
                                                  ; значение слова
               @DisNum ax,10,1,0 ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr TotalBytes_Msg     ; отобразить на экране
                      ; дисплея общее количество байтов на диске
               mov   ax,word ptr TotalBytes ; получить  значение,
                                  ; состоящее из двух слов и ...
               mov   dx,word ptr TotalBytes.2 ; поместить его в
                                            ; регистры  AX и DX
               call  bin2dec2               ; и вывести на экран
                                            ; результат DX:AX
               @NewLine
         ;
               @DisStr ReservedSec_Msg    ; отобразить на экране
                  ; дисплея количество зарезервированных секторов
               mov   ax,word ptr es:[di].ReservedSec    ; получить
                                                   ; значение слова
               @DisNum ax,10,1,0  ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr FATsectors_Msg    ;отобразить на
                               ; экране дисплея количество секторов
                               ; в одной таблице FAT

                                      - 11-25 -
               mov   ax,word ptr es:[di].FATsectors ; получить
                                                   ; значение слова
               @DisNum ax,10,1,0 ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr FATcopies_Msg    ; отобразить на  экране дисплея
                                        ; количество копий таблицы FAT
               xor   ah,ah          ; очистить AH
               mov   al,byte ptr es:[di].FATcopies  ; получить
                                                ; значение байта
               @DisNum  ax,10,1,0 ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr TotalFATsectors_Msg  ; отобразить на экране
                           ; дисплея общее количество секторов для
                           ; всех таблиц FAT
               mov   ax,word ptr TotalFATSec  ; получить значение слова
               @DisNum ax,10,1,0    ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr DirEntries_Msg         ; отобразить на экране
                   ; дисплея количество элементов корневого каталога
               mov   ax,word ptr es:[di].DirEntries ; получить значение
                                                    ; слова
               @DisNum ax,10,1,0    ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr DirSektors_Msg       ; отобразить  на экране
                               ; дисплея  общее количество секторов
                               ; корневого каталога
               mov   ax,word ptr DirSectors ; получить значение слова
               @DisNum ax,10,1,0   ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr DataSectors_Msg      ; отобразить на экране
         ;            ; дисплея общее  количество  секторов данных
               mov   ax,word ptrDataSectors ; получить значение слова
               @DisNum ax,10,1,0   ; вывод десятичного числа без знака
               @NewLine
         ;

               @DisStr ClusterSectors_Msg        ; отобразить на экране
                             ; дисплея количество секторов  в  кластере
               xor   ah,ah                       ; очистить AH
               mov   al,byte ptr es[di].ClusterSec ; получить значение
                                                 ; байта
               @DisNum  ax,10,1,0   ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr ClusterBytes_Msg          ; отобразить на экране
                                ; дисплея количество байтов в  кластере
               mov   ax,word ptr ClusterBytes ; получить значение слова
               @DisNum ax,10,1,0   ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr Totalclusters-Msg     ; отобразить на экране
                                   ; дисплея общее количество кластеров

                                      - 11-26 -
               mov   ax,word ptr Totalclusters ; получить значение слова
               @DisNum ax,10,1,0   ; вывод десятичного числа без знака
               @NewLine
         ;
               @DisStr FATentrySize_Msg         ; отобразить на экране
                         ; дисплея размер каждого элемента таблицы  FAT
               xor   ah,ah                      ; очистить AH
               mov   al,byte ptr FATentryBits   ; получить значение
                                                ; байта
               @DisNum ax,10,1,0   ; вывод десятичного числа без знака
               @DisStr Bits_Msg                ; указать, что значение
                                               ; задано в битах
               cmp   byte ptr FATentryBits,12  ; определить, сколько
                                               ; имеется байтов
               jg   dis_two_bytes
               @DisStr SmallFAT_Msg   ; элемент таблицы FAT = 1,5 байта
               jmp  short show_fat_done
         dis_two_bytes:
                      @DisStr LargeFAT_Msg     ; элемент таблицы
                                               ; FAT = 2 байта
         show_fat_done:
         ;
                 @NewLine
         ;
                 @DisStr DataBytes_Msg  ; отобразить на экране дисплея
                                    ; количество байтов данных на диске
                  mov   ax,word ptr DataBytes     ; получить значение
                  mov   dx,word ptr DataBytes.2   ; состоящее из двух
                              ; слов и поместить его в регистры AX и DX
                  call  bin2dec2       ; и вывести его на экран дисплея
                  @NewLine
         ;
                  push   es            ; сохранить текущее значение ES
                  mov   ax,word ptr BootSeg   ; получить адрес сегмента
                                              ; распределенного блока
                  mov   es,ax                     ; и назначить ему ES
                  call  memfree                   ; освободить блок
                  pop   es                  ; восстановить значение ES
         ;
         terminate:
                  @ExitToDOS                ; завершить  программу
         ;
         ;************************************************************
         ; Конец программы
         ;************************************************************
         main   ENDP               ; конец главного процесса
         ;
         ;************************************************************
         ; Запуск стандартных программ
         ;*************************************************************
         ;
         ;+++++++++++++++++++++++++++++++++++++++++++++++++
         ; MEM_ERR_HANDLER: Описатель ошибки распределения памяти
         ; (освобождения памяти) изменения размера.
         ;BXОД:       AX = код ошибки
         ;            BX = максимальный доступный блок памяти
         ;                 (если код  ошибки  =  8)
         ;            ЕX = адрес сегмента распределенного блока

                                      - 11-27 -
         ;                 (если код ошибки = 9)
         ;
         ;ВЫХОД:        ни  один  (все  регистры восстановлены)
         ;
         ;Вызываемые стандартные программы : нет
         ;- - - - - - - - - - - - - - - - - - - - - - - - -
         mem_err_handler PROC  NEAR
         ;
                      cmp   ax,7     ; очищенные от мусора управляющие
                                     ;  блоки  памяти ?
                      jne   mem_error8     ; нет, продолжить проверку
         .DATA
         NranshedMemErr_Msg db  "Ошибка распределения памяти:"
                      db"разрушены управляющие блоки памяти.",CR,LF,"$"
         .CODE
                 @DisStr TrashedMemErr_Msg    ; да, выйти с сообщением
                 ret                          ; возврат
         ;
         mem_error8:
                      cmp   ax,8             ; недостаточно памяти ?
                      jne   mem_error9       ; нет, продолжить проверку
         .DATA
         InsuffMemErr_Msg  db  "Ошибка распределения памяти:"
                           db  "недостаточно памяти",CR,LF
                           db  "Hаибольший доступный блок памяти = $"

         .CODE
                  @DisStr InsuffMemErr_Msg   ; да, выйти с сообщением
                  @DisNum bx,10,1,0          ; доступен
                  @NewLine           ; вывести на экран пустую строку
                  ret                        ; возврат
         ;
         mem_error9:
                   cmp   ax,9      ; неправильный  адрес блока памяти?
                   jne   mem_err_unknown    ; нет, неизвестная причина
         .DATA
         IncorrSegAddr_Msg db "Неправильный адрес сегмента для изменения"
                           db "изменения размера/освобождения.",CR,LF
                           db "Адрес сегмента = $"
         .CODE
                      @DisStr IncorrSegAddr_Msg   ; вывести на экран
                                       ; дисплея сообщение об ошибке
                      @DisNum es,16,4  ; вывести на экран дисплея адрес
                                       ; сегмента
                      @NewLine         ; вывести на экран пустую строку
                      ret              ; возврат
         ;
         mem_err_unknown:
         .DATA
         UnknownMemErr_Msg db "Hеизвестная  ошибка распределения/"
                 db "/изменения размера/освобождения памяти.",CR,LF,"$"
         .CODE
                 @DisStr UnknownMemErr_Msg  ; вывести на экран
                                            ; дисплея сообщение
                 ret
         ;
         mem_err_handler ENDP

                                      - 11-28 -
         ;
         ;;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         ; MEMALLOC: Распределить блок памяти заданного размера в
         ; параграфах  (1 параграф = 16 байтам).
         ;
         ;BXОД:       BX = размер в 16-байтовых параграфах запрошенного
         ;                 блока
         ;
         ;ВЫХОД:      "Успешно", если признак переноса = 0  при
         ;             AX = адрес сегмента распределенного
         ;             блока памяти (BX восстанавливается)
         ;             "Сбой",  если признак переноса = 1 при
         ;              AX = код ошибки
         ;                     7 = разрушены управляющие блоки памяти
         ;                     8 = недостаточно памяти
         ;              BX = наибольший  доступный блок памяти
         ;                   в параграфах
         ; Вызываемые стандартные программы: нет
         ;- - - - - - - - - - - - - - - - - - - - - - - - - -- - -
         memalloc          PROC      NEAR
         ;
                      push  bp               ; сохранить указатель базы
                      push  bx               ; сохранить  регистр  BX
                      mov   bp,sp     ; инициализировать указатель базы
         ;
                      xor   al,al     ; очистить AL
                      mov   ah,48h    ; загрузить функцию распределения
                                      ; памяти
                      @DosCall        ; выполнить распределение памяти
                      jnc   end_memalloc     ; выйти, если нет ошибок с
                                     ; с адресом сегмента в регистре AX
                                     ; иначе, выйти с установленным
                                     ; признаком переноса;
                      mov   word ptr [bp],bx ; блок максимального размера
                                             ; (BX) и код ошибки в AX
         ;
         end_memalloc:
                      pop  bx         ; восстановить регистр BX
                      pop  bp         ; восстановить указатель базы
                      ret
         memalloc     ENDP            ;
         ;
         ;
         ;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         ; MEMFREE:  Освобождение  памяти : освободить блок памяти,
         ;          распределенный ранее стандартной программой MALLOC
         ;
         ;BXОД:     ES = адрес сегмента  распределенного блока памяти
         ;
         ;ВЫХОД:   "Успешно", если признак переноса = 0
         ;          (ES восстанавливается)
         ;
         ;         "Сбой",  если признак переноса = 1 при
         ;          AX = код ошибки
         ;              7 = разрушены управляющие блоки памяти
         ;              9 = неправильный адрес (ES  восстанавливается)
         ;

                                      - 11-29 -
         ; Вызываемые стандартные программы: нет
         ;- - - - - - - - - - - - - - - - - - - - - - - - - -- - -
         memfree      PROC      NEAR
         ;
                      push   bp      ; сохранить указатель базы
                      push   es
                      push   ax      ; сохранить регистр AX
                      mov    bp,sp   ; инициализировать указатель базы
         ;
                      xor    al,al             ; очистить AL
                      mov    ah,49h            ; загрузить функцию
                                               ; освобождения памяти
                      @DosCall         ; выполнить освобождение памяти
                      jnc    end_memfree  ; выход, если не было ошибок
                                        ; иначе, выйти с установленным
                                        ; признаком переноса
                      mov    word ptr [bp],ax  ; и код ошибки
                                               ;(в регистре AX)
         ;
         end_memfree:
                      pop    ax         ; восстановить регистр AX
                      pop    es
                      pop    bp         ; восстановить  указатель базы
                      ret
         ;
         memfree ENDP
         ;
         ;
         ;************************************************************
         ; Конец стандартной программы
         ;************************************************************
         ;
         .DATA                       ; переключение на сегмент данных
         ;************************************************************
         ; Hачало области сохранения данных
         ;************************************************************
         ;
         ; Переменные
         ;
         DiskDrive       db 0    ; рабочий дисковод (начальное
                                 ; значение = дисковод по умолчанию)
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Остальные (из вычисленных) переменные параметров дискового
         ; формата :
         Cylinders    dw   ?   ; общее количество цилиндров
         TotalBytes   dd   ?   ; общая емкость диска в байтах
         TotalFATSec  dw   ?   ; общее  количество  секторов  таблицы
                               ; FAT (всех  копий)
         DirEntBytes  dw   32  ; число байтов в элементе каталога
         DirSectors   dw   ?   ; сектора, занятые корневым каталогом
         DataSectors  dw   ?   ; общее количество секторов для хранения
                               ; файлов
         ClusterBytes dw   ?   ; количество  байтов  в  кластере
         TotalSectors dw   ?   ; общее количество кластеров
         FATentryBits db   12  ; количество битов в элементе таблицы FAT
         DataBytes    dd   ?   ; общее количество байтов данных (для
                               ; хранения файла)

                                     - 11-30 -
         Kbytes       dw   ?   ; общее количество килобайт (всего в
                               ; диске)
         Mbytes       dw   0   ; общее количество мегабайт (всего в
                               ; диске)
         Mbytes2      dw   0   ; и общее количество частей в мегабайтах
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Tекстовые сообщения
         ;
         Start1_Msg   db "Идентификатор формата диска операционной"
                      db   "системы  MS-DOS"
                      db "-- Версия 1.00",CR,LF,"$"
         Start2_Msg   db "BPB = Значение, извлеченное из записи"
                      db  " начальной загрузки;"
                      db "CAL = Вычисленное  значение",CR,LF,CR,LF
                      db "Информация о формате для дисковода $"
         ;
         OEM_Msg              db  "BPB: Форматируется при помощи:    $"
         SectorBytes_Msg      db  "BPB: Количество байтов в секторе: $"
         ClusterSectors_Msg   db  "BPB: Количество секторов в "
                              db  "кластере: $"
         ReservedSec_Msg      db  "BPB: Зарезервированные сектора:    $"
         FATcopies_Msg        db  "BPB: Копии таблицы FAT:            $"
         DirEntries_Msg       db  "BPB: Элементы корневого каталога:  $"
         TotalSectors_Msg     db  "BPB: Общее количество секторов "
                              db  "диска: $"
         MediaDescrip_Msg     db  "BPB: Описатель носителя:           $"
         FATsectors_Msg       db  "BPB: Сектора  таблицы FAT "
                              db  "(1 таблицы FAT):  $"
         TrackSectors_Msg     db  "BPB: Общее количество секторов "
                              db  "в цилиндре:  $"
         Heads_Msg            db  "BPB: Головки:                      $"
         HiddenSectors_Msg    db  "BPB: Скрытые  секторы:             $"
         ;
         TotalFATsectors_Msg  db  "CAL: Общее количество секторов "
                              db  "таблицы FAT: $"
         DirSectors_Msg       db  "CAL: Секторы каталога:             $"
         Total Bytes_Msg      db  "CAL: Общее количество байтов на"
                              db  "диске: $"
         Cylinders_Msg        db  "CAL: Общее  количество цилиндров:  $"
         DataSectors_Msg      db  "CAL: Общее количество секторов "
                              db  "данных:    $"
         TotalCluaters_Msg    db  "CAL: Общее количество кластеров:   $"
         ClusterBytes_Msg     db  "CAL: Количество байтов в кластере: $"
         FATentrySyze_Msg     db  "CAL: Размер элемента таблицы FAT:  $"
         DataBytes_Msg        db  "CAL: Общее количество байтов "
                              db  "данных:  $"
         ;
         FixedMedia_Msg       db  "(жесткий $"
         RemovableMedia_Msg   db  "(сменный $"
         Media_Msg            db  "носитель)$"
         Bits_Msg             db  "биты$"
         Bytes_Msg            db  "байты$"
         SmallFAT_Msg         db  "1,5 байта)$"
         LargeFAT_Msg         db  "(2 байта)$"
         CurrPartition_Msg    db  "(в пределах текущего разделения)$"
         PartitionInfo_Msg    db  "(информация о разделении)$"

                                      - 11-31 -
         ;
         ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         ; Сообщения об ошибках:
         NonDOSerr_Msg db "Диск не может быть считан."
                       db "Вероятно, это не диск системы DOS.",CR,LF,"$"
         BadDrive_Msg  db "синтаксическая ошибка или"
                       db "заданный дисковод не разрешен.",CR,LF,"$"
         ReadError_Msg db "Общая ошибка при чтении диска."
                       db CR,LF,"$"
         UnknownErr_Msg db "Неизвестная ошибка - завершение."CR,LF,"$"
         ;
         ;
         ;***********************************************************
         ; Конец памяти данных
         ;***********************************************************
                   END    main                   ; конец программы

         ─────────────────────────────────────────────────────────────



                         Таблицы разделения жесткого диска

              При ведении поддержки жестких или "фиксированных" дисков под
         управлением  операционной  системы MS-DOS версии 2.00 к сведениям
         по форматированию дисков был добавлен новый элемент: таблица раз-
         деления диска. Таблица разделения диска используется для описания
         того,  как диск разделяется на секции.  Эта таблица почти  всегда
         используется  только для жестких дисков (несменных) с емкостями в
         10 Мегабайт и выше. Таблица разделения диска состоит из 16 байтов
         информации,  начинающейся  со  смещением "шестнадцатиричное 01ВЕ"
         относительно начала записи начальной загрузки (первый  сектор  на
         диске). Структура таблицы разделения диска представлена в таблице
         11-2.
              Когда жесткий  диск разделен на одну или более частей коман-
         дой FDISK,  новая запись начальной загрузки с таблицей разделения
         диска  помещается  в  первый сектор каждой части.  Таким образом,
         диск с одной частью содержит  главную  таблицу  разделения  диска
         (она  хранится в записи начальной загрузки в самом первом секторе
         диске), а вторая таблица разделения диска в записи начальной заг-
         рузки  помещается  в  первом секторе самой части.  Дополнительные
         части также содержат свои собственные записи начальной загрузки и
         таблица разделения диска. Главная таблица разделения диска обнов-
         ляется каждый раз, когда используется команда FDISK для изменения
         разделения  диска  тогда  обновляется "поле состояния разделения"
         каждой отдельной части для того, чтобы оно отображало ее активное
         или неактивное состояние.



                                      - 11-32 -
                                                      Таблица 11-2
                      Структура таблица разделения диска
         ─────────────────────────────────────────────────────────────
         Смещение   Смещение
         (деся-     (шестнад-  Размер  Название     Содержимое
         тичное)   цатиричное)
         ─────────────────────────────────────────────────────────────
          0          00        1 байт  Состояние   0 = неактивное
                                       разделения  80h = начально
                                                   загружаемое,
                                                   активное
          1          01        1 байт  Начальная   Целое число
                                       головка
          2          02        1 слово Начальный   См. примечание*
                                       сектор и
                                       цилиндр
          4          04        1 байт  Тип разде-  1 = DOS с 12-битовой
                                       ления**         таблицей FAT
                                                   4 = DOS с 16-битовой
                                                       таблицей FAT
                                                   5 = расширенная DOS
          5          05        1 байт  Конечная    Целое число
                                       головка
          6          06        1 слово Конечный    См. примечание*
                                       сектор  и
                                       цилиндр
          8          08        2 слова Начальный   Целое число****
                                       абсолютный
                                       сектор
         12          0С        2 слова Количество  Целое число****
                                       секторов
         ───────────────────────────────────────────────────────────────
              *  Таблица разделения  диска начинается  со смещением
                 "шестнадцатиричное  01ВЕ" в исходной записи началь-
                 ной загрузки (1-ый абсолютный сектор жесткого  дис-
                 ка). Таблица  разделения диска содержит сведения о
                 начале начальной головки, цилиндра и сектора записи
                 начальной загрузки для активной части.
              ** Типы дополнительного разбиения используются некото-
                 рыми  производителями  для идентификации их системы
                 или для идентификации дисков большой емкости,  раз-
                 деленных на несколько логических дисков.
              ***  Разделение  расширенной  операционной  системы  DOS
                   поддерживается только под управлением  операционной
                   системы MS-DOS версии 3.30 и выше.
              **** Цилиндр и сектор помещаются в битовую позицию - за-
                   кодированное обозначение, применяемое к начальному/
                   конечному цилиндру и сектору.
                       байт n                       байт n+1
         │<─────────────────────────────>┼<─────────────────────────────>┤
         ├───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┤
         │ C │ C │ S │ S │ S │ S │ S │ S │ C │ C │ C │ C │ C │ C │ C │ C │
         └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
         Cтар-    Cтар-                    Млад-                     Млад-
          ший      ший                     ший                        ший
          бит      бит                     бит                        бит
              Два самых  старших  бита байта "n" предшествуют восьми битам
              байта "n+1" для  образования  10-битового  номера  цилиндра.
              Шесть младших битов байта "n" образуют номер сектора.

                                      - 11-33 -
              Несмотря на то,  что сектора таблицы FAT расположены следую-
         щими в последовательности секторов на диске, мы должны пропустить
         их и сначала обсудить сектора каталога.  Вы должны  понять  смысл
         секторов каталога для того,  чтобы понять, что размещается на ос-
         тальной части диска.

                                 Сектора каталога

              Сектора каталога содержат информацию  о  каталоге  для  всех
         файлов в корневом каталоге диска. Информация для файлов, содержа-
         щихся в подкаталогах,  хранится в файле подкаталога,  элемент для
         которой  помещен  в его родительский каталог (корневой или другой
         подкаталог). Когда вы выдаете команду DIR, информацию получают из
         секторов каталога, если считывается корневой каталог, или получа-
         ют из файла подкаталога,  описывающего текущий  подкаталог.  Пос-
         кольку  один сектор обычно занимает 512 байтов в длину,  мы можем
         легко вычислить,  что каждый элемент каталога имеет длину 32 бай-
         та. Общее количество элементов в корневом каталоге зависит от то-
         го,  сколько секторов каталога  задано.  Например,  односторонние
         гибкие  диски  всего имеют 64 элемента в корневом каталоге,  в то
         время,  как двухсторонние 40-трековые диски имеют 112 таких  эле-
         ментов, а двухсторонние 80-трековые 5,25-дюймовые диски имеют 224
         элемента в корневом каталоге.
              Для большинства жестких  дисков общее количество элементов в
         каталоге зависит от того, как был отформатирован диск. Каждый ва-
         риант разбиения жесткого диска имеет максимальное количество эле-
         ментов корневого каталога, которое соответствует регистрам частей
         разбиения.  Общее количество элементов корневого каталога опреде-
         ляет максимальное количество имен файлов,  которое может быть по-
         мещено в корневой каталог.  Это ограничение, однако, не распрост-
         раняется  на   подкаталоги.   Поскольку   элементы   подкаталога,
         соответствующие размещенным в подкаталогах файлам,  сами помещены
         в файл описания подкаталога,  не существует ограничений на  коли-
         чество файлов, помещенных в подкаталог; файл описания подкаталога
         может увеличиваться по мере надобности.
              Информация, содержащаяся  в элементе каталога подразделяется
         на шесть компонентов,  четыре из которых прямо или косвенно отно-
         сятся  к восстановлению стертых файлов.  На рисунке 11-4 показаны
         составляющие части элемента каталога,  длина каждого компонента и
         определение каждого из них.


              Четырьмя частями  элемента  каталога,  с  которыми  мы будем
         иметь дело,  как показано на рисунке 11-4,  являются:  имя и  тип
         файла, атрибут (атрибуты ), начальный кластер и размер файла.


                      Имя файла, тип файла и состояние файла

              Имя и тип файла состоят из 11 байтов, в которых представлено
         имя файла,  которому соответствует элемент каталога.  Каждый байт
         содержит символ АSCII.
              В операционной  системе MS-DOS версии 2.0 и выше имя файла в
         элементе каталога всегда относится к файлу,  хранящемуся в корне-
         вом каталоге. Поскольку имена подкаталогов считаются операционной
         системой MS-DOS файлами, они также имеют свои элементы в секторах
         каталога. Имя подкаталога, однако, содержит информацию в элементе
         каталога,  который слегка отличается от обычных  файлов.  Ниже  в
         разделах этой главы мы обсудим эти различия.

                                      - 11-34 -










                                                                 Атрибут
                 │<────────────── 11 байтов ─────────────────>│  (1 байт)
                 │<─────────── Имя файла ───────>│<───Тип────>│   
                 ┌────────────────────────────────────────────┬────┬──
                 │ xx  xx  xx  xx  xx  xx  xx  xx  xx  xx  xx │ xx │ < ──┐
                 │  0   1   2   3   4   5   6   7   8   9  10 │ 11 │  >  │
                 └────────────────────────────────────────────┴────┴─/   │
                 │   │                                                  │
                   │                                                     │
                  Состояние файла                                        │
                  или первый символ                                      │
                  имени файла                                            │
                                                                         │
           ┌─────────────────────────────────────────────────────────────┘
           │
           │
           │        Зарезервировано операционной     Штамп о времени
           │              cистемой MS-DOS                и дате
           │      │<──────── (10 байтов) ────────>│<─── (4 байта) ──>│
           │      │                               │<─Время─>│<─Дата─>│
           │    ──┬───────────────────────────────┬─────────┬────────┬──
           └─> <  │ xx xx xx xx xx xx xx xx xx xx │ xx  xx  │ xx  xx │ < ─┐
                > │ 12 13 14 15 16 17 18 19 20 21 │ 22  23  │ 24  25 │  > │
               /──┴───────────────────────────────┴─────────┴────────┴─/  │
           ┌──────────────────────────────────────────────────────────────┘
           │
           │      Начальный кластер    Размер файла
           │       │<─(2 байта)─>│<──────(4 байта)───────>│
           │     ──┬─────────────┬────────────────────────┐
           └──> <  │  xx    xx   │  xx    xx    xx    xx  │
                 > │  26    27   │  28    29    30    31  │
                /──┴─────────────┴────────────────────────┘

                 Рис. 11-4. Компоненты элемента каталога:
            1 - 11 байтов; 2 - атрибут (1 байт); 3 - имя файла; 4 -  тип;
            5 - состояние файла или первый символ имени файла; 6 - зарезерви-
            ровано для операционной системы MS-DOS (10 байтов); 7 - штамп о
            времени и дате (4 байта);  8 - время;  9 - дата; 10 - начальный
            кластер (2 байта); 11 - размер файла (4 байта)










                                      - 11-35 -
              Отметим также,  что  под  управлением  операционной  системы
         MS-DOS версии 2.0 и выше, максимальное число файлов или элементов
         каталога, которые гибкий диск может вместить (64, 112 и 224), со-
         ответствует только объему корневого каталога.  Поскольку все фай-
         лы, размещенные в подкаталоге, имеют каталоговые элементы в самом
         подкаталоге "файл",  не существует ограничений на количество фай-
         лов,  которые можно разместить на диске в пределах места, предус-
         мотренного конкретным типом диска или формата. Подробнее о подка-
         талогах и восстановлении файлов мы поговорим позже в  этой главе.
              При стирании файла с диском происходят две вещи. Первым зат-
         рагиваемым элементом является первый символ имени файла в элемен-
         те каталога. Как показано на рисунке 11-4, первый байт в элементе
         каталога может либо указывать состояние файла,  либо представлять
         первый  символ ASCII в имени файла.  Если элемент каталога не был
         использован с момента  последнего  форматирования  диска,  первый
         байт всегда установлен в значение "00".  Таким образом операцион-
         ной системе MS-DOS нужно только считать первый байт элемента  ка-
         талога для определения,  может ли он использоваться. При создании
         файла первый байт меняется и превращается в первый  символ  имени
         файла. Когда позднее файл стирается, первый байт меняется в шест-
         надцатиричное значение "E5".  Остальная информация в элементе ка-
         талога, относящегося к стертому файлу, остается прежней. Когда вы
         просматриваете сектора диска в поисках информации об элементе ка-
         талога стертого файла, то значение является для вас первым ключом
         к разгадке нужного элемента каталога.
              Вторым ключом,  конечно,  является  представление  остальной
         части имени файла и ее набор в формате ASCII.  Но  первый  символ
         шестнадцатиричного значения "E5" говорит о том, что элемент ката-
         лога представляет собой стертый файл.  Этот байт установлен в та-
         кое  значение для того,  чтобы операционная система MS-DOS знала,
         что элемент каталога освободился и в него может быть внесена  ин-
         формация  о  новом файле,  если этот элемент потребуется системе.
         Слава богу, разработчики операционной системы MS-DOS предусмотре-
         ли такой способ удаления файлов. Благодаря этому, мы теперь можем
         (в большинстве случаев) восстановить только что стертый файл.


                                      Атрибут

              Байт атрибута  содержит  информацию  об атрибутах размещения
         файла.  Атрибуты указывают, как операционная система MS-DOS ведет
         себя с файлом. В таблице 11-3 даны определения каждого атрибута и
         соответствующие шестнадцатиричные значения,  которые  могут  быть
         помещены в байт атрибута. Каждый бит этого байта определяет какой
         -то конкретный атрибут и принимает значение "1" ,  когда этот ат-
         рибут назначается файлу.
              Отметим, что файлу может быть назначено несколько атрибутов.
         Например,  если  файлу  назначены  атрибуты  "только  для чтения"
         (шестнадцатиричное значение 01) и "скрытый" ("только  для чтения"
         (шестнадцатиричное значение 02),  результирующее значение в байте
         атрибута будет представлять собой сумму обоих значений атрибутов,
         то есть шестнадцатиричное значение 03. Информация, содержащаяся в
         байте атрибута может быть,  а может не быть полезной для  восста-
         новления файла.  Например,  маловероятно, чтобы мы стали пытаться
         восстанавливать  файл,  атрибутом  которого было значение "только
         для чтения",  если только мы не пытаемся восстановить весь разру-
         шенный диск.  Обычно, мы не заботимся об атрибутах файла. Но, ес-
         ли, однако, мы восстанавливаем файл с атрибутом "скрытый", мы за-
         хотим изменить этот атрибут,  потому что в противном случае мы не

                                      - 11-36 -
         сможем  увидеть этого файла при выдаче команды DIR,  а,  следова-
         тельно,  не сможем убедиться в том,  что файл  был  восстановлен.
         Другая  причина,  по которой мы можем захотеть обращаться к байту
         атрибута файла, заключается в желании восстановления имени подка-
         талога.

                                                    Таблица 11-3
                       Определение атрибутов файла
         --------------------------------------------------------------
         Бит      Шестнадцатирич-        Атрибут
                  ное  значение
         --------------------------------------------------------------
         1-ый         80          Не определен (в операционной системе
                                  МS-DOS версии 3.0 и ниже)
         2-ой         40          Не определен (в операционной системе
                                  МS-DOS версии 3.0 и ниже)
         3-ий         20          Состояние архива: Устанавливается
                                  когда файл открывается и закрывается
                                  и используется некоторыми утилитами
                                  копирования и восстановления жесткого
                                  диска
         4-ый         10          Элемент подкаталога: Указывает на то,
                                  что элемент каталога относится к под-
                                  каталогу "файл"
         5-ый         08          Метка тома: Указывает на то, что эле-
                                  мент каталога  содержит  метку  тома
                                  (только  для версий 2.0 и выше опера-
                                  ционной  системы  DOS);  в остальной
                                  части элемента  содержится  ненужная
                                  информация
         6-ой         04          Состояние системы:  используется  для
                                  указания системных файлов, таких, как
                                  те, что  используются  для  начальной
         Бит      Шестнадцатирич-        Атрибут
                  ное  значение
         --------------------------------------------------------------
                                  загрузки системы. Файлы начальной заг-
                                  рузки  операционной  системы  MS-DOS
                                  (например,   файлы   IBMDOS.СОМ    и
                                  IBMBIO.СОМ ) должны иметь этот атрибут
                                  установленным.
         7-ой         02          Состояние "скрытый". Файл исключается
                                  из нормального просмотра каталога
         8-ой         01          Состояние "только для чтения": Файл не
                                  может быть стерт.
         --------------------------------------------------------------

                                 Начальный кластер

              Начальный кластер представляет собой 2-байтовый, 16-цифровой
         двоичный номер,  который определяет первую секцию диска,  занятую
         файлом.  Эта секция диска называется кластером.  Несмотря на  то,
         что на рисунке 11-1 изображен форматированный диск с точки зрения
         треков и секторов, операционная система MS-DOS в действительности
         рассматривает  диск  с точки зрения кластеров секторов,  а не от-
         дельных целых секторов.  Начальный кластер представляет собой ис-
         ходный "указатель" на первый сектор данных файла, а также на пос-

                                      - 11-37 -
         ледующие указатели в секторах таблицы FAT.  Считав этот начальный
         указатель  в элементе каталога,  операционная система MS-DOS про-
         должает считывать остальные указатели. На сектора данных файлов в
         секторе  таблицы  FAT.  Ниже мы будем говорить о секторах таблицы
         FAT, но сейчас отметим, что обращение к начальному кластеру явля-
         ется одним из наиболее важных первых шагов в восстановлении стер-
         тых или разрушенных файлов.

                                   Размер файла

              Размер файла  представлен 4-байтовым двоичным числом, первый
         байт которого представляет собой  младшую  часть  размера  файла.
         Четвертый  байт  является старшей частью размера файла,  и мы ис-
         пользуем это значение для определения точкой длины файла,  и  тем
         самым для определения количества секторов,  которые занимал стер-
         тый файл или предполагается, что он занимал.
              Теперь, после того, как были определены важные части элемен-
         та каталога,  мы переходим к рассмотрению секторов  таблицы  FAT.
         Информация  в этих секторах представляет дополнительные ключи для
         разгадки того,  как стертый или разрушенный файл может быть восс-
         тановлен.


                           Элементы каталога "." и ".."

              Только что  описанная  каталоговая  информация действительна
         для всех файлов,  хранящихся под управлением операционной системы
         MS-DOS, за исключением двух специальных типов элементов каталогов
         - элементов "." и ".." в подкаталогах.  Элемент каталога "."  со-
         держит информацию по текущему подкаталогу,  а элемент ".." содер-
         жит информацию по родительскому каталогу для текущего каталога. В
         таблице  11-4 описывается содержимое каждого поля элементов ката-
         лога для каталогов "." и "..".

                                                       Таблица 11-4
                Содержимое элементов каталога  "."   и  ".."

         --------------------------------------------------------------
                         "."  (Текущий) каталог
         --------------------------------------------------------------
          Поле                     Содержимое поля
         --------------------------------------------------------------
          Имя/тип        Первый байт = шестнадцатиричное значение "2Е",
                         остальная часть = 00
          Атрибут        Только состояние каталога (шестнадцатиричное
                         значение 10)
          Время          Время создания
          Дата           Дата создания
          Начальный      Номер кластера текущего каталога
          кластер
          Размер         Пробел (размер задается в элементе родитель-
                         ского каталога для этого каталога)
         --------------------------------------------------------------


                                      - 11-38 -
         --------------------------------------------------------------
                         ".."  (Родительский) каталог
         --------------------------------------------------------------
          Поле                      Содержимое поля
         --------------------------------------------------------------
          Имя/тип        Первый и второй байты = шестнадцатиричное
                         значение "2Е", остальная часть = 00
          Атрибут        Только состояние каталога (шестнадцатиричное
                         значение 10)
          Время          Время создания
          Дата           Дата создания
          Начальный      Номер кластера родительского каталога только
          кластер        тогда, когда родительским является не корневой
                         каталог
          Размер         Пробел
         --------------------------------------------------------------

                      Cектора таблицы размещения файла (FAT)

              Сектора, содержащие  таблицу FAT,  используются операционной
         системой MS-DOS для определения местоположения  на  диске  каждой
         части каждого файла.  В отличие от некоторых операционных систем,
         которые всегда располагают  файлы  последовательно  и  используют
         сектора  непрерывно,  операционная система MS-DOS может размещать
         файлы и части одного файла произвольным образом. Система, которая
         всегда располагает файлы последовательно, более просто может отс-
         леживать местоположение файлов, а, следовательно, может обращать-
         ся к файлам более быстро. Для восстановления файла, расположенно-
         го непрерывно,  нам нужно знать только адреса его начала и конца.
         Все данные в этом промежутке являются данными файла.
              Несмотря на  сказанное,  непрерывное размещение файлов менее
         эффективно,  когда например,  файл,  расположенный между  другими
         файлами,  удаляется и его место должен занять больший по размеру.
         И,  если освободившегося после удаления файла места  недостаточно
         для размещения нового файла,  для этого нового файла должно выде-
         ляться достаточное непрерывное пространство после  последнего  из
         уже размещенных на диске файлов.  Если на диске уже нет достаточ-
         ного места для помещения файла,  диск считается полным. Это может
         вызывать  реальные  трудности  при использовании гибких дисков со
         сравнительно малой емкостью памяти, потому что большое количество
         свободной памяти тратится впустую.  Операционная система MS-DOS и
         сходные с ней микрокомпьютерные операционные системы, располагаю-
         щиеся на жестком диске,  были так разработаны,  что позволяют ис-
         пользование произвольного размещения,  а также  последовательного
         или  непрерывного  размещения.  Информация в секторах таблицы FAT
         позволяет операционной системе MS-DOS выполнять это.
              Когда диск первый раз форматируется операционной системой MS
         -DOS и несколько файлов копируются на этот диск,  информация, по-
         мещенная в секторах таблицы FAT, используется операционной систе-
         мой MS-DOS для определения адреса каждой части файла. Обращение к
         файлам  идет через таблицу FAT в единицах "кластер".  Файл всегда
         занимает,  по крайней мере,  один кластер, а , если он достаточно
         велик,  занимает несколько кластеров.  Кластер в действительности
         является частью распределения и состоит из одного  сектора данных
         на односторонних гибких дисках и двух секторов данных на двухсто-
         ронних гибких дисках.  Некоторые жесткие диски используют класте-
         ры,  каждый  из  которых состоит из восьми секторов.  Вся область
         хранения данных на диске (за исключением области  для  данных  по

                                      - 11-39 -
         начальной загрузке таблицы FAT. На рисунках 11-5 и 11-6 показано,
         как  одно- и двухсторонние 4--трековые гибкие диски с 8-секторным
         и 9-секторным форматами отображаются в виде кластеров. На рисунке
         11-7  показано  отображение 80-трекового гибкого диска повышенной
         плотности записи.

          Формат расположения восьми        Формат расположения девяти
              секторов на треке                 секторов на треке
         ┌──────────────────────────────┐ ┌──────────────────────────────┐
         │ \    Трек                    │ │ \    Трек                    │
         │   \                          │ │   \                          │
         │     \  0         1  2 ... 39 │ │     \  0         1  2 ... 39 │
         │Cектор┌───────────────────────┤ │Cектор┌───────────────────────┤
         │   1  │ Начальная 3 11        │ │   1  │ Начальная 2 11        │
         │      │ загрузка       ...  . │ │      │ загрузка       ...  . │
         │   2  │ FAT 1     4 12 ...  . │ │   2  │ FAT 1     3 12 ...  . │
         │   3  │ FAT 2     5 13 ... 309│ │   3  │ FAT 1     4 13 ... 346│
         │   4  │ Каталог   6 14 ... 310│ │   4  │ FAT 2     5 14 ... 347│
         │   5  │ Каталог   7 15 ... 311│ │   5  │ FAT 2     6 15 ... 348│
         │   6  │ Каталог   8 16 ... 312│ │   6  │ Каталог   7 16 ... 349│
         │   7  │ Каталог   9  . ... 313│ │   7  │ Каталог   8 17 ... 350│
         │   8  │ 2        10  . ... 314│ │   8  │ Каталог   9  . ... 351│
         └──────┴───────────────────────┘ │   9  │ Каталог  10  . ... 352│
                                          └──────┴───────────────────────┘

              Рис. 11-5. Число  кластеров на односторонних 40-трековых
                         гибких дисках

              Отметим, что на предыдущих рисунках сектора таблицы FAT были
         пронумерованы либо номером 1,  либо номером 2. Они обозначены так
         потому, что разработчики файловой операционной системы MS-DOS ре-
         зервировали в два раза больше секторов таблицы FAT,  чем действи-
         тельно требуется для отображения диска.  Возможной причиной такой
         разработки было желание предусмотреть пространство для расширения
         таблицы FAT с увеличением емкости гибких дисков. В версиях опера-
         ционной системы MS-DOS вплоть до 3.3,  однако, дополнительный на-
         бор секторов используется для размещения точной копии первого на-
         бора секторов таблицы FAT.  При наличии избыточных наборов таблиц
         FAT можно быть спокойным за них, если вдруг по какой-либо причине
         будет  разрушен первый набор.  Восстановление разрушенной таблицы
         FAT может быть очень трудным делом. При восстановлении файла, од-
         нако, вы обычно обязаны обращаться только к первой таблице FAT.
              Каждый кластер на диске имеет  соответствующий  ему  элемент
         таблицы FAT.  Элемент таблицы FAT,  который соответствует первому
         кластеру файла,  содержит номер следующего кластера занятого  тем
         же файлом. Если посмотреть на элемент таблицы FAT соответствующий
         этому "следующему" кластеру, мы обнаружим, что либо был достигнут
         конец файла, либо элемент содержит номер еще одного кластера, за-
         нятого файлом. Таким образом, элементы таблицы FAT в действитель-
         ности содержат указатели как кластеры,  занятые файлом,  так и на
         последующие элементы таблицы FAT,  которые соответствуют дополни-
         тельным кластерам,  занятым тем же файлом.  Поскольку общее число
         элементов  в секторах таблицы FAT превышает общее число кластеров
         на  диске весь диск легко может быть отображен даже тогда,  когда
         максимально использована емкость его памяти.


                                      - 11-40 -
                              Формат расположения восьми
                                  секторов на треке
                        ┌─────────────────────────────────────┐
                        │       \   Трек                      │
                        │         \                           │
                        │           \   0         1  2 ... 39 │
                        │      Cектор ┌───────────────────────┤
                        │         1   │ Начальная 5 13        │
                        │             │ загрузка       ...  . │
                        │         2   │ FAT 1                 │
                        │         3   │ FAT 2     6 14 ...  . │
                        │ Сторона 4   │ Каталог               │
                        │    0    5   │ Каталог   7 15 ... 311│
                        │         6   │ Каталог               │
                        │         7   │ Каталог   8 16 ... 312│
                        │ ________8   │ Каталог               │
                        │         1   │ Каталог   9 16 ... 313│
             Начало     │         2   │ Каталог               │
             секторов ──────────> 3   │      2   10 18 ... 314│
             данных     │         4   │                       │
                        │Сторона  5   │      3   11 19 ... 315│
                        │   1     6   │                       │
                        │         7   │      4   12  . ... 316│  Конец
                        │         8   │              .        │
                        └─────────────┴───────────────────────┘

                            Формат расположения девяти
                                секторов на треке
                        ┌─────────────────────────────────────┐
                        │       \   Трек                      │
                        │         \                           │
                        │           \   0         1  2 ... 39 │
                        │      Cектор ┌───────────────────────┤
                        │         1   │ Начальная 5 14        │
                        │             │ загрузка       ...  . │
                        │         2   │ FAT 1                 │
                        │         3   │ FAT 1     6 15 ...  . │
                        │ Сторона 4   │ FAT 2                 │
                        │    0    5   │ FAT 2     7 16 ... 349│
                        │         6   │ Каталог               │
                        │         7   │ Каталог   8 17 ... 350│
                        │         8   │ Каталог               │
                        │ ________9   │ Каталог   9 18 ... 351│
                        │         1   │ Каталог               │
                        │         2   │ Каталог  10 19 ... 352│
             Начало     │         3   │ Каталог               │
             секторов ──────────> 4   │      2   11 20 ... 353│
             данных     │         5   │                       │
                        │ Сторона 6   │      3   12  . ... 354│
                        │    1    7   │                       │   Конец
                        │         8   │      4   13  . ... 355│
                        │         9   │                       │
                        └─────────────┴───────────────────────┘

              Рис.  11-6. Число кластеров на двухсторонних 40-трековых
                                   гибких дисках

                                      - 11-41 -
              На рисунках 11-5, 11-6 и 11-7 нумерация кластеров начинается
         с  цифры 2.  Это делается потому,  что кластеры нумеруются также,
         как элементы таблицы FAT (что позволяет вести их быстрый  поиск в
         таблице FAT ), а элементы 0 и 1 таблицы FAT используются для дру-
         гих целей.  Для собирания зарезервированных элементов таблицы FAT
         кластеры нумеруются,  начиная с числа 2 и продолжается до послед-
         него элемента таблицы FAT минус 1.  Поскольку  секторы  начальной
         загрузки,  таблицы  FAT  и  каталога  не имеют номеров кластеров,
         кластер N2 содержит первый сектор (секторы) данных на диске. При-
         мер на рисунке 11-8 демонстрирует то, как можно вести обращение к
         элементам таблицы FAT.

                            Формат расположения пятнадцати
                                  секторов на треке
                        ┌────────────────────────────────────────────┐
                        │       \   Трек                             │
                        │         \                                  │
                        │           \   0         1    2   ...    79 │
                        │      Cектор ┌──────────────────────────────┤
                        │         1   │ Начальная 3   33   ...     . │
                        │             │ загрузка      34             │
                        │         2   │ FAT 1     4   35   ...     . │
                        │         3   │ FAT 1     5   36         1166│
                        │         4   │ FAT 1     6   37   ...   1167│
                        │         5   │ FAT 1     7   38         1168│
                        │         6   │ FAT 1     8   39   ...   1169│
                        │ Сторона 7   │ FAT 1     9   40         1170│
                        │    0    8   │ FAT 1    10    .   ...   1171│
                        │         9   │ FAT 2    11    .         1172│
                        │        10   │ FAT 2    12    .   ...   1173│
                        │        11   │ FAT 2    13    .         1174│
                        │        12   │ FAT 2    14    .   ...   1175│
                        │        13   │ FAT 2    15    .         1176│
                        │        14   │ FAT 2    16    .         1177│
                        │ _______15   │ FAT 2    17    .   ...   1178│
                        │         1   │ Каталог  18    .         1179│
                        │         2   │ Каталог  19    .   ...   1180│
                        │         3   │ Каталог  20    .         1181│
                        │         4   │ Каталог  21    .   ...   1182│
                        │         5   │ Каталог  22    .         1183│
                        │         6   │ Каталог  23    .   ...   1184│
                        │         7   │ Каталог  24    .         1185│
                        │ Сторона 8   │ Каталог  25    .   ...   1186│
                        │    1    9   │ Каталог  26    .         1187│
                        │        10   │ Каталог  27    .   ...   1188│
                        │        11   │ Каталог  28    .         1189│
                        │        12   │ Каталог  29    .   ...   1190│
                        │        13   │ Каталог  30    .         1191│
             Начало     │        14   │ Каталог  31    .   ...   1192│
             секторов ──────────>15   │ 2        32    .         1193│
             данных     └─────────────┴──────────────────────────────┘

              Рис.  11-7.  Число  кластеров на двухсторонних 80-треко-
         вых гибких дисках



                                      - 11-42 -
                        Декодирование элементов таблицы FAT

              Значение в элементе 0 таблицы FAT всегда указывает на формат
         диска.  Элемент 1 всегда установлен в значение (F)FFF, чтобы выс-
         тупать в роли преграды или заполнителя между элементом 0  и  эле-
         ментом 2.  В таблице 11-5 представлены разные значения по каждому
         формату,  поддерживаемому операционной системой MS-DOS  версий  с
         1.0 по 3.3.
              Все последующие элементы таблицы FAT используются для  отоб-
         ражения диска.  Каждый из этих элементов содержит один из четырех
         типов информации:
              - следующий номер кластера в файле;
              - маркер конца файла;
              - неиспользованный кластер;
              - кластер,  помеченный, как зарезервированный, или испорчен-
                ный.
              В таблице 11-6 перечислены значения,  которые могут присутс-
         твовать в элементах таблицы FAT.

                                      - 43 -
         Элемент каталога для файла 1.   Элемент каталога для файла 2.
         Начальный номер кластера ука-   Начальный номер кластера ука-
         зывает на элемент 2 таблицы     зывает на элемент 5 таблицы
         FAT (первая часть файла нахо-   FAT (первая часть файла нахо-
         дится в кластере 2)             дится в кластере 5)
             ┌────│───────────────────────────────┘
             │    │    ┌───────┐
             │    │   0│  FFD  │ Двухсторонний  гибкий диск с 9
             │    │    └───────┘ секторами на треке
             │    │    ┌───────┐
             │    │   1│  FFF  │  (Заполнитель)
             │    │    └───────┘
             │    │    ┌───────┐
             │    └──>2│  003  │  Следующая часть файла 1 указывает──┐
             │         └───────┘  на элемент/кластер 3               │
             │    ┌──────────────────────────────────────────────────┘

             │    │

             │    │    ┌───────┐
             │    └──>3│  004  │  Следующая часть файла 1 указывает──┐
             │         └───────┘  на элемент/кластер 4               │
             │    ┌──────────────────────────────────────────────────┘
             │    │    ┌───────┐
             │    └──>4│  008  │  Следующая часть файла 1 указывает────┐
             │         └───────┘  на элемент/кластер 8                 │
             │         ┌───────┐                                       │
             └───────>5│  006  │  Следующая часть файла 2 указывает──┐ │
                       └───────┘  на элемент/кластер  6              │ │
                  ┌──────────────────────────────────────────────────┘ │
                  │    ┌───────┐                                       │
                  └──>6│  007  │  Следующая часть файла 2 указывает──┐ │
                       └───────┘  на элемент/кластер  7              │ │
                  ┌──────────────────────────────────────────────────┘ │
                  │    ┌───────┐                                       │
                  └──>7│  FFF  │  Конец файла 2                        │
                       └───────┘                                       │
                  ┌────────────────────────────────────────────────────┘
                  │    ┌───────┐
                  └──>8│  009  │  Следующая часть файла 1 указывает──┐
                       └───────┘  на элемент/кластер 9               │
                  ┌──────────────────────────────────────────────────┘
                  │    ┌───────┐
                  └──>9│  010  │  Следующая часть файла 1 указывает──┐
                       └───────┘  на элемент/кластер 10              │
                  ┌──────────────────────────────────────────────────┘
                  │    ┌───────┐
                  └─>10│  FFF  │  Конец файла 1
                       └───────┘
                       ┌───────┐
               11 - 13 │  000  │  Не используется - распределяется,
                       └───────┘     как свободная память

                            Рис. 11-8. Пример таблицы FAT

                                      - 11-44 -


                                                      Таблица 11-5
              Значения типа диска в элемента 0 таблицы FAT
         ---------------------------------------------------------------
         В элементе 0                  Тип диска и формат
         (шестнадцате-
         ричное значение)
         ---------------------------------------------------------------
         (F)FF0           3,5-дюймовая, 1,44-Мегабайтная дискета (для
                          версий 3.30 и выше операционной системы MS-DOS
                          или
                          другой неопределенный формат (для версий 3.30
                          и выше операционной системы MS-DOS)
         (F)FF8           Жесткий диск (жесткие диски в персональных
                          компьютерах  IBM  PC, IBM PC-XT, IBM PC-AT с
                          операционной системой MS-DOS  версии  2.0  и
                          выше)
         (F)FF9           Сменный носитель. Обычно имеют 5,25-дюймовый,
                          1,2 Мбайтный формат гибких дисков повышенной
                          емкости  (для  операционной  системы  MS-DOS
                          версии 3.0 и выше)
                          или
                          3,5  -  дюймовый, 720 Мбайтный формат гибких
                          дисков (для операционной системы MS-DOS вер-
                          сии 3.20 и выше)
         (F)FFC           Сменный носитель. Обычно используется для
                          5,25- дюймовых, 180-Кбайтных  гибких  дисков
                          (для операционной системы MS-DOS версии 2.00
                          и выше)
         (F)FFD*          Сменный  носитель. Обычно  используется  для
                          5,25-  дюймовых,  360-Кбайтных гибких дисков
                          (для операционной системы MS-DOS версии 2.00
                          и выше)
                          или
                          8-дюймовых  501-Кбайтных  (двухсторонних   с
                          одинарной плотностью записи) гибких дисков
         (F)FFE*          Сменный носитель. Обычно используется для
                          5,25-  дюймовых,  160-Кбайтных гибких дисков
                          (для операционной системы MS-DOS версии 1.00
                          и выше)
                          или
                          8-дюймовых  250-Кбайтных  (односторонних   с
                          одинарной плотностью записи) гибких дисков
                          или
                          8-дюймовых 1,232-Мегабайтных (двухсторонних
                          с удвоенной плотностью записи) гибких дисков
         (F)FFF           Сменный носитель. Обычно используется для
                          5,25-  дюймовых,  320-Кбайтных гибких дисков

                                      - 11-45 -
                          (для операционной системы MS-DOS версии 1.10
                          и выше)
         ---------------------------------------------------------------

              Примечание. Некоторые  реализации  операционной  системы
              ----------  MS-DOS поддерживают работу 8-дюймовых дисков
              с программной разметкой. Несмотря  на  то,  что  обычные
              драйверы  устройств должны быть написаны для конкретного
              типа дисководов 8-дюймовых дисков, используемых в систе-
              ме, "родовая" операционная система  MS-DOS  поддерживает
              четыре  формата  8-дюймовых  одинарной плотностью записи
              (128 байтов в секторе), один двухсторонний формат с оди-
              нарной плотностью записи, и один двухсторонний формат  с
              удвоенной  плотностью  записи  (1024  байтов в секторе).
              Единственная разница между двумя односторонними формата-
              ми одинарной плотности заключается в том, что один имеет
              один зарезервированный сектор под запись начальной  заг-
              рузки, а второй имеет четыре таких сектора. Значение оп-
              ределения  формата  диска  в  элементе 0 таблицы FAT для
              формата с одинарной плотностью записи с одним зарезерви-
              рованным сектором и для формата с двойной плотностью за-
              писи одинаково и равняется  шестнадцатиричному  значению
              FFE.  Для  формата с одинарной плотностью записи и с че-
              тырьмя зарезервированными секторами таким значением  бу-
              дет  значение  FFD. Использование такого же значения для
              5,25-дюймовых гибких дисков не является проблемой, пото-
              му что операционная система MS-DOS через  свои  драйверы
              устройств,  узнает,  когда  она  обращается к 8-дюймовым
              дискам. Для того,  однако,  чтобы  операционная  система
              MS-DOS могла отличать 8-дюймовые форматы от других, ког-
              да  она встречает значение FFE в элементе 0 таблицы FAT,
              она сначала считывает диск, предполагая,  что  он  имеет
              одинарную  плотность  записи, а потом пытается прочитать
              адресную отметку одинарной плотности в  первом  секторе.
              Если не происходит ошибок операционная система продолжа-
              ет чтение диска, уже зная, что он имеет формат одинарной
              плотности. Если при чтении происходит ошибка, операцион-
              ная система MS-DOS предполагает, что диск был отформати-
              рован  с удвоенной плотностью записи. Тогда операционная
              система возвращается к началу считывания диска уже наст-
              роенная на чтение диска в формате с  двойной  плотностью
              записи. Если ваша система имеет дисководы для 8-дюймовых
              гибких  дисков,  в  руководстве  по операционной системе
              MS-DOS, приложенном к вашей конкретной реализации опера-
              ционной системы MS-DOS должна иметься необходимая техни-
              ческая информация о форматах 8-дюймовых дисков.


              Как видно из таблиц 11-5 и 11-6,  все элементы  таблицы  FAT
         содержат либо трехцифровые, либо четырехцифровые  шестнадцатирич-
         ные номера. Это значит, что элемент таблицы FAT содержит либо 12-
         битовое, либо 16-битовое значение. Все диски, содержащие 4085 или
         меньше кластеров (большинство гибких дисков и других сменных  но-
         сителей) используют 12-битовые элементы таблицы FAT,  в то время,
         как диски, имеющие более 4085 кластеров (большинство жестких дис-
         ков  и  некоторые  сменные  диски) используют 16-битовые элементы
         таблицы FAT.

                                      - 11-46 -

                                                     Таблица 11-6
                Значения  элементов таблицы FAT, управляющие
                        размещением файлов
         -------------------------------------------------------------
         Шестнадцатиричное
         значение элемента         Значение
         таблицы FAT
         -------------------------------------------------------------
         (0)000          Кластер не используется и доступен для
                         размещения нового файла
         с (F)FF0 до     Зарезервированный кластер (недоступен для
         (F)FF6          обычного хранения файлов)
         с (F)FF7        Кластер помечен, как испорченный,
                         операционной системой MS-DOS и не использу-
                         ется хранения файлов.
         с (F)FF8 до     Последний кластер, занятый файлом
         (F)FFF
         (X)XXX          Любое другое значение указывает номер клас-
                         тера в цепи, определяющей порядок  размещения
                         файла
         -------------------------------------------------------------

              Почему существует два разных формата таблицы FAT?  До  того,
         как  была введена поддержка жестких дисков под управлением опера-
         ционной системы MS-DOS (версия 2.0 операционной  системы MS-DOS),
         разработчики операционной системы MS-DOS старались минимизировать
         размер памяти,  необходимый для размещения таблицы FAT. Поскольку
         максимальный размер кластеров для гибких дисков меньше числа 4085
         (2847 кластеров на 1,44 Мегабайтных 3,5-дюймовых дисках),  диско-
         вое  пространство будет тратиться напрасно,  если будут использо-
         ваться 16-битовые элементы таблицы FAT, а максимальное количество
         кластеров,  которое может быть отображено при 8-битовых элементах
         будет равняться 255,  что не отвечает  требованиям  использования
         памяти.  Поэтому для того,  чтобы декодировать значения элементов
         таблицы FAT,  сначала нужно определить общее количество кластеров
         на диске.
                    Обработка 12-битовых элементов таблицы FAT

              Схема операционной системы MS-DOS размещения чисел, име ющих
         1,5 байта в длину, в элементах таблицы FAT на гибких дисках может
         показаться странной.  Но надо  знать,  что  операционная  система
         MS-DOS  была  спроектирована  с целью быстрого декодирования этих
         байтов. Способ, которым операционная система MS-DOS хранит инфор-
         мацию  в таблице FAT,  заключается в зашифровке элементов таблицы
         FAT парами,  в которых два 1,5-байтовых элемента объединены в не-
         большую 3-байтовую пару.  Если мы хотим определить номер кластера
         в элементе 2 таблицы FAT, мы также должны посмотреть на элемент 3
         таблицы FAT. Если мы хотим посмотреть на номер кластера в элемен-
         те 3 таблицы FAT,  мы должны вернуться назад и посмотреть на эле-
         мент 2 таблицы FAT.  Элементы 4 и 5 таблицы FAT будут тоже сдвое-
         ны,  как и элементы 6 и 7,  8 и 9 и так далее.  На  рисунке  11-9
         показано, как происходит кодирование номеров двух кластеров в па-
         ру элементов таблицы FAT при просмотре отладчиком  DEBUG  номеров
         так, как они представлены.
              На рисунке 11-10 показано,  как происходит кодирование номе-
         ров двух кластеров из пары элементов таблицы FAT.

                                      - 11-47 -
              Если из номера кластера извлекается только три цифры, почему
         же  вторая по старшинству цифра номера первого кластера перестав-
         ляется на место младшей цифры второго кластера?  Схема перестано-
         вок работает быстрее, когда машина сама декодирует байты и извле-
         кает информацию.  Цифры  появляются  уже  в  переставленном  виде
         только тогда,  когда пользователь читает таблицу FAT через отлад-
         чик DEBUG.
              Для декодирования  информации в 12-битовых элементах таблицы
         FAT на бумаге или внутри программы нужно  пользоваться  представ-
         ленной ниже последовательностью действий:  1. Умножить номер эле-
         мента таблицы FAT или кластера на 1,5
            байтов (сначала умножайте число на 3, а потом делите результат
            на 2).
         2. Используйте результат в качестве смещения в таблицу FAT,  ука-
            зывающий на элемент,  отражающий только  что  использовавшийся
            кластер.  Этот элемент содержит номер следующего кластера, за-
            нимаемого тем же файлом.
         3. Загрузите слово (2-байтовое число),  расположенное с этим сме-
            щением, в регистр
         4. Теперь  в  регистре  находятся четыре шестнадцатиричные цифры.
            Поскольку нам нужно только три цифры для трехзначного элемента
            таблицы  FAT,  следует определить,  является ли номер элемента
            таблицы FAT четным или нечетным числом.
                             Не
                         используется
                         /          \
                  ┌────/────────┐     \──────────────┐
         Первый   │  /          │     │ \            │ Второй
         номер    │ 0  1  2  3  │     │  0  4  5  6  │ номер
         кластера │    │  │  │  │     │     │  │  │  │ кластера
                  └────┼──┼──┼──┘     └─────┼──┼──┼──┘
                       └──┼──┼───────────┐  │  │  │
                          │  │  ┌────────┼──┼──┼──┘
                        ┌─┼──┼──┼───┬────┼──┼──┼─┐
             Первый     │        │         │Второй
             элемент    │ 2  3  6   │    1  4  5 │элемент
             таблицы FAT└───────────┴────────────┘таблицы FAT
                                      
                   Трехбайтовая пара элементов таблицы FAT
              Рис. 11-9. Кодирование  номеров  двух  кластеров  в пару
                         12-битовых элементов таблицы FAT

                        ┌──────────┐     ┌───────────┐
             Первый     │          │     │           │ Второй
             элемент    │ 0  2  3  │     │  0  0  0  │ элемент
             таблицы FAT│ │  │  │  │     │  │  │  │  │ таблицы FAT
                        └─┼──┼──┼──┘     └──┼──┼──┼──┘
                          │  │  └───────────┼──┼──┼──┐
                       ┌──┼──│──────────────┘  │  │  │
                  ┌────┼──┼──┼──┐        ┌─────┼──┼──┼──┐
         Первый   │          │        │           │ Второй
         номер    │ 0  0  0  2  │        │  0  0  0  3  │ номер
         кластера │  \          │        │ /            │ кластера
                  └────\────────┘        /──────────────┘
                         \             /
                         Не используется
              Рис. 11-10. Декодирование пары 12-битовых элементов
         таблицы FAT в два номера кластера

                                      - 11-48 -

         5. Если номер элемента представлен четным числом, в регистре сле-
            дует сохранять три младшие цифры путем выполнения операции ло-
            гического сложения "И" со смещением 0FFF.  Если номер элемента
            представлен  нечетным  числом,  следует  сохранить три старшие
            цифры путем сдвига регистра вправо  на  четыре  бита  командой
            SHR.
         6. Если результирующие три цифры представляют собой число  от FF8
            до FFF,  это значит,  что вы достигли конца файла. В противном
            случае эти три цифры представляют собой номер следующего клас-
            тера, занятого тем же файлом.


                    Обработка 16-битовых элементов таблицы FAT

              Работа с номерами кластеров и элементами таблицы FAT на дис-
         ках,  которые используют 126-битовые элементы таблицы FAT, значи-
         тельно облегчается по сравнению с работой, в которой используются
         12-битовые элементы таблицы FAT,  потому что все элементы таблицы
         FAT здесь выровнены на границу слова,  то  есть,  каждый  элемент
         таблицы FAT может считываться или записываться,  как целое полное
         слово.  При этом не нужно заботиться о соседних элементах таблицы
         FAT.
              На рисунке 11-9 показано, как происходит кодирование номеров
         двух  кластеров в пару элементов таблицы FAT при просмотре отлад-
         чиком DEBUG номеров так, как они представлены.
              На рисунке 11-10 показано,  как происходит кодирование номе-
         ров двух кластеров из пары элементов таблицы FAT.
              Для декодирования  информации в 12-битовых элементах таблицы
         FAT на бумаге или внутри программы нужно  пользоваться  представ-
         ленной ниже последовательностью действий:
              1. Получить начальный кластер файла из элемента каталога
              2. Умножить используемый номер кластера на 2 (байта;  1 сло-
                 во).
              3. Используйте  результат в качестве смещения в таблицу FAT,
                 указывающий на элемент,  отражающий только что  использо-
                 вавшийся кластер.  Этот элемент содержит номер следующего
                 кластера, занимаемого тем же файлом.
              4. Загрузите слово (2-байтовое число),  расположенное с этим
                 смещением, в регистр
              5. Если результирующие четыре цифры представляют собой число
                 от FFF8 до FFFF, это значит, что вы достигли конца файла.
                 В  противном  случае  эти четыре цифры представляют собой
                 номер следующего кластера, занятого тем же файлом.


                   Преобразование кластеров в логические сектора

              Если вы пишете программу, которая будет обращаться к области
         хранения данных на диске, вы найдете, что такие средства операци-
         онной системы MS-DOS, как прерывание "int 25h" (Абсолютное считы-

                                      - 11-49 -
         вание с диска) и  прерывание  "int  26h"  (Абсолютная  запись  на
         диск), а также программа-отладчик DEBUG, требуют, чтобы вы указы-
         вали номера логических секторов. Несмотря на то, что на иллюстра-
         циях  структур  диска (см.рисунки 11-2 и 11-3) указывается первый
         сектор диска, как сторона 0, дорожка 0, сектор 1, первый сектор в
         действительности равняется логическому сектору 0. Все последующие
         логические сектора представляют собой  последовательные  смещения
         от  0.  Таким образом,  логический сектор 1 будет представляться,
         как сторона 0,  до рожка 0, сектор 2, а логический сектор 2 будет
         представляться,  как сторона 0,  дорожка 0,  сектор 3.  Поскольку
         каждый элемент таблицы FAT, согласно результатам, полученным пос-
         ле выполнения указанных выше пяти действий,  всегда создает номер
         кластера, перечисленные ниже действия покажут вам, как нужно пре-
         образовывать номер кластера в номер логического сектора:
              1. Вычесть 2 из номера кластера.
              2. Умножить полученный результат на количество векторов, ис-
                 пользуемых в кластере, следующим образом:
                 а. Для всех  односторонних  форматов  гибких  дисков  или
                    для двухстороннего 80-трекового, 5,25-дюймового форма-
                    та  диска повышенной плотности записи произвести умно-
                    жение на 1.
                 б. Для всех двухсторонних 40-трековых, 5,25-дюймовых фор-
                    матов дисков повышенной  плотности  записи  произвести
                    умножение на 2.
                 в. Для двухсторонних 8-дюймовых гибких  дисков повышенной
                    плотности записи произвести умножение на 4.
                 г. Для жестких дисков следует использовать одно из  четы-
                    рех вышеприведенных значений или другое число, завися-
                    щее от формата диска.
              3. Добавить  результат  к  номеру логического сектора начала
                 области хранения данных.

              Применяя соответствующую последовательность действий в  пра-
         вильном порядке,  вы теперь можете перейти от элемента каталога к
         элементу таблицы FAT,  к номеру кластера,  к  номеру  логического
         сектора. А если есть такое средство, кому нужна операционная сис-
         тема MS-DOS ?!  Вы и сами можете считывать файлы сектор за секто-
         ром !



                         Обзор процедур восстановления

              Если файл, находящийся на диске, был каким-то образом разру-
         шен или поврежден,  существует три основных способа его исправле-
         ния. Первый способ заключается в использовании одного из встроен-
         ных средств операционной системы MS-DOS :  программы  CHKDSK  или
         программы  RECOVER.  Эти программы могут найти и изолировать пов-
         режденные области диска для того,  чтобы могли восстановить часть
         или весь разрушенный файл.
              Второй способ заключается в использовании  программы  DEBUG,
         которая  позволяет вам делать все что угодно с целью восстановле-
         ния разрушенного или стертого файла. К сожалению, программы DEBUG
         предлагает  не слишком "интеллектуальную" помощь в достижении ва-
         шей цели, и часто является просто "последней соломинкой". Похожий
         на этот способ заключается в написании вашей собственной програм-
         мы восстановления,  такой,  как программа RESCUE,  представленная

                                      - 11-50 -
         ниже в этой главе.  Информация, находящаяся в предыдущем разделе,
         по декодированию каталога диска и таблицы FAT является существен-
         но важной для написания собственных программ восстановления.
              Последний и наиболее удобный способ заключается в  использо-
         вании одной из уже имеющихся готовых программ - утилит таких, как
         "Norton-утилиты" или "Ultra-утилиты". Эти утилиты подобны ящику с
         инструментами,  и в них предусмотрены все возможности перечислен-
         ных выше способов,  включая декодирование таблиц FAT, исправление
         поврежденных файлов и восстановление стертых файлов.


                Восстановление разрушенных файлов при помощи утилит
                               CHKDSK и RECOVER

              Понимание структуры расположения диска в операционной систе-
         ме MS-DOS может оказаться очень полезным,  когда файл  или  часть
         диска  оказывается разрушенным.  К счастью,  операционная система
         содержит несколько функций, которые не только привлекают внимание
         к поврежденным частям диска,  но позволяют вам также восстанавли-
         вать данные,  доступ к которым другими способами оказался  закры-
         тым.  Встречаясь  с проблемами размещения файлов или неисправными
         дисками, операционная система MS-DOS автоматически изолирует пов-
         режденные  части  диска,  если система пытается обратиться к ним.
         Несмотря на то,  что операционная система MS-DOS  не  обязательно
         будет точно сообщать вам о том, что произошло, вы, вероятнее все-
         го,  получите сообщение об ошибке,  указывающее на то,  что часть
         диска,  с которого вы хотели вести считывание,  недоступна.  Если
         это случается,  используйте команду DIR  для  просмотра  каталога
         диска. Если команда DIR покажет, что каталог исправен, восстанов-
         ление файла (файлов),  должно вестись более или менее прямолиней-
         но: следует использовать команду RECOVER для файла или файлов.
              Если элементы каталога отсутствуют в каталоге, следует поль-
         зоваться командой CHKDSK, сначала без параметров. Вероятно вы по-
         лучите сообщение,  говорящее о том,  что определенное  количество
         кластеров утеряно с диска, что является хорошим признаком, потому
         что он указывает на то,  что вы можете снова использовать команду
         CHKDSK,  но на этот раз с параметром /F. Этот параметр заставляет
         команду CHKDSK считывать все "потерянные" кластеры и  помещать их
         в один файл.  Иногда команда CHKDSK не может восстановить все по-
         терянные данные за один проход. Нужно использовать команду CHKDSK
         столько раз, сколько необходимо до появления сообщения "Утерянные
         кластеры".  Команда CHKDSK создает новый файл каждый раз  при  ее
         использовании  для восстановления потерянных данных.  После того,
         как новый файл (файлы) создан,  скопируйте его на новый  диск,  а
         затем просмотрите только что созданного командой CHKDSK файла.
              Если восстановленные данные соответствуют  текстовым файлам,
         вы можете открыть файл текстовым редактором или текстовым процес-
         сорам и отсортировать информацию в нем.  Если, однако, восстанов-
         ленные данные соответствуют файлам в нечитаемом формате (например
         в виде объектного кода или машинного кода),  вы должны  использо-
         вать  программу  DEBUG  или какую-то другую утилиту для просмотра
         информации и ее сортировки.  В любом случае не удивляйтесь,  если
         небольшая  часть данных будет все-таки утеряна.  Часть диска,  на
         которой хранились данные,  была повреждена так сильно, что данные
         с нее не могут считываться. В большинстве случаев невосстановимые
         данные состоят из приращений по 512 или по 1024 байт, что зависит
         от  формата  диска (один 512-байтовый сектор в одном кластере для

                                      - 11-51 -
         односторонних гибких дисков или два 512-байтовый сектор  в  одном
         кластере для двухсторонних гибких дисков).  Причина ,  по которой
         операционная система MS-DOS не  может  восстановить  эти  данные,
         заключается в том, что рассматриваемый кластер (кластеры) уже за-
         изолированы в соответствующих элементах таблицы FAT и каждый  та-
         кой  элемент  содержит  значение (F)FF7,  указывающее на то,  что
         кластеры испорчены и что ни одна программа не  может использовать
         их  ни при каких обстоятельствах.  Вы могли попробовать прочитать
         эти кластеры программой DEBUG, но они могут также быть так сильно
         повреждены, что и программа DEBUG не сможет их прочитать.
              В следующем разделе говорится о том,  как следует  использо-
         вать программу DEBUG для считывания частей диска сектор за секто-
         ром.

                         Восстановление стертых файлов

              К счастью,  когда  файл был стерт при работе под управлением
         операционной системы MS-DOS, только часть элемента каталога этого
         файла меняется: первый символ имени меняется на шестнадцатиричное
         значение E5. Это значение используется, как флаг (признак). Когда
         операционная  система MS-DOS просматривает секторы каталога в по-
         исках свободного места для размещения  каталоговой  информации  о
         новом файле, система находит и использует первый элемент, начина-
         ющийся либо с шестнадцатиричного значения  E5  (элемент  каталога
         еще  не использовался).  Остальная информация в элементе каталога
         остается без  изменений.  Если бы все,что нам нужно сделать,  это
         изменить значение E5 на значение первого символа  имени  стертого
         файла, процедура восстановления стертых файлов была бы очень лег-
         кой.  К сожалению,  операционная система MS-DOS значительно более
         эффективно работает при стирании информации помещенной в секторах
         таблицы FAT.  Несмотря на то,  что операционная система MS-DOS не
         затрагивает информации,  хранящейся в секторах данных или класте-
         рах,  занятых файлом,  система устанавливает в значение  000  все
         элемента таблицы FAT,  соответствующие этим кластерам. Операцион-
         ная система MS-DOS делает это потому, что это - единственный спо-
         соб  для системы быстро просмотреть диск в поисках пустого места,
         когда она хочет разместить новые файлы. Таким образом, наша зада-
         ча по восстановлению стертого файла чуть более сложная, чем может
         сначала показаться.  Некоторые основные правила по восстановлению
         стертых файлов описываются ниже.


                                 Основные принципы

              Существует много способов потерять файл.  Может быть, вы не-
         ловко использовали команду стирания ERASE  или  команду  удаления
         DEL. Или, может быть, произошел сбой в ваших аппаратных средствах
         или сбой питания во время сеанса редактирования.  После просмотра
         диска  вы  обнаружили,  что редактируемый вами файл не может быть
         найден.
              В общем  случае файл в действительности будет стерт (при за-
         мене первого символа имени файла в элементе каталога на  шестнад-
         цатиричное значение E5) только тогда, когда он стирается командой
         ERASE или DEL или любой другой программой,  которая выполняет  ту
         же  функцию.  Если вы теряете файл из-за неисправности аппаратных
         средств или сбоя питания, файл, вероятно, не будет в действитель-
         ности стерт.  Он просто будет потерян с диска,  если используемая

                                      - 11-52 -
         вами программа не имела достаточно времени,  чтобы  закрыть  файл
         должным  образом.  В этом случае вы можете использовать программы
         операционной системы MS-DOS восстановления диска RECOVER и CHKDSK
         для восстановления потерянных данных.

         ┌──────────────────────────────────────────────────────────┐
         │                    Предостережение                       │
         │     При восстановлении файлов первое, что вы должны сде- │
         │лать, это создать точную копию диска при помощи программы │
         │копирования  диска. Не  размещайте  больше новые файлы на │
         │диске  до  тех пор, пока вы не сделаете попытку восстано- │
         │вить потерянные или стертые файлы.                        │
         └──────────────────────────────────────────────────────────┘

              Это предупреждение очень важно,  потому что помещение  новых
         данных на диск, вероятно, затруднит процесс восстановления файлов
         или сделает его невозможным. Создавая сначала точную копию диска,
         вы избежите возможности порчи некоторых частей диска(а,  следова-
         тельно,  оградите себя от постоянной потери данных) в  результате
         неправильного восстановления файла. Таким образом, если с первого
         раза что-то не будет ладиться, в вас есть в запасе исходный диск,
         с  которого вы можете скопировать данные и снова начать процедуру
         восстановления файла.
              Лучшим способом определения, был ли файл действительно стерт
         или он просто потерян является использование программы CHKDSK без
         параметров.  Если файл потерян, программа CHKDSK выводит на экран
         дисплея сообщение:  "Потерянные кластеры найдены".  Это сообщение
         выводится  на  экран  если программа CHKDSK находит разрыв в цепи
         кластеров,  описанных в таблице  FAT,  например,  если  последний
         кластер в цепи не указывает на элемент таблицы FAT, в котором со-
         держится маркер конца файла (значение от (F)FF8 до  (F)FFF. Когда
         такое случается, вы должны повторно ввести программу CHKDSK с па-
         раметром /F для восстановления всех потерянных кластеров и  поме-
         щения данных в файл, созданный программой CHKDSK.
              Именно в этом месте начальный момент  создания  копии  всего
         исходного  диска может оказаться благословенным,  потому что если
         вы имели на диске также и другие действительно стертые файлы, ко-
         манда CHKDSK /F поместит файл,  содержащий восстановленные данные
         поверх области,  содержащей стертые файлы.  Восстановление файлов
         во всех случаях должно проводиться методично и аккуратно.
              После того,  как стало  ясно,  что  файл  был  действительно
         стерт,  вам точно известны три вещи:  во-первых, элемент каталога
         остается неповрежденным,  за исключением  первого  символа  имени
         файла,   который  был  заменен  шестнадцатиричным  значением  E5.
         Во-вторых,  кластеры или секторы в области данных диска использо-
         вавшиеся  исходно  файлом,  по-прежнему  содержат  данные  файла.
         В-третьих (что весьма печально!),  каждый  из  элементов  таблицы
         FAT,  использовавшихся  исходно для отражения кластеров,  занятых
         файлом, содержит значение (0)000.
              Для восстановления стертого файла следует выполнить перечис-
         ленные ниже шаги:
              1. Вести просмотр элементов каталога до тех пор,  пока вы не
                 найдете элемент, который бы начинался с шестнадцатирично-
                 го значения E5 в байте 00. Посмотрите на остальные симво-
                 лы в имени файла в байтах с 1 по 10,  и проверьте  ,  что
                 это действительно был файл,  который вы хотите восстанав-
                 ливать.

                                      - 11-53 -
              2. Посмотрите на номер начального кластера (байты  26  и
                 27). Используйте номер  начального  кластера  в  качестве
                 указателя на первый кластер в области данных диска, заня-
                 того файлом, а также на первый начально используемый эле-
                 мент таблицы FAT.
              3. Посмотреть на размер файла (байты с 28 по  31,  последние
                 четыре  байта  в  элементе каталога).  Знать размер файла
                 важно в том,  случае ,  если файл занимает  более  одного
                 кластера в области данных диска,  а особенно важно,  если
                 части файла разбросаны по разным частям диска.
              4. Определив номер кластера,  занятого началом файла,  прос-
                 мотрим содержимое этого кластера.  Поищем в кластере сим-
                 вол  кода  ASCII  "Control-Z" (шестнадцатиричное значение
                 А1).  Если вы знаете,  что файл содержит  текст  (в  коде
                 ASCII) , и , если будет обнаружен один или несколько сим-
                 волов "Control-Z",  восстанавливать файл нужно  следующим
                 образом (в противном случае продолжайте работу с шага 5):
                 а. Если был обнаружен один или несколько символов
                    "Control-Z", вы знаете,  что файл занимает только один
                    кластер.  Начинайте восстанавливать файл путем помеще-
                    ния любого числа от (F)FF8 до (F)FFF в элемент таблицы
                    FAT, соответствующий этому кластеру.
                 б. Измените  шестнадцатиричное значение E5 в элементе ка-
                    талога на любой нужный вам первый символ имени файла .
                 в. Вернувшись  на  подсказку операционной системы MS-DOS,
                    используйте команду DIR для проверки  того,  что  файл
                    появился в списке файлов диска.  Откройте файл тексто-
                    вым редактором или  текстовым  процессором  для  того,
                    чтобы убедиться,  что его содержимое осталось правиль-
                    ным.  Все! Теперь вам нужно на этом остановиться и иг-
                    норировать все следующие шаги.
              5. Если конец файла не был найден, просмотрите все следующие
                 элементы  таблицы FAT (последовательно) до тех пор,  пока
                 вы не встретите элемент,  содержащий значение 000.  Прос-
                 мотрите содержимое кластера, имеющего такой же номер, что
                 и элемент таблицы FAT.  Если содержимое  окажется  частью
                 стертого файла,  запомните номер этого кластера и продол-
                 жите просмотр других элементов таблицы FAT и  эквивалент-
                 ных им кластеров до тех пор, пока вы не сочтете, что дос-
                 тигли конца файла.  Объем просмотра зависит от нескольких
                 моментов, описанных в следующем шаге.
              6. Определите по размеру файла,  взятому из элемента катало-
                 га, сколько кластеров  должен занимать файл. Кроме этого,
                 помните,  что,  если вы восстанавливаете текстовый файл в
                 коде ASCII,  наличие в кластере символа "Control-Z"(шест-
                 надцатиричное значение A1) указывает  на  конец  файла  .
                 Следовательно,  возвращайтесь обратно на шаг 5 до тех пор
                 ,пока вы не достигните максимального числа кластеров, за-
                 нятых  файлом.  Отмечайте каждый номер кластера,  который
                 содержит данные, относящиеся, по вашему мнению, к стерто-
                 му  файлу.  Если  в каком-то кластере вы встретили символ
                 "Control-Z",  но еще  не  определили,  сколько  кластеров
                 должно составлять искомый файл,  будьте осторожны:  клас-
                 тер,  в котором появился символ "Control-Z",  может озна-
                 чать  конец  другого  стертого файла.  Просмотрите другие
                 последующие элементы каталога по стертым файлам и отметь-
                 те  для  себя  их начальные кластеры,  а также размеры их

                                      - 11-54 -
                 файлов.  Возможно,  что два или более стертых файла имеют
                 переплетенные пути  доступа  к  последовательностям своих
                 кластеров.
              7. После  того,  как вы обоснованно решите,  какие кластеры,
                 занятые нужным файлом,  как они сцеплены,  а также будете
                 уверены в том, что нашли конец файла, перестройте таблицу
                 FAT.  Начиная с первого кластера, перейдите к эквивалент-
                 ному  элементу  таблицы  FAT и сохраните номер следующего
                 кластера занятого файлом. Затем перейдите на этом следую-
                 щий  элемент  таблицы  FAT  и  сохраните номер следующего
                 кластера.  Продолжайте выполнять эту операцию до тех пор,
                 пока  не достигнете последнего кластера.  Тогда в элемент
                 таблицы FAT вы поместите любое число от (F)FF8 до (F)FFF,
                 чтобы  отметить  конец файла.  Далее перейдите к элементу
                 каталога,  относящемуся к нашему файлу и измените  первый
                 символ  из шестнадцатиричного значение E5 в то значение в
                 коде ASCII в шестнадцатиричном виде),  которое вы  хотели
                 бы видеть в качестве первого символа имени файла.
              8. Итак,  все сделано. После возвращения на подсказку опера-
                 ционной системы MS-DOS, введите команду DIR, чтобы прове-
                 рить, что файл появился в каталоге диска. Если восстанав-
                 ливаемый  файл  является текстовым файлом,  откройте файл
                 текстовым редактором  или  текстовым  процессором,  чтобы
                 проверить его содержимое. Если это файл какого-то другого
                 типа (например, файл, имеющий расширение имени .СОМ или .
                 EXE),  загрузите файл, как программу для проверки , рабо-
                 тает ли она правильно.

              По перечисленным выше шагам может показаться,  что процедура
         восстановления файлов является довольно прямолинейной.  В зависи-
         мости от имеющихся в вашем распоряжении программных инструментов,
         в  действительности  однако просмотр данных на диске и запись ин-
         формации на диск может быть сложным занятием.  Отметим здесь, что
         шаги 6 и 7 содержат предостережения о возможности того,  что нес-
         колько ранее стертых файлов могут переплестись из-за сложной пос-
         ледовательности расположения их кластеров. Восстановление перепу-
         танных данных  указанным  выше  способом  может  оказаться  очень
         нудным и в то же время головоломным занятием. Но при наличии тер-
         пения (возможно всего лишь небольшого!),  и,  заставить себя быть
         методичным, вы непременно сможете распутать файлы.
              Теперь, когда вы имеете представление о  том,  какие  усилия
         потребуется  затратить для восстановления стертых файлов,  пришло
         время продемонстрировать, что самый быстрый способ восстановления
         стертых файлов заключается в копировании их на  диск-дубликат. Вы
         должны взять себе за правило,  часто копировать проделанную  вами
         работу  и  всегда пользоваться копиями приобретенного или личного
         программного обеспечения,  но никогда не оригиналами диска  (дис-
         ков).


                 Восстановление стертых файлов аппаратным способом

              Если в вашем распоряжении имеется только  программа  отладки
         DEBUG  для восстановления файлов, и вы имеете достаточно терпения
         и времени для набора и ассемблирования описанной в этой главе про-
         граммы контроля RESCUE, данные ниже советы могут оказаться полез-
         ными для вас.

                                      - 11-55 -
              Существует четыре   функции  или  команды  программы  DEBUG,
         представляющие  для  нас интерес:  L (Загрузка), D (Отображение),
         E (Ввод), W (Запись).  После того,  как вы создали копию диска со
         стертым файлом на нем,  загрузите программу DEBUG.  При появлении
         подсказки программы DEBUG введите команду L для загрузки данных с
         той части диска, которую вы хотите просмотреть:

             L <адрес> <дисковод> <начальный сектор> <конечный сектор>

              В данном случае <адрес> представляет собой начальный адрес в
         памяти,  в который должны загружаться данные, <дисковод> означает
         номер дисковода (например, 0 для А, 1 для В, 2 для С), а <началь-
         ный сектор> и <конечный  сектор>  указывают  диапазон  логических
         секторов (только шестнадцатиричные числа), которые вы хотите заг-
         рузить.  Для загрузки содержимого всех секторов каталога на двус-
         тороннюю 40-трековую 5,25-дюймовую дискету,  отформатированную по
         девять секторов на трек и помещения ее 0 дисковод В, введите сле-
         дующую команду:

              А>DEBUG
              -L 0 1 5 B

              После того,  как  информация будет загружена,  вы можете ис-
         пользовать команду D для отображения на экране дисплея содержимо-
         го памяти и команду Е для изменения отдельных байтов, если нужно.
         После того,  как вы пометили нужную вам  информацию  и  произвели
         требуемые  изменения,  данные могут быть обратно записаны на диск
         при помощи команды W. Команда W использует точно такой же синтак-
         сис,  что и команда L.  Удостоверьтесь, что вы задали те же пара-
         метры, что и в команде L. Это будет вам гарантией того, что толь-
         ко правильная часть диска будет переписываться.
              Единственным моментом, когда вам нужно записывать информацию
         на диск, является тот момент, когда вы меняете первый символ име-
         ни стертого файла в относящемся к данному файлу элементе  катало-
         га,  или когда вы модифицируете содержимое элементов таблицы FAT,
         соответствующей этому файлу.  При изучении содержимого кластеров,
         занятых реальным файлом,  вам не обязательно нужно записывать ин-
         формацию обратно на диск,  если только вы не производили каких-то
         сложных работ по исправлению, которые иначе нельзя выполнить. Бо-
         лее подробную информацию по использованию программы отладки DEBUG
         и  ее команд можно найти в Руководстве пользователя по операцион-
         ной системе MS-DOS (или в аналогичном руководстве по вашей  конк-
         ретной системе).

                      Использование программы контроля RESCUE

              Программа, описанная листингом 11-4,  очень проста в исполь-
         зовании. После набора команды RESCUE задается имя стертого файла.
         Команда RESCUE требует задания только имени файла,  то есть,  за-
         данные по умолчанию дисковод и каталог,  содержащие стертый файл,
         должны быть установлены командой CHDIR (или сокращенно -  CD)  до
         запуска  программы  RESCUE.  Подлежащий  стиранию файл может быть
         файлом любого типа: обычным, скрытым, системным, доступным только
         по чтению или расположенным в подкаталоге. Если вы восстанавлива-
         ете файл, находящийся в подкаталоге, который тоже был стерт, или,
         если вы хотите проконтролировать все дерево каталога, расположен-

                                      - 11-56 -
         ное ниже стертого подкаталога,  вы  должны  сначала  восстановить
         этот подкаталог по имени, используя команду RESCUE; создать зано-
         во подкаталог в заданном по умолчанию каталоге (используя команду
         CHDIR или CD) и затем вручную восстановить стертый файл (файлы) в
         подкаталоге, используя программу RESCUE.
              Если имя  файла  найдено  в  каталоге (корневом каталоге или
         подкаталоге), будет произведена попытка проведения восстановления
         файла путем анализа и записи информации в таблицу FAT.  Если файл
         не был найден,  или,  если было обнаружено,  что он не уделен, на
         экране дисплея появится сообщение об этом.  Как пояснялось ранее,
         путь доступа,  проходящий через таблицу FAT для заданного  файла,
         может  быть  сложным.  Если программа RESCUE не сможет найти путь
         размещения файла (может быть он был  сложно  переплетен  с  путем
         доступа к другому файлу) выполнение программы завершается и ника-
         кая информация не записывается на диск.  Важным фактором в работе
         программы является то, что она не будет записывать любую информа-
         цию на диск до тех пор, пока все проблемы, связанные с файлом, не
         будут разрешены. Эта программа решает все свои задачи путем пере-
         писывания всех секторов каталога и таблицы FAT в  память,  где  и
         выполняются все модификации элементов каталога файла и его табли-
         цы FAT.  Когда все изменения были проведены, программа RESCUE за-
         писывает весь каталог и всю таблицу FAT обратно на диск.  Если во
         время анализа данных и их модифицирования  встречаются трудности,
         выполнение программы RESCUE завершается и диск остается без изме-
         нений.
              Как было отмечено ранее,  программа RESCUE была так разрабо-
         тана,  что она может работать с любым форматом диска, который со-
         ответствует стандартным соглашениям по форматированию, принятым в
         операционной системе MS-DOS.  Программа RESCUE использует не вхо-
         дящую  в  документацию по операционной системе MS-DOS функцию 32h
         (получить блок параметров диска) для получения необходимой ей ин-
         формации,  касающейся формата диска.  Эта программа также  широко
         использует  функции содержащиеся в библиотеке поддержки  языка Си
         фирмы "Майкрософт".  Если вы будете перестраивать  эту  программу
         для работы ее на другом языке или с другим компилятором, вам при-
         дется найти или самим написать заменяющие значения для этих функ-
         ций.
              Программа RESCUE намеренно сделана очень простой,  и для  ее
         понимания и для того,  чтобы она соответствовала уровню этой кни-
         ги.  Существует ряд расширений, которые вы возможно, захотите до-
         бавить в программу RESCUE,  чтобы сделать ее еще более широко ис-
         пользуемой  и   полезной.   Возможно,   вы   захотите   позволить
         пользователю  самому  указывать  в  командной  строке  по заданию
         RESCUE дисковод и катало, где расположен файл или вы можете захо-
         теть разрешить универсальное задание стертых файлов с применением
         символов "*" и "?".  Весьма полезным добавлением может  оказаться
         средство  проверки  попыток  восстановления пользователем файлов,
         имена которых уже существуют (что может быть сделано при разумном
         использовании имеющихся стандартных программ).
              Другая модификация,  которую вы можете захотеть  произвести,
         заключается  в  разрешении  программе  RESCUE работать с жесткими
         дисками,  которые имеют части, превышающие 32 Мегабайта, что воз-
         можно в работе под управлением операционной системы MS-DOS версии
         4.0.  Разбиения расширенного размера используют 32-битовые номера
         секторов  вместо 16-битовых номеров секторов,  использовавшихся в
         разбиениях по 32 Мегабайта и меньше. Для того, чтобы избежать ра-
         боты с 32-битовыми элементами таблицы FAT, отношение сектор/клас-

                                      - 11-57 -

         тер увеличивается в  разбиениях  расширенного  размера  так,  что
         16-битовые элементы таблицы FAT тоже могут,  по-прежнему, исполь-
         зоваться.  Однако,  максимальный размер таблицы FAT (одной ее ко-
         пии)  был  увеличен  с 64 Кбайт (для операционной системы MS- DOS
         версии 3.3) до 128 Кбайт (для операционной системы  MS-DOS версии
         4 0).  Прикладные программы операционной системы MS-DOS экраниру-
         ются от кластера разбиения повышенного размера и от схемы отобра-
         жения секторов,  при условии, что используются только стандартные
         файловые функции операционной системы MS-DOS или абсолютные ссыл-
         ки на кластеры. Но использование абсолютными ссылками на кластеры
         прерываний 25h и 26h требует разных соглашений по обращениям меж-
         ду частями в 32 Мегабайта или меньше и частями, большими 32 Мега-
         байт. В представленных ниже листингах продемонстрированы два сог-
         лашения  в  операционной системе MS-DOS версии 4.0 для прерывания
         25h (Абсолютное чтение диска) и прерывания 26h (Абсолютная запись
         на диск).
              При некоторых изменениях программы RESCUE может быть превра-
         щена в очень могучую прикладную программу, которая может работать
         с любым типом дискового носителя, независимо от конкретной реали-
         зации и версии операционной системы MS-DOS.


              Листинг 11-2. Условия вызова операций  абсолютного  чте-
         ния/записи  на  диск  (по  прерываниям "int 25h/int 26h") для
         разделений диска в 32 Мегабайта или меньше (Все версии опера-
         ционной системы MS-DOS)

         Вход :    AL = Hомер дисковода (0=А, 1=В и т.д.)
                   CX = Количество секторов для чтения (прерывание
                        "int 25h") или для  записи  (прерывание
                        "int 26h")
                   DX =  Hачальный логический номер сектора
                   DS:BX = Aдрес передачи
         Bозврат:  Признак переноса = 0 (успешная передача) или
                                    = 1 (не успешная передача)
                                     AL = Kод ошибки
                                     AH = Tип ошибки
         Примечание: B  регистре AX возвращается значение 0207h, если
                     была сделана попытка чтения или записи части раз-
                     мером больше 32 Мегабайт

              Листинг 11-3.  Условия вызова операций абсолютного чтения/за-
         писи на диск (по прерываниям "int  25h/int  26h")  для  разделений
         диска,  больших  32  Мегабайт  (только для версии 4.0 операционной
         системы MS-DOS)

         Вход :    AL = Hомер дисковода (0=А, 1=В и т.д.)
                   BX = Указатель на список параметров
                   CX = -1 (указывает на расширенный
                           (> 32 Мегабайт) формат)
         Bозврат:  Признак переноса = 0 (успешная передача) или
                                    = 1 (не успешная передача)
                                     AL = Kод ошибки
                                     AH = Tип ошибки
         Примечание: POP AX (код ошибки) при выходе. Коды ошибок

                                      - 11-58 -
                     такие же как указанные выше.

                      Cтруктура списка параметров:

                      rba     dd   ?  ; первый сектор (32-битовый с
                                      ; началом в 0) для чтения-записи
                      count   dw   ?  ; количество секторов для
                                      ; чтения-записи
                      buffer  dd   ?  ; буфер данных

                 Листинг 11-4. Программа контроля RESCUE
         _________________________________________________________

         /********************************************************
             FILE:   RESCUE2.C   Rescue File Utility Version 2.00

         Расширения:  Контроль  файла  в подкаталогах
                      Контроль стертого подкаталога
                      Управление  любым  типом  дискового носителя
                      операционной системы MS-DOS (гибкие диски,
                      жесткие диски, сменные кассеты)

         Компилирование компилятором "Си" "фирмы "Майкрософт":
            cl /c /Zp1 /AS /GO /Ze /Ot rescue2.c

         Редактирование редактором фирмы "Майкрософт":
            Link /Dosseg/MA/LI/CPAR:1/STACK:4096 rescue2,rescue2.exe,
                 rescue2.map,slibce;
            *********************************************************

            /*  В К Л Ю Ч Е Н Н Ы Е    Ф А Й Л Ы  */

            #include  <stdio.h>   /*для функции printf() и еще многих*/
            #include  <conio.h>   /*для getch() */
            #include <dos.h>      /*для intdos(),int86(), и так  далее*/
            #include  <malloc.h>  /*для _fmalloc ()& malloc */
            #include <string.h>   /*для memory "mem...()" и  str..."*/
            #iclude   <ctype.h>   /*для topper() and "есть...()" */
            #include  <direct.h>  /*для getcwd() */

            /*  О П Р Е Д Е Л Е Н И Е    К О Н С Т А Н Т  */

            #define FALSE     0   /* эти определения предназначены*/
            #define TRUE      1   /* для того, чтобы сделать програм-*/
            #define AND       &&  /* му более читаемой и  понятной*/
            #define OR        ││
            #define EQ        ==
            #define NE        !=
            #define LE        <=
            #define ABS_READ       0x25 /* прерывание чтения диска */
            #define ABS_WRITE      0x26 /* прерывание записи на диск */
           /* Функции прерываний  "int 21h"  операционной системы DOS:*/
            #define DFUNC_RESETDSK 0x0D /* сброс  дисковода */
            #define DFUNC_GETDISK  0x19 /* получить текущий дисковод */
            #define DFUNC_GETDPB   0x32 /* получить блок дисковых */
                                        /* параметров */
            #define DFUNC_GETCD    0x47 /* получить текущий дисковод */

                                      - 11-59 -

              /* Биты атрибутов файла операционной системы DOS: */
            #define FATR_NONE      0x00 /* соответствует ANY */
            #define FATR_READ      0x01 /* только для чтения */
            #define FATR_HIDDEN    0x02 /* скрытый */
            #define FATR_SYSTEM    0x04 /* файл системы */
            #define FATR_VOLUME    0x08 /* метка тома */
            #define FATR_SUBDIR    0x10 /* подкаталог */
            #define FATR_ARCHIV    0x20 /* архивированный файл */

            #define CL_OFF      2    /* первым номером кластера */
                                     /* является число 2*/
            #define TENMB       20740L /* максимальное количество */
                                     /* секторов, поддерживаемых */
                                     /* 12-битовой таблице FAT */

            #define CHAIN_END   1    /* используется  функцией */
                                     /* "get_cluster ()" для */
                                     /*  обозначения конца файла*/
            #define FILE_END    0xfff8   /* элемент таблицы FAT для */
                                         /* конца файла */
              /* стандартная программа match() для совпадающих типов*/
            #define NO_MATCH    0   /* не совпадают*/
            #define IS_MATCH    1   /* совпадают */
            #define IS_ERASED   2   /* со стертыми файлами */
            #define IS_UNIQUE   4   /* со нестертыми файлами */

            #define DNAME_SIZE  80  /* максимальный размер имени в */
                                    /* каталоге */
            /*  ОПРЕДЕЛЕНИЕ  СТРУКТУР  И  ТИПОВ  */

            typedef unsigned int BOOL;
            typedef unsigned char BYTE;
            typedef unsigned int WORD;
            typedef unsigned long DWORD;
            typedef union {
                    BYTE far * ptr;
                    struct {
                        WORD off ;
                        WORD seg ;
                        } a;
                    } LONGPTR ;
            typedef struct dpbbuf {   /* буфер блока дисковых пара- */
                                      /* метров */
                BYTE PhysDrive;       /* номер дисковода */
                Byte DriverUnit ;     /* номер узла в пределах дис- */
                                      /* ковода */
                WORD BytesSector ;    /* количество байтов в секторе */
                BYTE SectorsCluster ; /* количество секторов в кластере
                                      /* минус 1 */
                BYTE ClusterShift;    /* сдвиг кластера */
                WORD  Reserve;        /* количество зарезервированных
                                      /* секторов */
                BYTE NumberOfFATs;    /* копии таблицы FAT */
                WORD DirEntries;      /* количество  элементов корне- */
                                      /* вого каталога */
                WORD DataSect;        /* первый сектор данных */

                                      - 11-60 -
                WORD TotClust;        /* общее количество кластеров */
                                      /* плюс 1 */
                BYTE nFATsec;         /* количество секторов  таблицы */
                                      /* FAT  (1 таблица FAT) */
                WORD DirSect;         /* номер сектора каталога */
                DWORD DevHeaderAddr;  /* адрес головки дисковода */
                BYTE MediaByte;       /* байт описателя носителя */
                BYTE DiskAccFlag;     /* признак доступа к диску */
                DWORD NextBlockAddr;  /* адрес следующего блока диска */
                } DPB;
            typedef struct dirbuf {   /* элемент каталога диска */
                char  name [8];       /* имя */
                char  ext  [3];       /* расширение */
                BYTE  attrib ;        /* атрибут */
                BYTE reserved [10];
                WORD time  ;          /* время: часы минуты- */
                                      /* -минуты секунды */
                WORD date ;           /* дата: год месяц-месяц день */
                WORD cluster ;        /* начальный кластер */
                DWORD fsize ;         /* общий размер в байтах */
                } DENTRY;

            /*  Г Л О Б А Л Ь Н Ы Е   П Е Р Е М Е Н Н Ы Е   * /

            DPB    far * DPBPtr ;       /* указатель блок параметров */
                                        /* диска (DPB) */
            WORD   ClUnit ;             /* количество секторов в */
                                        /* кластере (а также размер */
                                        /* буфера  каталога) */
            WORD   ByteClust ;          /* количество байтов в */
                                        /* кластере */
            DWORD  TotSect ;            /* общее количество секторов */
                                        /* на  диске */
            WORD   FATSize ;            /* количество байтов в таб- */
                                        /* лице FAT */
            WORD   far * FatAnchor ;    /* адрес буфера таблицы FAT */
            DENTRY near * DirAnchor ;   /* адрес буфера  каталога */
            DENTRY near * AltAnchor ;   /* адрес  буфера другого ка- */
                                        /* талога */
            char   defalt_sname [] ={"*.*"};  /* имя поиска по умол- */
                                        /* чанию */

            /*  ОПРЕДЕЛЕНИЕ ПСЕВДО-СТAHДАРТНЫХ ПОДПРОГРАММ  */

         #define diskread(d,s,c,b)   diskaccess(ABS_READ,d,s,c,b)
         #define diskwrite(d,s,c,b)   diskaccess(ABS_WRITE,d,s,c,b)

         #define sector_of(cl)   (DPBPtr->DataSect+(cl-CL_OFF)*ClUnit)
         #define cluster_of(sec) (CL_OFF+(sec-DPBPtr->DataSect)/ClUnit)
            /*  ПРЕДВАРИТЕЛЬНЫЕ ОБЪЯВЛЕНИЯ СТAHДАРТНОЙ ПОДПРОГРАММЕ  */

            WORD   get_cluster ();      /* получить значение элемента */
                                        /* кластера */
            void   put_cluster ();      /* сохранить значение в клас- */
                                        /* тере */
            BOOL   savefile ();         /* восстановить файл(ы) */
            DENTRY near * findt ();     /* просмотр буфера каталога */

                                      - 11-61 -
            DPB    far * getdpb () ;    /* получить адрес блока пара- */
                                        /* метров диска */
            void   diskaccess () ;      /* абсолютное чтение/запись */
                                        /* диска */
            BOOL   match () ;           /* соответствие определенного */
                                        /* имени  с файлом */

            /* *******************************************************
            /*
            /*           Главная   точка   входа
            /*
            /* *******************************************************

            main (argc,argv,envp)
            int argc ;
            char   * argv [] ;
            char   * envp [] ;
               }
               char   near * sspec ;       /* характеристика поиска */
               char   dname [DNAME_SIZE];  /* буфер имени каталога */
               char   * pptr ;             /* указатель на каталоговое
                                           /* имя */
               WORD   dnum ;               /* номер дисковода (исход- */
                                           /* ное значение 0) */
               WORD   snum ;               /* номер сектора каталога */
               WORD   savenum ;            /* используется для хра- */
                                           /* нения */
                                           /* значения snum */
               DENTRY near * dptr ;         /* элемент текущего каталога */
               print ("\nRESCUE, Version 2.OO\n\n");

               if (argc<2) {               /* если  параметров  нет */
                      print ("*** Имя файла не указано ***\n");
                      exit (1) ;
                      };
               sspec =argv [1];           /* файл для восстановления */
               getcwd (dname, DNAME_SIZE) ;  /* получить дисковод по */
                                             /* умолчанию и каталог */
               if (*(char *)((WORD)dname + strlen(dname) - 1) NE '\\')
                    strcat (dname, "\\");  /* имя пути доступа за- */
                                          /* канчивается знаком "\"*/
               pptr = dname+3;            /* указатель  начального */
                                          /* имени пути доступа*/
               dnum = *dname - 'A' ;      /* извлечь номер дисковода */

         /*  Определить разные глобальные значения из блока парамет- */
         /*  ров диска (DPB), включая размер таблицы FAT, количество */
         /*  байтов в кластере, общее количество секторов и т.д.     */

         DPBPtr = getdpb (dnum) ;  /* получить блок параметров диска */

          if(dnum NE DPBPtr->PhysDrive) {
             printf ("Дисковод %c: является замененным\n",(dnum+ 'A'));
             printf("Программа RESCUE будет работать только
                     на физических дисководах\n");
             exit (1);
             } ;

                                      - 11-62 -

            FATSize = DPBPtr->BytesSector * DPBPtr->nFATsec:
            CLUnit  = DPBPtr->SectorsCluster + 1;

         TotSect = (DWORD) DPBPtr->TotClust * (DWORD) ClUnit
                      + (DWORD) DPBPtr->DataSect;
            BytCLust= DPBPtr->BytesSector * CLUnit;
           /* Pаспределить память для буферов каталога и таблиц FAT */

              If (((DirAnchor=(Dentry near *) malloc(BytClust)) EQ
                              NULL) OR
                  ((AltAnchor=(DENTRY near *) malloc(BytCLust)) EQ
                              NULL) OR
                  ((FATAnchor=(WORD far *)_fmalloc(FATSize)) EQ
                               NULL)) {
                  printf ("*** Can't Allocate Working Memory ***\n");
                  exit (1);
                  } ;

            /* Cчитать в исходную таблицу FAT */

            discread (dnum,DPBPtr->Reserve,DPBPtr->nFATsec,FATAnchor);

            /* Двигаться по цепи элементов каталога в поисках  */
            /* соответствующего  имени пути доступа */

               snum = DPBPtr->Dirsect;    /* первый сектор каталога */
               while (*pptr NE '\0')      /* до тех пор, пока путь */
                                    /* доступа к каталогу ненулевой */
                  if ((dptr = findf (dnum, &snum, pptr, DirAnchor,
                    NULL,FATR_SUBDIR,IS_INIQUE)) NE NULL) {
                       snum = sector_of (dptr->cluster);
                       while ((*pptr NE '\0') AND (*pptr NE '\\'))
                           pptr++;
                       if (*pptr EQ '\\') pptr++;
                    } else {
                      printf ("*** Can't Find  Directory  %s  ***\n",
                                                               pptr);
                      exit (1);   };
              /* Ненормальное завершение, если файл, подлежащий  */
              /* восстановлению, не стерт. */

                    savenum = snum;    /* сохранить сектор каталога */
                   if (findf (dnum, &dnum, sspec, DirAnchor,
                      NULL,FATR_NONE,IS_UNIQUE) NE NULL) {
                  printf ("***%s%s не стерто ***\n",dname,sspec);
                  exit (1) ;
                   };
             /* Eсли файл стерт, подкаталог или файл затем */
             /* восстанавливает его */
                  snum = savenum;   /* восстановить сектор каталога */
                  if ((dptr = findf (dnum,&snum,sspec, DirAnchor,
                     NULL,FATR_NONE,IS_ERASED)) NE NULL){
                  if(get_cluster (dptr->cluster) NE 0)
                     printf ("Hестертый файл%s%s не может быть
                                                     восстановлен\n",

                                      - 11-63 -
                       dname, sspec);
                     else {
                   if (savefile (dnum,dptr, snum,toupper(*sspec))) {
                      if (dptr->attrib & FATR_SUBDIR)
                          print ("Подкаталог %s%s восстановлен\n,
                             dname,sspec);
                          else
                            printf ("Файл %s%s восстановлен\n",
                               dname,sspec);
                       } else {
                         printf (Неудачное восстановление %s%s\n",
                           dname,sspec);
                         diskread (dnum,DPBPtr->Reserve,
                           DPBPtr->nFARsec,FatAnchor);
                       };
                     };
                 } else {
                   printf ("Не могу найти нестертый файл %s%s\n",
                     dname,sspec);
                   };
                 };
         /* **** Найти следующий кластер в цепи ********************

              Эта стандартная программа находит значение элемента FAT.
         Это эквивалентно соединению кластеров FAT в цепь.  Эта  стан-
         дартная  программа возвращает либо значение кластера (следую-
         щий кластер в цепи файлов операционной системы DOS) либо  ну-
         левое значение NULL, если в цепи больше нет кластеров.

              Если диск имеет емкость 10 Мегабайт или меньше,  то использу-
         ются 12-битовые элементы таблицы FAT (кластеры). Если диск больше,
         то используются 16-битовые элементы таблицы FAT.

         Значения кластера: (0)000 ................ свободный кластер
                            (0)001 ................ неопределен
                            (0)002 -(F)FEF......... следующий кластер
                            (F)FF0 -(F)FF6......... зарезервирован
                            (F)FF7 ................ испорченный кластер
                            (F)FF8 -(F)FFF......... конец цепи
         */

            WORD   get_cluster (clust)   /* номер кластера */
                WORD clust;
                {
                union { WORD FAR }* w;  /* указатель на таблицу FAT */
                    BYTE far * b;
                    }fatptr;
                WORD   value;            /* содержимое кластера */

                    if (TotSect > TENMB){
                    fatptr.b=(BYTE far *)
                      ((DWORD) FatAnchor + (DWORD)(clust * 2));
                    value = *fatptr.w;
                } else {
                fatptr.b= (BYTE far *)
                ((DWORD) FatAnchor + (DWORD)(clust * 3/2));
                value = *fatptr.w;

                                      - 11-64 -
         /*  Кластеры с нечетными номерами сдвигаются влево */
         /*  на 4 бита в слове */
                    if (clust & 0x01) value >>= 4;
                    value &= 0x0fff;
                    } ;
            if ((value & 0x0ff0) EQ 0xff0) return (CHAIN_END);
                    else return (value);
                    } ;

         /* ****  Сохранить значение кластера *************************
                 Эта стандартная  программа  помещает  значение  в  элемент
            кластера  в  таблице  FAT,  если диск имеет емкость 10 Мегабайт
            пользуются 12-битовые элементы  таблицы  FAT  (кластеры).  Если
            диск больше, то используются 16-битовые элементы таблицы FAT.

         */
            void put_cluster (clust,value)
                WORD clust;              /* номер кластера */
                WORD value;              /* значение нового кластера */
                {

            union { WORD FAR }* w;       /* указатель на таблицу FAT */
                BYTE far * b;
                }fatptr ;
            WORD   cur_val;          /* значение текущего кластера */

            if (TotSect > TENMB) {
                fatptr.b=(BYTE far *)
                ((DWORD) FatAnchor + (DWORD) (clust * 2));
                *fatptr.w=value;
                } else {
                fatptr.b= (BYTE far *)
                ((DWORD)FatAnchor + (DWORD)(clust * 3/2));
                cur_val = *fatptr.w;
         /*  Кластеры с нечетными номерами сдвигаются влево */
         /*  на 4 бита в слове */
            if (clust & 0x01)
                *fatptr.w = (cur_val & 0x000f) │ (значение << 4);
            else
                *fatptr.w = (cur_val & 0xf000) │ (значение & 0x0fff);
                } ;
            };

         /* *** Найти  кластер файла и сохранить каталог и
                                               таблицу FAT файла ***

               Эта программа восстанавливает стертый  файл,  если  это
            можно.  Она вычисляет количество кластеров, которые должен
            занимать файл, и ищет эти кластеры в таблице FAT.

                Эта стандартная программа предполагает, что номер  на-
            чального  кластера  файла, подлежащего восстановлению, был
            проверен, и его значение равно нулю.
         */

                                      - 11-65 -
            BOOL savefile (dnum,dptr,sect,ch)
                WORD    dnum ;                /* рабочий дисковод */
                DENTRY  near * dptr ;     /* элемент  каталога, */
                                          /*  подлежащий сохранению */
                WORD    sect ;            /* дать оглавление секторов */
                                          /* кластера */
                BYTE    ch ;          /* первый  символ  в имени файла */
                {
                DENTRY  far * writeptr ; /*указатель на буфер каталога*/
                WORD    filecls ;        /* размер файла (в кластерах) */
                WORD    last ;           /* номер последнего  кластера */
                WORD    current ;        /* номер текущего кластера */
                WORD    next ;           /* следующий кластер в цепи */
                WORD    fatsect ;        /* номер сектора таблицы FAT */
                union { WORD FAR }* w ;  /* указатель на таблицу FAT */
                    BYTE far * b ;
                    } fatptr ;

            if (dptr->attrib & FATR_SUBDIR)  /* если файл находится в */
                                             /* подкаталоге */
                filecls = 0 ;                /* дополнений не нужно */
            else
                filecls = (WORD) ((dptr->fsize + (DWORD)BytClust-1L)/
                (DWORD) BytClust) -1 ;
            current = last =dptr->cluster ;   /* первый кластер */

            /* Исправление таблицы FAT */

            while (filecls) {
                if (++current > DPBPtr->TotClust) {
                   print ("\n*** Нельзя восстановить файл ***/n");
                   return (FALSE) ;
                   } ;
                if (get_cluster(current) EQ 0) {  /* пустой  кластер */
                   put_cluster (last,current) ;   /* часть цепи */
                   last = current ;
                   filecls-- ;
                   } ;
                } ;
                put_cluster (last, FILE_END) ;         /* конец цепи */
                *(dptr->name) = ch ;     /* сохранить первый символ */

            /* Подготовка завершена - писать сектора таблицы FAT */
            /* и каталога */

                writeptr = DirFnchor ;
                fatsect = DPBPtr->Reserve ;
                disckwrite (dnum,fatsect,DPBPtr->nFATsec,FatAnchor) ;
                fatsect += DPBPtr->FATsec ;
                disckwrite (dnum,fatsect,DPBPtr->nFATsec,FatAnchor) ;
                disckwrite (dnum,sect,ClUnit,writeptr) ;
                dbos (DFUNC_RESETDSK,NULL,NULL);
                return(TRUE)) ;
                } ;

            /* **** Найти определенный  элемент в этом каталоге **** */


                                      - 11-66 -
            DENTRY near * findf (dnum,sect,pptr,dbuf,bptr,sattr,mtype)
                WORD    dnum ;         /* рабочий дисковод */
                WORD    * sect ;       /* сектор текущего каталога*/
                char    near * pptr ;  /* указатель имени пути доступа*/
                DENTRY  near * dbuf ;  /* буфер каталога */
                DENTRY  near * bptr ;  /* указатель другого буфера */
                BYTE    sattr ;        /* атрибут поиска */
                int     mtipe ;        /* требуемый тип совпадения */
                {
                int     i ;            /* счетчик циклов */
                WORD    cluster ;      /* используется для сцепления */
                DENTRY  near * dirptr ; /* указатель  буфера каталога*/
                DENTRY  far  * readptr ; /*указатель  буфера каталога*/
                DENTRY  near * dirend ;  /* адрес конца буфера */

                readptr = dbuf ;
                dirend = (DENTRY near *) ((WORD) dbuf + BitClust - 1) ;

                while (TRUE) {
                   if (bptr NE NULL) {    /* продолжить с ... */
                       dirptr =++bptr ;   /* того места, где */
                                          /* остановились */
                       bptr = NULL ;
                     } else {             /* иначе, начать с начала */
                       diskread (dnum,*sect,ClUnit,readptr) ;
                       dirptr = dbuf ;
                       } ;

                              /* Eсть ли совпадающие файлы ? */
                while (dirptr < dirend) {
                   if (((dirptr->attrib & sattr) EQ sattr) AND
                       (match (pptr,dirptr->name,mtype)))
                       return (dirptr) ;
                   dirptr++ ;
                   } ;

            /* Bсе элементы в этом кластере приведены, перейти к */
            /* другому */

            if (*sect >=DPBPtr->DataSect) {      /* подкаталог */
                  cluster = cluster_of (*sect) ; /* следующий кластер*/
                  if ((cluster = get_cluster (cluster)) LE CHAIN_END)
                        return (NULL) ;
                      else *sect = (sector_of (cluster)) ;
                   } else                       /* корневой каталог */
                   if (*sect >= DPBPtr->DIRSect) {
                       *sect += ClUnit ;        /* следующие сектора */
                   if (*sect >=DPBPtr->DATASect) return (NULL) ;
                   } else return (NULL) ;
                   } ;
                 } ;
               /* **** Получить блок параметров системы BIOS  ****** */
               /* **** для заданного дисковода ********* */

         DPB far *getdpb (dnum)  /* возврат указателя на блок DPB */

           Word    dnum ;     /* номер рабочего дисковода */

                                      - 11-67 -
           {
           union REGS inregs, outregs ;
           struct SREGS segregs ;
           LONGPTR farptr ;
           inregs.h.ah = DFUNC_GETDPB ;
           inregs.h.dl = dnum + 1 ;
           intdosx (&inregs, &outregs, &segregs) ; /*получить блок DPB*/
           if (outregs.x.cflag) {
            if (outregs.h.al EQ 0xff)
             print ("*** Дисковод %c неисправен ***\n",(dnum + 'A')) ;
                else
             printf ("*** Не могу считать параметры дисковода %c ***\n",
                     (dnum + 'A')) ;
              exit (1) ;
              } ;

            farptr.a.off = outregs.x.bx ;
            farptr.a.seg = segregs.ds ;
            return ((DPB far *) farptr.ptr ;
            } ;

         /* **** Чтение/запись на диск прямого доступа *********** */

         void diskaccess ((function, dnum, sector, count, buffer)
              BYTE function ;         /* функция прерывания */
              BYTE dnum ;             /* номер физического дисковода */
              WORD sector ;           /* номер сектора */
              WORD count ;            /* счет секторов */
              BYTE far * buffer ;     /* буфер */
              {
              union REGS inregs, outregs ;
              struct SREGS segregs ;
              LONGPTR farptr ;

              farptr.ptr = buffer ;
              inregs.h.al = dnum ;
              inregs.x.dx = sector ;
              inregs.x.cx = count ;
              inregs.x.bx = farptr.a.off ;
              segregs.ds = farptr.a.seg ;
              int86x (function,&inregs,&outregs,&segregs) ;
              if (outregs.x.cflag) {
                if (function EQ ABC_READ)
                 printf ("*** Ошибка во время считывания диска ***\n") ;
                   else
                       print ("*** Ошибка во время записи на диск ***\n") ;
                     exit (1) ;
                     } ;
                  } ;

         /* ************ Проверить имена на совпадение ********** */

         /*     Отметим, что обращение к  массивам  имен  ведется
            без знака, поэтому сравнение с ОхE5 будет выполняться
            надлежащим образом.*/


                                      - 11-68 -
            BOOL match (sname, fname, mtype)
                 BYTE   near *sname ;   /* поиск совпадающего имени */
                 BYTE   near *fname ;     /* имя файла или каталога */
                 int    mtype ;            /* тип требуемого совпадения */
                 {
                 int    i ;                /* индекс */
                 char   near *fext ; /*расширение файла или каталога*/
                 fext = fname + 8;      /* расширение  файла */

         /*Сверка состояния файла (стерт/восстановлен) с типом поиска*/

                 if  (((*fname NE 0xe5) AND (mtype EQ IS_ERASED)) OR
                      ((*fname EQ 0xe5) AND (mtype NE IS_ERASED)))
                      return (NO_MATCH) ;

                 if  (*fname EQ 0xe5) {    /* игнорировать первый */
                     fname++ ;             /* символ стертого файла */
                     sname++;
                     } ;

                 while (fname < (fext+3)) {
                 if (*fname EQ toupper(*sname)) {
                    fname++ ;
                    sname++ ;
                  } else                   /* если имена различны, */
                    switch (*sname++) {    /* выяснить почему */
                      case '.':
                          if ((*fname EQ ' ') OR (fname EQ fext)) {
                            fname = fext ;  /* проверка расширения */
                            break ;
                            } ;                  /* иначе */
                          return (NO_MATCH) ;
                      case '\\':
                      case '\0:
                          if (*fname EQ ' ')   /* конец имени sname */

                                 return (IS_MATCH) ;
                      default:
                          return (NO_MATCH) ;
                      } ;
                   } ;
                   return (IS_MATCH) ;
                 } ;

            /* Конец файла RESCUE.C */


                           Использование утилит Нортона

              Утилиты Нортона очень легко использовать, особенно, когда вы
         что-то знаете о структуре дисков MS-DOS. В версиях утилит Нортона
         до 3.0 программы DL (просмотр блока и UE(восстановление) являются
         наиболее широко используемыми для восстановления файлов. Програм-
         ма просмотра диска DL просматривает сектор за сектором любой час-
         ти диска,  отображая шестнадцатиричные данные в левой части экра-
         на,  а  эквивалентные  им  значения в коде ASCII - в правой части
         экрана. Эта программа, достаточно удобная для определения формата

                                      - 11-69 -
         диска, а  также для определения типа считываемых секторов (таких,
         как секторов начальной загрузки, таблицы FAT, каталога или облас-
         ти  данных),  эта  программа отображает на экране эту информацию.
         Программа может также выводить на экран простое отображение  дис-
         ка,  подобное иллюстрациям структуры диска, представленным в этой
         главе, показывающим для чего используется каждый сектор или клас-
         тер с точки зрения трековой структуры. Она также показывает в ка-
         ких частях диска расположены файлы, а какие части пусты.
              Программа восстановления UnErase подобна программе DiskLook.
         Но  программа  UnErase  испытывает трудности,  если она встречает
         проблемы,  описанные в этой главе.  Например,  незавершенный файл
         поверх которого писалась новая информация или несколько файлов со
         сложными переплетениями.
              В некоторой степени ценность утилит Нортона зависит от того,
         как хорошо вы понимаете структуру дисков MS-DOS и от того, что вы
         знаете о секторах таблицы FAT и секторов каталогов, где они начи-
         наются  и  кончаются.  Даже если вы это хорошо знаете,  вы можете
         увидеть,  что эти программ являются хорошим обучающим  материалом
         благодаря  ясному и подробному способу отображения на экране дан-
         ных дисках.  Другое преимущество заключается в том,  что средства
         защиты  встроены в программе с целью ограждения вас от каких-либо
         разрушающих диск действий.
              В версиях  3.0  утилит  Нортона  функции  этих двух программ
         DiskLook и UnErase объединены в программу NU  (Norton Utilities).
         Используемые  в  этой реализации функции были усовершенствованы и
         включают в себя более подробные описания содержимого диска вместо
         преимущественного криптографического шестнадцатиричного представ-
         ления данных.  Только утилиты Нортона версии 3.0 и выше могут ра-
         ботать с 80-трековыми, двухсторонними 5,25-дюймовыми гибкими дис-
         ками  высокой  плотности,  а  также  с  20-Мегабайтными  жесткими
         дисками в персональных компьютерах типа IBM PC-AT и совместимых с
         ними.  Ни одна из версий (вплоть до версии 3.0) не может работать
         с  8-дюймовыми  гибкими дисками,  а также они не могут работать с
         жесткими дисками, имеющими формат, отличный от тех, что использу-
         ются  в системах персональных компьютеров IBM XT и IBM AT. Только
         утилиты Нортона версии 4.0 могут работать со всеми форматами дис-
         ков,  которые соответствуют стандартным соглашениям по форматиро-
         ванию в операционной системе MS-DOS.  Кроме этого, поскольку спо-
         соб,  которым  эти  программы  отображают  информацию  на  экране
         сложен, они работают только с дисплейным оборудованием, совмести-
         мым или близко совместимым с оборудованием, использующимся в сис-
         темах "ИБМ".  Если,  однако,  вы будете использовать персональных
         компьютер  фирмы  "ИБМ" IBM PC или совместимую с ним систему,  вы
         увидите, что утилиты Нортона работают здесь эффективно и разнооб-
         разно, поэтому что они очень хорошо подходят к темам, описанным в
         этой главе.


                           Использование "Ultra-утилит"

              "Ultra-утилита" представляет собой набор программ восстанов-
         ления файлов, подобных  утилиты  Нортона. "Ultra-утилита" являет-
         ся поддерживаемыми пользователями программами, также иногда назы-
         ваемыми  "коммерчески  распространяемыми  программами"*,  которые


                                      - 11-70 -
         можно приобрести через многие каналы поставки программного  обес-
         печения.  "Ultra-утилиты"  содержат примечание для пользователя о
         том, что если приобретенные программы окажутся для вас полезными,
         вы можете заплатить установленную
         сумму их создателям,  а  взамен  вы  станете  "зарегистрированным
         пользователем"  и  будете в будущем получать полную информацию об
         обновлениях имеющегося у вас программного обеспечения.
              На главном диске "Ultra-утилит"  находятся три программы:
         U-ZAP, U-FORMAT  и  U-FILE.  Программа  U-ZAP  похожа на программу
         просмотра диска DiskLook из утилит Нортона и представляет вам  ши-
         рокие  возможности  по модификации содержимого любых частей диска.
         Программа U-FORMAT очень специфичная  программа,  потому  что  она
         обеспечивает  форматирование  отдельных  треков  диска.  Программа
         U-FORMAT может даже переформатировать  отдельный  трек  диска,  не
         разрушив  данные операционной системы MS-DOS,  находящиеся на нем.
         Эта возможность может оказаться очень полезной для ненадежно рабо-
         тающих  дисков во время возникновения таких серьезных трудностей с
         их форматированием,  что даже операционная система MS-DOS не может
         восстановить  данные,  к  которым  нет  доступа.  Программа U-FILE
         располагает многими возможностями отображения на экране и  модифи-
         цирования файлов на диске,  включая функцию восстановления стертых
         файлов.
              "Ultra-утилиты" являются   прекрасной  альтернативой  утилиты
         Нортона ,  если вы заботитесь о стоимости программных продуктов. И
         не   позволяйте   разубедить   себя   доступностью  этого  пакета:
         "Ultra-утилиты" действительно  являются  прекрасными  программами,
         разработанными   профессионалами,   которые  используют  недорогие
         способы их распространения.


                                    Заключение

              В этой  главе  внимание  было  сконцентрировано на структуре
         диска и на процедуре восстановления файлов под управлением опера-
         ционной  системы MS-DOS.  Информация,  предложенная в этой главе,
         говорит о том,  что, если вы обладаете нужными знаниями вы можете
         восстановить стертый, разрушенный или потерянный файл. Даже, нес-
         мотря на то,  что различные упомянутые здесь средства для восста-
         новления  файлов  обеспечивают  разные  степени простоты работы с
         дисковыми файлами,  основная последовательность действий по восс-
         тановлению файлов, описанная в этой главе, остается той же.
              В следующей главе рассматривается подобный  вопрос:  восста-
         новление данных, потерянных в памяти. Понимание структуры диска и
         схемы хранения файлов поможет вам понять смысл следующей главы.
