Листинг 11-2. Условия вызова операций абсолютного чте-
ния/записи на диск (по прерываниям "int 25h/int 26h") для
разделений диска в 32 Мегабайта или меньше (Все версии опера-
ционной системы MS-DOS)
----------------------------------------------------------------
Вход : AL = Hомер дисковода (0=А, 1=В и т.д.)
CX = Количество секторов для чтения (прерывание
"int 25h") или для записи (прерывание
"int 26h")
DX = Hачальный логический номер сектора
DS:BX = Aдрес передачи
Bозврат: Признак переноса = 0 (успешная передача) или
= 1 (не успешная передача)
AL = Kод ошибки
AH = Tип ошибки
Примечание: B регистре AX возвращается значение 0207h, если
была сделана попытка чтения или записи части раз-
мером больше 32 Мегабайт
Листинг 11-3. Условия вызова операций абсолютного чтения/за-
писи на диск (по прерываниям "int 25h/int 26h") для разделений
диска, больших 32 Мегабайт (только для версии 4.0 операционной
системы MS-DOS)
-----------------------------------------------------------------
Вход : AL = Hомер дисковода (0=А, 1=В и т.д.)
BX = Указатель на список параметров
CX = -1 (указывает на расширенный
(> 32 Мегабайт) формат)
Bозврат: Признак переноса = 0 (успешная передача) или
= 1 (не успешная передача)
AL = Kод ошибки
AH = Tип ошибки
Примечание: POP AX (код ошибки) при выходе. Коды ошибок
такие же как указанные выше.
Cтруктура списка параметров:
rba dd ? ; первый сектор (32-битовый с
; началом в 0) для чтения-записи
count dw ? ; количество секторов для
; чтения-записи
buffer dd ? ; буфер данных
Листинг 11-4. Программа контроля RESCUE
_________________________________________________________
/********************************************************
FILE: RESCUE2.C Rescue File Utility Version 2.00
Расширения: Контроль файла в подкаталогах
Контроль стертого подкаталога
Управление любым типом дискового носителя
операционной системы MS-DOS (гибкие диски,
жесткие диски, сменные кассеты)
Компилирование компилятором "Си" "фирмы "Майкрософт":
cl /c /Zp1 /AS /GO /Ze /Ot rescue2.c
Редактирование редактором фирмы "Майкрософт":
Link /Dosseg/MA/LI/CPAR:1/STACK:4096 rescue2,rescue2.exe,
rescue2.map,slibce;
*********************************************************
/* В К Л Ю Ч Е Н Н Ы Е Ф А Й Л Ы */
#include /*для функции printf() и еще многих*/
#include /*для getch() */
#include /*для intdos(),int86(), и так далее*/
#include /*для _fmalloc ()& malloc */
#include /*для memory "mem...()" и str..."*/
#iclude /*для topper() and "есть...()" */
#include /*для getcwd() */
/* О П Р Е Д Е Л Е Н И Е К О Н С Т А Н Т */
#define FALSE 0 /* эти определения предназначены*/
#define TRUE 1 /* для того, чтобы сделать програм-*/
#define AND && /* му более читаемой и понятной*/
#define OR ‹‹
#define EQ ==
#define NE !=
#define LE <=
#define ABS_READ 0x25 /* прерывание чтения диска */
#define ABS_WRITE 0x26 /* прерывание записи на диск */
/* Функции прерываний "int 21h" операционной системы DOS:*/
#define DFUNC_RESETDSK 0x0D /* сброс дисковода */
#define DFUNC_GETDISK 0x19 /* получить текущий дисковод */
#define DFUNC_GETDPB 0x32 /* получить блок дисковых */
/* параметров */
#define DFUNC_GETCD 0x47 /* получить текущий дисковод */
/* Биты атрибутов файла операционной системы DOS: */
#define FATR_NONE 0x00 /* соответствует ANY */
#define FATR_READ 0x01 /* только для чтения */
#define FATR_HIDDEN 0x02 /* скрытый */
#define FATR_SYSTEM 0x04 /* файл системы */
#define FATR_VOLUME 0x08 /* метка тома */
#define FATR_SUBDIR 0x10 /* подкаталог */
#define FATR_ARCHIV 0x20 /* архивированный файл */
#define CL_OFF 2 /* первым номером кластера */
/* является число 2*/
#define TENMB 20740L /* максимальное количество */
/* секторов, поддерживаемых */
/* 12-битовой таблице FAT */
#define CHAIN_END 1 /* используется функцией */
/* "get_cluster ()" для */
/* обозначения конца файла*/
#define FILE_END 0xfff8 /* элемент таблицы FAT для */
/* конца файла */
/* стандартная программа match() для совпадающих типов*/
#define NO_MATCH 0 /* не совпадают*/
#define IS_MATCH 1 /* совпадают */
#define IS_ERASED 2 /* со стертыми файлами */
#define IS_UNIQUE 4 /* со нестертыми файлами */
#define DNAME_SIZE 80 /* максимальный размер имени в */
/* каталоге */
/* ОПРЕДЕЛЕНИЕ СТРУКТУР И ТИПОВ */
typedef unsigned int BOOL;
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef union {
BYTE far * ptr;
struct {
WORD off ;
WORD seg ;
} a;
} LONGPTR ;
typedef struct dpbbuf { /* буфер блока дисковых пара- */
/* метров */
BYTE PhysDrive; /* номер дисковода */
Byte DriverUnit ; /* номер узла в пределах дис- */
/* ковода */
WORD BytesSector ; /* количество байтов в секторе */
BYTE SectorsCluster ; /* количество секторов в кластере
/* минус 1 */
BYTE ClusterShift; /* сдвиг кластера */
WORD Reserve; /* количество зарезервированных
/* секторов */
BYTE NumberOfFATs; /* копии таблицы FAT */
WORD DirEntries; /* количество элементов корне- */
/* вого каталога */
WORD DataSect; /* первый сектор данных */
WORD TotClust; /* общее количество кластеров */
/* плюс 1 */
BYTE nFATsec;/* количество секторов таблицы */
/* FAT (1 таблица FAT) */
WORD DirSect;/* номер сектора каталога */
DWORD DevHeaderAddr; /* адрес головки дисковода */
BYTE MediaByte; /* байт описателя носителя */
BYTE DiskAccFlag; /* признак доступа к диску */
DWORD NextBlockAddr; /* адрес следующего блока диска */
} DPB;
typedef struct dirbuf { /* элемент каталога диска */
char name [8]; /* имя */
char ext [3]; /* расширение */
BYTE attrib ; /* атрибут */
BYTE reserved [10];
WORD time ; /* время: часы минуты- */
/* -минуты секунды */
WORD date ; /* дата: год месяц-месяц день */
WORD cluster ; /* начальный кластер */
DWORD fsize ;/* общий размер в байтах */
} DENTRY;
/* Г Л О Б А Л Ь Н Ы Е П Е Р Е М Е Н Н Ы Е * /
DPB far * DPBPtr ; /* указатель блок параметров */
/* диска (DPB) */
WORD ClUnit ; /* количество секторов в */
/* кластере (а также размер */
/* буфера каталога) */
WORD ByteClust ; /* количество байтов в */
/* кластере */
DWORD TotSect ; /* общее количество секторов */
/* на диске */
WORD FATSize ; /* количество байтов в таб- */
/* лице FAT */
WORD far * FatAnchor ; /* адрес буфера таблицы FAT */
DENTRY near * DirAnchor ; /* адрес буфера каталога */
DENTRY near * AltAnchor ; /* адрес буфера другого ка- */
/* талога */
char defalt_sname [] ={"*.*"}; /* имя поиска по умол- */
/* чанию */
/* ОПРЕДЕЛЕНИЕ ПСЕВДО-СТAHДАРТНЫХ ПОДПРОГРАММ */
#define diskread(d,s,c,b) diskaccess(ABS_READ,d,s,c,b)
#define diskwrite(d,s,c,b) diskaccess(ABS_WRITE,d,s,c,b)
#define sector_of(cl) (DPBPtr->DataSect+(cl-CL_OFF)*ClUnit)
#define cluster_of(sec) (CL_OFF+(sec-DPBPtr->DataSect)/ClUnit)
/* ПРЕДВАРИТЕЛЬНЫЕ ОБЪЯВЛЕНИЯ СТAHДАРТНОЙ ПОДПРОГРАММЕ */
WORD get_cluster (); /* получить значение элемента */
/* кластера */
void put_cluster (); /* сохранить значение в клас- */
/* тере */
BOOL savefile ();/* восстановить файл(ы) */
DENTRY near * findt (); /* просмотр буфера каталога */
DPB far * getdpb () ; /* получить адрес блока пара- */
/* метров диска */
void diskaccess () ; /* абсолютное чтение/запись */
/* диска */
BOOL match () ; /* соответствие определенного */
/* имени с файлом */
/* *******************************************************
/*
/* Главная точка входа
/*
/* *******************************************************
main (argc,argv,envp)
int argc ;
char * argv [] ;
char * envp [] ;
}
char near * sspec ; /* характеристика поиска */
char dname [DNAME_SIZE]; /* буфер имени каталога */
char * pptr ; /* указатель на каталоговое
/* имя */
WORD dnum ; /* номер дисковода (исход- */
/* ное значение 0) */
WORD snum ; /* номер сектора каталога */
WORD savenum ; /* используется для хра- */
/* нения */
/* значения snum */
DENTRY near * dptr ;/* элемент текущего каталога */
print ("\nRESCUE, Version 2.OO\n\n");
if (argc<2) { /* если параметров нет */
print ("*** Имя файла не указано ***\n");
exit (1) ;
};
sspec =argv [1]; /* файл для восстановления */
getcwd (dname, DNAME_SIZE) ; /* получить дисковод по */
/* умолчанию и каталог */
if (*(char *)((WORD)dname + strlen(dname) - 1) NE '\\')
strcat (dname, "\\"); /* имя пути доступа за- */
/* канчивается знаком "\"*/
pptr = dname+3; /* указатель начального */
/* имени пути доступа*/
dnum = *dname - 'A' ; /* извлечь номер дисковода */
/* Определить разные глобальные значения из блока парамет- */
/* ров диска (DPB), включая размер таблицы FAT, количество */
/* байтов в кластере, общее количество секторов и т.д. */
DPBPtr = getdpb (dnum) ; /* получить блок параметров диска */
if(dnum NE DPBPtr->PhysDrive) {
printf ("Дисковод %c: является замененным\n",(dnum+ 'A'));
printf("Программа RESCUE будет работать только
на физических дисководах\n");
exit (1);
} ;
FATSize = DPBPtr->BytesSector * DPBPtr->nFATsec:
CLUnit = DPBPtr->SectorsCluster + 1;
TotSect = (DWORD) DPBPtr->TotClust * (DWORD) ClUnit
+ (DWORD) DPBPtr->DataSect;
BytCLust= DPBPtr->BytesSector * CLUnit;
/* Pаспределить память для буферов каталога и таблиц FAT */
If (((DirAnchor=(Dentry near *) malloc(BytClust)) EQ
NULL) OR
((AltAnchor=(DENTRY near *) malloc(BytCLust)) EQ
NULL) OR
((FATAnchor=(WORD far *)_fmalloc(FATSize)) EQ
NULL)) {
printf ("*** Can't Allocate Working Memory ***\n");
exit (1);
} ;
/* Cчитать в исходную таблицу FAT */
discread (dnum,DPBPtr->Reserve,DPBPtr->nFATsec,FATAnchor);
/* Двигаться по цепи элементов каталога в поисках */
/* соответствующего имени пути доступа */
snum = DPBPtr->Dirsect; /* первый сектор каталога */
while (*pptr NE '\0') /* до тех пор, пока путь */
/* доступа к каталогу ненулевой */
if ((dptr = findf (dnum, &snum, pptr, DirAnchor,
NULL,FATR_SUBDIR,IS_INIQUE)) NE NULL) {
snum = sector_of (dptr->cluster);
while ((*pptr NE '\0') AND (*pptr NE '\\'))
pptr++;
if (*pptr EQ '\\') pptr++;
} else {
printf ("*** Can't Find Directory %s ***\n",
pptr);
exit (1); };
/* Ненормальное завершение, если файл, подлежащий */
/* восстановлению, не стерт. */
savenum = snum; /* сохранить сектор каталога */
if (findf (dnum, &dnum, sspec, DirAnchor,
NULL,FATR_NONE,IS_UNIQUE) NE NULL) {
printf ("***%s%s не стерто ***\n",dname,sspec);
exit (1) ;
};
/* Eсли файл стерт, подкаталог или файл затем */
/* восстанавливает его */
snum = savenum; /* восстановить сектор каталога */
if ((dptr = findf (dnum,&snum,sspec, DirAnchor,
NULL,FATR_NONE,IS_ERASED)) NE NULL){
if(get_cluster (dptr->cluster) NE 0)
printf ("Hестертый файл%s%s не может быть
восстановлен\n",
dname, sspec);
else {
if (savefile (dnum,dptr, snum,toupper(*sspec))) {
if (dptr->attrib & FATR_SUBDIR)
print ("Подкаталог %s%s восстановлен\n,
dname,sspec);
else
printf ("Файл %s%s восстановлен\n",
dname,sspec);
} else {
printf (Неудачное восстановление %s%s\n",
dname,sspec);
diskread (dnum,DPBPtr->Reserve,
DPBPtr->nFARsec,FatAnchor);
};
};
} else {
printf ("Не могу найти нестертый файл %s%s\n",
dname,sspec);
};
};
/* **** Найти следующий кластер в цепи ********************
Эта стандартная программа находит значение элемента FAT.
Это эквивалентно соединению кластеров FAT в цепь. Эта стан-
дартная программа возвращает либо значение кластера (следую-
щий кластер в цепи файлов операционной системы DOS) либо ну-
левое значение NULL, если в цепи больше нет кластеров.
Если диск имеет емкость 10 Мегабайт или меньше, то использу-
ются 12-битовые элементы таблицы FAT (кластеры). Если диск больше,
то используются 16-битовые элементы таблицы FAT.
Значения кластера: (0)000 ................ свободный кластер
(0)001 ................ неопределен
(0)002 -(F)FEF......... следующий кластер
(F)FF0 -(F)FF6......... зарезервирован
(F)FF7 ................ испорченный кластер
(F)FF8 -(F)FFF......... конец цепи
*/
WORD get_cluster (clust) /* номер кластера */
WORD clust;
{
union { WORD FAR }* w; /* указатель на таблицу FAT */
BYTE far * b;
}fatptr;
WORD value; /* содержимое кластера */
if (TotSect > TENMB){
fatptr.b=(BYTE far *)
((DWORD) FatAnchor + (DWORD)(clust * 2));
value = *fatptr.w;
} else {
fatptr.b= (BYTE far *)
((DWORD) FatAnchor + (DWORD)(clust * 3/2));
value = *fatptr.w;
/* Кластеры с нечетными номерами сдвигаются влево */
/* на 4 бита в слове */
if (clust & 0x01) value >>= 4;
value &= 0x0fff;
} ;
if ((value & 0x0ff0) EQ 0xff0) return (CHAIN_END);
else return (value);
} ;
/* **** Сохранить значение кластера *************************
Эта стандартная программа помещает значение в элемент
кластера в таблице FAT, если диск имеет емкость 10 Мегабайт
пользуются 12-битовые элементы таблицы FAT (кластеры). Если
диск больше, то используются 16-битовые элементы таблицы FAT.
*/
void put_cluster (clust,value)
WORD clust; /* номер кластера */
WORD value; /* значение нового кластера */
{
union { WORD FAR }* w; /* указатель на таблицу FAT */
BYTE far * b;
}fatptr ;
WORD cur_val; /* значение текущего кластера */
if (TotSect > TENMB) {
fatptr.b=(BYTE far *)
((DWORD) FatAnchor + (DWORD) (clust * 2));
*fatptr.w=value;
} else {
fatptr.b= (BYTE far *)
((DWORD)FatAnchor + (DWORD)(clust * 3/2));
cur_val = *fatptr.w;
/* Кластеры с нечетными номерами сдвигаются влево */
/* на 4 бита в слове */
if (clust & 0x01)
*fatptr.w = (cur_val & 0x000f) ‹ (значение << 4);
else
*fatptr.w = (cur_val & 0xf000) ‹ (значение & 0x0fff);
} ;
};
/* *** Найти кластер файла и сохранить каталог и
таблицу FAT файла ***
Эта программа восстанавливает стертый файл, если это
можно. Она вычисляет количество кластеров, которые должен
занимать файл, и ищет эти кластеры в таблице FAT.
Эта стандартная программа предполагает, что номер на-
чального кластера файла, подлежащего восстановлению, был
проверен, и его значение равно нулю.
*/
BOOL savefile (dnum,dptr,sect,ch)
WORD dnum ; /* рабочий дисковод */
DENTRY near * dptr ; /* элемент каталога, */
/* подлежащий сохранению */
WORD sect ; /* дать оглавление секторов */
/* кластера */
BYTE ch ; /* первый символ в имени файла */
{
DENTRY far * writeptr ; /*указатель на буфер каталога*/
WORD filecls ; /* размер файла (в кластерах) */
WORD last ; /* номер последнего кластера */
WORD current ; /* номер текущего кластера */
WORD next ; /* следующий кластер в цепи */
WORD fatsect ; /* номер сектора таблицы FAT */
union { WORD FAR }* w ; /* указатель на таблицу FAT */
BYTE far * b ;
} fatptr ;
if (dptr->attrib & FATR_SUBDIR) /* если файл находится в */
/* подкаталоге */
filecls = 0 ; /* дополнений не нужно */
else
filecls = (WORD) ((dptr->fsize + (DWORD)BytClust-1L)/
(DWORD) BytClust) -1 ;
current = last =dptr->cluster ; /* первый кластер */
/* Исправление таблицы FAT */
while (filecls) {
if (++current > DPBPtr->TotClust) {
print ("\n*** Нельзя восстановить файл ***/n");
return (FALSE) ;
} ;
if (get_cluster(current) EQ 0) { /* пустой кластер */
put_cluster (last,current) ; /* часть цепи */
last = current ;
filecls-- ;
} ;
} ;
put_cluster (last, FILE_END) ;/* конец цепи */
*(dptr->name) = ch ; /* сохранить первый символ */
/* Подготовка завершена - писать сектора таблицы FAT */
/* и каталога */
writeptr = DirFnchor ;
fatsect = DPBPtr->Reserve ;
disckwrite (dnum,fatsect,DPBPtr->nFATsec,FatAnchor) ;
fatsect += DPBPtr->FATsec ;
disckwrite (dnum,fatsect,DPBPtr->nFATsec,FatAnchor) ;
disckwrite (dnum,sect,ClUnit,writeptr) ;
dbos (DFUNC_RESETDSK,NULL,NULL);
return(TRUE)) ;
} ;
/* **** Найти определенный элемент в этом каталоге **** */
DENTRY near * findf (dnum,sect,pptr,dbuf,bptr,sattr,mtype)
WORD dnum ;/* рабочий дисковод */
WORD * sect ; /* сектор текущего каталога*/
char near * pptr ; /* указатель имени пути доступа*/
DENTRY near * dbuf ; /* буфер каталога */
DENTRY near * bptr ; /* указатель другого буфера */
BYTE sattr ; /* атрибут поиска */
int mtipe ; /* требуемый тип совпадения */
{
int i ; /* счетчик циклов */
WORD cluster ; /* используется для сцепления */
DENTRY near * dirptr ; /* указатель буфера каталога*/
DENTRY far * readptr ; /*указатель буфера каталога*/
DENTRY near * dirend ; /* адрес конца буфера */
readptr = dbuf ;
dirend = (DENTRY near *) ((WORD) dbuf + BitClust - 1) ;
while (TRUE) {
if (bptr NE NULL) { /* продолжить с ... */
dirptr =++bptr ; /* того места, где */
/* остановились */
bptr = NULL ;
} else { /* иначе, начать с начала */
diskread (dnum,*sect,ClUnit,readptr) ;
dirptr = dbuf ;
} ;
/* Eсть ли совпадающие файлы ? */
while (dirptr < dirend) {
if (((dirptr->attrib & sattr) EQ sattr) AND
(match (pptr,dirptr->name,mtype)))
return (dirptr) ;
dirptr++ ;
} ;
/* Bсе элементы в этом кластере приведены, перейти к */
/* другому */
if (*sect >=DPBPtr->DataSect) { /* подкаталог */
cluster = cluster_of (*sect) ; /* следующий кластер*/
if ((cluster = get_cluster (cluster)) LE CHAIN_END)
return (NULL) ;
else *sect = (sector_of (cluster)) ;
} else /* корневой каталог */
if (*sect >= DPBPtr->DIRSect) {
*sect += ClUnit ; /* следующие сектора */
if (*sect >=DPBPtr->DATASect) return (NULL) ;
} else return (NULL) ;
} ;
} ;
/* **** Получить блок параметров системы BIOS ****** */
/* **** для заданного дисковода ********* */
DPB far *getdpb (dnum) /* возврат указателя на блок DPB */
Word dnum ; /* номер рабочего дисковода */
{
union REGS inregs, outregs ;
struct SREGS segregs ;
LONGPTR farptr ;
inregs.h.ah = DFUNC_GETDPB ;
inregs.h.dl = dnum + 1 ;
intdosx (&inregs, &outregs, &segregs) ; /*получить блок DPB*/
if (outregs.x.cflag) {
if (outregs.h.al EQ 0xff)
print ("*** Дисковод %c неисправен ***\n",(dnum + 'A')) ;
else
printf ("*** Не могу считать параметры дисковода %c ***\n",
(dnum + 'A')) ;
exit (1) ;
} ;
farptr.a.off = outregs.x.bx ;
farptr.a.seg = segregs.ds ;
return ((DPB far *) farptr.ptr ;
} ;
/* **** Чтение/запись на диск прямого доступа *********** */
void diskaccess ((function, dnum, sector, count, buffer)
BYTE function ;/* функция прерывания */
BYTE dnum ; /* номер физического дисковода */
WORD sector ; /* номер сектора */
WORD count ; /* счет секторов */
BYTE far * buffer ; /* буфер */
{
union REGS inregs, outregs ;
struct SREGS segregs ;
LONGPTR farptr ;
farptr.ptr = buffer ;
inregs.h.al = dnum ;
inregs.x.dx = sector ;
inregs.x.cx = count ;
inregs.x.bx = farptr.a.off ;
segregs.ds = farptr.a.seg ;
int86x (function,&inregs,&outregs,&segregs) ;
if (outregs.x.cflag) {
if (function EQ ABC_READ)
printf ("*** Ошибка во время считывания диска ***\n") ;
else
print ("*** Ошибка во время записи на диск ***\n") ;
exit (1) ;
} ;
} ;
/* ************ Проверить имена на совпадение ********** */
/* Отметим, что обращение к массивам имен ведется
без знака, поэтому сравнение с ОхE5 будет выполняться
надлежащим образом.*/
BOOL match (sname, fname, mtype)
BYTE near *sname ; /* поиск совпадающего имени */
BYTE near *fname ; /* имя файла или каталога */
int mtype ; /* тип требуемого совпадения */
{
int i ; /* индекс */
char near *fext ; /*расширение файла или каталога*/
fext = fname + 8; /* расширение файла */
/*Сверка состояния файла (стерт/восстановлен) с типом поиска*/
if (((*fname NE 0xe5) AND (mtype EQ IS_ERASED)) OR
((*fname EQ 0xe5) AND (mtype NE IS_ERASED)))
return (NO_MATCH) ;
if (*fname EQ 0xe5) { /* игнорировать первый */
fname++ ; /* символ стертого файла */
sname++;
} ;
while (fname < (fext+3)) {
if (*fname EQ toupper(*sname)) {
fname++ ;
sname++ ;
} else /* если имена различны, */
switch (*sname++) { /* выяснить почему */
case '.':
if ((*fname EQ ' ') OR (fname EQ fext)) {
fname = fext ; /* проверка расширения */
break ;
} ;/* иначе */
return (NO_MATCH) ;
case '\\':
case '\0:
if (*fname EQ ' ') /* конец имени sname */
return (IS_MATCH) ;
default:
return (NO_MATCH) ;
} ;
} ;
return (IS_MATCH) ;
} ;
/* Конец файла RESCUE.C */
----------------------------------------------------------------
|