[comp.lang.pascal] how can I readout my FAT?

erwvegm@cs.vu.nl (Erwin van Egmond) (04/22/91)

Hi, 
   I'm using TP5.5 and I want to know if and how I can find out
   on wich sector/cluster a file is placed.
   I must probably readout my FAT, but how do I do that?
   Is there someone out there who can help me? Please?

Thankx in advance

		Erwin van Egmond <erwvegm@cs.vu.nl>

P.S
   A while ago I asked something about GIF-pictures in een .EXE file.
   Someone asked me to pass along any info.
   Unfortunately I lost has email adress, so could that someone
   please send me his email adress again?
	


--
++ Erwin van Egmond UUCP: ...!mcsun!cs.vu.nl!erwvegm            ++
++								++
++  With a rubber duck, one's never alone		   	++
++	-- "The Hitchhiker's Guide to the Galaxy"		++

focke@gmdzi.gmd.de (Stefan Focke) (04/22/91)

erwvegm@cs.vu.nl (Erwin van Egmond) writes:

>Hi, 
>   I'm using TP5.5 and I want to know if and how I can find out
>   on wich sector/cluster a file is placed.
>   I must probably readout my FAT, but how do I do that?
>   Is there someone out there who can help me? Please?

Hello,

it is not too hard to do that:

- Read the boot-sektor to find out where your directory and FAT is
- From the directory you get the first cluster of your file
- Than you have to follow the FAT to find all clusters of your file
- You have to find out if you have a 12-bit or a 16-Bit FAT (DOS 4.x)
  I do not know where you can find this information. Who can help?

mfg
  Stefan


-------------------------------------------------------------------

Stefan Focke                  Tel. 02241-14-2265
GMD-Z2.W                      e-mail: focke@gmdzi.uucp
Postfach 1240                         focke@gmdzi.gmd.de 
5205 St. Augustin 1                   ...!{uunet!mcvax!}unido!gmdzi!focke

campbell@cutmcvax.cs.curtin.edu.au (Trevor George Campbell CC361) (04/24/91)

focke@gmdzi.gmd.de (Stefan Focke) writes:

>erwvegm@cs.vu.nl (Erwin van Egmond) writes:

>>   I must probably readout my FAT, but how do I do that?

>- You have to find out if you have a 12-bit or a 16-Bit FAT (DOS 4.x)
>  I do not know where you can find this information. Who can help?

you can tell if it is a 12 bit FAT by the fact that with a you can only
access at most 4087 clusters (?? sectors) using a 12 bits.. (ie: 4096 - 
the flags that indicate end of file... = 4087).  If on the other hand
the disk has more than 4087 (strictly greater) then it must be a 16 bit FAT
.... you can find out how many allocation units the disk has by checking the
DPB (Drive Parameter Block) part of the boot block....

I don't have more info on me at this stage... but if you want I may be able
to e-mail (or post if enough interest) the source for such a program (limited
capabilities) in TURBO ASSEMBLER (with a bit more time I could probably do a
quick program in TURBO PASCAL)....

Trevor    alias <**<TOMCAT>**>

Kai_Henningsen@ms.maus.de (Kai Henningsen) (04/27/91)

Stefan Focke focke @ gmdzi.gmd.de schrieb am 22.04.1991, 08:33

SF>Hello,
SF>
SF>it is not too hard to do that:
SF>
SF>- Read the boot-sektor to find out where your directory and FAT is
SF>- From the directory you get the first cluster of your file
SF>- Than you have to follow the FAT to find all clusters of your file
SF>- You have to find out if you have a 12-bit or a 16-Bit FAT (DOS 4.x)
SF>  I do not know where you can find this information. Who can help?

Well, looks like it's time to post a program I wrote. The purpose is to set the
date of every directory on a disk to that of the youngest file within. Be
warned that, while the program runs without a problem on *my* harddisk (DOS 4),
I do not make any claims that the same will be true elsewhere - the risk is
yours, completely; I wrote this only for myself. You better make a backup
first!!

Also, the code is for TP 6.0, I use the inline assembler. As for comments, well
... Pascal is supposed to be selfdocumenting, no? But ask me if you don't
understand something ...

So, first a support unit   ...

unit DosAbsUt;
interface
uses Dos;
type
  BootRec = record
              jmp: array[1..3] of byte;
              OEM: array[1..8] of char;
              bps: word;
              spc: byte;
              res: word;
              nFAT: byte;
              RootSz: word;
              Size: word;
              Media: byte;
              spFAT: word;
              spt: word;
              nHeads: word;
              res40: longint;
              Size40: longint;
              Phys: byte;
              nix: byte;
              Sig: byte; { $29 }
              ID: longint;
              Volume: array [1..11] of char;
              nix2: array[1..8] of char;
            end;
function AbsRead(Drive: byte; nSecs: word; Start: longint; var Buffer): word;
function AbsWrite(Drive: byte; nSecs: word; Start: longint; var Buffer): word;
function SecSize(Drive: byte): word;
procedure ResetDisk;
implementation
var
  r: registers;
  Dos4Abs : record
              First: longint;
              Count: word;
              Buf: pointer;
            end;
function AbsRead(Drive: byte; nSecs: word; Start: longint; var Buffer): word;
begin
  if lo(dosversion)<4 then begin
    asm {[f-]}
      mov        al, [Drive];
      mov        cx, [nSecs];
      mov        dx, word ptr [Start];
      push        ds;
      lds        bx, [Buffer];
      int        $25;
      jc        @Err;
      xor        ax, ax;
@Err:
      popf;
      pop        ds;
      mov        [@Result], ax
    end {[f+]};
  end
  else begin
    with Dos4Abs do begin
      First:=Start;
      Count:=nSecs;
      Buf:=@Buffer;
    end;
    asm {[f-]}
      mov        al, [Drive];
      mov        cx, -1;
      push        ds;
      mov        bx, seg Dos4Abs;
      mov        ds, bx;
      mov        bx, offset Dos4Abs;
      int        $25;
      jc        @Err;
      xor        ax, ax;
@Err:
      popf;
      pop        ds;
      mov        [@Result], ax
    end {[f+]};
  end;
end;
function AbsWrite(Drive: byte; nSecs: word; Start: longint; var Buffer): word;
begin
  if lo(dosversion)<4 then begin
    asm {[f-]}
      mov        al, [Drive];
      mov        cx, [nSecs];
      mov        dx, word ptr [Start];
      push        ds;
      lds        bx, [Buffer];
      int        $26;
      jc        @Err;
      xor        ax, ax;
@Err:
      popf;
      pop        ds;
      mov        [@Result], ax
    end {[f+]};
  end
  else begin
    with Dos4Abs do begin
      First:=Start;
      Count:=nSecs;
      Buf:=@Buffer;
    end;
    asm {[f-]}
      mov        al, [Drive];
      mov        cx, -1;
      push        ds;
      mov        bx, seg Dos4Abs;
      mov        ds, bx;
      mov        bx, offset Dos4Abs;
      int        $26;
      jc        @Err;
      xor        ax, ax;
@Err:
      popf;
      pop        ds;
      mov        [@Result], ax
    end {[f+]};
  end;
end;
function SecSize(Drive: byte): word;
begin
  with r do begin
    ah:=$1c;
    dl:=drive+1;
    msdos(r);
    secsize:=cx;
  end;
end;
procedure ResetDisk;
begin
  r.ah:=$0d;
  msdos(r);
end;

end.

MfG Kai

Kai_Henningsen@ms.maus.de (Kai Henningsen) (04/27/91)

... and now for the program proper ...
program DirDate;
uses Dos, DosAbsUt, m7utillo;
type
  FATbuf= array[0..65520] of byte;
  FATarray= array[0..16380] of ^FATbuf;
  DIRent = record
             Fn: array[1..8] of char;
             Fe: array[1..3] of char;
             Attr: byte;
             Res: array[$0c..$15] of byte;
             Timestamp: longint;
             Start: word;
             Size: longint;
           end;
  Direct= array[0..2046] of DIRent;
var
  BootSec: ^BootRec;
  p: string;
  dr: byte;
  err: word;
  ss: word;
  Clust: word;
  DskSz: longint;
  FAT0, ROOT0, DATA0: longint;
  FATbytes: longint;
  FATsecs: longint;
  shortFAT: boolean;
  FAT: ^FATarray;
  i: longint;
  dps, dpc: word;
  Indent: word;

  function FATentry(n: word): word;
  type
    wp = ^word;
  var
    b, bm, bd: longint;
    w: word;
  begin
    if shortFAT then b:=n*longint(3) div 2
    else b:=n*longint(2);
    bm:=b mod ss;
    bd:=b div ss;
    if bm+1<ss then w:=wp(@FAT^[bd]^[bm])^
    else w:=FAT^[bd]^[bm] or swap(FAT^[bd+1]^[0]);
    if shortFAT then begin
      if odd(n) then w:=w shr 4
      else w:=w and $FFF;
      if w>=$ff8 then w:=w or $f000;
    end;
    FATentry:=w;
  end;

  procedure WriteName(n,e: string);
  begin
    trim(n);
    trim(e);
    if e='' then write(n,'':12-length(n))
    else write(n,'.',e,'':11-length(n)-length(e));
  end;

  procedure WriteDate(ts: longint);
  var
    dt : DateTime; { For Pack/UnpackTime}
  function LeadingZero(w : Word) : String;
  var
    s : String;
  begin
    Str(w:0,s);
    if Length(s) = 1 then
      s := '0' + s;
    LeadingZero := s;
  end;
  begin
    UnpackTime(ts,dt);
    with dt do
      begin
        Write(day:2,'.',month:2,'.',year,' ',
             LeadingZero(hour),':',LeadingZero(min),':',LeadingZero(sec));
      end;
  end;

  function TraverseSubdir(Start: word): longint;
  forward;

  function Process(var D: DIRent; var dt0: longint): boolean;
  var
    dt: longint;
  begin
    Process:=false;
    with D do begin
      case Fn[1] of
        #0: Process:=true;
        #$E5: ;
        else begin
          write('':indent*2);
          writename(Fn,Fe);
          write('   ');
          writedate(Timestamp);
          writeln;
          if Fn[1]<>'.' then begin
            if (attr and directory)=directory then begin
              dt:=TraverseSubdir(Start);
{              if Timestamp<dt then}
                Timestamp:=dt;
              write('':indent*2);
              writename(Fn,Fe);
              write('   ');
              writedate(Timestamp);
              writeln;
            end;
            if Timestamp>dt0 then dt0:=Timestamp;
          end
          else Timestamp:=0;
        end;
      end;
    end;
  end;

  procedure TraverseRoot;
  var
    CurDir: ^Direct;
    i: word;
    cur: word;
    var dt: longint;
  begin
    dt:=0;
    Indent:=0;
    getmem(CurDir, ss);
    i:=0;
    cur:=$ffff;
    while (i<BootSec^.RootSz) do begin
      if (i div dps)<>cur then begin
        if cur<>$ffff then begin
          err:=AbsWrite(dr, 1, ROOT0+cur, CurDir^);
          if err<>0 then runerror(err);
        end;
        cur:=i div dps;
        err:=AbsRead(dr, 1, ROOT0+cur, CurDir^);
        if err<>0 then runerror(err);
      end;
      if Process(CurDir^[i mod dps], dt) then i:=$ffff
      else inc(i);
    end;
    err:=AbsWrite(dr, 1, ROOT0+cur, CurDir^);
    if err<>0 then runerror(err);
    freemem(CurDir, ss);
  end;

  function TraverseSubdir(Start: word): longint;
  var
    CurDir: ^Direct;
    i: word;
    cur: word;
    dt: longint;
    Last: word;
  begin
    dt:=0;
    inc(Indent);
    getmem(CurDir, Clust*ss);
    i:=0;
    cur:=$ffff;
    Last:=0;
    while (i<$FFFF) do begin
      if (i div dpc)<>cur then begin
        if cur<>$ffff then begin
          err:=AbsWrite(dr, Clust, DATA0+longint(Last)*Clust, CurDir^);
          if err<>0 then runerror(err);
        end;
        cur:=i div dpc;
        if (Start>=$FFF8) or (Start<2) then begin
          fillchar(CurDir^, Clust*ss, 0);
          Last:=0;
        end
        else begin
          err:=AbsRead(dr, Clust, DATA0+longint(Start)*Clust, CurDir^);
          if err<>0 then runerror(err);
          Last:=Start;
          Start:=FATentry(Start);
        end;
      end;
      if Process(CurDir^[i mod dpc], dt) then i:=$ffff
      else inc(i);
    end;
    if Last<>0 then begin
      err:=AbsWrite(dr, Clust, DATA0+longint(Last)*Clust, CurDir^);
      if err<>0 then runerror(err);
    end;
    freemem(CurDir, Clust*ss);
    dec(Indent);
    TraverseSubdir:=dt;
  end;

... rest follows ...

MfG Kai

Kai_Henningsen@ms.maus.de (Kai Henningsen) (04/27/91)

... last part ...


begin
  writeln; writeln;
  ResetDisk;
  p:=paramstr(1);
  if (paramcount<>1) or (length(p)<>1) then runerror;
  dr:=ord(upcase(p[1]))-ord('A');
  ss:=SecSize(dr);
  getmem(bootsec, ss);
  err:=absread(dr, 1, 0, bootsec^);
  if err<>0 then runerror(err);
  with bootsec^do begin
    writeln(OEM);
    FAT0:=res;
    ROOT0:=FAT0+(longint(nFAT)*spFAT);
    DATA0:=ROOT0+(RootSz*longint(sizeof(DIRent))+ss-1) div ss - 2*spc;
    dps:=ss div sizeof(DIRent);
    dpc:=ss*spc div sizeof(DIRent);
    Clust:=spc;
    DskSz:=size;
    if size=0 then begin
      dsksz:=size40;
      if sig=$29 then begin
        writeln(volume,' ',nix2);
      end;
    end;
    FATbytes:=((DskSz-DATA0) div spc)*2;
    if fatbytes<8000 then shortFAT:=true
    else begin
      FATsecs:=(FATbytes+(ss-1)) div ss;
      shortFAT:=FATsecs<>spFAT;
    end;
    if shortFAT then begin
      FATbytes:=(((DskSz-DATA0) div spc)*3+1) div 2;
      FATsecs:=(FATbytes+(ss-1)) div ss;
    end;
    writeln(shortFAT,' ',FATsecs,' ',spFAT);
    if FATsecs<>spFAT then runerror;
    FATsecs:=spFAT;
    FATbytes:=FATsecs*ss;
  end;
  writeln(FAT0,' ',ROOT0,' ',DATA0);
  getmem(FAT, sizeof(pointer)*FATsecs);
  for i:=0 to FATsecs-1 do begin
    getmem(FAT^[i], ss);
    err:=AbsRead(dr, 1, i+FAT0, FAT^[i]^);
    if err<>0 then runerror(err);
  end;
  if FATentry(0)<>($ff00 or BootSec^.Media) then runerror;
  if FATentry(1)<>$ffff then runerror;
  TraverseRoot;
  ResetDisk;
end.

MfG Kai