unit Partition;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type

{$A-,Z+}

 TPartEntry = record
	boot_ind    : Byte;		// 0x80 - active
	head        : Byte;		// starting head
	sector      : Byte;		// starting sector
	cyl         : Byte;		// starting cylinder
	sys_ind     : Byte;		// What partition type
	end_head    : Byte;		// end head
	end_sector  : Byte;	   // end sector
	end_cyl     : Byte;		// end cylinder
	start_sect  : UINT;	   // starting sector counting from 0
	nr_sects    : UINT;  	// nr of sectors in partition
  end;

  TDiskTable = record
   Data  : array[1..446] of Char;
   Table : array[1..4] of TPartEntry;

   Signature : WORD;
  end;

{$A+,Z+}

 TPartition = class
// private
  public
   DriveNo              : Integer;
   PartNo               : Integer;
   FileName             : String;

   Cylinders         : _LARGE_INTEGER;
   MediaType         : Integer;
   TracksPerCylinder : DWORD;
   SectorsPerTrack   : DWORD;
   BytesPerSector    : DWORD;

   PartitionType        : Integer;
   BootIndicator        : BOOLEAN;
   RecognizedPartition  : BOOLEAN;
   RewritePartition     : BOOLEAN;
   StartingOffset       : _LARGE_INTEGER;//TLargeInteger;
   PartitionLength      : _LARGE_INTEGER;//TLargeInteger;
   HiddenSectors        : DWORD;

 public
   procedure Dump;
 end;

 TPartitionList = class
 public
   ScanFloppy : Boolean;

   constructor Create;
   destructor Destroy; override;

   procedure NT_Scan(PartType : Integer);
   procedure LL_Scan(PartType : Integer);
   procedure Win95_Scan(PartType : Integer);
   procedure Dump;
   function Count : Integer;
   function GetPartition(i : Integer) : TPartition;

 private
   Partitions : TList;

   function MediaPresent(h : THandle) : Boolean;
 end;


 function YesNo(b : Boolean) : String;


implementation

uses WinIOCTL, ex2explore, DiskIO;


function YesNo(b : Boolean) : String;
begin
   if b then
   begin
      Result := 'Yes';
   end
   else
   begin
      Result := 'No';
   end;
end;

function LockVolume(h : THandle) : Boolean;
var
   ReturnedByteCount : DWORD;
begin
   Result := DeviceIoControl(h,
                CtlCode(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
                nil,
                0,
                nil,
                0,
                ReturnedByteCount,
                nil);
end;

function UnLockVolume(h : THandle) : Boolean;
var
   ReturnedByteCount : DWORD;
begin
   Result := DeviceIoControl(h,
                CtlCode(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS),
                nil,
                0,
                nil,
                0,
                ReturnedByteCount,
                nil);
end;

constructor TPartitionList.Create;
begin
   ScanFloppy := False;
   Partitions := TList.Create;
end;

destructor TPartitionList.Destroy;
var
   i : Integer;
begin
   for i := 0 to Partitions.Count - 1 do
   begin
      TPartition(Partitions[i]).Free;
   end;
   Partitions.Free;
end;

function TPartitionList.Count : Integer;
begin
   Result := Partitions.Count;
end;

function TPartitionList.GetPartition(i : Integer) : TPartition;
begin
   Result := TPartition(Partitions[i]);
end;

// This does a Low Level scan (reads partition table from disk);
procedure TPartitionList.LL_Scan(PartType : Integer);
var
   DriveNo  : Integer;
   FileName : String;
   h        : THandle;
   Err      : Integer;
   Geometry : TDISK_GEOMETRY;
   Length   : DWORD;
   PartNo   : Integer;
   ExtendedStart : ULong;

   procedure AddFloppy(h : THandle);
   var
      Size     : DWORD;
      NewPart  : TPartition;
   begin
      NewPart := TPartition.Create;
      Partitions.add(NewPart);
      NewPart.DriveNo   := DriveNo;
      NewPart.FileName  := FileName;

      NewPart.Cylinders          := Geometry.Cylinders;
      NewPart.TracksPerCylinder  := Geometry.TracksPerCylinder;
      NewPart.SectorsPerTrack    := Geometry.SectorsPerTrack;
      NewPart.BytesPerSector     := Geometry.BytesPerSector;
      NewPart.MediaType          := Geometry.MediaType;

      Size := {Round}(Geometry.Cylinders.QuadPart) * Geometry.TracksPerCylinder * Geometry.SectorsPerTrack;

      NewPart.PartitionType            := PartType;
      NewPart.BootIndicator            := False;
      NewPart.RecognizedPartition      := True;
      NewPart.RewritePartition         := False;
      NewPart.PartNo                   := 0;
      NewPart.StartingOffset.QuadPart  := 0;
      NewPart.PartitionLength.QuadPart := Size;
      NewPart.PartitionLength.QuadPart := NewPart.PartitionLength.QuadPart * Geometry.BytesPerSector;
      NewPart.HiddenSectors            := 0;
   end;

   function ProcessSector(h : THandle; Sector : ULong; Depth : Integer) : Boolean;
   var
      Size     : DWORD;
      Buffer   : TDiskTable;
      i        : Integer;
      SeekPos  : _LARGE_INTEGER; //TLargeInteger;
      NewPart  : TPartition;
   begin
      Result := True;
      Size := sizeof(Buffer);
      Debug('Looking for table at sector ' + IntToStr(Sector), DebugMedium);


      SeekPos.QuadPart := Sector;
      SeekPos.QuadPart := SeekPos.QuadPart * 512;

      if SetFilePointer(h, SeekPos.LowPart, @SeekPos.HighPart, FILE_BEGIN) = $FFFFFFFF then
      begin
         Debug('Seek error ' + IntToStr(GetLastError), DebugOff);
         Result := False;
      end
      else
      begin
         if not ReadFile2(h, @Buffer, Size, Size, nil) then
         begin
            Result := False;
            exit;
         end;
         Debug('Signature is ' + IntToHex(Buffer.Signature, 4), DebugMedium);
         if (Buffer.Signature = $AA55) then
         begin
            for i := 1 to 4 do
            begin
               Debug('Processing partitions', DebugMedium);
               if Buffer.Table[i].sys_ind <> 0 then
               begin
                  Debug('Partition           ' + IntToStr(i) + ' /dev/hdx' + IntToStr(PartNo), DebugMedium);
//                  Debug(S + 'boot indicator      ' + IntToHex(Buffer.Table[i].boot_ind,2));
//                  Debug(S + 'starting head       ' + IntToStr(Buffer.Table[i].head));
//                  Debug(S + 'starting sector     ' + IntToStr(Buffer.Table[i].sector));
//                  Debug(S + 'starting cylinder   ' + IntToStr(Buffer.Table[i].cyl));
                  Debug(' partition type      ' + IntToHex(Buffer.Table[i].sys_ind,2), DebugMedium);
                  case Buffer.Table[i].sys_ind of
                     PARTITION_EXTENDED         : Debug('Extended... (dos)', DebugMedium);
                     PARTITION_EXTENDED_LINUX   : Debug('Extended... (linux)', DebugMedium);
                     PARTITION_EXTENDED_WIN98   : Debug('Extended... (win98)', DebugMedium);
                     PARTITION_FAT_16           : Debug('FAT 16', DebugMedium);
                     PARTITION_HUGE             : Debug('VFAT', DebugMedium);
                     PARTITION_IFS              : Debug('NTFS', DebugMedium);
                     PARTITION_LINUX            : Debug('Linux', DebugMedium);
                     PARTITION_LINUX_SWAP       : Debug('Linux Swap', DebugMedium);
                  else
                     Debug('Unknown', DebugMedium);
                  end;
//                  Debug(S + 'end head            ' + IntToStr(Buffer.Table[i].end_head));
//                  Debug(S + 'end sector          ' + IntToStr(Buffer.Table[i].end_sector));
//                  Debug(S + 'end cylinder        ' + IntToStr(Buffer.Table[i].end_cyl));
                  Debug(' starting sector     ' + IntToStr(Buffer.Table[i].start_sect), DebugMedium);
                  Debug(' number of sectors   ' + IntToStr(Buffer.Table[i].nr_sects), DebugMedium);
                  Debug('', DebugMedium);


//                  else
                  begin
                     if (Buffer.Table[i].sys_ind = PartType) or (PartType = 0) then
                     begin
                        NewPart := TPartition.Create;
                        Partitions.add(NewPart);
                        NewPart.DriveNo   := DriveNo;
                        NewPart.FileName  := FileName;

                        NewPart.Cylinders          := Geometry.Cylinders;
                        NewPart.TracksPerCylinder  := Geometry.TracksPerCylinder;
                        NewPart.SectorsPerTrack    := Geometry.SectorsPerTrack;
                        NewPart.BytesPerSector     := Geometry.BytesPerSector;
                        NewPart.MediaType          := Geometry.MediaType;

                        NewPart.PartitionType            := Buffer.Table[i].sys_ind;
                        NewPart.BootIndicator            := (Buffer.Table[i].boot_ind = $80);
                        NewPart.RecognizedPartition      := True;
                        NewPart.RewritePartition         := False;
                        NewPart.PartNo                   := PartNo;
                        NewPart.StartingOffset.QuadPart  := (Buffer.Table[i].start_sect + Sector);// Offset from start of partition
                        NewPart.StartingOffset.QuadPart  := NewPart.StartingOffset.QuadPart * Geometry.BytesPerSector;
                        NewPart.PartitionLength.QuadPart := Buffer.Table[i].nr_sects;
                        NewPart.PartitionLength.QuadPart := NewPart.PartitionLength.QuadPart * Geometry.BytesPerSector;
                        NewPart.HiddenSectors            := 0;

                     end;
//                     if (Buffer.Table[i].sys_ind = PARTITION_EXTENDED) and (PartNo > 4) then
                     if (Buffer.Table[i].sys_ind in EXTENDED_PARTITIONS) and (PartNo > 4) then
                     begin
                        Dec(PartNo); // We do not want to assign a number to extend partitions after the 1st (I don't know why?, it is what Linux does)
                     end;
                  end;
                  Inc(PartNo);
               end;
            end;
            for i := 1 to 4 do
            begin
//               if Buffer.Table[i].sys_ind = PARTITION_EXTENDED then
               if Buffer.Table[i].sys_ind in EXTENDED_PARTITIONS then
               begin
                  Debug('Processing extended partition....', DebugMedium);
                  if Depth < 32 then
                  begin
                     if PartNo < 5 then
                     begin
                        PartNo := 5;
                     end;
                     if Depth = 1 then
                     begin
                        ExtendedStart := Sector;
                     end;
                     // There is a new partition table at offset start_sect...
                     if Depth >= 2 then
                     begin
                     if not ProcessSector(h, ExtendedStart + Buffer.Table[i].start_sect, Depth + 1) then
                        begin
                           Debug('Did not seem to be a valid extended partition', DebugMedium);
                        end;
                     end
                     else
                     begin
                        if not ProcessSector(h, Sector + Buffer.Table[i].start_sect, Depth + 1) then
                        begin
                           Debug('Did not seem to be a valid extended partition', DebugMedium);
                        end;
                     end;
                  end
                  else
                  begin
                     Debug('More than 32 partitions detected! This is most likely a bug!', DebugOff);
                  end;
               end;
            end;
         end
         else
         begin
            Result := False;
         end;
      end;
   end;
begin
   DriveNo := 0;

   while true do
   begin
      Debug('Opening device...', DebugHigh);
      FileName := '\\.\PHYSICALDRIVE' + IntToStr(DriveNo);
      Debug(FileName, DebugMedium);
      h := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ	, nil, OPEN_EXISTING, 0, 0);
      if h = INVALID_HANDLE_VALUE then
      begin
         Err := GetLastError;
         if Err = 5 then
         begin
            MessageDlg('This program requires Administrator privilages to run', mtError, [mbOK], 0);
            break; // out of while loop
         end
         else if Err = 2 then
         begin
            // no more physical drives found...
            break;
         end
         else
         begin
            MessageDlg('Unknown error scanning ' + FileName + ' errorcode = ' + IntToStr(Err), mtError, [mbOK], 0);
            break;
         end;
      end
      else // we have the handle, lets look at the partitions....
      begin
         // first see if the media is present...
         if not MediaPresent(h) then
         begin
            Debug('Media not present', DebugOff);
         end
         else
         begin
            Debug('Reading drive geometry...', DebugHigh);
            if not DeviceIOControl(h, CtlCode(FILE_DEVICE_DISK, 0, METHOD_BUFFERED, FILE_ANY_ACCESS),
                              nil, 0,
                              Pointer(@Geometry), sizeof(Geometry),
                              Length, nil) then
            begin
               MessageDlg('Error reading drive geometry. errorcode = ' + IntToStr(GetLastError), mtError, [mbOK], 0);
               break;
            end;
            Debug(MediaDescription(Geometry.MediaType), DebugMedium);
            // Time to read the table
            PartNo := 1;
            ExtendedStart := 0;
            ProcessSector(h, 0, 0);
         end;
         CloseHandle(h);
         Inc(DriveNo);
      end;
   end;

   ////////////////////////////////////////////
   ////////////////////////////////////////////
   ////////////////////////////////////////////
   ////////////////////////////////////////////

   if ScanFloppy then
   begin
      DriveNo := 0;

      while true do
      begin
         FileName := '\\.\' + Char(Ord('A') + DriveNo) + ':';
         Debug(FileName, DebugMedium);
         h := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
//         h := CreateFile(PChar(FileName), 0, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
         if h = INVALID_HANDLE_VALUE then
         begin
            Err := GetLastError;
            if Err = 5 then
            begin
               MessageDlg('This program requires Administrator privilages to run', mtError, [mbOK], 0);
               break; // out of while loop
            end
            else if Err = 2 then
            begin
               // no more physical drives found...
               break;
            end
            else if Err = 21 then
            begin
               Debug('Drive not ready (no disk?)', DebugMedium);
               break;
            end
            else
            begin
               MessageDlg('Unknown error scanning ' + FileName + ' errorcode = ' + IntToStr(Err), mtError, [mbOK], 0);
               break;
            end;
         end
         else // we have the handle, lets look at the partitions....
         try
//            LockVolume(h);
            // first see if the media is present...
            begin
               if not DeviceIOControl(h, CtlCode(FILE_DEVICE_DISK, 0, METHOD_BUFFERED, FILE_ANY_ACCESS),
                                 nil, 0,
                                 Pointer(@Geometry), sizeof(Geometry),
                                 Length, nil) then
               begin
                  Err := GetLastError;
                  if Err <> 21 then
                  begin
                     MessageDlg('Error reading drive geometry. errorcode = ' + IntToStr(GetLastError), mtError, [mbOK], 0);
                  end;
                  break;
               end;
               Debug(MediaDescription(Geometry.MediaType), DebugMedium);
               if (Geometry.MediaType = Media_Type_Unknown) and (MediaPresent(h) = False) then
               begin
                  Debug('Media not present', DebugOff);
               end
               else
               begin
                  // Time to read the table
                  PartNo := 1;
                  ExtendedStart := 0;
                  ProcessSector(h, 0, 0);
                  Debug('PartNo = ' + IntToStr(PartNo), DebugMedium);
//                  if PartNo = 1 then
                  begin
                     // no Partitons found, should we add the whole disk?
                     AddFloppy(h);
                  end;
               end;
            end;
         finally
//            UnLockVolume(h);
            CloseHandle(h);
            Inc(DriveNo);
         end;
      end;
   end;
end;

procedure TPartitionList.NT_Scan(PartType : Integer);
var
   DriveNo  : Integer;
   h        : THandle;
   Buffer   : String;
   Length   : DWORD;
   Layout   : PDRIVE_LAYOUT_INFORMATION;
   Geometry : TDISK_GEOMETRY;
   i        : Integer;
   Err      : DWORD;
   FileName : String;
   NewPart  : TPartition;
begin
   DriveNo := 0;

   while true do
   begin
      FileName := '\\.\PHYSICALDRIVE' + IntToStr(DriveNo);
      h := CreateFile(PChar(FileName), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
      if h = INVALID_HANDLE_VALUE then
      begin
         Err := GetLastError;
         if Err = 5 then
         begin
            MessageDlg('This program requires Administrator privilages to run', mtError, [mbOK], 0);
            break; // out of while loop
         end
         else if Err = 2 then
         begin
            // no more physical drives found...
            break;
         end
         else
         begin
            MessageDlg('Unknown error scanning ' + FileName + ' errorcode = ' + IntToStr(Err), mtError, [mbOK], 0);
            break;
         end;
      end
      else // we have the handle, lets look at the partitions....
      begin
         // read the disk geometry, so we know sector size it there are any Linux partitions...
         Debug('Looking at geometry...', DebugHigh);
         if not DeviceIOControl(h, CtlCode(FILE_DEVICE_DISK, 0, METHOD_BUFFERED, FILE_ANY_ACCESS),
                           nil, 0,
                           Pointer(@Geometry), sizeof(Geometry),
                           Length, nil) then
         begin
            MessageDlg('Error reading drive geometry. errorcode = ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            break;
         end;


         Length := sizeof(TDRIVE_LAYOUT_INFORMATION) + (sizeof(TPARTITION_INFORMATION) * 128); //enough for 128 partitions...
         Debug('Buffer length is ' + IntToStr(Length), DebugMedium);
         SetLength(Buffer, Length);
         Debug('Looking at drive layout...', DebugHigh);
         if DeviceIOControl(h, CtlCode(FILE_DEVICE_DISK, 3, METHOD_BUFFERED, FILE_READ_ACCESS),
                           nil, 0,
                           Pointer(Buffer), Length,
                           Length, nil) then
         begin
            Layout := Pointer(Buffer);
            Debug('There seems to be ' + IntToStr(Layout.PartitionCount) + ' partitions', DebugMedium);
            for i := 0 to Layout.PartitionCount - 1 do
            begin
               Debug('Partition ' + IntToStr(i), DebugMedium);
               if Layout.PartitionEntry[i].PartitionType <> PARTITION_ENTRY_UNUSED then
               begin
                  Debug('is type ' + IntToStr(Layout.PartitionEntry[i].PartitionType), DebugMedium);
                  if (Layout.PartitionEntry[i].PartitionType = PartType) or (PartType = 0) then
                  begin
                     begin
                        NewPart := TPartition.Create;
                        Partitions.add(NewPart);
                        NewPart.DriveNo   := DriveNo;
                        NewPart.FileName  := FileName;

                        NewPart.Cylinders          := Geometry.Cylinders;
                        NewPart.TracksPerCylinder  := Geometry.TracksPerCylinder;
                        NewPart.SectorsPerTrack    := Geometry.SectorsPerTrack;
                        NewPart.BytesPerSector     := Geometry.BytesPerSector;
                        NewPart.MediaType          := Geometry.MediaType;

                        NewPart.PartitionType         := Layout.PartitionEntry[i].PartitionType;
                        NewPart.BootIndicator         := Layout.PartitionEntry[i].BootIndicator;
                        NewPart.RecognizedPartition   := Layout.PartitionEntry[i].RecognizedPartition;
                        NewPart.RewritePartition      := Layout.PartitionEntry[i].RewritePartition;
                        NewPart.RecognizedPartition   := Layout.PartitionEntry[i].RecognizedPartition;
                        NewPart.PartNo                := Layout.PartitionEntry[i].PartitionNumber;
                        NewPart.StartingOffset        := Layout.PartitionEntry[i].StartingOffset;
                        NewPart.PartitionLength       := Layout.PartitionEntry[i].PartitionLength;
                        NewPart.HiddenSectors         := Layout.PartitionEntry[i].HiddenSectors;

                     end;
                  end;
                  Debug('Starting offset ' + IntToStr(Layout.PartitionEntry[i].StartingOffset.QuadPart), DebugMedium);
                  Debug('Length          ' + IntToStr(Layout.PartitionEntry[i].PartitionLength.QuadPart), DebugMedium);
               end
               else
               begin
                  Debug('is not a partition', DebugMedium);
               end;
            end;
         end
         else
         begin
            MessageDlg('Error reading drive layout. errorcode = ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            break;
         end;
      end;
      CloseHandle(h);
      inc(DriveNo);
   end;
end;

function TPartitionList.MediaPresent(h : THandle) : Boolean;
var
   Length : DWord;
begin
   Debug('Looking for media...', DebugHigh);
   Result := DeviceIOControl(h, CtlCode(IOCTL_STORAGE_BASE, $200, METHOD_BUFFERED, FILE_READ_ACCESS),
       nil, 0, nil, 0, Length, nil)
//CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
end;

procedure TPartitionList.Dump;
var
   i : Integer;
begin
   for i := 0 to Partitions.Count - 1 do
   begin
      TPartition(Partitions[i]).Dump;
   end;
end;

procedure TPartition.Dump;
begin
   Debug('Partition number ' + IntToStr(PartNo) + ' on drive ' + IntToStr(DriveNo), DebugMedium);
   Debug(FileName, DebugMedium);

   Debug('Media type ' + IntToStr(MediaType), DebugMedium);
   Debug('Cylinders        : ' + IntToStr(Cylinders.QuadPart), DebugMedium);
   Debug('Tracks / Cylinder : ' + IntToStr(TracksPerCylinder), DebugMedium);
   Debug('Sectors / Track   : ' + IntToStr(SectorsPerTrack), DebugMedium);
   Debug('Bytes / Sector    : ' + IntToStr(BytesPerSector), DebugMedium);

   Debug('Partition:', DebugMedium);

   Debug('Type       : ' + IntToHex(PartitionType, 4), DebugMedium);
   Debug('Bootable   : ' + YesNo(BootIndicator), DebugMedium);
   Debug('Recognised : ' + YesNo(RecognizedPartition), DebugMedium);
   Debug('Rewrite    : ' + YesNo(RewritePartition), DebugMedium);

   Debug('Starting Offset : ' + IntToStr(StartingOffset.QuadPart), DebugMedium);

   Debug('Partition Length : ' + IntToStr(PartitionLength.QuadPart), DebugMedium);
   Debug('Hidden sectors : ' + IntToStr(HiddenSectors), DebugMedium);
   Debug('', DebugMedium);
   Debug('', DebugMedium);
end;

////////////////////////////////////
////////////////////////////////////
// Windows 95 scan
// This does a Low Level scan (reads partition table from disk);
// This is the same as LL_Scan, but it uses the DiskIO unit

procedure TPartitionList.Win95_Scan(PartType : Integer);
var
   DriveNo  : Integer;
   PartNo   : Integer;
   ExtendedStart : ULong;
   Disk     : T95Disk;

   procedure AddFloppy(Disk : T95Disk);
   var
      Size     : DWORD;
      NewPart  : TPartition;
   begin
      NewPart := TPartition.Create;
      Partitions.add(NewPart);
      NewPart.DriveNo   := DriveNo;
      NewPart.FileName  := '';

      NewPart.Cylinders.QuadPart := Disk.GetGeometry.Cylinder + 1;
      NewPart.TracksPerCylinder  := Disk.GetGeometry.Head + 1;
      NewPart.SectorsPerTrack    := Disk.GetGeometry.Sector;
      NewPart.BytesPerSector     := 512;
      NewPart.MediaType          := Media_Type_RemovableMedia;

      Size := Disk.SectorCount * 512;

      NewPart.PartitionType            := PartType;
      NewPart.BootIndicator            := False;
      NewPart.RecognizedPartition      := True;
      NewPart.RewritePartition         := False;
      NewPart.PartNo                   := 0;
      NewPart.StartingOffset.QuadPart  := 0;
      NewPart.PartitionLength.QuadPart := Size;
      NewPart.PartitionLength.QuadPart := NewPart.PartitionLength.QuadPart * 512;
      NewPart.HiddenSectors            := 0;
   end;

   function ProcessSector(Disk : T95Disk; Sector : ULong; Depth : Integer) : Boolean;
   var
      Size     : DWORD;
      Buffer   : TDiskTable;
      i        : Integer;
      NewPart  : TPartition;
   begin
      Result := True;
      Size := sizeof(Buffer);
      Debug('Looking for table at sector ' + IntToStr(Sector), DebugMedium);

      if not Disk.ReadSector(Sector, @Buffer, size div 512) then
         begin
            Result := False;
            exit;
         end;
         Debug('Signature is ' + IntToHex(Buffer.Signature, 4), DebugMedium);
         if (Buffer.Signature = $AA55) then
         begin
            for i := 1 to 4 do
            begin
               Debug('Processing partitions', DebugMedium);
               if Buffer.Table[i].sys_ind <> 0 then
               begin
                  Debug('Partition           ' + IntToStr(i) + ' /dev/hdx' + IntToStr(PartNo), DebugMedium);
//                  Debug(S + 'boot indicator      ' + IntToHex(Buffer.Table[i].boot_ind,2));
//                  Debug(S + 'starting head       ' + IntToStr(Buffer.Table[i].head));
//                  Debug(S + 'starting sector     ' + IntToStr(Buffer.Table[i].sector));
//                  Debug(S + 'starting cylinder   ' + IntToStr(Buffer.Table[i].cyl));
                  Debug(' partition type      ' + IntToHex(Buffer.Table[i].sys_ind,2), DebugMedium);
                  case Buffer.Table[i].sys_ind of
                     PARTITION_EXTENDED         : Debug('Extended... (dos)', DebugMedium);
                     PARTITION_EXTENDED_LINUX   : Debug('Extended... (linux)', DebugMedium);
                     PARTITION_EXTENDED_WIN98   : Debug('Extended... (win98)', DebugMedium);
                     PARTITION_FAT_16           : Debug('FAT 16', DebugMedium);
                     PARTITION_HUGE             : Debug('VFAT', DebugMedium);
                     PARTITION_IFS              : Debug('NTFS', DebugMedium);
                     PARTITION_LINUX            : Debug('Linux', DebugMedium);
                     PARTITION_LINUX_SWAP       : Debug('Linux Swap', DebugMedium);
                  else
                     Debug('Unknown', DebugMedium);
                  end;
//                  Debug(S + 'end head            ' + IntToStr(Buffer.Table[i].end_head));
//                  Debug(S + 'end sector          ' + IntToStr(Buffer.Table[i].end_sector));
//                  Debug(S + 'end cylinder        ' + IntToStr(Buffer.Table[i].end_cyl));
                  Debug(' starting sector     ' + IntToStr(Buffer.Table[i].start_sect), DebugMedium);
                  Debug(' number of sectors   ' + IntToStr(Buffer.Table[i].nr_sects), DebugMedium);
                  Debug('', DebugMedium);


//                  else
                  begin
                     if (Buffer.Table[i].sys_ind = PartType) or (PartType = 0) then
                     begin
                        NewPart := TPartition.Create;
                        Partitions.add(NewPart);
                        NewPart.DriveNo   := DriveNo;// - $80;
                        NewPart.FileName  := '';

                        NewPart.Cylinders.QuadPart := Disk.GetGeometry.Cylinder + 1;
                        NewPart.TracksPerCylinder  := Disk.GetGeometry.Head + 1;
                        NewPart.SectorsPerTrack    := Disk.GetGeometry.Sector;
                        NewPart.BytesPerSector     := 512;
                        NewPart.MediaType          := Media_Type_FixedMedia;

                        NewPart.PartitionType            := Buffer.Table[i].sys_ind;
                        NewPart.BootIndicator            := (Buffer.Table[i].boot_ind = $80);
                        NewPart.RecognizedPartition      := True;
                        NewPart.RewritePartition         := False;
                        NewPart.PartNo                   := PartNo;
                        NewPart.StartingOffset.QuadPart  := (Buffer.Table[i].start_sect + Sector);// Offset from start of partition
//                        NewPart.StartingOffset.QuadPart  := NewPart.StartingOffset.QuadPart * Geometry.BytesPerSector;
                        NewPart.PartitionLength.QuadPart := Buffer.Table[i].nr_sects;
//                        NewPart.PartitionLength.QuadPart := NewPart.PartitionLength.QuadPart * Geometry.BytesPerSector;
                        NewPart.HiddenSectors            := 0;

                     end;
//                     if (Buffer.Table[i].sys_ind = PARTITION_EXTENDED) and (PartNo > 4) then
                     if (Buffer.Table[i].sys_ind in EXTENDED_PARTITIONS) and (PartNo > 4) then
                     begin
                        Dec(PartNo); // We do not want to assign a number to extend partitions after the 1st (I don't know why?, it is what Linux does)
                     end;
                  end;
                  Inc(PartNo);
               end;
            end;
            for i := 1 to 4 do
            begin
//               if Buffer.Table[i].sys_ind = PARTITION_EXTENDED then
               if Buffer.Table[i].sys_ind in EXTENDED_PARTITIONS then
               begin
                  Debug('Processing extended partition....', DebugMedium);
                  if Depth < 32 then
                  begin
                     if PartNo < 5 then
                     begin
                        PartNo := 5;
                     end;
                     if Depth = 1 then
                     begin
                        ExtendedStart := Sector;
                     end;
                     // There is a new partition table at offset start_sect...
                     if Depth >= 2 then
                     begin
                     if not ProcessSector(Disk, ExtendedStart + Buffer.Table[i].start_sect, Depth + 1) then
                        begin
                           Debug('Did not seem to be a valid extended partition', DebugMedium);
                        end;
                     end
                     else
                     begin
                        if not ProcessSector(Disk, Sector + Buffer.Table[i].start_sect, Depth + 1) then
                        begin
                           Debug('Did not seem to be a valid extended partition', DebugMedium);
                        end;
                     end;
                  end
                  else
                  begin
                     Debug('More than 32 partitions detected! This is most likely a bug!', DebugOff);
                  end;
               end;
            end;
         end
         else
         begin
            Result := False;
         end;
      end;
begin
   Disk := T95Disk.Create;
   try
      DriveNo := $80;

      while true do
      begin
         Debug('Scanning disk ' + IntToHex(DriveNo, 2), DebugMedium);
         if not Disk.SetDisk(DriveNo) then
         begin
               // no more physical drives found...
               break;
         end
         else // we have the handle, lets look at the partitions....
         begin
            // first see if the media is present...
               // Time to read the table
               PartNo := 1;
               ExtendedStart := 0;
               ProcessSector(Disk, 0, 0);
            Inc(DriveNo);
         end;
      end;

      ////////////////////////////////////////////
      ////////////////////////////////////////////
      ////////////////////////////////////////////
      ////////////////////////////////////////////

      if ScanFloppy then
      begin
         DriveNo := 0;

         while true do
         begin
            Debug('Scanning ' + IntToHex(DriveNo, 2), DebugMedium);
            if not Disk.SetDisk(DriveNo) then
            begin
               break;
            end
            else // we have the handle, lets look at the partitions....
            try
               // Time to read the table
               PartNo := 1;
               ExtendedStart := 0;
               ProcessSector(Disk, 0, 0);
               Debug('PartNo = ' + IntToStr(PartNo), DebugMedium);
//               if PartNo = 1 then
               begin
                  // no Partitons found, should we add the whole disk?
                  AddFloppy(Disk);
               end;
            finally
               Inc(DriveNo);
            end;
         end;
      end;
   finally
      Disk.Free;
   end;
end;


end.
