MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 18, М.: Диалог-МИФИ, 1995, 254 стр. 2.5. Список управляющих блоков устройствПоле dev_cb векторной таблицы связи содержит дальний адрес списка блоков управления устройствами MS-DOS (MS-DOS Device Control Block), который мы назвали DDCB . Блок DDCB строится операционной системой для каждого дискового устройства и содержит информацию о характеристиках этого устройства, указатель на заголовок драйвера, обслуживающего данное устройство и многое другое. Как мы уже говорили, блок DDCB может быть использован программами, которые выполняют доступ к диску на уровне секторов. Подробнее назначение и использование полей блока DDCB будет описано в разделе, посвященном файловой системе, так как эта информация требуется в основном для организации работы с диском на низком уровне. Формат блока управления устройствами DDCBНиже мы привели формат блока управления устройствами DDCB , адрес которого доступен через векторную таблицу связи MS-DOS.
Мы приведем также описание формата блока DDCB в следующем виде: typedef struct
{
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 ;
Еще раз уместно заметить, что формат этого блока не описан в документации по MS-DOS, поэтому он может отличаться в различных версиях операционных систем. Программа DDCBLISTПрограмма DDCBLIST (листинг 2.3) выводит на консоль содержимое всех блоков DDCB в расшифрованном виде. Так как при большом количестве дисков выводится очень много информации, следует использовать средство переназначения стандартного устройства вывода MS-DOS, запустив программу следующим образом: ddcblist > ddcb.txt Затем вы сможете просмотреть полученный файл при помощи любого текстового редактора. Листинг 2.3. Файл ddcblist\ddcblist.cpp #include <dos.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned mcb_seg;
void far *dev_cb;
void far *file_tab;
void far *clock_dr;
void far *con_dr;
unsigned max_btbl;
void far *disk_buf;
void far *drv_info;
void far *fcb_tabl;
unsigned fcb_size;
unsigned char num_bdev;
unsigned char lastdriv;
} CVT ;
typedef CVT far* LPCVT ;
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 ;
typedef DDCB far* LPDDCB;
void main(void);
LPDDCB get_fddcb(LPCVT cvt);
LPDDCB get_nddcb(LPDDCB ddcb);
void main(void)
{
union REGS regs;
struct SREGS sregs;
LPCVT lpCVT;
LPDDCB lpDDCB;
printf("\nБлоки управления дисковыми устройствами DDCB "
"\n(C) Фролов А.В., 1995\n\n");
// Получаем адрес векторной таблицы связи
regs.h.ah = 0x52;
intdosx (®s, ®s, &sregs);
// Передвигаем указатель на поле msb_seg
lpCVT = (LPCVT )MK_FP (sregs.es, regs.x.bx - 2);
// Получаем адрес первого блока DDCB
lpDDCB = get_fddcb(lpCVT);
for(;;)
{
// Если это последний блок, завершаем цикл
if(lpDDCB == NULL) break;
printf("Адрес DDCB : %Fp\n"
"Номер устройства: %d\n"
"Дополнительный номер: %d\n"
"Размер сектора: %d\n"
"Размер кластера в секторах: %d\n"
"База размера кластера: %d\n"
"Зарезервировано секторов: %d\n"
"Число копий FAT : %d\n"
"Макс. файлов в корневом каталоге : %d\n"
"Первый кластер данных: %d\n"
"Всего кластеров: %ld\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",
lpDDCB, lpDDCB->drv_num, lpDDCB->drv_numd,
lpDDCB->sec_size, lpDDCB->clu_size,
lpDDCB->clu_base, lpDDCB->boot_siz,
lpDDCB->fat_num, lpDDCB->max_dir,
lpDDCB->data_sec, lpDDCB->hi_clust,
lpDDCB->fat_size, lpDDCB->root_sec,
lpDDCB->reserv1, lpDDCB->drv_addr,
lpDDCB->media, lpDDCB->acc_flag,
lpDDCB->next, lpDDCB->reserv2,
lpDDCB->built);
// Получаем адрес следующего блока DDCB
lpDDCB = get_nddcb(lpDDCB);
}
}
// ---------------------------------------------
// get_fddcb
// Функция возвращает адрес первого блока DDCB .
// В качестве параметра ей следует передать
// адрес векторной таблицы связи
// ---------------------------------------------
LPDDCB get_fddcb(LPCVT cvt)
{
LPDDCB ddcb;
ddcb = (LPDDCB)cvt->dev_cb;
return(ddcb);
}
// ---------------------------------------------
// get_nddcb
// Функция возвращает адрес следующего блока DDCB
// ---------------------------------------------
LPDDCB get_nddcb(LPDDCB ddcb)
{
LPDDCB ddcb_n;
ddcb_n = (LPDDCB)ddcb->next;
if(FP_OFF (ddcb_n) == 0xffff)
return((LPDDCB)NULL);
return(ddcb_n);
}
Программа DDCBLST1Приведенный выше способ получения доступа к блокам DDCB больше всего подходит для просмотра блоков управления всеми дисковыми устройствами. Если вам требуется получить DDCB для какого-нибудь конкретного устройства, можно воспользоваться недокументированной функцией 32h прерывания INT 21h (со всеми ограничениями, связанными с использованием недокументированных возможностей). Функция 32h получает в регистре DL номер устройства (0 - текущий диск , 1 - А: и т. д.) и возвращает в регистрах DS:BX адрес соответствующего DDCB . Если номер устройства был задан неправильно, после выполнения функции регистр AL будет содержать значение FFh. Если требуется получить адрес DDCB для НГМД , необходимо установить дискету в приемный карман накопителя. Программа, исходный текст который приведен в листинге 2.4, выводит адреса всех DDCB в виде списка. Можете запустить ее (она есть на дискете, которая продается вместе с книгой) и посмотреть, что получится. Перед запуском не забудьте вставить дискеты во все НГМД . Листинг 2.4. Файл ddcblst1\ddcblst1.cpp #include <dos.h>
#include <stdio.h>
#include <stdlib.h>
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 ;
typedef DDCB far* LPDDCB;
void main(void);
LPDDCB get_ddcb(unsigned char device_number);
void main(void)
{
LPDDCB lpDDCB;
unsigned char dr;
for(dr=1;; dr++)
{
lpDDCB = get_ddcb(dr);
if(lpDDCB == NULL) break;
printf("%Fp\n", lpDDCB);
}
}
LPDDCB get_ddcb(unsigned char device_number)
{
union REGS regs;
struct SREGS sregs;
regs.h.ah = 0x32;
regs.h.al = 0;
regs.h.dl = device_number;
intdosx ( ®s, ®s, &sregs );
if(regs.h.al == 0xff)
return(LPDDCB)NULL;
return((DDCB far*)MK_FP (sregs.ds, regs.x.bx));
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

