Portál AbcLinuxu, 1. května 2025 04:52

Oprava root dir na FAT16

25.12.2007 14:34 | Přečteno: 1157× | Linux | poslední úprava: 25.12.2007 15:39

Před týdnem mi po probuzení PDA ze suspendu přestaly fungovat nainstalované aplikace. Zjistil jsem že root dir na SD kartě (2GB, FAT16) najednou obsahuje nesmyslné položky. Bohužel jsem ta data potřeboval, tak jsem dd-čkem zkopíroval image na desktop, a sháněl něco čím to opravit. Nástrojů hafo (jak pro win tak pro lin), ovšem žádný nefungoval, tak jsem ho musel napsat sám.

Tento zápisek je pro případ, že by Windows Mobile 6 opět napadlo že zápis náhodného sektoru do root dir je dobrý nápad, a já bych to musel psát znovu. Algoritmus: načte se FAT, identifikují se konce chainů (0xffff marker), zpětně se dojde na začátek chainu, načte se cluster a otestuje se jestli je to začátek adresáře. Pokud ano a .. ukazuje na cluster 0, je tento chain adresářem odkazovaným z root dir. Takto nalezené adresáře se proto zapíšou jako nová root dir. Soubory v root dir mě nezajímají, to co jsem potřeboval bylo v adresářích. Jejich jména si skript samozřejmě musí vyvyslet.

Vážně by mě zajímalo co se vlastně stalo. FAT i data byly v pořádku, jen byl přepsán root dir. Taky jsem si všiml že poslední dva bajty boot sectoru nebyly jak má správně být 0xaa, 0x55 ale 0xff, 0x55.

from struct import unpack, pack
from string import split
from array import array

# read boot sec
f = open('image', 'r+')
bps, spc, res, fats, rdir, spf, secs, fat = \
    unpack('<11xHBHBH3xH8xI18x8s450x', f.read(512))
fat = split(fat)[0]
if fat != "FAT16": raise
rdir = (rdir * 32 + bps - 1) / bps
clu0 = res + fats * spf + rdir
clus = (secs - clu0) / spc
print "DISK: %d + %d * %d %s + %d" % (res, fats, spf, fat, rdir)
print "DATA: %d * %d * %d" % (clus, spc, bps)

# read fat
prev = {}
f.seek(res * bps)
for i, x in enumerate(array("H", f.read(spf * bps))):
    prev.setdefault(x, []).append(i)

# process chains
root = ''
for i in prev[0xffff]:
    chain = []
    while 1:
        chain.append(i)
        try: i, = prev[i]
        except: break
    if i < 2 or len(chain) > 5:
        continue
    # read first 2 dir entries
    f.seek((clu0 + (i - 2) * spc) * bps)
    n1, c1, s1, n2, c2, s2 = unpack('<' + '12s14xHI'*2, f.read(64))
    if n1 == '.          \x10' and c1 == i and s1 == 0 and \
       n2 == '..         \x10' and c2 == 0 and s2 == 0:
        root += 'DIR%-5d   \x10' % i + pack('<14xHI', i, 0)

# write new root dir
if len(root) > rdir * bps: raise
f.seek((res + fats * spf) * bps)
f.write(root + '\0' * (rdir * bps - len(root)))
       

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.