Получение справочной информации
Прежде чем мы начнем обзор функций получения справочной информации о состоянии и параметрах дисковой подсистемы, введем понятие текущего диска и текущего каталога.
Если вы запускаете программу, которая находится в каком-либо каталоге на одном из дисков, то эти диск и каталог становятся текущими для MS-DOS. Это можно понимать в том смысле, что программе не требуется каждый раз при работе с файлами указывать требуемый диск или каталог.
В любой момент времени программа может узнать текущие диск или каталог, а также заменить их. Для этого она должна использовать специальные функции прерывания INT 21h.
Для установки текущего диска можно использовать функцию 0Eh, которая имеет следующий формат вызова:
На входе: | AH = 0Eh | |
DL = Номер дисковода (0 - А:, 1 - В:, и т.д.) | ||
На выходе: | AL = Общее количество дисководов в системе. Эта величина соответствует параметру LASTDRIVE
файла CONFIG.SYS. |
Для того чтобы узнать номер текущего дисковода, программа может воспользоваться функцией 19h:
На входе: | AH = 19h |
На выходе: | AL = Номер текущего дисковода (0 - А:, 1 - В:, и т.д.). |
Функция 3Bh предназначена для установки текущего каталога:
На входе: | AH = 3Bh |
DL = Номер дисковода (0 - текущий, 1 - А:, 2 - В:, и т.д.) | |
DS:DX = Адрес буфера, содержащего путь каталога, который должен стать текущим. | |
На выходе: | AX = Код ошибки, если CY установлен в 1. |
Буфер пути может иметь максимальный размер 64 байта. Он должен содержать путь в формате ASCIIZ, т.е. строку, закрытую двоичным нулем, например: "path\dirname",0. Строка не должна содержать литеры, обозначающие диск. Если текущим должен стать корневой каталог, строка должна состоять только из одного двоичного нуля.
Для того чтобы узнать текущий каталог, вы можете воспользоваться функцией 47h:
На входе: | AH = 47h |
DL = Номер дисковода (0 - текущий, 1 - А:, 2 - В:, и т.д.) | |
DS:SI = Адрес буфера для записи пути текущего каталога. | |
На выходе: | AX = Код ошибки, если флаг переноса CF
установлен в 1. |
Буфер должен иметь размер не менее 64 байтов, текущий каталог возвращается в формате ASCIIZ без литеры, обозначающей диск. Если текущим является корневой каталог, регистровая пара DS:SI будет указывать на нулевую строку (состоящую из одного двоичного нуля).
Функции MS-DOS могут помочь вам в получении информации, необходимой для организации доступа к диску на уровне секторов и кластеров. При этом вы будете избавлены от необходимости читать в память и анализированть содержимое загрузочного сектора логического диска.
Информация о таблице размещения файлов FAT
для текущего диска может быть получена с помощью функции 1Bh прерывания INT 21h, имеющего следующий формат:
На входе: | AH = 1Bh |
На выходе: | DS:BX = Адрес первого байта FAT. Это байт ID идентификации среды носителя данных, соответствует байту media в блоке параметров BIOS. |
DX = Общее количество кластеров на диске. | |
AL = Количество секторов в одном кластере. | |
CX = Количество байтов в одном секторе. |
Для получения аналогичной информации не о текущем, а о любом диске, используйте функцию 1Ch. Эта функция полностью аналогична предыдущей, за исключением того, что в регистре DL должен быть указан код дисковода: 0 - текущий, 1 - А:, 2 - В: и т.д. Эта функция доступна в MS-DOS версии 2.0 и в более поздних версиях.
Если вас интересует размер свободного места на диске, вы можете его узнать с помощью функции 36h, имеющей следующий формат:
На входе: | AH = 36h |
DL = Номер дисковода (0 - текущий, 1 - А:, 2 - В:, и т.д.) | |
На выходе: | AX = Количество секторов в кластере; 0FFFFh, если был задан неправильный номер дисковода; |
BX = Количество свободных кластеров на диске. | |
CX = Количество байтов в одном секторе. | |
DX = Общее количество кластеров на диске. |
Эта функция возвращает в регистре AX число 0FFFFh, если вы неправильно указали номер дисковода.
При обсуждении векторной таблицы связи мы рассказывали о блоках управления устройствами DDCB. Поле dev_cb векторной таблицы связи содержит FAR-адрес цепочки этих блоков.
Приведем еще раз формат блока DDCB. Напомним, что он изменяется в зависимости от версии DOS. Для версий 2.х и 3.х блок DDCB имеет следующий формат:
(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 был построен |
Формат блока 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 был построен |
для MS-DOS версии 4.х:
/* Блок управления устройством 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()
При описании векторной таблицы связи мы приводили примеры использования блоков DDCB. Для получения адреса блока DDCB конкретного дисковода можно воспользоваться недокументированной функцией 32h. Она имеет следующий формат вызова:
На входе: | AH = 32h |
DL = Номер дисковода (0 - текущий, 1 - А:, 2 - В:, и т.д.) | |
На выходе: | AL = 0, если был задан правильный номер дисковода; 0FFh, если был задан неправильный номер дисковода; |
DS:BX = Адрес блока DDCB |
Какая еще полезная информация может быть получена при использовании функций MS-DOS?
С помощью функции 33h программа может проверить или установить флаг Ctrl-Break и узнать номер диска, с которого выполнялась загрузка операционной системы:
На входе: | AH = 33h |
AL = Код подфункции: 0 - Проверить текущее состояние флага Ctrl-Break; 1 - Установить флаг Ctrl-Break; 5 - Определить номер диска, который был использован для загрузки операционной системы. |
|
DL = Значение устанавливаемого флага Ctrl-Break для подфункции 1 (0 - OFF, 1 - ON). | |
На выходе: | DL = Текущее состояние флага Ctrl-Break для подфункции 0; Номер диска, использованного для загрузки операционной системы для подфункции 5 (1 - А:, 2 - В:, и т.д.). |
Состояние флага Ctrl-Break влияет на возможность прервать выполнение программы нажатием комбинации клавиш Ctrl-Break или Ctrl-C. Если флаг находится в состоянии OFF, DOS проверяет эту комбинацию клавиш только при вызове функций стандартного ввода/вывода на консоль, принтер и последовательный порт. Если флаг установлен в состояние ON, комбинация клавиш проверяется и при вызове других функций MS-DOS. Если операционная система зафиксировала нажатие указанной комбинации клавиш, она выполняет прерывание INT 23h, которое завершает работу текущей программы.
Функция 2Fh возвращает в регистровой паре ES:BX
адрес текущей области DTA (Disk Transfer Area), которая используется при поиске файлов в каталогах.
Функция 54h позволяет программе узнать текущее состояние флага проверки записывающейся на диск информации. В регистре AL эта функция возвращает текущее состояние флага. Если содержимое регистра равно 1, операционная система после записи сектора считывает его для проверки. Разумеется, такая проверка снижает скорость работы программы. Если после вызова функции регистр AL содержит 0, проверка записи не выполняется.
Для установки флага проверки записи можно использовать функцию 2Eh. Перед вызовом функции в регистр AL необходимо занести новое значение флага проверки: 0 - проверка не нужна; 1 - должна выполняться проверка записанной информации.
Стандартные библиотеки трансляторов Microsoft QC 2.5 и C 6.0 содержат несколько функций, облегчающих получение справочной информации о состоянии дисковой подсистемы.
Функция _dos_getdiskfree() использует функцию 36h
для получения информации о диске. Файл dos.h
содержит описание этой функции:
unsigned _dos_getdiskfree(unsigned drive, struct diskfree_t *diskspace);
Параметр drive задает номер используемого дисковода: 0 - текущий, 1 - А:, и т.д.
Информация возвращается в структуре diskfree_t, которая определена в файле dos.h:
struct diskfree_t { unsigned total_clusters; unsigned avail_clusters; unsigned sectors_per_cluster; unsigned bytes_per_sector; };
В этой структуре:
unsigned total_clusters | общее количество кластеров на диске; |
unsigned avail_clusters | количество свободных кластеров; |
unsigned sectors_per_cluster | количество секторов, занимаемых кластером; |
unsigned bytes_per_sector | размер сектора в байтах. |
и _dos_setdrive().
Функция _dos_getdrive() имеет формат:
void _dos_getdrive(unsigned *drive);
Эта функция пользуется функцией 19h для получения номера текущего диска, который записывается по адресу, задаваемому параметром. Значение 1 соответствует диску А:, 2 - В:, и т.д.
Функция _dos_setdrive() предназначена для установки текущего диска и может быть использована для определения общего числа дисков в системе:
void _dos_setdrive(unsigned drive, unsigned *drivecount);
Параметр drive опеределяет текущий диск (1 - А:, и_т.д.), по адресу, задаваемому вторым параметром, функция записывает общее количество логических дисков, установленных в системе. Функция _dos_setdrive() использует функцию 0Eh
прерывания INT 21h.
Для иллюстрации способов использования функций _dos_getdrive(), _dos_setdrive(), _dos_getdiskfree() мы составили следующую программу:
#include <dos.h> #include <bios.h> #include <conio.h> #include <stdio.h>
void main(void); void main(void) {
struct diskfree_t dinfo; unsigned drive, drivecount;
printf("\n" "\nОпределение параметров текущего логического диска" "\n (C)Фролов А., 1991" "\n");
// Определяем номер текущего диска
_dos_getdrive(&drive);
// Выводим на экран литеру текущего диска
printf("\nТекущий диск: %c:\n", 'A' + drive - 1);
// Вызываем функцию установки текущего диска. // Мы не изменяем текущий диск, вызов этой функции // нужен нам для определения количества установленных // в системе логических дисков
_dos_setdrive(drive, &drivecount);
// Получаем характеристики текущего диска
_dos_getdiskfree(drive, &dinfo);
printf("\nОбщее количество кластеров на диске: %d" "\nКоличество свободных кластеров: %d" "\nКоличество секторов в кластере: %d" "\nКоличество байтов в секторе: %d" "\nРазмер диска в байтах: %ld" "\n", dinfo.total_clusters, dinfo.avail_clusters, dinfo.sectors_per_cluster, dinfo.bytes_per_sector, (long)dinfo.avail_clusters * dinfo.sectors_per_cluster * dinfo.bytes_per_sector );
printf("\nКоличество логических дисков: %d" "\n", drivecount);
}