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)); } |