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

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

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

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

2.3. Список управляющих блоков устройств

Поле dev_cb векторной таблицы связи содержит FAR-адрес цепочки блоков управления устройствами DOS (DOS Device Control Block) - DDCB. Блок DDCB строится операционной системой для каждого дискового устройства и содержит информацию о характеристиках этого устройства и указатель на заголовок драйвера, обслуживающего данное устройство.

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

Приведем формат блока DDCB для DOS версий 2.х и 3.х:

(0) 1 drv_num номер устройства (0 соответствует устройству А:, 1 - В: и т.д.)
(+1) 1 drv_numd дополнительный номер устройства внутри драйвера
(+2) 2 sec_size размер сектора в байтах
(+4) 1 clu_size число, на единицу меньшее количества секторов в кластере
(+5) 1 clu_base если содержимое этого поля не равно нулю, то для получения общего числа секторов в кластере надо возвести 2 в степень clu_base и получившееся число прибавить к clu_size
(+6) 2 boot_siz количество зарезервированных секторов (boot-сектора, начало корневого каталога)
(+8) 1 fat_num количество копий FAT
(+9) 2 max_dir максимальное число дескрипторов файлов в корневом каталоге (т.е. максимальное число файлов, которое может содержать корневой каталог на этом устройстве)
(+11) 2 data_sec номер первого сектора данных на диске (номер сектора, соответствующего кластеру номер 2)
(+13) 2 hi_clust максимальное количество кластеров (равно увеличенному на 1 количеству кластеров данных)
(+15) 1 fat_size количество секторов, занимаемых одной копией FAT
(+16) 2 root_sec номер первого сектора корневого каталога
(+18) 4 drv_addr FAR-адрес заголовка драйвера, обслуживающего данное устройство
(+22) 1 media байт описания среды носителя данных
(+23) 1 acc_flag флаг доступа, 0 означает, что к устройству был доступ
(+24) 4 next адрес следующего блока DDCB, для последнего блока в поле смещения находится число FFFF
    --------------- только для DOS 2.x -----------------
(+28) 2 dir_clu номер начального кластера текущего каталога (0 для корневого каталога)
(+30) 64 dir_path строка в формате ASCIIZ, содержащая путь к текущему каталогу
    ----- DOS 3.х ------
(+28) 2 reserv1 зарезервировано, обычно равно 0
(+30) 2 built число FFFF в этом поле означает, что блок DDCB был построен

Для DOS версии 4.х формат этого блока другой. Кроме того, изменилась его длина:

(0) 1 drv_num номер устройства (0 соответствует устройству А:, 1 - В: и т.д.)
(+1) 1 drv_numd дополнительный номер устройства внутри драйвера
(+2) 2 sec_size размер сектора в байтах
(+4) 1 clu_size число, на единицу меньшее количества секторов в кластере
(+5) 1 clu_base если содержимое этого поля не равно нулю, то для получения общего числа секторов в кластере надо возвести 2 в степень clu_base и получившееся число прибавить к clu_size
(+6) 2 boot_siz количество зарезервированных секторов (boot-сектора, начало корневого каталога)
(+8) 1 fat_num количество копий FAT
(+9) 2 max_dir максимальное число дескрипторов файлов в корневом каталоге (т.е. максимальное число файлов, которое может содержать корневой каталог на этом устройстве)
(+11) 2 data_sec номер первого сектора данных на диске (номер сектора, соответствующего кластеру номер 2)
(+13) 2 hi_clust максимальное количество кластеров (равно увеличенному на 1 количеству кластеров данных)
(+15) 1 fat_size количество секторов, занимаемых одной копией FAT
(+16) 1 reserv1 зарезервироано
(+17) 2 root_sec номер первого сектора корневого каталога
(+19) 4 drv_addr FAR-адрес заголовка драйвера, обслуживающего данное устройство
(+23) 1 media байт описания среды носителя данных
(+24) 1 acc_flag флаг доступа, 0 означает, что к устройству был доступ
(+25) 4 next адрес следующего блока DDCB, для последнего блока в поле смещения находится число FFFF
(+29) 2 reserv2 зарезервироано
(+31) 2 built число FFFF в этом поле означает, что блок DDCB был построен

Файл sysp.h содержит определение типа DDCB для MS-DOS версии 4.х и 5.0:

/* Блок управления устройством DOS */

#pragma pack(1)

typedef struct _DDCB_ {
        unsigned char drv_num;
        unsigned char drv_numd;
        unsigned sec_size;
        unsigned char clu_size;
        unsigned char clu_base;
        unsigned boot_siz;
        unsigned char fat_num;
        unsigned max_dir;
        unsigned data_sec;
        unsigned hi_clust;
        unsigned char fat_size;
        char reserv1;
        unsigned root_sec;
        void far *drv_addr;
        unsigned char media;
        unsigned char acc_flag;
        struct _DDCB_ far *next;
        unsigned reserv2;
        unsigned built;
} DDCB;

#pragma pack()

Еще раз уместно заметить, что формат этого блока не описан в документации по MS-DOS, поэтому он может отличаться в различных версиях операционных систем.

Приведем тексты программ для получения адресов первого и последующих блоков DDCB:

/**
*.Name      get_fddcb
*
*.Title     Получить адрес первого DDCB
*
*.Descr     Функция возвращает адрес первого блока DDCB
*
*.Params    DDCB far *get_fddcb(CVT far *cvt)
*
*              cvt - адрес векторной таблицы связи
*
*.Return    Указатель на первый блок DDCB
**/

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

DDCB far *get_fddcb(CVT far *cvt) {

        DDCB far * ddcb;
        ddcb = cvt->dev_cb;
        return(ddcb);
}

/**
*.Name      get_nddcb
*
*.Title     Получить адрес следующего DDCB
*
*.Descr     Функция возвращает адрес следующего блока DDCB
*           или 0, если это последний блок в цепочке
*
*.Params    DDCB far *get_nddcb(DDCB far *ddcb)
*
*              ddcb - адрес предыдущего DDCB
*
*.Return    Указатель на следующий блок DDCB
*           или 0, если это последний блок в цепочке
**/

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

DDCB far *get_nddcb(DDCB far *ddcb) {

        DDCB far *ddcb_n;

        ddcb_n = ddcb->next;
        if(FP_OFF(ddcb_n) == 0xffff) return((DDCB far *)0);
        return(ddcb_n);
}

С помощью приведенной ниже программы можно просмотреть содержимое всех блоков DDCB. Так как при большом количестве дисков выводится очень много информации, следует использовать средство переназначения стандартного устройства вывода DOS:

show_ddc > drives.lst

Эта программа проверена для версии MS/DOS 4.01.

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

void main(void);

void main(void)
{
        CVT far *cvt;
        DDCB far *ddcb;

        printf("\nБлоки управления дисковыми устройствами (DDCB)"
               "\nCopyright (C)Frolov A., 1990\n"
               "\n");

        cvt=get_mcvt();
        ddcb=get_fddcb(cvt);

        for(;;) {
            if(ddcb == (DDCB far *)0) break;
            printf("Адрес DDCB:                         %Fp\n"
                   "Номер устройства:                   %d\n"
                   "Дополнительный номер:                %d\n"
                   "Размер сектора:                      %d\n"
                   "Размер кластера в секторах:          %d\n"    
                   "База размера кластера:               %d\n" 
                   "Зарезервировано секторов:            %d\n"
                   "Число копий FAT:                     %d\n"
                   "Макс. файлов в корневом каталоге :   %d\n"
                   "Первый кластер данных:               %d\n"
                   "Всего кластеров:                     %d\n"
                   "Размер FAT в секторах:               %d\n"
                   "Первый сектор корневого каталога:    %d\n"
                   "Поле reserv1:                       %01X\n"
                   "Адрес драйвера:                     %Fp\n"
                   "Байт описателя среды носителя:      %01X\n"
                   "Флаг доступа:                       %01X\n"
                   "Адрес следующего DDCB:              %Fp\n"
                   "Поле reserv2:                       %04X\n"
                   "Блок построен:                      %04X\n"
                   "-------------------------------------\n\n",
                    ddcb,
                    ddcb->drv_num,
                    ddcb->drv_numd,
                    ddcb->sec_size,
                    ddcb->clu_size,
                    ddcb->clu_base,
                    ddcb->boot_siz,
                    ddcb->fat_num,
                    ddcb->max_dir,
                    ddcb->data_sec,
                    ddcb->hi_clust,
                    ddcb->fat_size,
                    ddcb->root_sec,
                    ddcb->reserv1,
                    ddcb->drv_addr,
                    ddcb->media,
                    ddcb->acc_flag,
                    ddcb->next,
                    ddcb->reserv2,
                    ddcb->built);
        ddcb=get_nddcb(ddcb);
        }
        exit(0);
}

Приведенный выше способ получения доступа к блокам DDCB больше всего подходит для просмотра блоков управления всеми дисковыми устройствами. Если вам требуется получить DDCB для какого-нибудь конкретного устройства, можно воспользоваться недокументированной функцией 32H прерывания INT 21H (со всеми ограничениями, связанными с использованием недокументированных возможностей).

Функция 32H получает в регистре DL номер устройства (0 - текущий диск, 1 - А: и т.д.) и возвращает в регистровой паре DS:BX адрес соответствующего DDCB. Если номер устройства был задан неправильно, регистр AL после выполнения функции будет содержать значение FF.

Если требуется получить адрес DDCB флоппи-диска, необходимо установить диск в приемный карман дисковода.

Приведем текст программы, возвращающей указатель на DDCB диска с заданным номером:

/**
*.Name      get_ddcb
*
*.Title     Получить адрес DDCB заданного диска
*
*.Descr     Функция возвращает адрес блока управления
*           устройством DOS DDCB
*
*.Params    DDCB far *get_ddcb(int device_number)
*
*           device_number - номер диска, для которого
*                            требуется получить DDCB
*                            Номер задается так:
*                            0 - текущий диск, 1 - В и т.д.
*
*.Return    Указатель на DDCB заданного диска
**/

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

DDCB far *get_ddcb(unsigned char device_number) {

        union  REGS  inregs, outregs;
        struct SREGS segregs;

        inregs.h.ah = 0x32;
        inregs.h.al = 0;
        inregs.h.dl = device_number;
        intdosx( &inregs, &outregs, &segregs );
        if(outregs.h.al == 0xff) return(DDCB far *)0;

        return((DDCB far*)FP_MAKE(segregs.ds,outregs.x.bx));
}

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

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

void main(void);

void main(void)
{
         DDCB far *ddcb;
         unsigned char dr;

         for(dr=1;;dr++) {
                ddcb=get_ddcb(dr);
                if(ddcb == (DDCB far *)0) break;
                printf("%Fp\n",ddcb);
         }
         exit(0);
}
[Назад] [Содеожание] [Дальше]