Глава – 12
Чтение и изменение MBR с помощью программирования
Основная загрузочная запись (MBR) или основная таблица разделов (MPT)
Основная загрузочная запись (MBR) или иногда называемая основной таблицей разделов (MPT) создается на жестком диске путем выполнения команды FDISK.EXE DOS.
MBR содержит небольшую программу для загрузки и запуска активного (или загрузочного) раздела с жесткого диска. Основная загрузочная запись содержит информацию обо всех четырех основных разделах на жестком диске, такую как начальный сектор, конечный сектор, размер раздела и т. д.
MBR расположена в абсолютном секторе 0 или, можно сказать, в цилиндре 0, головке 0 и секторе 1, и если на диске присутствует более одного раздела, то существуют расширенные главные загрузочные записи, расположенные в начале каждого тома расширенного раздела.
Подробное описание см. в главе «Логический подход к дискам и ОС», обсуждавшейся ранее в этой книге.
 
Формат основной загрузочной записи
Мы можем разбить жесткий диск на несколько логических дисков, которым DOS обычно назначает собственную букву диска. Только один раздел за раз может быть отмечен как активный (или загрузочный) раздел.

Основная загрузочная запись имеет ограничение в четыре записи в основной таблице разделов. Однако местоположение расширенной основной загрузочной записи можно получить с помощью основной загрузочной записи, содержащей расширенные таблицы разделов, формат которой точно такой же, как у основной таблицы разделов, за исключением того, что в ней нет загрузочного кода, и это пространство в 446 байт обычно зарезервировано для загрузочного кода и остается пустым.
Все 512 байт основной загрузочной записи разбиты следующим образом, как показано в таблице:

Все расширенные разделы должны существовать в пространстве, зарезервированном записью расширенного раздела. Только два из расширенных разделов предназначены для использования, первый как обычный раздел, а второй как другой расширенный раздел, если он существует.
Таким образом, с помощью одной Главной таблицы разделов мы можем получить местоположение другой Расширенной главной таблицы разделов рядом с ней, если таковая имеется.
 
Формат записи таблицы разделов
Формат записи таблицы разделов любого раздела в MBR приведен в следующей таблице. Каждая запись раздела любого MBR может быть разбита на следующие байты с их конкретными значениями:

 
Написание программы для чтения таблицы разделов MBR
Далее приведена программа для чтения всех четырех записей разделов из таблицы разделов MBR. Программа отображает все параметры информации о разделах, записанные в таблице разделов MBR.
 
Кодировка программы выглядит следующим образом:
/* Программа для чтения таблицы разделов MBR */
    # включить <bios.h>
  /* структура для чтения записи раздела из таблицы разделов */
  структурный раздел
  {
  unsigned char bootable ; /* Активный байт раздела */
  unsigned char start_side ;/* Начальная голова */
  unsigned int start_sec_cyl ; /* комбинация
  Стартовый сектор и
  номер цилиндра */
  unsigned char parttype ; /* Файловая система
  Индикаторный байт */
  unsigned char end_side ; /* Конечный заголовок */
  беззнаковое целое end_sec_cyl ; /* комбинация
  Стартовый сектор и
  номер цилиндра */
  unsigned long part_beg ; /* Относительный сектор
  Число */
  unsigned long plen ; /* Длина раздела в
  секторы */
  } ;
 
/* Структура для чтения MBR */
    часть структуры
  {
  unsigned char master_boot[446] ; /* IPL (Начальная
  Загрузчик программ)*/
  struct partition pt[4] ; /* Таблица разделов */
  int lasttwo ; /* Магическое число */
  } ;
  часть структуры p ;
  недействительный основной()
  {
  clrscr();
 
/* Чтение первого сектора первого жесткого диска */
    biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
  display(); /* Отображение информации MBR
  Таблица разделов */
  получить();
}
 
/* Функция отображения информации о таблице разделов MBR */
    отображать()
  {
  беззнаковое целое s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
  тип символа[20], boot[5] ;
  printf("\n\nЧасть. Начальное местоположение загрузки
  Конечное местоположение Относительное количество");
  printf("\nType   Side Cylinder Sector 
  Side Cylinder Sector    Sectors     Sectors\n");
  for ( i = 0 ; i <= 3 ; i++ )
  {
  if ( p.pt[i].bootable == 0x80 )
  strcpy ( boot, "Yes" ) ;
  else
  strcpy ( boot, "No" ) ;
  switch ( p.pt[i].parttype )
  {
  case 0x00 :
  strcpy ( type, "Unused" ) ; break ;
  case 0x1 :
  strcpy ( type, "FAT12" ) ; break ;
  case 0x2 :
  strcpy ( type, "Xenix" ) ; break ;
  case 0x3 :
  strcpy ( type, "Xenix:usr" ) ; break ;
  case 0x4 :
  strcpy ( type, "FAT16<32M" ) ; break ;
  case 0x5 :
  strcpy ( type, "DOS-Ext." ) ; break ;
  case 0x6 :
  strcpy ( type, "FAT16>32M" ) ; break ;
  case 0x7 :
  strcpy ( type, "NTFS" ) ; break ;
  case 0x0b :
  strcpy ( type, "FAT32" ) ; break ;
  case 0x0c :
  strcpy ( type, "FAT32-LBA" ) ; break ;
  case 0x0d :
  strcpy ( type, "VFAT16" ) ; break ;
  case 0x0e :
  strcpy ( type, "VFAT16-LBA" ) ; break ;
  case 0x0f :
  strcpy ( type, "VFAT EXT" ) ; break ;
  case 0x17 :
  strcpy ( type, "HPFS" ) ; break ;
  case 0x81 :
  strcpy ( type, "Old LINUX" ) ; break ;
  case 0x82 :
  strcpy ( type, "LinuxSwap" ) ; break ;
  case 0x83 :
  strcpy ( type, "LinuxNative" ) ; break ;
  case 0x85 :
  strcpy ( type, "Linux Ext." ) ; break ;
  default :
  strcpy ( type, "Unknown" ) ; break ;
  }
  s_sec = ( p.pt[i].start_sec_cyl & 0x3f )  ; /* starting 
  Sector of the 
  partition */
  t1    = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
  t2    = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
  s_trk = t1 | t2 ;  /* Starting Cylinder */
  e_sec = ( p.pt[i].end_sec_cyl & 0x3f ) ; /*Ending Sector */
  t1    = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
  t2    = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
  e_trk = t1 | t2 ; /* ending Cylinder */
  printf ( "\n%6s %3s", type, boot ) ;
  printf ( "%4d %6d %8d", p.pt[i].start_side, s_trk,s_sec ) ;
  printf ( "%7d %6u %8u", p.pt[i].end_side,  e_trk, e_sec ) ;
  printf ( "  %10lu  %10lu", p.pt[i].part_beg,
  p.pt[i].plen ) ;
  }
  return 0;
  }
 
The information given by the output of the program is displayed something like as given below:

 
 
Comments on coding:
The structure partition is used to read the various parameters of partition entry of partition in partition table of MBR. The structure part is used to read MBR information.
The function display() displays the information of MBR Partition Table parameters on the screen. As we see the output of the program, the starting and ending cylinder and sector number are displayed as follows:
    Starting Sector   =      1
  Starting Cylinder  =      0
  Ending Sector    =    63
  Ending Cylinder  =  701
 These sector and cylinder numbers are calculated from the combination of two bytes. The following tables show that how these numbers are calculated:

Thus Starting C-H-S of the partition= 0-0-1.
Similarly, the Encoding for the Ending Cylinder and Sector number of the partition have been given in the next table:

Thus the Ending C-H-S of the Partition = 701-254-63.
 
Program to find all logical partitions and their information
 The program we discussed earlier was to read the partition information from the partition table of MBR. But just only by reading the MBR, we can not get the information of other logical partitions which are in extended partition of the disk.
We have already discussed that the Master Boot Record has the limit of four entries in the Master Partition Table. However the location of Extended Master Boot Record can be obtained with the help of Master Boot Record that contains Extended Partition Tables, whose format is exactly the same as of the main Partition Table.
All the extended partitions should exist within the space reserved by the extended partition entry. Only two of the extended partitions are meant to be used, the first as a normal partition and the second as another extended partition if exists.
Thus with the help of one Master Partition Table We can get the location of another Extended Master Partition Table next to it, if present.
The following program is for finding all the logical partitions and their partition entry information, reading MBR and Extended MBRs from the disk. The coding of the program is as follows:
 
/* Program to read the parameters of all logical partition present in the disk */
    #include<dos.h>
  har buffer[512], report_par[20];
  unsigned drive_num =0x80;
  unsigned long   star_sec[20], sec;
 
/* Structure of Disk Address packet format, to be used by the readabsolutesectors Function */
    struct diskaddrpacket
  {
  char packetsize ; /* Size of Packet, generally 10H */
  char reserved ;   /* Reserved (0) */
  int blockcount ;  /* Number of Blocks to Transfer */
  char far *bufferaddress ;   /* address to Transfer 
  Buffer */
  unsigned long blocknumber[2] ; /* Starting Absolute 
  Block Number */
  } ;
  void main()
  {
  int no_par,i;
  clrscr();
  no_par = 0;
  All_partition_information (star_sec,&no_par, &sec, buffer, 
  report_par);
  printf(" \n\n  Total Partitions in Disk = %d\n ", 
  no_par);
  for(i=0;i<no_par;i++)
  {
  printf("\n   Starting Sector Number of Partition %d = 
  %lu    " , i+1, star_sec[i]);
  }
  printf("\n");
  getch();
}
 
The Output of the program will be displayed as similar to this:
  Partition 1 - FAT32
  
Partition 2 - FAT32
  Partition 3 - FAT32
  Total Partitions in Disk = 3
  Starting Sector Number of Partition 1 = 63
  Starting Sector Number of Partition 2 = 11277693
  Starting Sector Number of Partition 3 = 25623738
 
 
Comments on coding:
 The structure diskaddrpacket is used to read Disk Address packet format, to be used by the readabsolutesectors function.
The function All_partition_information( ) is used to find all the parameters of all partitions from the partition entry.
Although in this program, we have displayed only the File system and relative sector information of all available logical partitions in the disk, you can also print the information of other parameters of partition information by using the function All_partition_information( ) with some more printf.
 
The coding of the function is as follows:
/* Function to Find all logical partitions’ information reading their partition entry */
    All_partition_information( unsigned long *star_sec, 
  unsigned *no_par,
  long *sec, char *buffer,
  unsigned char *report_par )
  {
  unsigned long   fat_check;
  unsigned long   *sectors_part;
  static long     se_p;
  int             temp_var1,active_offset,active_pos=0,i,           extended_pos=0, partloc1;
  unsigned long   b_sec,se;
  unsigned char   active_par;
  long    relative_sec;
  long    no_sectors;
  if(*sec==0 || *sec==1)
  se_p=0;
  do{
  se=*sec;
 
/* Read absolute sector specified by *sec */
 readabsolutesectors (drive_num,*sec,1,buffer);
/*  ***** check for active partition *****  */
    if(*sec==se && *no_par==0)   /*if primary 
  partition */
  {
  *sec=se=0;
  for(active_offset=446; active_offset<=494;active_offset+=16)
  { 
  active_par=buffer[active_offset];
  if(active_par==0x80)   /* check for active 
  partition */
  break;
  else
  active_pos++; /* position of active 
  partition */
  }
 
 /* for extended partition */
    for(active_offset=450; active_offset<=511;active_offset+=16)
  {
  active_par=buffer[active_offset];
  if(active_par==0x05 | active_par==0x0F) 
  /*check for extended partition */
  break;
  else
  extended_pos++;  /*position of extended 
  partition */
  }
  if(active_pos==4)
  active_pos=1;
  if(extended_pos==4)
  extended_pos=1;
  partloc1=0x1C0+extended_pos*16;
  }
  else
  { 
  active_pos=0;
  extended_pos=1;
  partloc1=0x1D0;
  if(se_p!=0)
  {
  *sec=se=se_p;   /*starting of extended 
  partition */ 
  }
  }
 
/* Relative Sectors in partition */
 relative_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* Number of Sectors in Partition */
 no_sectors=*(long *)(buffer+458+active_pos*16);
/* Identify the File System Indicator Byte */
    if( buffer[0x1C2+active_pos*16]==0x04 || 
  buffer[0x1C2+active_pos*16]==0x05 ||
  buffer[0x1C2+active_pos*16]==0x06 || 
  buffer[0x1C2+active_pos*16]==0x0B || 
  buffer[0x1C2+active_pos*16]==0x0C ||
  buffer[0x1C2+active_pos*16]==0x0E ||
  buffer[0x1C2+active_pos*16]==0x0F ||
  buffer[0x1C2+active_pos*16]==0x07) 
  {
  switch(buffer[0x1C2+active_pos*16])
  {
  /* For NTFS Partition */
  case 0x07:    report_par[*no_par]='N';
  printf("\n        Partition -%d   = NTFS", 
  *no_par+1);
  break;
 
 /* For FAT32 Partition */
    case 0x0B:
  case 0x0C:    report_par[*no_par]='3';
  printf("\n        Partition -%d   = FAT32", 
  *no_par+1);
  break;
 
 /* For FAT16 Partition */
    case 0x04:
  case 0x06:
  case 0x0E: report_par[*no_par]='1';
  printf("\n Partition -%d   = FAT16", 
  *no_par+1);
  break;
  } // End of the Switch
  b_sec=*sec+relative_sec;
  sectors_part[*no_par]=no_sectors; /* Array to store Number of sectors of partitions */
  } //End of if Condition
  else
  {   /* if partition indicator not match */
  if(*sec==0)
  { no_par=0;
  break;
  }
  if((fat_check!=0x3631)&&(fat_check!=0x3233))
  b_sec=*sec=0;
  }
  if((b_sec!=0)&&(sec!=0)) 
  {
  star_sec[*no_par]=b_sec;
  (*no_par)++;
  }
  else
  break;
 
 /* checking if extended partition exist */
    if(buffer[0x1C2+extended_pos*16]==0x05 ||
  buffer[0x1C2+extended_pos*16]==0x0F )
  { 
  temp_var1=(unsigned )buffer[partloc1];
  *sec=temp_var1 & 0x003F;   /* sector of 
  extended 
  partition */
  if(*sec!=0)
  { 
  se_p=se+relative_sec+no_sectors;
  *sec=se_p;
  }
  else
  { *sec=-1;
  break;
  }
  } //close of if statement
  else
  { 
  if(*sec>0)
  *sec=-1;
  break;
  }
  } while(1); // close of do–while loop
 
 /* check for other non active primary partitions on sector 0 */
    if(*sec==0)
  { 
  for(i=0;i<4;i++)
  { 
  active_par=buffer[446+i*16];
 
/* Identify the file system indicator Byte */
    if((buffer[0x1C2+i*16]==(char)0x06 || 
  buffer[0x1C2+i*16]==(char)0x0B ||
  buffer[0x1C2+i*16]==(char)0x0C || 
  buffer[0x1C2+i*16]==(char)0x07 ||
  buffer[0x1C2+i*16]==(char)0x0E || 
  buffer[0x1C2+i*16]==(char)0x04) && active_par!=0x80)
  {
  switch(buffer[0x1C2+active_pos*16])
  {
 
 /* For NTFS Partition */
    case 0x07: report_par[*no_par]='N';
  printf("\n  Partition -%d  = NTFS",
  *no_par+1);
  break;
 
 /* For FAT32 Partition */
    case 0x0B:
  case 0x0C:    report_par[*no_par]='3';
  printf("\n    Partition -%d   = FAT32",
  *no_par+1);
  break;
 
 /* For FAT16 Partition */
    case 0x04:
  case 0x06:
  case 0x0E:    report_par[*no_par]='1';
  printf("\n     Partition -%d   = FAT16",
  *no_par+1);
  break;
  } // End of switch
 
/* relative sectors Number of Partition */
    relative_sec=*(long *)(buffer+454+i*16); 
  no_sectors=*(long *)(buffer+458+i*16); /*  number of 
  sectors in 
  partition*/
  sectors_part[*no_par]=no_sectors;  /* Array to store 
  Number of 
  sectors of 
  partitions */
  *sec=star_sec[*no_par]=relative_sec; 
  (*no_par)++;
  }
  } //loop close of for(i=0;i<4;i++)
  } //loop close of if(*sec==0)
  return;
  }
 
Comments on coding:
 The function starts reading the partitions information from the MBR and then reads the Extended MBRs if required. The function readabsolutesectors reads the absolute sector, specified by *sec.
sectors_part[*no_par] is the array to store the number of sectors of partitions. The partition number is specified by *no_par starting from 0.
no_sectors is the number of sectors in partition and relative_sec is the relative sector number for that partition.
star_sec[*no_par] is the array to store the stating sector numbers of partitions. The partition number is specified by *no_par starting from 0.
star_cyl,  star_hea  and star_sec are the arrays which keep the information of starting of each partition in terms of CHS. star_cyl stores the information of starting cylinders, star_hea stores the information of starting heads and star_sec stores the information of starting sectors of partitions.
For the description of readabsolutesectors function refer the chapters given earlier in this book.
 
Modify MBR by Programming
The sample program to show, how we can modify the values of MBR partition table entry has been given below. The program modifies the values second partition entry of MBR partition table.
The coding of the program has been given below:
/* Program to modify the values of partition table entry of MBR */
# include <bios.h>
/* structure to read the partition entry from partition table */
    struct partition
  {
  unsigned char bootable ;  /* Active Partition 
  Byte */
  unsigned char start_side ;  /* Starting Head    */
  unsigned int start_sec_cyl ;  /* combination of 
  Starting sector and 
  cylinder number  */
  unsigned char parttype ;  /* File system 
  Indicator Byte   */
  unsigned char end_side ;  /* Ending Head    */
  unsigned int end_sec_cyl ;  /* combination of 
  Starting sector and 
  cylinder number  */
  unsigned long part_beg ;  /* Relative Sector 
  Number      */
  unsigned long plen ;    /* Partition length in 
  sectors */
  } ;
 
/* Structure to read MBR */
    struct part
  {
  unsigned char master_boot[446] ; /* IPL (Initial 
  Program Loader)*/
  struct partition pt[4] ;     /* Partition table*/
  int lasttwo ;        /* Magic Number   */
  } ;
  struct part p ;
  void main()
  {
  unsigned int t1,t2;
  clrscr();
  biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
  display();      /* display the partition 
  Table information      */
  getch();
 
/* Let us assume that we want to modify the partition information of second partition entry from partition table of MBR, with these values */
 p.pt[1].bootable = 0x80;  /* Active Boot Partition */
 p.pt[1].parttype = 0x7;   /* NTFS Partition      */
 p.pt[1].start_side = 0;   /* Starting Head =0      */
p.pt[1].end_side = 31; /* Конечный заголовок == 31 */
p.pt[1].part_beg = 808416;/* Относительный сектор = 808416 */
стр.пт[1].полный = 405216; /* Общее количество секторов в разделе = 405216 */
 
/* Запись новой информации в MBR *\
/* Чтобы записать значения в таблицу разделов MBR, раскомментируйте функцию biosdisk, указанную ниже */
// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
    display(); /* Отображение измененного
  Информация */
  получить();
  }
 
Комментарии по кодированию:
Программа, приведенная выше, является примером программы, показывающей, как мы можем изменить значения записи таблицы разделов MBR . Если вы хотите изменить значения записи раздела для таких логических разделов , которые лежат в расширенном разделе , вам нужно изменить значения в таблице разделов Extended MBR .
Значения, которые были даны здесь для изменения записи таблицы разделов, просто для демонстрации того, как изменять. Никогда не изменяйте таблицу разделов недопустимыми или нелогичными значениями. В результате весь раздел может стать недоступным.
Раздел структуры используется для чтения записи раздела из таблицы разделов, а часть структуры — для чтения MBR. Чтобы внести изменения в таблицу разделов, раскомментируйте функцию biosdisk() .
Если вы хотите изменить начальные и конечные значения, номера секторов и цилиндров раздела, рассчитайте значения, как описано в комментариях к программе для чтения и отображения таблицы разделов MBR , обсуждаемой в начале этой главы.