Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система MS-DOS

© Александр Фролов, Григорий Фролов
Том 1, книга 3, М.: Диалог-МИФИ, 1992.

[Назад] [Содеожание] [Дальше]

2.4. Файлы и каталоги

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

Корневой каталог находится сразу за последней копией FAT. Количество секторов, занимаемых одной копией FAT, находится в блоке параметров BIOS в BOOT-секторе в поле fatsize, количество копий FAT - в поле fatcnt блока BPB. Следовательно, перед корневым каталогом находится один BOOT-сектор и (fatcnt_*_fatsize) секторов таблицы размещения файлов FAT.

Размер корневого каталога можно определить исходя из значения поля rootsize. В этом поле при форматировании диска записывается максимальное количество файлов и каталогов, которые могут находиться в корневом каталоге. Для каждого элемента в каталоге отводится 32 байта, поэтому корневой каталог имеет длину (32_*_rootsize) байтов.

Корневой каталог занимает непрерывную область фиксированного размера. Размер корневого каталога задается при форматировании и определяет максимальное количество файлов и каталогов, которые могут быть описаны в корневом каталоге. Для определения количества секторов, занимаемых корневым каталогом, можно воспользоваться следующей формулой:

RootSecs = sectsize_/_(32_*_rootsize)

В этой формуле sectsize - размер сектора в байтах, он может быть получен из соответствующего поля BOOT-сектора.

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

Области логического диска       Номер начального сектора
                                                на логическом диске

+­­­­­­­­­­­­­­­­­­­+
¦                   ¦             0
¦ BOOT-сектор и     ¦
¦ зарезервированные ¦
¦ сектора           ¦
¦                   ¦
+­­­­­­­­­­­­­­­­­­­¦
¦                   ¦             ressecs - количество резервных
¦ Первая копия FAT  ¦                            секторов
¦                   ¦
+­­­­­­­­­­­­­­­­­­­¦
¦                   ¦             ressecs+fatsize
¦ Вторая копия FAT  ¦
¦                   ¦
+­­­­­­­­­­­­­­­­­­­¦
¦                   ¦             ressecs+(fatsize*fatcnt)
¦ Корневой каталог  ¦
¦                   ¦
+­­­­­­­­­­­­­­­­­­­¦
¦                   ¦             ressecs+(fatsize*fatcnt)+
¦ Область данных    ¦               sectsize_/_(32*rootsize)
¦                   ¦
+­­­­­­­­­­­­­­­­­­­+

Область данных разбита на кластеры, причем нумерация кластеров начинается с числа 2. Кластеру с номером 2 соответствуют первые сектора области данных. Теперь мы можем привести формулу, которая позволит нам связать номер кластера с номерами секторов, занимаемых им на логическом диске:

SectNu = DataStart + ((ClustNu-2) * clustsize)

В этой формуле:

SectNu  - номер первого сектора, распределенного
                  кластеру с номером ClustNu;

DataStart = ressecs+(fatsize*fatcnt)+(sectsize/(32*rootsize));

ClustNu - номер кластера, для которого необходимо определить
                  номер первого сектора;

clustsize       - количество секторов, занимаемых кластером,
                  находится в блоке параметров BIOS.

Этой формулой мы воспользуемся для чтения корневого каталога.

Как мы уже говорили, любой каталог содержит 32-байтовые элементы - дескрипторы, описывающие файлы и другие каталоги. Приведем формат дескриптора:

Смещение Размер Содержимое
(+0) 8 Имя файла или каталога, выравненное на левую границу и дополненное пробелами.
(+8) 3 Расширение имени файла, выравненное на левую границу и дополненное пробелами.
(+11) 1 Атрибуты файла.
(+12) 10 Зарезервировано.
(+22) 2 Время создания файла или время его последней модификации.
(+24) 2 Дата создания файла или дата его последней модификации.
(+26) 2 Номер первого кластера, распределенного файлу.
(+28) 4 Размер файла в байтах.

Байт атрибутов является принадлежностью каждого файла. Биты этого байта имеют следующие значения:

0 Файл предназначен только для чтения, в этот файл нельзя писать и его нельзя стирать.
1 Скрытый файл, этот файл не будет появляться в списке файлов, создаваемом командой операционной системы DIR.
2 Системный файл. Этот бит обычно установлен в файлах, являющихся составной частью операционной системы.
3 Данный дескриптор описывает метку диска. Для этого дескриптора поля имени файла и расширения имени файла должны рассматриваться как одно поле длиной 11 байтов. Это поле содержит метку диска.
4 Дескриптор описывает файл, являющийся подкаталогом данного каталога.
5 Флаг архивации. Если этот бит установлен в 1, то это означает, что данный файл не был выгружен утилитой архивации (например, программой BACKUP).
6-7 Зарезервированы.

Обычно файлы имеют следующие комбинации битов в байте атрибутов:

0 Обычные файлы (тексты программ, загрузочные модули, пакетные файлы).
7 Только читаемые, скрытые, системные файлы. Такая комбинация битов байта атрибутов используется для файлов операционной системы IO.SYS, MSDOS.SYS.
8 Метка тома. Дескриптор метки тома может находиться только в корневом каталоге логического диска.
10h Дескриптор, описывающий каталог.
20h Обычный файл, который не был выгружен утилитами BACKUP или XCOPY.

В любом каталоге, кроме корневого, два первых дескриптора имеют специальное назначение. Первый дескриптор содержит в поле имени строку:

".       "

Этот дескриптор указывает на содержащий его каталог. Т.е. каталог имеет ссылку сам на себя.

Второй специальный дескриптор содержит в поле имени строку:

"..      "

Этот дескриптор указывает на каталог более высокого уровня.

Если в поле номера первого занимаемого кластера дескриптора с именем ".. " находится нулевое значение, это означает, что данный каталог содержится в корневом каталоге.

Таким образом, в древовидной структуре каталогов имеются ссылки как в прямом, так и в обратном направлении. Эти ссылки можно использовать для проверки сохранности структуры каталогов файловой системы.

При удалении файла первый байт его имени заменяется на байт E5h (символ 'х'). Все кластеры, распределенные файлу, отмечаются в FAT как свободные. Если вы только что удалили файл, его еще можно восстановить, так как в дескрипторе сохранились все поля, кроме первого байта имени файла. Но если на диск записать новые файлы, то содержимое кластеров удаленного файла будет изменено и восстановление станет невозможным.

Остановимся подробнее на полях времени и даты создания или последней модификации файла. DOS обновляет содержимое этих полей после любой операции, изменяющей содержимое файла - создания файла, перезаписи содержимого файла, добавления данных в файл или обновления содержимого файла. После обновления файла DOS устанавливает бит архивации 5 байта атрибутов в 1.

Формат поля времени показан на рисунке:

15            11 10               5 4                   0
+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+
¦ Часы (0...23) ¦  Минуты (0...59) ¦  Секунды/2 (0...29) ¦
+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+

Старшие пять битов содержат значение часа модификации файла, шесть битов с номерами 5-10 содержат значение минут модификации файла, и, наконец, в младших 5 битах хранится значение секунд, деленное на 2. Для того, чтобы время обновления файла уместилось в шестнадцати битах, пришлось пойти на снижение точности времени до двух секунд.

Формат даты обновления файла напоминает формат времени:

15             9 8               5 4              0
+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+
¦ Год (0...119) ¦  Месяц (1...12) ¦  День (1...31) ¦
+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+

Для того, чтобы получить значение года обновления файла, необходимо прибавить к величине, хранимой в старших семи битах, значение 1980. Поля месяца и дня каких-либо особенностей не имеют, они полностью соответствуют календарной дате.

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

Для удобства работы с каталогами файл sysp.h содержит следующие определения типов:

#pragma pack(1)


/* Время последнего обновления файла */

typedef struct _FTIME_ {
        unsigned sec : 5, min : 6, hour : 5;
} FTIME;



/* Дата последнего обновления файла */

typedef struct _FDATE_ {
        unsigned day : 5, month : 4, year : 7;
} FDATE;



/* Дескриптор файла в каталоге */

typedef struct _FITEM_ {
        char name[8];
        char ext[3];
        char attr;
        char reserved[10];
        FTIME time;
        FDATE date;
        unsigned cluster_nu;
        unsigned long size;
} FITEM;
#pragma pack()

Приведем исходный текст программы, которая читает BOOT-сектор выбранного диска, определяет формат FAT, вычисляет размер и расположение FAT и корневого каталога. Затем программа читает FAT и корневой каталог в динамически получаемые буфера и выводит на экран содержимое корневого каталога.

#include <stdio.h>
#include <malloc.h>
#include <dos.h>
#include "sysp.h"

void main(void);
void main(void) {

  BOOT _far *boot_rec;
  int i,j, k, status, fat_sectors;
  long total_sectors;
  int fat, root_begin, root_sectors;
  char drive;
  unsigned _far *fat_buffer;
  FITEM _far *root_buffer, _far *rptr;

  union REGS reg;
  struct SREGS segreg;


  printf("\n"
                "\nЧтение корневого каталога логического диска"
                "\n  (C)Фролов А., 1991"
                "\n");


// Заказываем буфер для чтения BOOT-записи.
// Адрес буфера присваиваем FAR-указателю.

  boot_rec = _fmalloc(sizeof(*boot_rec));

// Запрашиваем диск, для которого необходимо
// выполнить чтение загрузочной записи.

  printf("\n"
                "\nВведите обозначение диска, для просмотра"
                "\nкорневого каталога (A, B, ...):");

  drive = getche();

// Вычисляем номер дисковода

  drive = toupper(drive) - 'A';

// Читаем загрузочную запись в буфер

  status = getboot((BOOT _far*)boot_rec, drive);

// Если произошла ошибка (например, неправильно указано
// обозначение диска), завершаем работу программы

  if(status) {
        printf("\nОшибка при чтении BOOT-сектора");
        exit(-1);
  }

// Определяем формат таблицы FAT

  total_sectors = boot_rec->bpb.totsecs;

// Если мы работаем с расширенным разделом диска,
// общее количество секторов на диска берем из
// расширенного PBP

  if(total_sectors == 0) total_sectors = boot_rec->bpb.drvsecs;

// Формат FAT определяем исходя из общего
// количества секторов на логическом диске

  if(total_sectors > 20791) {
        printf("\nFAT имеет 16-битовый формат");
        fat=16;
  }
  else {
        printf("\nFAT имеет 12-битовый формат");
        fat=12;
  }

// Определяем количество секторов, занимаемых FAT

  fat_sectors = boot_rec->bpb.fatsize;

// Заказываем буфер для FAT

  fat_buffer = _fmalloc(fat_sectors * boot_rec->bpb.sectsize);

// Вычисляем номер первого сектора FAT

  j = boot_rec->bpb.ressecs;

// Читаем FAT в буфер fat_buffer

// Заполняем регистровые структуры для вызова
// прерывания DOS INT 25h

         reg.x.ax = drive;
         reg.x.bx = FP_OFF(fat_buffer);
         segreg.ds = FP_SEG(fat_buffer);
         reg.x.cx = fat_sectors;
         reg.x.dx = j;
         int86x(0x25, &reg, &reg, &segreg);

// Извлекаем из стека оставшееся там после
// вызова прерывания слово

         _asm pop ax

// Вычисляем номер первого сектора корневого каталога

        root_begin = j + fat_sectors * boot_rec->bpb.fatcnt;

// Вычисляем длину корневого каталога

        root_sectors = (boot_rec->bpb.rootsize * 32) /
                                boot_rec->bpb.sectsize;

// Заказываем буфер для корневого каталога

        root_buffer = _fmalloc(root_sectors * boot_rec->bpb.sectsize);


// Читаем корневой каталог в буфер root_buffer

         reg.x.ax = drive;
         reg.x.bx = FP_OFF(root_buffer);
         segreg.ds = FP_SEG(root_buffer);
         reg.x.cx = root_sectors;
         reg.x.dx = root_begin;
         int86x(0x25, &reg, &reg, &segreg);
         _asm pop ax

// Показываем содержимое корневого каталога

        printf("\n"
         "\nИмя файла    Аттр. Дата        Время     Кластер Размер"
         "\n------------ ----- ----------  --------  ------- ------");

        for(rptr = root_buffer;;rptr++) {
                printf("\n");

// Признак конца каталога - нулевой байт в начале
// имени файла

                if(rptr->name[0] == 0) break;

// Выводим содержимое дескриптора файла

                for(i=0; i<8; i++) printf("%c",rptr->name[i]);
                printf(".");
                for(i=0; i<3; i++) printf("%c",rptr->ext[i]);
                printf(" %02X    %02d-%02d-%02d  %02d:%02d:%02d ",
                        rptr->attr,
                        rptr->date.day,
                        rptr->date.month,
                        rptr->date.year + 1980,
                        rptr->time.hour,
                        rptr->time.min,
                        rptr->time.sec * 2);
                printf(" %-5d   %lu",
                        rptr->cluster_nu,
                        rptr->size);

        }

// Освобождаем буфера

  _ffree(root_buffer);
  _ffree(boot_rec);
  _ffree(fat_buffer);
}

Запустив программу два раза для диска С: и RAM-диска G: мы получили на экране следующую картину:

Чтение корневого каталога логического диска
  (C)Фролов А., 1991


Введите обозначение диска, для просмотра
корневого каталога (A, B, ...):c
FAT имеет 12-битовый формат

Имя файла    Аттр. Дата        Время     Кластер Размер
------------ ----- ----------  --------  ------- ------
IO      .SYS 07    26-11-1988  00:55:26  2       33337
MSDOS   .SYS 07    26-11-1988  00:56:18  11      37376
DOS     .    10    22-09-1990  00:50:34  21      0
ARC     .    10    22-09-1990  00:58:08  22      0
SYSPRG  .    10    03-10-1990  12:09:10  23      0
COMMAND .COM 20    30-11-1988  00:00:04  25      37557
SSTOR   .SYS 20    03-04-1989  12:00:00  354     17884
DUMM1004.COM 20    17-06-1990  12:59:24  35      1004
AUTOEXEC.B21 20    20-12-1990  11:21:02  359     677
AUTOEXEC.C60 20    28-07-1990  09:17:26  360     241
хYSLOG  .    20    15-01-1991  19:42:48  441     510
SD      .INI 20    08-10-1990  10:05:52  362     2497
NULLFILE.    20    17-02-1991  13:59:28  0       0
CLSCREEN.SYS 20    06-06-1990  20:58:36  363     157
AUTOEXEC.BAT 20    18-10-1990  16:14:14  364     677
FRECOVER.IDX 27    08-10-1990  10:07:16  504     29
FRECOVER.DAT 21    08-10-1990  10:07:16  467     18432
CONFIG  .SYS 20    02-02-1991  21:19:34  332     390
х       .    20    04-02-1991  21:34:34  361     254


Чтение корневого каталога логического диска
  (C)Фролов А., 1991


Введите обозначение диска, для просмотра
корневого каталога (A, B, ...):g
FAT имеет 12-битовый формат

Имя файла    Аттр. Дата        Время     Кластер Размер
------------ ----- ----------  --------  ------- ------
MS-RAMDR.IVE 08    03-01-1990  00:00:00  0       0
TEMP    .    10    17-02-1991  13:59:22  2       0
INCLUDE .    10    17-02-1991  13:59:26  3       0
BOOK3   .DOC 20    17-02-1991  15:27:38  18      181248

Заметьте, что приведенная выше программа предоставляет вам параметр, который невозможно получить с помощью команды операционной системы DIR - номер первого кластера, распределенного файлу. Операционная система MS-DOS не дает программам иной возможности определить номер первого кластера файла, чем чтение каталога по секторам.

Для исследования подкаталогов корневого каталога и для демонстрации основных приемов работы с таблицей размещения файлов FAT предназначена следующая программа. Вы можете использовать ее для исследования структуры каталогов диска.

#include <stdio.h>
#include <malloc.h>
#include <dos.h>
#include "sysp.h"

void main(void);
void main(void) {

  BOOT _far *boot_rec;
  int i,j, k, status, fat_sectors;
  long total_sectors;
  int ffat, root_begin, root_sectors;
  char drive;
  unsigned _far *fat_buffer;
  FITEM _far *root_buffer, _far *rptr;
  char cbuf[128];
  char _far *clust_buffer;
  int cur_clust;

  union REGS reg;
  struct SREGS segreg;


  printf("\n"
                "\nЧтение каталогов логического диска"
                "\n  (C)Фролов А., 1991"
                "\n");


// Заказываем буфер для чтения BOOT-записи.
// Адрес буфера присваиваем FAR-указателю.

  boot_rec = _fmalloc(sizeof(*boot_rec));

// Запрашиваем диск, для которого необходимо
// выполнить чтение загрузочной записи.

  printf("\n"
                "\nВведите обозначение диска (A, B, ...):");

  drive = getche();

// Вычисляем номер дисковода

  drive = toupper(drive) - 'A';

// Читаем загрузочную запись в буфер

  status = getboot((BOOT _far*)boot_rec, drive);

// Если произошла ошибка (например, неправильно указано
// обозначение диска), завершааем работу программы

  if(status) {
        printf("\nОшибка при чтении BOOT-сектора");
        exit(-1);
  }

// Определяем формат таблицы FAT

  total_sectors = boot_rec->bpb.totsecs;

// Если мы работаем с расширенным разделом диска,
// общее количество секторов на диска берем из
// расширенного PBP

  if(total_sectors == 0) total_sectors = boot_rec->bpb.drvsecs;

// Формат FAT определяем исходя из общего
// количества секторов на логическом диске

  if(total_sectors > 20791) {
        printf("\nFAT имеет 16-битовый формат");
        ffat=16;
  }
  else {
        printf("\nFAT имеет 12-битовый формат");
        ffat=12;
  }

// Определяем количество секторов, занимаемых FAT

  fat_sectors = boot_rec->bpb.fatsize;

// Заказываем буфер для FAT

  fat_buffer = _fmalloc(fat_sectors * boot_rec->bpb.sectsize);

// Вычисляем номер первого сектора FAT

  j = boot_rec->bpb.ressecs;

// Читаем FAT в буфер fat_buffer

// Заполняем регистровые структуры для вызова
// прерывания DOS INT 25h

         reg.x.ax = drive;
         reg.x.bx = FP_OFF(fat_buffer);
         segreg.ds = FP_SEG(fat_buffer);
         reg.x.cx = fat_sectors;
         reg.x.dx = j;
         int86x(0x25, &reg, &reg, &segreg);

// Извлекаем из стека оставшееся там после
// вызова прерывания слово

         _asm pop ax

// Вычисляем номер первого сектора корневого каталога

        root_begin = j + fat_sectors * boot_rec->bpb.fatcnt;

// Вычисляем длину корневого каталога

        root_sectors = (boot_rec->bpb.rootsize * 32) /
                                boot_rec->bpb.sectsize;

// Заказываем буфер для корневого каталога

        root_buffer = _fmalloc(root_sectors * boot_rec->bpb.sectsize);

// Читаем корневой каталог в буфер root_buffer

         reg.x.ax = drive;
         reg.x.bx = FP_OFF(root_buffer);
         segreg.ds = FP_SEG(root_buffer);
         reg.x.cx = root_sectors;
         reg.x.dx = root_begin;
         int86x(0x25, &reg, &reg, &segreg);
         _asm pop ax

// Показываем содержимое корневого каталога

        printf("\n"
         "\nИмя файла    Аттр. Дата        Время     Кластер Размер"
         "\n------------ ----- ----------  --------  ------- ------");

        for(rptr = root_buffer;;rptr++) {
                printf("\n");

// Признак конца каталога - нулевой байт в начале
// имени файла

                if(rptr->name[0] == 0) break;

// Выводим содержимое дескриптора файла

                for(i=0; i<8; i++) printf("%c",rptr->name[i]);
                printf(".");
                for(i=0; i<3; i++) printf("%c",rptr->ext[i]);
                printf(" %02X    %02d-%02d-%02d  %02d:%02d:%02d ",
                        rptr->attr,
                        rptr->date.day,
                        rptr->date.month,
                        rptr->date.year + 1980,
                        rptr->time.hour,
                        rptr->time.min,
                        rptr->time.sec * 2);
                printf(" %-5d   %lu",
                        rptr->cluster_nu,
                        rptr->size);

        }

// Получаем буфер для чтения кластеров каталога

        clust_buffer = _fmalloc(boot_rec->bpb.clustsize
                                                * boot_rec->bpb.sectsize);

        printf("\nНомер первого кластера каталога:");
        gets(cbuf);
        cur_clust = atoi(cbuf);

// Переменная k используется в качестве флага.
// При первом просмотре каталога ее значение равно 0,
// затем эта переменная устанавливается в 1.

        k=0;

        for(;;) {

// Сохраняем номер кластера каталога

                j=cur_clust;

// Вычисляем номер следующего кластера, распределенного
// каталогу

                cur_clust = fat(fat_buffer, ffat, cur_clust);
                printf("%d ",cur_clust);

// Читаем кластер в буфер clust_buffer

                 reg.x.ax = drive;
                 reg.x.bx = FP_OFF(clust_buffer);
                 segreg.ds = FP_SEG(clust_buffer);
                 reg.x.cx = boot_rec->bpb.clustsize;
                 reg.x.dx = root_begin + root_sectors
                                        + ((j-2)*boot_rec->bpb.clustsize);
                 int86x(0x25, &reg, &reg, &segreg);
                 _asm pop ax

// Показываем содержимое каталога

                 rptr = (FITEM _far *)clust_buffer;

// Первый дескриптор в каталоге указывает на
// этот же каталог. В поле имени первого дескриптора
// находится строка ".       ". Этот факт можно использовать
// для проверки каталога. Если вы по ошибке указали
// номер кластера, не принадлежащего каталогу,
// программа завершит работу с сообщением об ошибке.

                 if(k == 0) {
                        k=1;
                        if(strncmp(rptr->name,".       ",8) != 0) {
                                printf("\nЭто не каталог !");
                                exit(-1);
                        }
                 }

                 printf("\n"
                 "\nИмя файла    Аттр. Дата        Время     Кластер Размер"
                 "\n------------ ----- ----------  --------  ------- ------");

                 for(;;rptr++) {
                        printf("\n");

// Признак конца каталога - нулевой байт в начале
// имени файла

                        if(rptr->name[0] == 0) break;

// Выводим содержимое дескриптора файла

                        for(i=0; i<8; i++) printf("%c",rptr->name[i]);
                        printf(".");
                        for(i=0; i<3; i++) printf("%c",rptr->ext[i]);
                        printf(" %02X    %02d-%02d-%02d  %02d:%02d:%02d ",
                                rptr->attr,
                                rptr->date.day,
                                rptr->date.month,
                                rptr->date.year + 1980,
                                rptr->time.hour,
                                rptr->time.min,
                                rptr->time.sec * 2);
                        printf(" %-5d   %lu",
                                rptr->cluster_nu,
                                rptr->size);

                }

// Если этот кластер - последний из распределенных каталогу,
// завершаем работу программы

                if((cur_clust == 0xfff) || (cur_clust == 0xffff)) break;

        }

// Освобождаем буфера

  _ffree(root_buffer);
  _ffree(boot_rec);
  _ffree(fat_buffer);
  _ffree(clust_buffer);
}

Эта программа обращается к таблице размещения файлов при помощи функции fat():

/**
*.Name      fat
*
*.Title     Выбрать элемент из FAT
*
*.Descr     Функция выбирает элемент с заданным номером из таблицы
*           размещения файлов FAT. Формат FAT передается
*           функции как параметр.
*
*.Params    int fat(b_fat, t_fat, idx);
*
*           char _far *b_fat  - буфер, содержащий FAT
*
*           int t_fat         - формат FAT, может быть
*                               равен 12 или 16
*
*           int idx           - номер элемента FAT, который
*                               должен быть выбран
*
*.Return    Содержимое ячейки FAT с указанным номером
**/

#include <stdio.h>
#include <stdlib.h>
#include "sysp.h"

int fat(char _far *b_fat, int t_fat, int idx) {

  div_t clust_nu ;
  int cluster;

  if(t_fat == 12) {

                /*  FAT -  12  */

          clust_nu = div(idx * 3, 2);

          if( clust_nu.rem != 0 )

                cluster = (*((int*)(b_fat + clust_nu.quot)) >> 4) & 0xfff;

          else

                cluster = *((int*)(b_fat + clust_nu.quot)) & 0xfff;
  }

  else if(t_fat == 16) {

                /*  FAT - 16  */

          cluster = *((int*)(b_fat + idx * 2));
  }

  else {
                printf("*FAT()* FAT format error\n");
                exit(-100);
  }

  return(cluster);
}

В качестве примера приведем результат работы программы для диска E:

Чтение каталогов логического диска
  (C)Фролов А., 1991


Введите обозначение диска (A, B, ...):e
FAT имеет 12-битовый формат

Имя файла    Аттр. Дата        Время     Кластер Размер
------------ ----- ----------  --------  ------- ------
C600    .    10    22-09-1990  01:22:14  2       0
SOLO    .    10    22-09-1990  11:15:42  6       0
QC25    .    10    07-10-1990  22:53:48  7       0
SYSPRG  .    10    03-10-1990  09:19:08  12      0
WORD    .    10    02-02-1991  14:02:14  15      0
SD      .INI 20    17-02-1991  15:36:52  799     2497
FRECOVER.IDX 27    17-02-1991  15:42:10  2551    29
FRECOVER.DAT 21    17-02-1991  15:42:10  1958    21504
х       .    20    17-02-1991  16:37:30  1973    347

Номер первого кластера каталога:3
4095 

Имя файла    Аттр. Дата        Время     Кластер Размер
------------ ----- ----------  --------  ------- ------
.       .    10    22-09-1990  01:22:24  3       0
..      .    10    22-09-1990  01:22:24  2       0
UTILS   .HLP 20    08-02-1990  00:09:42  800     162023
QH      .HLP 20    29-01-1990  19:32:04  840     20763
CV      .HLP 20    07-02-1990  21:33:32  846     239863

Обратите внимание на выделенные элементы каталога. Это ссылки соответственно на сам каталог и на каталог более высокого уровня.

[Назад] [Содеожание] [Дальше]