Un sector de disc conține 0x200 (512) octeți. Tabela de partiții se află
în primul sector al discului, începând cu deplasamentul (octetul) 0x1BE.
Ea conține 4 intrări a câte 16 octeți. (Cei doi octeți rămași la sfârșitul
sectorului sunt ocupați de "semnătura" convențională 0x55 0xAA).
Conținutul unei intrări din tabela de partiții este următorul:
- un octet care indică dacă partiția e activă (0x80) sau nu (0), adică
dacă de pe ea se poate lansa ("boot") spre încărcare sistemul de operare.
- o secvență de 3 octeți care indică poziția primului sector fizic
al partiției (în format HSC - head, sector, cylinder - descris ulterior)
- un octet identificator pentru tipul de partiție (0 pentru partiție
goală, 7 pentru NTFS, 0x83 pentru Linux, etc.)
- o altă secvență de 3 octeți în format HSC indicând poziția ultimului
sector fizic al partiției
- un întreg fără semn pe 4 octeți indicând numărul logic al primului
sector al partiției (numărul de sectoare care-l preced pe disc)
- un întreg fără semn pe 4 octeți indicând dimensiunea partiției
în sectoare
Formatul HSC conține:
- în primul octet, numărul capului de citire (numerotat de la zero,
cel mult 255)
- în cei 6 biți inferiori ai octetului al doilea, numărul sectorului
în cadrul unei piste (numerotat de la 1, cel mult 63)
- în octetul al treilea, și biții 7 și 6 din octetul al doilea
(considerați ca biți superiori, de rang 9 și 8), numărul cilindrului
de pe disc (începând cu 0, cel mult 1023).
(Se constată că formatul HSC e limitat la 24 de biți, deci discuri de
cca 8GB. Dincolo de această limită se folosește doar numărul logic de sector
în cadrul discului; pentru simplificare nu vom trata acest caz.)
Scrieți un program care acceptă următoarele comenzi (câte o literă mică):
d șterge o partiție: cere un număr între 1 și 4, pune identificatorul
și toți octeții din intrarea respectivă pe zero.
m afișează meniul de comenzi
n creează o partiție nouă: solicită un număr între 1 și 4; un
cilindru de început de partiție; un cilindru de sfârșit de partiție;
un tip (identificator) de partiție. Partiția nu trebuie să se suprapună
peste cele existente.
p afișează tabela de partiții (un tabel cu câte un rând pentru
fiecare partiție existentă)
q iese din program, ignoră modificările făcute
w iese din program, scrie modificările pe disc
Convențional, fiecare partiție e aliniată de regulă la un cilindru nou (începe la sectorul 1 al capului 0 de pe acel cilindru). Excepție face începutul discului, unde se rezervă o pistă specială (cilindrul 0, capul 0, toate sectoarele) care include și primul sector unde se află chiar tabela de partiții.
Pentru implementare, vor trebui manipulate zonele corespunzătoare (intrările în tabela de partiții) dintr-un tablou de 512 octeți reprezentând conținutul unui sector. E elegantă și utilă definirea unui tip structură care reprezintă o intrare din tabela de partiții. Se poate defini un tip și pentru formatul HSC, eventual cu câmpuri pe biți, deși cu ordonarea dată a biților nu se poate trata "dintr-o bucată" câmpul de cilindri. Pentru întregii pe dimensiune fixă în octeți, soluția portabilă în standardul C99 este folosirea tipurilor definite în stdint.h, în acest caz tipul uint32_t. (Pentru gcc/x86/linux acesta e definit ca unsigned int; vom învăța cum să dăm o definiție portabilă cu directive de compilare condițională, în funcție de valoarea dată de sizeof).
Pentru simplificare, și întrucât citirea/scrierea din fișiere nu s-a tratat
încă la curs, s-au implementat funcții ajutătoare, în fișierul
rwsect.c:
funcția size_t readsect(void *ptr) citește un sector (512
octeți) la adresa ptr unde se presupune că există suficient loc.
funcția size_t writesect(const void *ptr) scrie un sector
(512 octeți) de la adresa ptr.
Funcțiile lucrează implicit cu fișierul mbr.bin
aflat în catalogul curent și nu se vor apela de mai multe ori în execuția
programului (deoarece implicit deschid și închid fișierul respectiv).
Ele returnează numărul octeților citiți/scriși cu succes, și setează
variabila standard errno în caz de eroare.
În realitate, programul fdisk poate afla din hardware informațiile
despre geometria discului (număr de cilindri, capete, sectoare). Pentru
problema dată, considerăm C=528, H=64, S=63, valori consistente cu
structura dată în fișierul de test.
Când folosim structuri pentru a defini formate cu număr precizat de octeți,
e bine să ne asigurăm că deplasamentul fiecărui câmp în cadrul structurii
este cel dorit, modul de aliniere a câmpurilor în memorie fiind dependent
de implementare (compilator). Dacă x are tipul struct s
și f e un câmp, atunci expresia (char *)&x.f - (char *)&x
indică deplasamentul câmpului f în cadrul structurii. În C99 există
și macro-ul offsetof din stddef.h care utilizat sub forma
offsetof(struct s, f) dă o constantă întreagă cu același rezultat.