El siguiente programa permite leer el sector de arranque de una partición del tipo FAT32, el mismo tipo de partición que usan la mayoría de las memorias USB y tarjetas de memoria, y volcar la información que contiene, así como extraer la estructura de directorios directamente de la FAT. La lectura se puede hacer directamente sobre un disco, o sobre un fichero de imagen creado con alguna herramienta como Dump. En futuras versiones tengo intención de poder extraer el contenido de los ficheros, aunque por ahora solo podemos ver su nombre.
El código es el siguiente (es una aplicación de consola):
unit umain; interface uses Windows, Sysutils, Classes; procedure main; implementation type PDWordArray = ^TDWordArray; TDWordArray = array[0..$0FFFFFFF] of DWord; TPartition = record Stream: TFileStream; PartType: Byte; PartBegin: DWord; BytsPerSec: Word; SecPerClus: Byte; BytsPerClus: Word; RsvdSecCnt: Word; NumFATs: Byte; FATSz32: Word; ClusCount: DWord; ClusBegin: DWord; RootClus: DWord; FAT: PDWordArray; end; function Min(i,j: Integer): Integer; begin if i < j then Result:= i else Result:= j; end; // Muestra el contenido del buffer en hexadecimal y como texto procedure WriteHex(Buffer: PAnsiChar; Count: Integer); var i,j: Integer; begin j:= 0; while Count > 0 do begin Write(IntToHex(j,8) + ':' + #32#32); for i:= 0 to Min(Count,8) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); Write(#32); for i:= 8 to Min(Count,16) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); for i:= Min(Count,16) to 15 do Write(#32#32#32); Write(#32 + '|'); for i:= 0 to Min(Count,16) - 1 do if Char(Buffer[i]) in ['A'..'Z','a'..'z','0'..'9'] then Write(Buffer[i]) else Write('.'); Writeln('|'); Dec(Count,16); inc(Buffer,16); inc(j,16); end; end; function FormatFileSize(const Bytes: int64): String; const B = 1; // Byte KB = 1024 * B; // Kilobyte MB = 1024 * KB; // Megabyte GB = 1024 * MB; // Gigabyte begin if Bytes > GB then Result := FormatFloat('0.00 GB', Bytes / GB) else if Bytes > MB then Result := FormatFloat('0.00 MB', Bytes / MB) else if Bytes > KB then Result := FormatFloat('0.00 KB', Bytes / KB) else Result := FormatFloat( '0 ', Bytes); end; // Lee el MasterBootRecord procedure ReadMasterBootRecord(var Partition: TPartition); var i,j: Integer; Buffer: PByteArray; begin // Reservamos memoria para guardar el MBR GetMem(Buffer,$0200); try with Partition do begin // Leemos el MBR Stream.ReadBuffer(Buffer^,$0200); // Volcamos en pantalla el contenido del MBR Writeln('=== Master Boot Record ==='); WriteHex(PAnsiChar(Buffer), $0200); Writeln; // Comprobamos la firma del MBR if PWORD(@Buffer[$01FE])^ <> $AA55 then raise Exception.Create('Invalid MBR signature = ' + IntToHex(Swap(PWORD(@Buffer[$01FE])^),2)); // Volcamos la tabla de particiones Writeln('=== Table ==='); WriteHex(PAnsiChar(@Buffer[$01BE]), $0040); Writeln; // Volcamos cada entrada de la tabla de particiones Writeln('=== Partitions ==='); for i:= 0 to 3 do begin j:= $01BE + (16 * i); if Buffer[j] = $80 then Writeln(Format('[%d] %8.8x/%8.8x A',[i, PDWORD(@Buffer[j + $08])^,PDWORD(@Buffer[j + $0C])^])) else Writeln(Format('[%d] %8.8x/%8.8x',[i, PDWORD(@Buffer[j + $08])^,PDWORD(@Buffer[j + $0C])^])) end; Writeln; // Usamos siempre la primera particion Writeln('Go to partition 0 ...'); Writeln; PartType:= Buffer[$01BE + $04]; PartBegin:= PDWORD(@Buffer[$01BE + $08])^; end; finally FreeMem(Buffer); end; end; // Lee el primer sector de la particion procedure ReadBootSector(var Partition: TPartition); var Buffer: PByteArray; begin // Reservamos memoria para guardar el sector de arranque GetMem(Buffer,$0200); try with Partition do begin // Leemos el sector de arranque Stream.ReadBuffer(Buffer^,$0200); // Volcamos en pantalla el contenido del sector de arranque Writeln('=== Boot Sector ==='); WriteHex(PAnsiChar(Buffer), $0200); Writeln; // Comprobamos la firma del sector de arranque if PWORD(@Buffer[$01FE])^ <> $AA55 then raise Exception.Create('Invalid Boot Sector signature = ' + IntToHex(Swap(PWORD(@Buffer[$01FE])^),2)); // Comprobamos que es FAT32 if PartType <> 0 then begin // si no lo es mostramos el error if not (PartType in [$0B,$0C]) then raise Exception.Create('Invalid Partition Type = 0x' + IntToHex(PartType,2)); Writeln('Partiton type: 0x' + IntToHex(PartType,2) + ' (FAT32)'); end else begin // Si no queda mas remedio usamos el "System ID" if Trim(Copy(PAnsiChar(@Buffer[$0052]),1,8)) <> 'FAT32' then raise Exception.Create('Invalid System ID = ' + Trim(Copy(AnsiString(PAnsiChar(@Buffer[$0052])),1,8))); end; // Mostramos la informacion de la particion por pantalla Writeln('Signature: ' + IntToHex(Swap(PWORD(@Buffer[$01FE])^),2)); Writeln('System ID: ' + Trim(Copy(PAnsiChar(@Buffer[$0052]),1,8))); Writeln('OEM ID: ' + Trim(Copy(PAnsiChar(@Buffer[$0003]),1,8))); Writeln('Volume label: ' + Trim(Copy(PAnsiChar(@Buffer[$0047]),1,11))); Writeln('Volume serial: ' + IntToHex(PDWORD(@Buffer[$0043])^,8)); BytsPerSec:= PWORD(@Buffer[$000B])^; Writeln('Bytes per sector: ' + IntToStr(BytsPerSec)); SecPerClus:= PByte(@Buffer[$000D])^; Writeln('Sectors per cluster: ' + IntToStr(SecPerClus)); BytsPerClus:= BytsPerSec * SecPerClus; Writeln('Bytes per cluster: ' + IntToStr(BytsPerClus)); RsvdSecCnt:= PWORD(@Buffer[$000E])^; Writeln('Reserved sectors: ' + IntToStr(RsvdSecCnt)); NumFATs:= PByte(@Buffer[$0010])^; Writeln('Number of FATs: ' + IntToStr(NumFATs)); FATSz32:= PWORD(@Buffer[$0024])^; Writeln('Sectors per FAT: ' + IntToStr(FATSz32)); ClusCount:= ((FATSz32 * BytsPerSec) div SizeOf(DWord)); Writeln('Cluster count: ' + IntToStr(ClusCount)); ClusBegin:= RsvdSecCnt + (NumFATs * FATSz32); RootClus:= PDWORD(@Buffer[$002C])^; Writeln('Root cluster: ' + IntToStr(RootClus)); Writeln; end; finally // Liberamos la memoria FreeMem(Buffer); end; end; // Lee la FAT procedure ReadFAT(Partition: TPartition); var i: DWord; FreeClus: int64; ResClus: int64; BadClus: int64; begin FreeClus:= 0; ResClus:= 0; BadClus:= 0; with Partition do begin // No colocamos al principio de la FAT Stream.Position:= (PartBegin + RsvdSecCnt) * BytsPerSec; // La cargamos en memoria Stream.ReadBuffer(FAT^, FATSz32 * BytsPerSec); Writeln('=== Clusters ==='); // La recorremos registro a registro for i:= 0 to ClusCount - 1 do begin // y contamos el estado de cada cluster case FAT[i] of 0: inc(FreeClus); $FFFFFF7: inc(BadClus); else inc(ResClus); end; end; // Mostramos los contadores Writeln('Free: ' + IntToStr(FreeClus)); Writeln('Used: ' + IntToStr(ResClus)); Writeln('Bad: ' + IntToStr(BadClus)); Writeln; end; end; // Escribe la FAT en el disco procedure WriteFAT(Partition: TPartition); var i: Byte; begin with Partition do begin Stream.Position:= (PartBegin + RsvdSecCnt) * BytsPerSec; // La escribimos tantas veces como indique el parametro NumFATs for i:= 1 to NumFATs do Stream.WriteBuffer(FAT^, FATSz32 * BytsPerSec); end; end; // Lee un cluster procedure ReadClus(Partition: TPartition; Cluster: DWord; Buffer: PByte); begin with Partition do begin Stream.Position:= (PartBegin + ClusBegin + (Cluster - 2) * SecPerClus) * BytsPerSec; Stream.ReadBuffer(Buffer^, BytsPerClus); end; end; // Escribe un cluster procedure WriteClus(Partition: TPartition; Cluster: DWord; Buffer: PByte); begin with Partition do begin Stream.Position:= (PartBegin + ClusBegin + (Cluster - 2) * SecPerClus) * BytsPerSec; Stream.WriteBuffer(Buffer^, BytsPerClus); end; end; // Lee los datos de un fichero a partir de su primer cluster procedure ReadFileData(Partition: TPartition; Cluster: DWord; Stream: TStream); var Buffer: PByte; begin // Reservamos memoria para guardar los datos de un cluster GetMem(Buffer,Partition.SecPerClus * Partition.BytsPerSec); try // Mientras no se llegue al final del fichero while Cluster < Partition.ClusCount do begin // Leemos el cluster ReadClus(Partition, Cluster, Buffer); // Lo grabamos en el stream Stream.WriteBuffer(Buffer^, Partition.SecPerClus * Partition.BytsPerSec); // Buscamos en la FAT el siguiente cluster Cluster:= Partition.FAT[Cluster]; end; finally FreeMem(Buffer); end; end; // Muestra la estructura de un directorio procedure Tree(Partition: TPartition; Cluster: DWord; Path: String); var Tmp: TMemoryStream; Entry: PAnsiChar; Name: String; Attr: Byte; Size: DWord; FTime: TFILETIME; STime: TSYSTEMTIME; FTimeStr: String; begin // Creamos un stream temporal Tmp:= TMemoryStream.Create; // Reservamos memoria para guardar cada entrada del directorio GetMem(Entry, 32); try // Leemos todas las entradas del directorio ReadFileData(Partition,Cluster,Tmp); Tmp.Position:= 0; // Procesamos cada una de las entradas del directorio while Tmp.Read(Entry^, 32) = 32 do begin // Si el primer byte es cero, significa que es la ultima if Entry[0] = #0 then break; // Si el primer bytes es alguno de estos, ignoramos la entrada if Entry[0] in [#$00,#$05,#$2E,#$E5] then continue; Attr:= Byte(Entry[$0B]); // Ignoramos los nombres largos if (Attr and $0F) = $0F then continue; // Obtenemos la extension Name:= Trim(Copy(Entry,9,3)); if Name <> EmptyStr then Name:= '.' + Name; // y se la sumamos al nombre Name:= Trim(Copy(Entry,1,8)) + Name; // Obtenemos el tamaño Size:= PDWord(@Entry[$1C])^; // La fecha de modificación DosDateTimeToFileTime(PDWord(@Entry[$18])^,PDWord(@Entry[$16])^,FTime); FileTimeToSystemTime(Ftime, STime); FTimeStr:= FormatDateTime('dd/mm/yyyy hh:nn', SystemTimeToDateTime(STime)); // Si es un directorio if Attr and faDirectory = faDirectory then begin Writeln(Format('%s %10.10s %s%s',[FTimeStr,'<DIR>',Path,Name])); // volvemos a llamar esta funcion de forma recursiva Tree(Partition, (PWord(@Entry[$14])^ * $10000) + PWord(@Entry[$1A])^, Path + Name + '\'); end else Writeln(Format('%s %10.10s %s%s',[FTimeStr,FormatFileSize(Size),Path,Name])); end; finally // Liberamos la memoria y el stream FreeMem(Entry); Tmp.Free; end; end; // Esta es la funcion principal procedure main; var C: Char; i: Integer; H: Integer; Str: String; LeerMBR: Boolean; Stream: TFileStream; Partition: TPartition; begin try // Si el archivo como parametro if (ParamCount > 0) and (Copy(ParamStr(1),1,1) <> '/') then begin LeerMBR:= FindCmdLineSwitch('MBR',TRUE); Stream:= TFileStream.Create(ParamStr(1),fmOpenRead or fmShareDenyWrite); end else begin with TStringList.Create do try Add(EmptyStr); Writeln('[' + IntToStr(Count-1) + '] Salir'); // Buscamos todas las unidades for C:= 'A' to 'Z' do begin Str:= '\\.\' + C + ':'; H:= FileOpen(PAnsiChar(Str),fmOpenRead or fmShareDenyNone); // Si se puede abrir lo añadimos a la lista if H > 0 then begin CloseHandle(H); AddObject(Str,TObject(0)); Writeln('[' + IntToStr(Count-1) + '] ' + Str); end; end; // Buscamos todos los discos (al menos los 16 primeros) for i:= 0 to 16 do begin Str:= '\\.\PhysicalDrive' + IntTostr(i); H:= FileOpen(PAnsiChar(Str),fmOpenRead or fmShareDenyNone); // Si se puede abrir lo añadimos a la lista if H > 0 then begin CloseHandle(H); AddObject(Str,TObject(1)); Writeln('[' + IntToStr(Count-1) + '] ' + Str); end; end; i:= -1; while i < 0 do begin Write('Escoge: '); Readln(Str); i:= StrToIntDef(Str,-1); end; Writeln; if i > 0 then begin Stream:= TFileStream.Create(Strings[i],fmOpenRead or fmShareDenyWrite); LeerMBR:= Integer(Objects[i]) = 1; end else Exit; finally Free; end; end; if Stream = nil then Halt; try // Borramos todas las variables Fillchar(Partition,Sizeof(Partition),#0); Partition.Stream:= Stream; // Si nos pasan el parametro /MBR if LeerMBR then begin // Leemos el MBR y buscamos la primera particion ReadMasterBootRecord(Partition); Stream.Position:= 512 * Partition.PartBegin; end; // Leemos el sector de arranque de la particion ReadBootSector(Partition); // Reservamos espacio en memoria para la FAT with Partition do GetMem(FAT,FATSz32 * BytsPerSec); try // Leemos la FAT y la guardamos en memoria ReadFAT(Partition); // Volcamos la informacion en pantalla Tree(Partition, Partition.RootClus, '\'); finally // Liberamos la memoria reservada para la FAT FreeMem(Partition.FAT); end; finally // Liberamos el stream Stream.Free; end; except // Si ocurre un error On E: Exception do begin // Lo mostramos Writeln('Exception: ' + E.Message); Writeln('LastError: ' + SysErrorMessage(GetLastError)); Writeln('ParamStr(1): ' + ParamStr(1)); end; end; Writeln; Writeln('Pulsa [ENTER] para cerrar el programa ...'); Readln; end; end.
El funcionamiento es muy simple, solo hay que tener la precaución de ejecutarlo como administrador
Si no se pasa ningún fichero como parámetro se dan a escoger entre los discos del sistema:
C:\fatexp>fatexp [0] Salir [1] \\.\C: [2] \\.\D: [3] \\.\E: [4] \\.\F: [5] \\.\PhysicalDrive0 [6] \\.\PhysicalDrive1 [7] \\.\PhysicalDrive2 Escoge:
Solo tenemos que escoger el disco y nos mostrara algo como esto:
[0] Salir [1] \\.\C: [2] \\.\D: [3] \\.\E: [4] \\.\F: [5] \\.\G: [6] \\.\PhysicalDrive0 [7] \\.\PhysicalDrive1 [8] \\.\PhysicalDrive2 [9] \\.\PhysicalDrive3 Escoge: === Master Boot Record === 00000000: 33 C0 8E D0 BC 00 7C 8E C0 8E D8 BE 00 7C BF 00 |3...............| 00000010: 06 B9 00 02 FC F3 A4 50 68 1C 06 CB FB B9 04 00 |.......Ph.......| 00000020: BD BE 07 80 7E 00 00 7C 0B 0F 85 0E 01 83 C5 10 |................| 00000030: E2 F1 CD 18 88 56 00 55 C6 46 11 05 C6 46 10 00 |.....V.U.F...F..| 00000040: B4 41 BB AA 55 CD 13 5D 72 0F 81 FB 55 AA 75 09 |.A..U...r...U.u.| 00000050: F7 C1 01 00 74 03 FE 46 10 66 60 80 7E 10 00 74 |....t..F.f.....t| 00000060: 26 66 68 00 00 00 00 66 FF 76 08 68 00 00 68 00 |.fh....f.v.h..h.| 00000070: 7C 68 01 00 68 10 00 B4 42 8A 56 00 8B F4 CD 13 |.h..h...B.V.....| 00000080: 9F 83 C4 10 9E EB 14 B8 01 02 BB 00 7C 8A 56 00 |..............V.| 00000090: 8A 76 01 8A 4E 02 8A 6E 03 CD 13 66 61 73 1C FE |.v..N..n...fas..| 000000A0: 4E 11 75 0C 80 7E 00 80 0F 84 8A 00 B2 80 EB 84 |N.u.............| 000000B0: 55 32 E4 8A 56 00 CD 13 5D EB 9E 81 3E FE 7D 55 |U2..V..........U| 000000C0: AA 75 6E FF 76 00 E8 8D 00 75 17 FA B0 D1 E6 64 |.un.v....u.....d| 000000D0: E8 83 00 B0 DF E6 60 E8 7C 00 B0 FF E6 64 E8 75 |.............d.u| 000000E0: 00 FB B8 00 BB CD 1A 66 23 C0 75 3B 66 81 FB 54 |.......f..u.f..T| 000000F0: 43 50 41 75 32 81 F9 02 01 72 2C 66 68 07 BB 00 |CPAu2....r.fh...| 00000100: 00 66 68 00 02 00 00 66 68 08 00 00 00 66 53 66 |.fh....fh....fSf| 00000110: 53 66 55 66 68 00 00 00 00 66 68 00 7C 00 00 66 |SfUfh....fh....f| 00000120: 61 68 00 00 07 CD 1A 5A 32 F6 EA 00 7C 00 00 CD |ah.....Z2.......| 00000130: 18 A0 B7 07 EB 08 A0 B6 07 EB 03 A0 B5 07 32 E4 |..............2.| 00000140: 05 00 07 8B F0 AC 3C 00 74 09 BB 07 00 B4 0E CD |........t.......| 00000150: 10 EB F2 F4 EB FD 2B C9 E4 64 EB 00 24 02 E0 F8 |.........d......| 00000160: 24 02 C3 49 6E 76 61 6C 69 64 20 70 61 72 74 69 |...Invalid.parti| 00000170: 74 69 6F 6E 20 74 61 62 6C 65 00 45 72 72 6F 72 |tion.table.Error| 00000180: 20 6C 6F 61 64 69 6E 67 20 6F 70 65 72 61 74 69 |.loading.operati| 00000190: 6E 67 20 73 79 73 74 65 6D 00 4D 69 73 73 69 6E |ng.system.Missin| 000001A0: 67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 |g.operating.syst| 000001B0: 65 6D 00 00 00 63 7B 9A 00 00 00 00 00 00 80 02 |em...c..........| 000001C0: 03 00 0B FE 7F EB 80 00 00 00 80 BF 78 00 00 00 |............x...| 000001D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000001E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000001F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA |..............U.| === Table === 00000000: 80 02 03 00 0B FE 7F EB 80 00 00 00 80 BF 78 00 |..............x.| 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| === Partitions === [0] 00000080/0078BF80 A [1] 00000000/00000000 [2] 00000000/00000000 [3] 00000000/00000000 Go to partition 0 ... === Boot Sector === 00000000: EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 08 C0 03 |.X.MSDOS5.0.....| 00000010: 02 00 00 00 00 F8 00 00 3F 00 FF 00 80 00 00 00 |................| 00000020: 80 BF 78 00 20 1E 00 00 00 00 00 00 02 00 00 00 |..x.............| 00000030: 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000040: 80 00 29 47 5D 32 AA 4E 4F 20 4E 41 4D 45 20 20 |...G.2.NO.NAME..| 00000050: 20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4 |..FAT32...3.....| 00000060: 7B 8E C1 8E D9 BD 00 7C 88 4E 02 8A 56 40 B4 41 |.........N..V..A| 00000070: BB AA 55 CD 13 72 10 81 FB 55 AA 75 0A F6 C1 01 |..U..r...U.u....| 00000080: 74 05 FE 46 02 EB 2D 8A 56 40 B4 08 CD 13 73 05 |t..F....V.....s.| 00000090: B9 FF FF 8A F1 66 0F B6 C6 40 66 0F B6 D1 80 E2 |.....f....f.....| 000000A0: 3F F7 E2 86 CD C0 ED 06 41 66 0F B7 C9 66 F7 E1 |........Af...f..| 000000B0: 66 89 46 F8 83 7E 16 00 75 38 83 7E 2A 00 77 32 |f.F.....u8....w2| 000000C0: 66 8B 46 1C 66 83 C0 0C BB 00 80 B9 01 00 E8 2B |f.F.f...........| 000000D0: 00 E9 2C 03 A0 FA 7D B4 7D 8B F0 AC 84 C0 74 17 |..............t.| 000000E0: 3C FF 74 09 B4 0E BB 07 00 CD 10 EB EE A0 FB 7D |..t.............| 000000F0: EB E5 A0 F9 7D EB E0 98 CD 16 CD 19 66 60 80 7E |............f...| 00000100: 02 00 0F 84 20 00 66 6A 00 66 50 06 53 66 68 10 |......fj.fP.Sfh.| 00000110: 00 01 00 B4 42 8A 56 40 8B F4 CD 13 66 58 66 58 |....B.V.....fXfX| 00000120: 66 58 66 58 EB 33 66 3B 46 F8 72 03 F9 EB 2A 66 |fXfX.3f.F.r....f| 00000130: 33 D2 66 0F B7 4E 18 66 F7 F1 FE C2 8A CA 66 8B |3.f..N.f......f.| 00000140: D0 66 C1 EA 10 F7 76 1A 86 D6 8A 56 40 8A E8 C0 |.f....v....V....| 00000150: E4 06 0A CC B8 01 02 CD 13 66 61 0F 82 75 FF 81 |.........fa..u..| 00000160: C3 00 02 66 40 49 75 94 C3 42 4F 4F 54 4D 47 52 |...f.Iu..BOOTMGR| 00000170: 20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000001A0: 00 00 00 00 00 00 00 00 00 00 00 00 0D 0A 52 65 |..............Re| 000001B0: 6D 6F 76 65 20 64 69 73 6B 73 20 6F 72 20 6F 74 |move.disks.or.ot| 000001C0: 68 65 72 20 6D 65 64 69 61 2E FF 0D 0A 44 69 73 |her.media....Dis| 000001D0: 6B 20 65 72 72 6F 72 FF 0D 0A 50 72 65 73 73 20 |k.error...Press.| 000001E0: 61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 61 |any.key.to.resta| 000001F0: 72 74 0D 0A 00 00 00 00 00 AC CB D8 00 00 55 AA |rt............U.| Partiton type: 0x0B (FAT32) Signature: 55AA System ID: FAT32 OEM ID: MSDOS5.0 Volume label: NO NAME Volume serial: AA325D47 Bytes per sector: 512 Sectors per cluster: 8 Bytes per cluster: 4096 Reserved sectors: 960 Number of FATs: 2 Sectors per FAT: 7712 Cluster count: 987136 Root cluster: 2 === Clusters === Free: 983750 Used: 3386 Bad: 0 27/04/2012 22:42 <DIR> \UNO 27/04/2012 22:42 0 \UNO\TRES.TXT 27/04/2012 22:42 0 \DOS.TXT 22/01/2012 17:47 <DIR> \WILLIA~1 14/06/2011 18:39 625,31 KB \WILLIA~1\LAMµQU~1.AZW 14/06/2011 18:39 466,13 KB \WILLIA~1\MONALI~1.MOB 14/06/2011 18:39 341,71 KB \WILLIA~1\NEUROM~1.AZW 22/01/2012 17:47 <DIR> \WILLIA~2 14/06/2011 18:39 305,49 KB \WILLIA~2\ELSE¥O~1.MOB ... etc ...
Por ultimo solo recordar que el programa se puede usar con imágenes de disco creadas con Dump, por ejemplo:
fatexp imagen.bin
El código y el programa ya compilado se pueden bajar de aquí
Enlaces de interés:
Dump - http://delphi.jmrds.com/node/45
http://www.pjrc.com/tech/8051/ide/fat32.html
http://en.wikipedia.org/wiki/File_Allocation_Table
http://en.wikipedia.org/wiki/Master_boot_record
http://technet.microsoft.com/en-us/library/cc977221.aspx