Список управляющих блоков устройств
Поле 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 был построен |
/* Блок управления устройством 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); }