КаталогИндекс раздела
НазадОглавлениеВперед


Лабораторная работа N9
ДИСКОВЫЕ СТРУКТУРЫ ДАННЫХ DOS.

1. Цель работы

Получение практических навыков в работе с Таблицей Размещения Файлов.

2. Темы для предварительного изучения

3. Постановка задачи

Определить номера всех кластеров диска, которые занимает заданный преподавателем файл в текущем каталоге.

4. Порядок выполнения

Порядок выполнения работы и содержание отчета определены в общих указаниях.

5. Пример решения задачи

5.1. Разработка алгоритма решения

5.1.1. Структура программы

Программа состоит из главной функции main() и одиннадцати вспомогательных функций.

5.1.2. Описание переменных

В программе описаны структуры такого вида:

Переменные, глобальные для всей программы:

5.1.3. Описание алгоритм программы

Функция main запрашивает имя файла, потом обрабатывает его и, если все нормально, то запускает вспомогательные функции необходимые для просмотра FAT заданного файла.

Функция Read_Mbr выполняет выборку элемента таблицы разделов для заданного диска.

Функция Read_Boot считывает boot-сектор логического диска, причем для гибкого диска адрес этого сектора назначается - 0, 0, 1, а для жесткого - выбирается из part.

Функция Get_First определяет абсолютный номер начального сектора логического диска и сохраняет его переменной First_Sect. Это значение вычисляется из физического адреса начала, который берется из полей Begin_Hd, Begin_SecTrk элемента таблицы разделов.

Функция Read_Fat считывает в память FAT целиком, адрес начала FAT на диске и ее размер определяются из ранее прочитанного boot-сектора.

Функция Read_13 читает один сектор с помощью прерывания BIOS.

Функция Sect_to_Daddr преобразует номер логического сектора в физический адрес.

Функция Clust_to_Sect преобразует номер кластера в номер сектора.

Функция Next_Clust определяет номер следующего кластера, анализируя FAT. Для последнего кластера (и для корневого каталога) эта функция возвращает нулевое значение.

Функция Get_Name предназначена для лексического разбора задания, она выделяет из задания очередное слово и переназначает jobptr. Пустое (NULL) значение jobptr - свидетельство об исчерпании задания.

Функция Find_Name выполняет поиск имени в каталоге. Здесь cname - требуемое имя, функция возвращает индекс найденного элемента в массиве dir или (-1).

Функция End_of_Job выполняет выдачу на экран различных сообщений при ошибках или при завершении программы.

5.2. Текст программы

/*------------------Лабораторная работа N9--------------------*/
/*--------------"Дисковые структуры данных DOS."--------------*/
/* Подключение стандартных заголовков */
#include <dos.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
/*-------------------------------------------------------------*/
/* Типи и структуры данных */
#define byte unsigned char
#define word unsigned int
#define dword unsigned long
#define daddr struct DADDR
struct DADDR { /* физический дисковый адрес */
        byte h;
        word s, t, ts;
       };
struct PART { /* структура элемента раздела */
        byte  Boot, Begin_Hd;
        word  Begin_SecTrk;
        byte  SysCode, End_Hd;
        word  End_SecTrk;
        dword RelSec, Size;
        };
struct MBR
       { /* стpуктуpа Главной Загрузочной Записи */
        char LoadCode[0x1be];
        struct PART rt[4];
        word EndFlag;
        };
struct BootRec
       { /* структура корневой записи */
        byte jmp[3], ident[8];
        word SectSize;
        byte ClustSize;
        word ResSect;
        byte FatCnt;
        word RootSize, TotSecs;
        byte Media;
        word FatSize, TrkSecs, HeadCnt;
        word HidnSecL, HidnSecH;
        dword LongTotSecs;
        byte Drive, reserved1, DOS4_flag;
        dword VolNum;
        char VolLabel[11], FatForm[8];
      };
struct Dir_Item
  { /* структура элемента директории */
   char fname[11];
   byte attr;
   char reserved[10];
   word time, date, cl;
  dword size;
 };
/*-------------------------------------------------------------*/

/* Описания функций */
void  Read_Mbr(void);             /* Чтение MBR и поиск требуе-
                                     мого раздела              */
void  Read_Boot(void);            /* Чтение boot-сектора       */
void  Get_First(void);            /* Определение абсолютного номе-
                                     ра сектора начала логического
                                     диска                     */
void  Read_Fat(void);             /* Чтение FAT                */
void  Read_13(void *mem);         /* Чтение сектора с омогощью
                                     прерывания 13             */
void  Sect_to_Daddr(dword sect);  /* Формирование физического дискового
                                     адреса из # сектора       */
dword Clust_to_Sect(word clust);  /* Вычисление номера  сектора
                                     из номера кластера        */
word  Next_Clust(word clust);     /* Выборка следующего кластера
                                     из FAT                    */
char *Get_Name(char *s, char *d); /* Выделение следующего элемен-
                                     та из строки-задания      */
int   Find_Name();                /* Поиск имени в каталоге    */
void  End_of_Job(int n);          /* Завершение  (при n=0-5 -
                                     аварийное)                */
/*-------------------------------------------------------------*/
/* Переменнi */
struct PART part;      /* текущий элемент раздела              */
byte buff1[512];       /* буфер MBR и boot                     */
struct MBR *mbr;       /* указатель на таблицу разделов        */
struct BootRec *boot;  /* указатель на корневую запись         */
byte buff2[512];       /* буфер каталога и текста              */
struct Dir_Item *dir;  /* указатель на часть каталога          */
char *text;            /* указатель на текстовий буфер         */
byte *fat;             /* указатель на FAT                     */
char job[81];          /* строка-задание                       */
char *jobptr;          /* текущий указатель в job              */
char cname[12];        /* текущее имя для поиска               */
byte Fdisk;            /* физический номер диска               */
daddr caddr;           /* текущий дисковый адрес               */
dword sect;            /* текущий номер сектора                */
word clust;            /* текущий  номер кластера              */
byte fat16;            /* признак формату FAT                  */
dword fsize;           /* размер файла                         */
int dirnum;            /* номер элемента в каталоге            */
dword FirstSect;       /* абс.сектор начала                    */
byte rootdir=1;        /* признак корневого каталога
                          или подкаталога (1/0)                */
word lastsect;         /* последний сектор при чтении          */
byte fatalloc=0;       /* признак выделения памяти             */
/*-------------------------------------------------------------*/
main() {
 int n,i;
  textattr(14);
  clrscr();
  /* ввод имени файла */
  cprintf("  Просмотр таблицы FAT. ");
  cprintf("Укажите полное имя файла -->");
  scanf("%s",job);
  /* перевод в верхний регистр */
  strupr(job);
  /* проверка правильности идентификатора диска */
  if ((!isalpha(job[0]))||(job[1]!=':')||(job[2]!='\\')) {
    printf("%c%c%c -",job[0],job[1],job[2]);
    End_of_Job(0);
  }
  textattr(10);
  clrscr();
  printf("              Лабораторная работа N9");
  printf("           Дисковые структуры данных DOS.");
  textattr(14);
  cprintf("Файл %s в FAT занимает такие кластеры :\n",job);
  jobptr=job+3;
  if (job[0]>'A') {
    /* для жесткого диска - физический номер и чтение MBR */
    Fdisk=0x80;
    Read_Mbr();
  }
  else  /* для гибкого диска - физический номер */
    Fdisk=job[0]-'A';
  Read_Boot(); /* чтение boot-сектора */
  Read_Fat();  /* чтение FAT */
  dir=(struct Dir_Item *)buff2;
  do { /* рух по каталогам */
    if (!rootdir) clust=dir[dirnum].cl;  /* начальный кластер */
    /* выделение следующего элемента из строки-задания */
    jobptr=Get_Name(jobptr,cname);
    do { /* пока не дойдем до последнего кластера */
      if (rootdir) {  /* корневой каталог */
        /* нач.сектор корневого кат. и количество секторов */
        sect=boot->ResSect+boot->FatSize*boot->FatCnt;
        lastsect=boot->RootSize*32/boot->SectSize+sect;
      }
      else { /* подкаталог */
        sect=Clust_to_Sect(clust);
        lastsect=boot->ClustSize+sect;
      }
      /* посекторное чтение всего корневого каталога
         или одного кластера подкаталога */
      for (; sect<lastsect; sect++) {
        Sect_to_Daddr(sect);
        Read_13(dir);
        /* поиск имени в прочитанном секторе */
        if ((dirnum=Find_Name())>=0) goto FIND;
      }
      /* до последнего кластера подкаталога */
    }
    while (clust=Next_Clust(clust));
    /* весь каталог просмотрен, а имя не найдено - ошибка */
    printf("%s -",cname);
    if (jobptr==NULL) End_of_Job(4);
    else End_of_Job(5);

FIND: /* имя найдено */
    rootdir=0;
  }
  while (jobptr!=NULL);
  /* найдено имя файла */
  /* из каталога получеем 1-й кластер */
  clust=dir[dirnum].cl;
  textattr(7);
  gotoxy(10,4);
  cprintf("Нажимайте любую клавишу ");
  cprintf(" пока не появится <КОНЕЦ ФАЙЛА>.");
  textattr(12);
  gotoxy(1,5);
  cprintf("-<НАЧАЛО ФАЙЛА>");
  gotoxy(1,6);
  cprintf("L->");
  i=0;
  do {
    i++;
    if((i%10)==0) getch();
    textattr(14+16);
    cprintf("%4x",clust);

    textattr(2);
    cprintf("--->");
  }
  while (clust=Next_Clust(clust));
  textattr(12);
  cprintf("<КОНЕЦ ФАЙЛА>\n");
  gotoxy(1,wherey());
  textattr(15+3*16);
  cprintf("Количество кластеров в файле: %u ",i);
  End_of_Job(7);
}
/*-------------------------------------------------------------*/
/* Чтение MBR и поиск нужного раздела */
void Read_Mbr(void) {
 int i;
 char ndrive;
 word *EndList;
  caddr.h=0;
  caddr.ts=1;
  ndrive='C';
  mbr=(struct MBR *)buff1;

NEXT: Read_13(buff1);
  for (EndList=(word *)&mbr->rt[(i=0)];
      (*EndList!=0xaa55)&&(mbr->rt[i].Size>0L);
      EndList=(word *)&mbr->rt[++i]) {
    if (mbr->rt[i].SysCode==5) {
      caddr.h=mbr->rt[i].Begin_Hd;
      caddr.ts=mbr->rt[i].Begin_SecTrk;
      goto NEXT;
    }
    if (ndrive==job[0]) {
      movmem(&mbr->rt[i],&part,sizeof(struct PART));
      return;
    }
    else ndrive++;
  }
  /* требуемый раздел не найден */
  printf("%c: -",job[0]);
  End_of_Job(1);
}
/*-------------------------------------------------------------*/
/* Чтение boot-сектора */
void Read_Boot(void) {
  if (Fdisk<0x80) {
    caddr.h=0;
    caddr.ts=1;
  }
  else {
    caddr.h=part.Begin_Hd;
    caddr.ts=part.Begin_SecTrk;
  }
  Read_13(buff1);
  boot=(struct BootRec *)buff1;
  Get_First();
}
/*-------------------------------------------------------------*/
/* Чтение FAT */
void Read_Fat(void) {
dword s, ls;
byte *f;
  fat=(byte *)malloc(boot->FatSize*boot->SectSize);
  if (fat==NULL) {
    printf("Размещение FAT -");
    End_of_Job(3);
  }
  fatalloc=1;
  s=boot->ResSect;
  ls=s+boot->FatSize;
  for (f=fat; s<ls; s++) {
    Sect_to_Daddr(s);
    Read_13(f);
    f+=boot->SectSize;
  }
  /* установление формата FAT */
  if (Fdisk>=0x80)
    if (part.SysCode==1) fat16=0;
    else fat16=1;
  else fat16=0;
}
/*-------------------------------------------------------------*/
/* Чтение сектора при помощи прерывания 13 */
void Read_13(void *mem) {
/* mem - адреса в ОП */
union REGS rr;
struct SREGS sr;
  rr.h.ah=2;
  rr.h.al=1;
  rr.h.dl=Fdisk;
  rr.h.dh=caddr.h;
  rr.x.cx=caddr.ts;
  sr.es=FP_SEG(mem);
  rr.x.bx=FP_OFF(mem);
  int86x(0x13,&rr,&rr,&sr);
  /* Проверка ошибок чтения */
  if (rr.x.cflag&1) {
    printf("%u -",rr.h.ah);
    End_of_Job(2);
  }
}
/*-------------------------------------------------------------*/
/* Определение абс.номера сектора начала лог.диска */
void Get_First(void) {
 word s, t;
  if (Fdisk<0x80) FirstSect=0;
  else {
    /* формирование # сектора из физич. дискового адреса */
    t=(part.Begin_SecTrk>>8)|((part.Begin_SecTrk<<2)&0x300);
    s=part.Begin_SecTrk&0x3f;
    FirstSect=(((dword)t*boot->HeadCnt)+part.Begin_Hd)*
    boot->TrkSecs+s-1;
  }
}
/*-------------------------------------------------------------*/
/* Формирование физического дискового адреса из # сектора */
void Sect_to_Daddr(dword sect) {
/* sect - номер сектора, caddr - адрес на диске */
dword s;
  if (Fdisk>=0x80) sect+=FirstSect;
  caddr.s=sect%boot->TrkSecs+1;
  s=sect/boot->TrkSecs;
  caddr.h=s%boot->HeadCnt;
  caddr.t=s/boot->HeadCnt;
  caddr.ts=(caddr.t<<8)|caddr.s|((caddr.t&0x300)>>2);
}
/*-------------------------------------------------------------*/
/* Вычисление номера сектора из номера кластера */
dword Clust_to_Sect(word clust) {
/* clust - номер кластера, возвращает номер сектора */
 dword ds, s;
  ds=boot->ResSect+boot->FatSize*boot->FatCnt+
  boot->RootSize*32/boot->SectSize;
  s=ds+(clust-2)*boot->ClustSize;
  return(s);
}
/*-------------------------------------------------------------*/
/* Выборка следующего кластера из FAT */
word Next_Clust(word clust) {
/* clust - номер кластера, возвращает номер следующего кластера
   или 0 - если следующего нет */
 word m, s;
  if (rootdir) return(0);
  if (!fat16) {
    m=(clust*3)/2;
    s=*(word *)(fat+m);
    if(clust%2)      /* нечетный элемент */
      s>>=4;
    else    /* четный элемент */
      s=s&0x0fff;
    if (s>0x0fef) return(0);
    else return(s);
  }
  else {
    m=clust*2;
    s=*(word *)(fat+m);
    if (s>0xffef) return(0);
    else return(s);
  }
}
/*-------------------------------------------------------------*/
/* Выделение следующего элемента из строки-задания */
char *Get_Name(char *s, char *d) {
/* s - строка задания, d - выделенный элемент, возвращает
   указатель на новое начало строки задания. */
char *p,*r;
int i;
  for(i=0;i<11;d[i++]=' ');
  d[11]='\0';
  if ((p=strchr(s,'\\'))==NULL) {
    /* последний элемент строки - имя файла */
    /* перезапись имени */
    for(r=s,i=0; (i<8)&&*r&&(*r!='.'); i++,r++) *(d+i)=*r;
    /* перезапись расширения */
    if (*r) for(i=0,r++; (i<3)&&*r; i++,r++) *(d+8+i)=*r;
    return(NULL);
  }
  else {
    /* следующий элемент - имя подкаталога */
    *p='\0';
    for(r=s,i=0; (i<11)&&*r; i++,r++) *(d+i)=*r;
    return(p+1);
  }
}
/*-------------------------------------------------------------*/
/* Поиск имени в каталоге */
int Find_Name() {
 int j;
/* cname - найденное имя; возвращает индекс найденного
   элемента в массиве dir или (-1) */
    for (j=0; j<boot->SectSize/sizeof(struct Dir_Item); j++) {
      if (dir[j].fname[0]=='\0') {
        /* конец использованных элементов каталога */
        printf("%s -",cname);
        if (jobptr==NULL) End_of_Job(4);
        else End_of_Job(5);
      }
      if ((byte)dir[j].fname[0]!=0xe5) {
        if (memcmp(dir[j].fname,cname,11)==0) {
          /* если iм`я збiгатся, то:
           - при поиске файла элемент не должен иметь атрибутов
             "подкаталог" или "метка тома",
           - при поиске подкаталога элемент должен иметь атрибут
             "подкаталог" */
           if (jobptr==NULL)
             if ( !(dir[j].attr&0x18) ) return(j);
            else
              if (dir[j].attr&0x10) return(j);
        }
      }
    }
  return(-1);
}
/*-------------------------------------------------------------*/
/* Завершение (при n=0-5 - аварийное) */
void End_of_Job(int n) {
/* n - номер сообщения */
static char *msg[] = {
       "неправильный идентификатор диска",
       "логический диск отсутствует",
       "ошибка чтения",
       "нехватка памяти",
       "подкаталог не найден",
       "файл не найден",
       "непредусмотренный конец файла",
       "" };
  /* освобождение памяти */
  if (fatalloc) free(fat);
  /* выдача сообщения */
  textattr(12+128);
  cprintf(" %s\n",msg[n]);
  gotoxy(28,wherey());
  cprintf(" Нажмите любую клавишу...\n");
  textattr(7);
  getch();
  /* завершение программы */
  exit(0);
}

5.3. Результаты работы программы

В процессе работы программы на экран выводится информация наподобие следующей:

              Лабораторная работа N9
           Дисковые структуры данных DOS.
Файл D:\TC\TC.EXE в FAT занимает такие кластеры :
Нажимайте любую клавишу пока не появится <КОНЕЦ ФАЙЛА>.
-<НАЧАЛО ФАЙЛА>
8L->2410--->2411--->2412--->2413--->2414--->2415--->2416--->2417-
-->2418--->2419--->241a--->241b--->241c--->241d--->241e--->241f-
-->2420--->2421--->2422--->2423--->2424--->2425--->2426--->2427-
-->2428--->2429--->242a--->242b--->242c--->242d--->242e--->242f-
-->2430--->2431--->2432--->2433--->2434--->2435--->2436--->2437-
-->2438--->2439--->243a--->243b--->243c--->243d--->243e--->243f-
-->2440--->2441--->2442--->2443--->2444--->2445--->2446--->2447-
-->2448--->2449--->244a--->244b--->244c--->244d--->244e--->244f-
-->2450--->2451--->2452--->2453--->2454--->2455--->2456--->2457-
-->2458--->2459--->245a--->245b--->245c--->245d--->245e--->245f-
-->2460--->2461--->2462--->2463--->2464--->2465--->2466--->2467-
-->2468--->2469--->246a--->246b--->246c--->246d--->246e--->246f-
-->2470--->2471--->2472--->2473--->2474--->2475--->2476--->2477-
-->2478--->2479--->247a--->247b--->247c--->247d--->247e--->247f-
-->2480--->2481--->2482--->2483--->2484--->2485--->2486--->2487-
-->2488--->2489--->248a--->248b--->248c--->248d--->248e--->248f-
-->2490--->2491--->2492--->2493--->2494--->2495--->2496--->2497-
-->2498--->2499--->249a--->249b--->249c--->249d---><КОНЕЦ ФАЙЛА>
Количество кластеров в файле: 142
                            Нажмите любую клавишу...


КаталогИндекс раздела
НазадОглавлениеВперед