
8.6.2018
V tomto textu si prohlédneme obsah karty, kterou jsme si připravili předem. Použijeme k tomu zapojení a funkce, které jsme si ukázali. Pro čtení a zobrazení dat použiju tento kód:
BYTE data[512];
unsigned long BLOCK_NUMBER=0;
sprintf(s,"\nreading block %lu\n",BLOCK_NUMBER);
sendSerialString(s);
readBlockSD(BLOCK_NUMBER,data);
for (int i=0;i<10;i++)
{
for (int j=0;j<50;j++)
{
sprintf(s,"%02X ",data[i*50+j]);
sendSerialString(s);
}
sendSerialString("\n");
}
for (int j=0;j<12;j++)
{
sprintf(s,"%02X ",data[500+j]);
sendSerialString(s);
}
Provede se to, že se do proměnné data načte požadovaný sektor a poté se jednotlivé byty v šestnáctkovém zápise na 10 řádcích po 50 bytech plus poslední řádek 12 bytů odešlou po seriové lince. Zápis bytů si případně přeuspořádáme následně tak, aby pro nás byl přehledný.
V prvním sektoru (sektor číslo nula) karty je Master Boot Record neboli MBR. Podíváme se na něj - přečteme data z bloku 0:

MBR se skládá z několika částí. Prvních 446 bytů nás nezajímá. Po nich následuje čtyřikrát 16 bytů s údaji pro 4 oddíly na disku. Poslední dvě místa v tomto bloku tvoří byty 0x55 0xAA. Ve výpise vidíme, že data obsahuje pouze první oddíl, zbylé tři šestnáctibytové úseky jsou vyplněny nulami. Ještě je třeba říci, že hodnoty jsou uloženy ve formátu little-endian, tedy byty jsou zapsány od LSB k MSB. Podíváme se podrobně na data o prvním oddíle:
00 00 09 66 83 01 CA FF 00 08 00 00 00 78 ED 00
První 4 byty nás nezajímají. Pátý byte obsahuje typ oddílu. Zde máme hodnotu 0x83, což je Linux - to nás nepřekvapí, protože tuto informaci známe (na obrázku je hodnota 83 označena jako Id). Další tři byty nás také nezajímají. Následující 4 byty ovšem obsahují číslo prvního sektoru oddílu na disku a to nás zajímá hodně. Ve výpisu vidíme 00 08 00 00, ale vzhledem k výše uvedené poznámce je pořadí bytů "obrácené", takže toto číslo je 0x00000800 neboli 2048. To souhlasí s tím, jak jsme oddíl vytvořili. Poslední čtyři byty značí počet sektorů v oddílu. Stejně jako před chvílí 00 78 ED 00 je 0x00ED7800 = 15562752. Tato hodnota opět souhlasí s tím, co jsme viděli při vytváření oddílu. Můžeme spočítat velikost oddílu, protože víme, že jeden sektor tvoří 512 B a proto oddíl obsahuje 512 * 15562752 B = 7968129024 B = 7781376 KB = 7599 MB = 7.42 GB.
Jak už víme, oddíl začíná sektorem číslo 2048, a proto si ho přečteme stejným způsobem jako před chvílí sektor číslo nula. Získáme tento výpis:

Podíváme se na prvních 36 bytů, což je tzv. BIOS Parameter Block (BPB):
EB 58 90 6D 6B 66 73 2E 66 61 74 00 02 08 20 00 02 00
00 00 00 F8 00 00 0A 00 02 00 00 08 00 00 00 78 ED 00
První 3 byty nás nezajímají. Dalších 8 bytů není důležitých, ale podíváme se na ně jen pro zajímavost. Měla by v nich být uvedena verze DOSu či něco podobného. Posloupnost bytů 6D 6B 66 73 2E 66 61 74 je textový řetězec "mkfs.fat", což je příkaz, kterým jsem vytvořil souborový systém v oddílu. V dalších dvou bytech je počet bytů na sektor: 00 02, což je 0x0200 = 512. Další byte je počet sektorů na cluster (alokační jednotku): 0x08. Dva byty počet reservovaných sektorů: 20 00, 0x20 = 32. Jeden byte počet FAT tabulek: 0x02 neboli oddíl obsahuje 2 kopie tabulky. Dalších 11 bytů nás nezajímá. Následující 4 byty obsahují počet skrytých sektorů (počátek oddílu): 00 08 00 00, 0x0800 = 2048. A konečně poslední 4 byty počet sektorů v oddílu: 00 78 ED 00 - to samé co v MBR.
Za BPB následuje tzv. EBPB neboli Extended Boot Record, což je v případě FAT32 dalších 54 bytů informací. Data následující po EBPB nás nezajímají, jen si všimneme, že stejně jako v MBR i zde jsou poslední dva byty 0x55 0xAA. Prohlídneme si EBPB:
41 3B 00 00 00 00 00 00 02 00 00 00 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00
00 80 00 29 2C 35 19 60 54 45 53 54 49 4E 47 20 20 20 20 46 41 54 33 32 20 20 20
První 4 byty počet sektorů, které zabírá FAT tabulka: 41 3B 00 00, 0x3B41 = 15169. Další 4 byty nezajímají. Následují 4 byty s počátečním clustrem kořenového adresáře: 02 00 00 00, 0x02. Dalších 18 bytů nezajímá. Jeden byte značka, musí být 0x28 nebo 0x29: 0x29. Další 4 byty nezajímá. V 11 bytech je název oddílu doplněný mezerami na konci: 54 45 53 54 49 4E 47 20 20 20 20, což je textový řetězec "TESTING ", který jsem zadal při vytváření souborového systému. Posledních 8 bytů je identifikační řetězec systému, mělo by být "FAT32 ": 46 41 54 33 32 20 20 20, což souhlasí.
Zjistili jsme, že alokační tabulka má velikost 15169 sektorů, což je 7.4 MB. Druhá kopie tabulky leží hned za první. Adresu (číslo sektoru) počátku FAT zjistíme tak, že sečteme první sektor oddílu a počet rezervovaných sektorů, kterých, jak jsme viděli, je 32. Tabulka tedy začíná sektorem číslo 2048 + 32 = 2080. Tento sektor si vypíšeme:

Druhá kopie tabulky leží hned za první, začíná tedy sektorem 2080 + 15169 = 17249. Načteme si i tento sektor:

Porovnáním zjistíme, že data jsou shodná v obou sektorech.
Z tabulky toho příliš nevyčteme, protože zatím nemáme kořenový adresář. Nicméně se podíváme na jednotlivé záznamy, z nichž každý je tvořen čtyřmi byty, přičemž je ale pro zápis čísla clusteru použito pouze 28 bitů (horní 4 bity jsou rezervovány - platí pro FAT32). Vezměme si první 4 záznamy (4 * 4 = 16 bytů) tabulky:
F8 FF FF 0F FF FF FF 0F F8 FF FF 0F 04 00 00 00
Zajímá nás kořenový adresář, o kterém víme, že začíná v clusteru číslo 2. Odpovídající hodnota ve FAT tabulce je F8 FF FF 0F, což je opět "obráceně" 0x0FFFFFF8. Tato hodnota znamená, že data kořenového adresáře jsou uložena pouze v clusteru číslo 2. Záznam clusteru číslo 3 v tabulce obsahuje hodnotu 04 00 00 00, 0x04, což znamená, že cokoli je uloženo v tomto clusteru (číslo 3), tak pokračuje v clusteru číslo 4. Pokud bysme sledovali tuto posloupnost, našli bysme všechny clustery, které patří k danému adresáři nebo souboru. Až bysme narazili na hodnotu FF FF FF 0F, která značí koncový cluster posloupnosti. Číslo prvního clusteru souboru nebo adresáře je uloženo v záznamu adresáře, ve kterém se daný objekt logicky nachází.
Tento adresář se nachází hned za druhou kopií FAT tabulky. Číslo sektoru tedy je 17249 + 15169 = 32418. Sektor číslo 32418 je zároveň začátkem clusteru číslo 2 (jak víme, cluster obsahuje 8 sektorů). Vypíšeme si sektor s kořenovým adresářem:

Každý záznam adresáře je tvořen 32 byty. V našem kořenovém adresáři vidíme 5 záznamů (délka řádků upravena na 32 bytů):
54 45 53 54 49 4E 47 20 20 20 20 08 00 00 A2 5A C5 4C C5 4C 00 00 A2 5A C5 4C 00 00 00 00 00 00
41 50 00 68 00 6F 00 74 00 6F 00 0F 00 BC 32 00 34 00 38 00 33 00 2E 00 6A 00 00 00 70 00 67 00
50 48 4F 54 4F 32 7E 31 4A 50 47 20 00 00 F3 4A C5 4C C5 4C 00 00 F3 4A C5 4C 03 00 5F 75 00 00
41 66 00 6F 00 74 00 6B 00 79 00 0F 00 BE 00 00 FF FF FF FF FF FF FF FF FF FF 00 00 FF FF FF FF
46 4F 54 4B 59 20 20 20 20 20 20 10 00 00 15 4B C5 4C C5 4C 00 00 15 4B C5 4C 0B 00 00 00 00 00
Očekával bych, že v kořenovém adresáři budou jen 2 záznamy, protože jsem na kartu nakopíroval soubor "Photo2483.jpg" a vytvořil adresář "fotky". To jsou 2 objekty v kořenovém adresáři (další soubor "Photo2496.jpg" jsem nakopíroval do adresáře "fotky"). Odpověď spočívá jednak v tom, že první záznam v kořenovém adresáři je název oddílu. A za druhé v tom, že souborový systém FAT32 umožňuje používat tzv. dlouhé názvy souborů a adresářů, což vede k tomu, že každý záznam je minimálně zdvojený.
Podíváme se nejdříve na třetí záznam, což je krátký název souboru "Photo2483.jpg":
50 48 4F 54 4F 32 7E 31 4A 50 47 20 00 00 F3 4A C5 4C C5 4C 00 00 F3 4A C5 4C 03 00 5F 75 00 00
Prvních 11 bytů je krátký název, zde 50 48 4F 54 4F 32 7E 31 4A 50 47, což je text "PHOTO2~1JPG". Další byte je atribut souboru 0x20, což znamená archiv. Následující 2 byty nejsou zajímavé. Dále 2 byty čas vytvoření 0x4AF3, 2 byty datum vytvoření 0x4CC5, 2 byty datum posledního přístupu 0x4CC5. Následující 2 byty horních 16 bitů čísla počátečního clusteru 0x0. Dva byty čas poslední úpravy 0x4AF3, 2 byty datum poslední úpravy 0x4CC5. Dva byty spodních 16 bitů čísla počátečního clusteru 0x03. A konečně 4 byty velikost v bytech 0x755F = 30047 B.
Malá poznámka ke způsobu uložení času a data. Čas je uložen ve formátu hodina (5 bitů), minuta (6 bitů), sekunda (5 bitů). Datum je uložený ve formátu rok (7 bitů), měsíc (4 bity), den (5 bitů).
Druhý záznam je dlouhý název stejného souboru:
41 50 00 68 00 6F 00 74 00 6F 00 0F 00 BC 32 00 34 00 38 00 33 00 2E 00 6A 00 00 00 70 00 67 00
První byte je pořadové číslo záznamů dlouhých jmen patřících jednomu objektu (resp. spodní 4 bity, protože horní 4 bity 0x40 značí poslední z vícero záznamů dlouhého názvu). Dalších 10 bytů je 5 dvoubytových znaků názvu, zde 50 00 68 00 6F 00 74 00 6F 00, což je text "Photo". Následuje jeden byte atribut, 0x0F, což značí dlouhý název. Další 1 byte nás nezajímá. Následující byte je kontrolní součet vytvořený z krátkého názvu. Dvanáct bytů představuje dalších 6 dvoubytových znaků názvu: 32 00 34 00 38 00 33 00 2E 00 6A 00 neboli text "2483.j". Další 2 byty mají být nulové. A nakonec 4 byty se dvěma dvoubytovými znaky: 70 00 67 00, což je text "pg".
Výše zmíněný kontrolní součet se dle informací na stránce https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html spočítá následovně:
int i;
unsigned char sum = 0;
for (i = 0; i < 11; i++)
{
sum = (sum >> 1) + ((sum & 1) << 7);
sum += name[i];
}
V uvedeném kódu proměnná sum obsahuje výsledný součet a proměnná name obsahuje text krátkého názvu souboru, ze kterého se součet počítá. Pokud vezmu za příklad uvedený soubor "Photo2483.jpg", pak proměnná name odkazuje na text "PHOTO2~1JPG".
První záznam kořenového adresáře, jak už bylo řečeno, je název oddílu, prvních 11 bytů 54 45 53 54 49 4E 47 20 20 20 20 je už známý text "TESTING ". Dvanáctý byte s hodnotou 0x08 je atribut říkající, že se jedná o název oddílu.
Pátý záznam obsahuje krátký název adresáře "fotky". Skutečně posloupnost bytů 46 4F 54 4B 59 20 20 20 20 20 20 je text "FOTKY ". Atribut 0x10 znamená adresář. Adresář začíná v clusteru 0x0B. Podíváme se do něho. K tomu potřebujeme přepočítat číslo clusteru 0x0B = 11 na číslo sektoru: 32418 + (11 - 2) * 8 = 32490. Načteme tedy data sektoru číslo 32490:

V adresáři jsou 4 záznamy:
2E 20 20 20 20 20 20 20 20 20 20 10 00 00 08 4B C5 4C C5 4C 00 00 08 4B C5 4C 0B 00 00 00 00 00
2E 2E 20 20 20 20 20 20 20 20 20 10 00 00 08 4B C5 4C C5 4C 00 00 08 4B C5 4C 00 00 00 00 00 00
41 50 00 68 00 6F 00 74 00 6F 00 0F 00 BC 32 00 34 00 39 00 36 00 2E 00 6A 00 00 00 70 00 67 00
50 48 4F 54 4F 32 7E 31 4A 50 47 20 00 00 15 4B C5 4C C5 4C 00 00 15 4B C5 4C 0C 00 B6 AA 00 00
První záznam má atribut 0x10, je to tedy adresář, a v názvu má na prvním místě 0x2E, což je znak tečky "." - takovýto záznam označuje aktuální adresář - vidíme, že odkazuje na stejný cluster 0x0B.
Druhý záznam je také adresář a má v názvu dvě tečky "..", což označuje nadřazený adresář v hierarchii adresářů. Hodnota clusteru je 0, což znamená, že nadřazený adresář je kořenový adresář.
Třetí záznam je dlouhý název souboru.
Čtvrtý záznam je krátký název souboru "Photo2496.jpg". Tento soubor má velikost 0xAAB6 = 43702 B a jeho začátek najdeme v clusteru číslo 0x0C = 12, což je sektor číslo 32418 + (12 - 2) * 8 = 32498. Víme, že soubor bude zabírat 43702/(512 * 8) = 10.7 clusteru přibližně. Stačí nám na ukázku načíst pouze první sektor 32498:

Podíváme se na prvních 20 bytů dat souboru:
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 48 00 48 00 00
To, co vidíme, je hlavička souboru typu JPG. Například od sedmého bytu máme sekvenci 4A 46 49 46 00, což je text "JFIF" ukončený nulou.