Операционная система MS-DOS© Александр Фролов, Григорий ФроловТом 1, книги 1-2, М.: Диалог-МИФИ, 1991. 2.3. Список управляющих блоков устройствПоле dev_cb векторной таблицы связи содержит FAR-адрес цепочки блоков управления устройствами DOS (DOS Device Control Block) - DDCB. Блок DDCB строится операционной системой для каждого дискового устройства и содержит информацию о характеристиках этого устройства и указатель на заголовок драйвера, обслуживающего данное устройство. Этот блок может быть использован программами, которые выполняют доступ к диску на уровне секторов. Подробнее назначение и использование полей блока DDCB будет описано в разделе, посвященном файловой системе, так как эта информация требуется в основном для организации работы с диском на низком уровне. Приведем формат блока DDCB для DOS версий 2.х и 3.х:
Для DOS версии 4.х формат этого блока другой. Кроме того, изменилась его длина:
Файл 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);
}
|

