Capitolo – 12
Lettura e modifica dell'MBR tramite programmazione
Master Boot Record (MBR) o Master Partition Table (MPT)
Il Master Boot Record (MBR), talvolta chiamato anche Master Partition Table (MPT), viene creato sul disco rigido eseguendo il comando DOS FDISK.EXE.
L'MBR contiene un piccolo programma per caricare ed eseguire la partizione attiva (o di avvio) dal disco rigido. Il Master Boot Record contiene informazioni su tutte e quattro le partizioni primarie del disco rigido, come il settore iniziale, il settore finale, la dimensione della partizione, ecc.
L'MBR si trova nel settore assoluto 0 o possiamo dire nel cilindro 0, nella testina 0 e nel settore 1 e se sul disco è presente più di una partizione, all'inizio di ogni volume della partizione estesa si trovano dei master boot record estesi.
Per una descrizione dettagliata, vedere il capitolo "Un approccio logico ai dischi e al sistema operativo" discusso in precedenza in questo libro.
Formato Master Boot Record
Possiamo partizionare il disco rigido in più unità logiche, alle quali solitamente il DOS assegna una propria lettera di unità. È possibile contrassegnare come attiva (o di avvio) solo una partizione alla volta.

Il master boot record ha un limite di quattro voci nella tabella delle partizioni primarie. Tuttavia, la posizione dell'MBR esteso può essere ottenuta utilizzando l'MBR contenente le tabelle delle partizioni estese, che ha lo stesso formato della tabella delle partizioni primarie, tranne per il fatto che non contiene codice di avvio e che 446 byte di spazio sono solitamente riservati al codice di avvio e vengono lasciati vuoti.
Tutti i 512 byte del master boot record sono suddivisi come mostrato nella tabella:

Tutte le partizioni estese devono esistere nello spazio riservato dalla voce di partizione estesa. Si prevede di utilizzare solo due delle partizioni estese: la prima come partizione normale e la seconda come ulteriore partizione estesa, se esistente.
Quindi, utilizzando una Master Partition Table possiamo ottenere la posizione di un'altra Extended Master Partition Table adiacente, se presente.
Formato di immissione della tabella delle partizioni
Nella tabella seguente è illustrato il formato delle voci della tabella delle partizioni di qualsiasi partizione nel MBR. Ogni voce di partizione di qualsiasi MBR può essere suddivisa nei seguenti byte con i loro significati specifici:

Scrivere un programma per leggere la tabella delle partizioni MBR
Di seguito è riportato un programma per leggere tutte e quattro le voci della partizione dalla tabella delle partizioni MBR. Il programma visualizza tutti i parametri delle informazioni sulla partizione registrate nella tabella delle partizioni MBR.
La codifica del programma appare così:
/* Programma per la lettura della tabella delle partizioni MBR */
# includere <bios.h>
/* struttura per la lettura della voce di partizione dalla tabella delle partizioni */
sezione strutturale
{
unsigned char avviabile; /* Byte attivo della sezione */
unsigned char start_side ;/* Testa iniziale */
intero senza segno start_sec_cyl ; /* combinazione
Settore di partenza e
numero del cilindro */
tipo di parte di un char senza segno; /* Sistema di file
Byte indicatore */
carattere senza segno end_side ; /* Fine intestazione */
intero senza segno end_sec_cyl ; /* combinazione
Settore di partenza e
numero del cilindro */
parte lunga non firmata_inizio ; /* Settore relativo
Numero */
intero lungo senza segno; /* Lunghezza della sezione in
settore */
} ;
/* Struttura per la lettura dell'MBR */
parte della struttura
{
carattere senza segno master_boot[446] ; /* IPL (iniziale
Caricatore di programma)*/
struct partizione pt[4] ; /* Tabella delle partizioni */
int ultimidue ; /* Numero magico */
} ;
parte della struttura p ;
main() non valido
{
clrscr();
/* Lettura del primo settore del primo disco rigido */
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Visualizza le informazioni MBR
Tabella delle partizioni */
Ottenere();
}
/* Funzione per visualizzare informazioni sulla tabella delle partizioni MBR */
display()
{
intero senza segno s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
tipo di carattere[20], avvio[5] ;
printf("\n\nParte. Posizione di caricamento iniziale
Posizione finale Quantità relativa");
printf("\nTipo Settore Cilindro Laterale
Settore Cilindro Laterale Settori Settori\n");
per ( i = 0 ; i <= 3 ; i++ )
{
se ( p.pt[i].bootable == 0x80 )
strcpy( avvio, "Sì" ) ;
altro
strcpy(avvio, "No" ) ;
interruttore ( p.pt[i].parttype )
{
caso 0x00 :
strcpy(tipo, "Non utilizzato"); break;
caso 0x1 :
strcpy (tipo, "FAT12" ) ; interruzione ;
caso 0x2 :
strcpy (tipo, "Xenix" ) ; interruzione ;
caso 0x3 :
strcpy (tipo, "Xenix:usr" ) ; interruzione ;
caso 0x4 :
strcpy (tipo, "FAT16<32M" ) ; interruzione ;
caso 0x5 :
strcpy ( tipo, "DOS-Ext." ) ; break ;
caso 0x6 :
strcpy (tipo, "FAT16>32M" ) ; interruzione ;
caso 0x7 :
strcpy (tipo, "NTFS" ) ; interruzione ;
caso 0x0b :
strcpy (tipo, "FAT32" ) ; interruzione ;
caso 0x0c :
strcpy (tipo, "FAT32-LBA" ) ; interruzione ;
caso 0x0d :
strcpy (tipo, "VFAT16" ) ; interruzione ;
caso 0x0e :
strcpy (tipo, "VFAT16-LBA" ) ; interruzione ;
caso 0x0f :
strcpy (tipo, "VFAT EXT" ) ; interruzione ;
caso 0x17 :
strcpy (tipo, "HPFS" ) ; interruzione ;
caso 0x81 :
strcpy (tipo, "Vecchio LINUX" ) ; break ;
caso 0x82 :
strcpy (tipo, "LinuxSwap" ) ; interruzione ;
caso 0x83 :
strcpy (tipo, "LinuxNative" ) ; interruzione ;
caso 0x85 :
strcpy (tipo, "Linux Ext." ) ; break ;
predefinito :
strcpy(tipo, "Sconosciuto"); break;
}
s_sec = ( p.pt[i].start_sec_cyl & 0x3f ) ; /* avvio
Settore del
partizione */
t1 = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
s_trk = t1 | t2 ; /* Cilindro di avviamento */
e_sec = ( p.pt[i].end_sec_cyl & 0x3f ) ; /*Settore finale */
t1 = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
e_trk = t1 | t2 ; /* Cilindro finale */
printf( "\n%6s %3s", tipo, avvio ) ;
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 ) ;
}
restituisci 0;
}
Le informazioni fornite dall'output del programma vengono visualizzate più o meno come segue:

Commenti sulla codifica:
La partizione di struttura è utilizzata per leggere i vari parametri della voce di partizione della partizione nella tabella delle partizioni di MBR. La parte di struttura è utilizzata per leggere le informazioni di MBR.
La funzione display() visualizza le informazioni dei parametri della tabella delle partizioni MBR sullo schermo. Come vediamo l'output del programma, il cilindro iniziale e finale e il numero di settore vengono visualizzati come segue:
Settore di partenza = 1
Cilindro di avviamento = 0
Settore finale = 63
Cilindro finale = 701
Questi numeri di settore e cilindro vengono calcolati dalla combinazione di due byte. Le seguenti tabelle mostrano come vengono calcolati questi numeri:

Quindi CHS iniziale della partizione = 0-0-1.
Allo stesso modo, la codifica per il cilindro finale e il numero di settore della partizione sono stati forniti nella tabella seguente:

Quindi la CHS finale della partizione = 701-254-63.
Programma per trovare tutte le partizioni logiche e le loro informazioni
Il programma di cui abbiamo parlato prima era quello di leggere le informazioni sulla partizione dalla tabella delle partizioni di MBR. Ma solo leggendo l'MBR, non possiamo ottenere le informazioni di altre partizioni logiche che si trovano nella partizione estesa del disco.
Abbiamo già discusso che il Master Boot Record ha il limite di quattro voci nella Master Partition Table . Tuttavia, la posizione dell'Extended Master Boot Record può essere ottenuta con l'aiuto del Master Boot Record che contiene Extended Partition Table , il cui formato è esattamente lo stesso della Main Partition Table.
Tutte le partizioni estese devono esistere all'interno dello spazio riservato dalla voce di partizione estesa. Solo due delle partizioni estese sono destinate a essere utilizzate, la prima come partizione normale e la seconda come un'altra partizione estesa, se esiste.
Pertanto, con l'aiuto di una tabella di partizione principale, possiamo ottenere la posizione di un'altra tabella di partizione principale estesa accanto ad essa, se presente.
Il seguente programma serve per trovare tutte le partizioni logiche e le informazioni sulle loro voci di partizione, leggendo MBR ed MBR estesi dal disco. La codifica del programma è la seguente:
/* Programma per leggere i parametri di tutte le partizioni logiche presenti sul disco */
#include<dos.h>
ha buffer[512], report_par[20];
unsigned drive_num =0x80;
star_sec[20] lungo senza segno, sec;
/* Struttura del formato del pacchetto di indirizzo del disco, da utilizzare dalla funzione readabsolutesectors */
struct diskaddrpacket
{
char packetsize ; /* Dimensione del pacchetto, generalmente 10H */
char riservato ; /* Riservato (0) */
int blockcount ; /* Numero di blocchi da trasferire */
char far *bufferaddress ; /* indirizzo da trasferire
Respingente */
unsigned long blocknumber[2] ; /* Avvio assoluto
Numero di blocco */
} ;
vuoto principale()
{
int non_pari,i;
clrscr();
nessun_pari = 0;
Tutte le informazioni sulla partizione (star_sec,&no_par, &sec, buffer,
segnala_par);
printf(" \n\n Partizioni totali sul disco = %d\n ",
nessun_pari);
per(i=0;i<no_par;i++)
{
printf("\n Numero del settore iniziale della partizione %d =
%lu " , i+1, stella_sec[i]);
}
stampa("\n");
ottenere();
}
L'output del programma verrà visualizzato in modo simile a questo:
Partizione 1 - FAT32
Partizione 2 - FAT32
Partizione 3 - FAT32
Partizioni totali nel disco = 3
Numero del settore iniziale della partizione 1 = 63
Numero di settore iniziale della partizione 2 = 11277693
Numero di settore iniziale della partizione 3 = 25623738
Commenti sulla codifica:
La struttura diskaddrpacket viene utilizzata per leggere il formato del pacchetto Disk Address, da utilizzare tramite la funzione readabsolutesectors.
La funzione All_partition_information() viene utilizzata per trovare tutti i parametri di tutte le partizioni dalla voce della partizione.
Sebbene in questo programma siano state visualizzate solo le informazioni sul file system e sui settori relativi di tutte le partizioni logiche disponibili sul disco, è possibile stampare anche le informazioni di altri parametri delle partizioni utilizzando la funzione All_partition_information() con qualche printf in più.
La codifica della funzione è la seguente:
/* Funzione per trovare le informazioni di tutte le partizioni logiche leggendo la loro voce di partizione */
Tutte le informazioni sulla partizione (unsigned long *star_sec,
senza segno *no_par,
lungo *sec, carattere *buffer,
carattere senza segno *report_par )
{
fat_check lungo senza segno;
unsigned long *settori_parte;
statico lungo se_p;
int temp_var1,offset_attivo,posizione_attiva=0,i,posizione_estesa=0,partloc1;
unsigned long b_sec,se;
carattere senza segno active_par;
lungo relative_sec;
lungo no_sectors;
se(*sec==0 || *sec==1)
se_p=0;
Fare{
se=*sec;
/* Legge il settore assoluto specificato da *sec */
readabsolutesectors (unità_num,*sec,1,buffer);
/* ***** verifica partizione attiva ***** */
if(*sec==se && *no_par==0) /*se primario
partizione */
{
*sec=se=0;
per(offset_attivo=446; offset_attivo<=494;offset_attivo+=16)
{
active_par=buffer[offset_attivo];
if(active_par==0x80) /* controlla se è attivo
partizione */
rottura;
altro
active_pos++; /* posizione attiva
partizione */
}
/* per partizione estesa */
per(offset_attivo=450; offset_attivo<=511;offset_attivo+=16)
{
active_par=buffer[offset_attivo];
se(par_attivo==0x05 | par_attivo==0x0F)
/*controlla la partizione estesa */
rottura;
altro
extended_pos++; /*posizione dell'estensione
partizione */
}
se(posizione_attiva==4)
posizione_attiva=1;
se(posizione_estesa==4)
posizione_estesa=1;
partloc1=0x1C0+posizione_estesa*16;
}
altro
{
posizione_attiva=0;
posizione_estesa=1;
parteloc1=0x1D0;
se(se_p!=0)
{
*sec=se=se_p; /*avvio dell'estensione
partizione */
}
}
/* Settori relativi nella partizione */
relative_sec= *(unsigned long *)(buffer+454+active_pos*16);
/* Numero di settori nella partizione */
no_sectors=*(long *)(buffer+458+active_pos*16);
/* Identifica il byte indicatore del file system */
se( buffer[0x1C2+posizione_attiva*16]==0x04 ||
buffer[0x1C2+posizione_attiva*16]==0x05 ||
buffer[0x1C2+posizione_attiva*16]==0x06 ||
buffer[0x1C2+posizione_attiva*16]==0x0B ||
buffer[0x1C2+posizione_attiva*16]==0x0C ||
buffer[0x1C2+posizione_attiva*16]==0x0E ||
buffer[0x1C2+posizione_attiva*16]==0x0F ||
buffer[0x1C2+posizione_attiva*16]==0x07)
{
switch(buffer[0x1C2+posizione_attiva*16])
{
/* Per partizione NTFS */
caso 0x07: report_par[*no_par]='N';
printf("\n Partizione -%d = NTFS",
*non_pari+1);
rottura;
/* Per partizione FAT32 */
caso 0x0B:
caso 0x0C: report_par[*no_par]='3';
printf("\n Partizione -%d = FAT32",
*non_pari+1);
rottura;
/* Per la partizione FAT16 */
caso 0x04:
caso 0x06:
caso 0x0E: report_par[*no_par]='1';
printf("\n Partizione -%d = FAT16",
*non_pari+1);
rottura;
} // Fine dello switch
b_sec=*sec+sec_relativi;
sector_part[*no_par]=no_sectors; /* Array per memorizzare il numero di settori delle partizioni */
} //Fine della condizione if
altro
{ /* se l'indicatore di partizione non corrisponde */
se(*sec==0)
{ no_par=0;
rottura;
}
se((controllo_grasso!=0x3631)&&(controllo_grasso!=0x3233))
b_sec=*sec=0;
}
se((b_sec!=0)&&(sec!=0))
{
star_sec[*no_par]=b_sec;
(*non_pari)++;
}
altro
rottura;
/* verifica se esiste una partizione estesa */
se(buffer[0x1C2+posizione_estesa*16]==0x05 ||
buffer[0x1C2+posizione_estesa*16]==0x0F )
{
temp_var1=(senza segno)buffer[partloc1];
*sec=temp_var1 & 0x003F; /* settore di
esteso
partizione */
se(*sec!=0)
{
se_p=se+sec_relativo+nessun_settore;
*sec=se_p;
}
altro
{ *sec=-1;
rottura;
}
} //chiusura dell'istruzione if
altro
{
se(*sec>0)
*secondo=-1;
rottura;
}
} while(1); // chiusura del ciclo do–while
/* controlla altre partizioni primarie non attive sul settore 0 */
se(*sec==0)
{
per(i=0;i<4;i++)
{
active_par=buffer[446+i*16];
/* Identifica il byte indicatore del file system */
se((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+posizione_attiva*16])
{
/* Per partizione NTFS */
caso 0x07: report_par[*no_par]='N';
printf("\n Partizione -%d = NTFS",
*non_pari+1);
rottura;
/* Per partizione FAT32 */
caso 0x0B:
caso 0x0C: report_par[*no_par]='3';
printf("\n Partizione -%d = FAT32",
*non_pari+1);
rottura;
/* Per la partizione FAT16 */
caso 0x04:
caso 0x06:
caso 0x0E: report_par[*no_par]='1';
printf("\n Partizione -%d = FAT16",
*non_pari+1);
rottura;
} // Fine dello switch
/* settori relativi Numero di partizione */
relative_sec=*(long *)(buffer+454+i*16);
no_sectors=*(long *)(buffer+458+i*16); /* numero di
settori in
partizione*/
sector_part[*no_par]=no_sectors; /* Array da memorizzare
Numero di
settori di
partizioni */
*sec=star_sec[*no_par]=sec_relativo;
(*non_pari)++;
}
} //chiusura del ciclo for(i=0;i<4;i++)
} //chiusura del ciclo if(*sec==0)
ritorno;
}
Commenti sulla codifica:
La funzione inizia a leggere le informazioni sulle partizioni dall'MBR e poi legge gli MBR estesi se necessario. La funzione readabsolutesectors legge il settore assoluto, specificato da *sec.
sector_part[*no_par] è l'array per memorizzare il numero di settori delle partizioni. Il numero di partizione è specificato da *no_par a partire da 0.
no_sectors è il numero di settori nella partizione e relative_sec è il numero di settore relativo per quella partizione.
star_sec[*no_par] è l'array per memorizzare i numeri di settore dichiaranti delle partizioni. Il numero di partizione è specificato da *no_par a partire da 0.
star_cyl, star_hea e star_sec sono gli array che conservano le informazioni di avvio di ogni partizione in termini di CHS. star_cyl conserva le informazioni di avvio dei cilindri, star_hea conserva le informazioni di avvio delle testine e star_sec conserva le informazioni di avvio dei settori delle partizioni.
Per la descrizione della funzione readabsolutesectors fare riferimento ai capitoli precedenti di questo libro.
Modificare MBR tramite programmazione
Di seguito è riportato il programma di esempio per mostrare come possiamo modificare i valori della voce della tabella delle partizioni MBR . Il programma modifica i valori della seconda voce di partizione della tabella delle partizioni MBR .
Di seguito è riportata la codifica del programma:
/* Programma per modificare i valori della voce della tabella delle partizioni di MBR */
# includere <bios.h>
/* struttura per leggere la voce della partizione dalla tabella delle partizioni */
partizione struttura
{
unsigned char avviabile ; /* Partizione attiva
Byte */
unsigned char start_side ; /* Testa iniziale */
unsigned int start_sec_cyl ; /* combinazione di
Settore di partenza e
numero del cilindro */
unsigned char parttype ; /* File system
Byte indicatore */
unsigned char end_side ; /* Testa finale */
unsigned int end_sec_cyl ; /* combinazione di
Settore di partenza e
numero del cilindro */
unsigned long part_beg ; /* Settore relativo
Numero */
unsigned long plen ; /* Lunghezza della partizione in
settori */
} ;
/* Struttura per leggere MBR */
parte struttura
{
unsigned char master_boot[446] ; /* IPL (iniziale
Caricatore di programma)*/
struct partition pt[4] ; /* Tabella delle partizioni*/
int lasttwo ; /* Numero magico */
} ;
parte della struttura p ;
vuoto principale()
{
intero senza segno t1,t2;
clrscr();
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* visualizza la partizione
Informazioni sulla tabella */
ottenere();
/* Supponiamo di voler modificare le informazioni sulla partizione della seconda voce di partizione dalla tabella delle partizioni di MBR, con questi valori */
p.pt[1].bootable = 0x80; /* Partizione di avvio attiva */
p.pt[1].parttype = 0x7; /* Partizione NTFS */
p.pt[1].start_side = 0; /* Testa iniziale =0 */
p.pt[1].end_side = 31; /* Fine intestazione == 31 */
p.pt[1].part_beg = 808416;/* Settore relativo = 808416 */
p.pt[1].full = 405216; /* Numero totale di settori nella partizione = 405216 */
/* Scrivi nuove informazioni su MBR *\
/* Per scrivere i valori nella tabella delle partizioni MBR, rimuovere il commento dalla funzione biosdisk sottostante */
// disco bios ( 3, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Visualizzazione modificata
Informazioni */
Ottenere();
}
Commenti sulla codifica:
Il programma sopra riportato è un esempio di programma che mostra come modificare i valori delle voci della tabella delle partizioni MBR . Se si desidera modificare i valori delle voci di partizione per le partizioni logiche che si trovano in una partizione estesa , è necessario modificare i valori nella tabella delle partizioni MBR estese .
I valori forniti qui per modificare la voce della tabella delle partizioni servono solo per dimostrare come effettuare la modifica. Non modificare mai la tabella delle partizioni con valori non validi o illogici. Di conseguenza, l'intera sezione potrebbe diventare inaccessibile.
La sezione struttura viene utilizzata per leggere il record di partizione dalla tabella delle partizioni, mentre la parte struttura viene utilizzata per leggere l'MBR. Per apportare modifiche alla tabella delle partizioni, rimuovere il commento dalla funzione biosdisk() .
Se si desidera modificare i valori iniziale e finale, i numeri di settore e cilindro di una partizione, calcolare i valori come descritto nei commenti del programma per la lettura e la visualizzazione della tabella delle partizioni MBR discussi all'inizio di questo capitolo.