home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9101 / tools / tvision1 / diskman.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-03-06  |  20.0 KB  |  535 lines

  1. (* ------------------------------------------------------ *)
  2. (*                    DISKMAN.PAS                         *)
  3. (*    objektorientierte Toolbox zum Zugriff auf Diskette  *)
  4. (*           (c) 1991 Gerd Cebulla & DMV-Verlag           *)
  5. (* ------------------------------------------------------ *)
  6. UNIT DiskMan;
  7. {$B-}
  8.  
  9. INTERFACE
  10.  
  11. USES Dos;
  12.  
  13. CONST
  14.   DiskError : WORD = 0;
  15.  
  16.     (* Error-Konstanten für DiskError: *)
  17.   dskOk           =  0;    { fehlerfreie Ausführung        }
  18.   dskFileNotFound =  2;    { Datei nicht gefunden          }
  19.   dskPathNotFound =  3;    { Verzeichnis nicht gefunden    }
  20.   dskAccessDenied =  5;    { unzulässige Parameter o.ä.    }
  21.   dskNoMemory     =  8;    { nicht genug Hauptspeicher     }
  22.   dskNoMoreFiles  = 18;    { keine weiteren Dateieinträge  }
  23.  
  24.     (* wenn DiskError > 255, gelten für die             *)
  25.     (* Interpretation des Low-Byte die folgenden Werte: *)
  26.   dskWriteProtected =  0;  { Diskette ist schreibgeschützt }
  27.   dskDriveNotReady  =  2;  { Laufwerk ist nicht bereit     }
  28.   dskCRCError       =  4;  { Prüfsumme fehlerhaft          }
  29.   dskSeekError      =  6;  { Suchfehler                    }
  30.   dskSectorNotFound =  8;  { Sektor nicht gefunden         }
  31.   dskWriteError     = 10;  { Schreibfehler                 }
  32.   dskReadError      = 11;  { Lesefehler                    }
  33.   dskGeneralError   = 12;  { allgemeiner Fehler            }
  34.  
  35. TYPE
  36.   DosNameStr = ARRAY [1..11] OF CHAR;
  37.   IDString   = ARRAY [1.. 8] OF CHAR;
  38.  
  39.   PDiskSector = ^DiskSector;
  40.   DiskSector  = ARRAY [0..MAXINT] OF BYTE;
  41.  
  42.   PBootSector = ^BootSector;
  43.   BootSector  = RECORD            { Aufbau des Bootsektors }
  44.     Jump              : ARRAY [1..3] OF BYTE;
  45.                                   { Sprung zur Bootroutine }
  46.     ID                : IDString;
  47.                                   { DOS-Name und -Version  }
  48.     BytesPerSector    : WORD;
  49.                                   { Sektorgröße in Byte    }
  50.     SectorsPerCluster : BYTE;
  51.                                 { Clustergröße in Sektoren }
  52.     BootSectors       : WORD;
  53.                                 { Anzahl der Boot-Sektoren }
  54.     Fats              : BYTE;
  55.                                 { Anzahl der FAT-Kopien    }
  56.     RootDirEntries    : WORD;
  57.                  { Anzahl der Einträge im Stammverzeichnis }
  58.     TotalSectors      : WORD;
  59.                  { Gesamtzahl Sektoren im Volume           }
  60.     MediaDescriptor   : BYTE;  { Datenträger-Kennbyte      }
  61.     SectorsPerFat     : WORD;  { Größe der FAT in Sektoren }
  62.     SectorsPerTrack   : WORD;  { Sektoren pro Spur         }
  63.     Heads             : WORD;  { Anzahl Köpfe bzw. Seiten  }
  64.     VolumeOffset      : LONGINT;
  65.              { Abstand des 1. Sektors                      }
  66.              { im Volume vom 1. Sektor auf dem Datenträger }
  67.  
  68.     { die folgenden Felder sind erst ab DOS 4.0 definiert: }
  69.     TotalSectors32    : LONGINT;
  70.                        { Gesamtzahl Sektoren im            }
  71.                        { Volume bei Partitionen > 32 MByte }
  72.     PhysDrive         : BYTE;
  73.           { physik. Laufwerksnummer:                       }
  74.           { 0 bei Disketten, $80 bei der ersten Festplatte }
  75.     Reserved          : BYTE;              { nicht benutzt }
  76.     BootBlockType     : BYTE;
  77.           { enthält den Wert $29, wenn                     }
  78.           { es sich um einen erweiterten Bootblock handelt }
  79.     VolumeNo          : LONGINT;       { Datenträgernummer }
  80.     VolumeLabel       : DosNameStr;    { Name des Volumes  }
  81.     FatSystem         : IDString;
  82.                 { FAT-Typ als String: 'FAT12' oder 'FAT16' }
  83.     Fill              : ARRAY [$3E..MAXINT] OF BYTE;
  84.                 { hier folgt die eigentliche Bootroutine   }
  85.   END;          { BootSector ----------------------------- }
  86.  
  87.   PDirEntry = ^DirEntry;
  88.   DirEntry  = RECORD    { Aufbau eines Verzeichniseintrags }
  89.     Name         : DosNameStr; { Dateiname und Erweiterung }
  90.     Attribute    : BYTE;       { Dateiattribut             }
  91.     Fill         : ARRAY [1..10] OF BYTE;  { nicht benutzt }
  92.     Time         : LONGINT;
  93.                    { Datum und Uhrzeit in gepacktem Format }
  94.     FirstCluster : WORD;   { Nr. des 1. Clusters der Datei }
  95.     Size         : LONGINT;           { Dateigröße in Byte }
  96.   END;                                { DirEntry --------- }
  97.  
  98.   PDirSector = ^DirSector;
  99.   DirSector  = ARRAY [0..1023] OF DirEntry;
  100.  
  101.   PDiskInfo = ^DiskInfo;
  102.   DiskInfo  = OBJECT
  103.     ID              : IDString;
  104.     VolumeLabel     : DosNameStr;
  105.     VolumeNo        : LONGINT;
  106.     FatSystem       : IDString;
  107.     PhysDrive       : BYTE;
  108.     MediaDescriptor : BYTE;
  109.     Heads           : WORD;
  110.     VolumeOffset    : LONGINT;
  111.     SectorsPerTrack : WORD;
  112.     TotalSectors    : LONGINT;
  113.     BytesPerSector  : WORD;
  114.     ClusterStart    : LONGINT;
  115.                   { Sektornummer des 1. Clusters im Volume }
  116.     TotalClusters   : WORD;
  117.                   { Gesamtzahl der Cluster im Volume       }
  118.     FreeClusters    : WORD;
  119.                   { Anzahl der freien Cluster              }
  120.     BytesPerCluster   : WORD;   { Clustergröße in Byte     }
  121.     SectorsPerCluster : BYTE;   { Clustergröße in Sektoren }
  122.     FatStart          : WORD;   { 1. Sektor der FAT        }
  123.     Fats              : BYTE;   { Anzahl FATs              }
  124.     Fat16             : BOOLEAN;
  125.          { Flag: True bei 16-Bit-FAT, False bei 12-Bit-FAT }
  126.     SectorsPerFat     : WORD;   { FAT-Größe in Sektoren    }
  127.     RootDirStart      : WORD;
  128.                        { 1. Sektor des Stammverzeichnisses }
  129.     RootDirEntries    : WORD;
  130.                  { Anzahl der Einträge im Stammverzeichnis }
  131.     RootDirSectors    : WORD;
  132.                { Größe des Stammverzeichnisses in Sektoren }
  133.     DirEntriesPerSector : WORD;
  134.                { Anzahl der Einträge pro Verzeichnis-Sektor }
  135.   END;                                  { DiskInfo -------- }
  136.  
  137.   PDiskManager = ^DiskManager;
  138.   DiskManager  = OBJECT (DiskInfo)
  139.     DriveNo    : BYTE;         { Nr. des Laufwerks (0 = A:) }
  140.     FatBuf     : PDiskSector;  { Zeiger auf FAT-Puffer      }
  141.     FatSector  : WORD;         { aktueller FAT-Sektor       }
  142.     FatChanged : BOOLEAN;
  143.              { Flag: wird True, wenn die FAT geändert wurde }
  144.  
  145.     CONSTRUCTOR Init(Laufwerk : CHAR);
  146.     DESTRUCTOR  Done; VIRTUAL;
  147.     PROCEDURE   FlushDosBuffers; VIRTUAL;
  148.     PROCEDURE   GetDiskInfo(VAR Info : DiskInfo);   VIRTUAL;
  149.     FUNCTION    GetFatEntry(ClusterNr : WORD) : WORD;
  150.                                                     VIRTUAL;
  151.     FUNCTION    GetFatWord(ByteNr : LONGINT) : WORD;
  152.                                                     VIRTUAL;
  153.     FUNCTION    GetFatByte(ByteNr : LONGINT) : BYTE;
  154.                                                     VIRTUAL;
  155.     PROCEDURE   PutFatEntry(ClusterNr, Eintrag : WORD);
  156.                                                     VIRTUAL;
  157.     PROCEDURE   PutFatWord(ByteNr  : LONGINT;
  158.                            Eintrag : WORD);         VIRTUAL;
  159.     PROCEDURE   PutFatByte(ByteNr  : LONGINT;
  160.                            Eintrag : BYTE);         VIRTUAL;
  161.     PROCEDURE   WriteFat; VIRTUAL;
  162.     FUNCTION    SaveFat : BOOLEAN; VIRTUAL;
  163.     PROCEDURE   ReadSector(VAR Buffer; SektorNr : LONGINT;
  164.                                SektorZahl : WORD);  VIRTUAL;
  165.     PROCEDURE   WriteSector(VAR Buffer; SektorNr : LONGINT;
  166.                                 SektorZahl : WORD); VIRTUAL;
  167.     FUNCTION    TryAgain : BOOLEAN;                 VIRTUAL;
  168.   END; { DiskManager }
  169.  
  170. IMPLEMENTATION
  171.  
  172. TYPE
  173.   DataBlock32 = RECORD
  174.     SektorNr   : LONGINT;
  175.     SektorZahl : WORD;
  176.     BufPtr     : POINTER;
  177.   END; { DataBlock32 }
  178.  
  179.   PROCEDURE ErrorHandler(AX, BX, CX, DX, SI, DI,
  180.                          DS, ES, BP : WORD); INTERRUPT;
  181.   BEGIN
  182.     DiskError := DI OR $FF00;
  183.     AX        := 0;
  184.   END; { ErrorHandler }
  185.  
  186.   CONSTRUCTOR DiskManager.Init(Laufwerk : CHAR);
  187.     { Nimmt Initialisierungen vor, legt einen Puffer für die }
  188.     { FAT an und holt allgemeine Informationen über das      }
  189.     { Laufwerk ein. Alle Aufrufe von Methoden einer Instanz  }
  190.     { beziehen sich auf das hier angegebene Laufwerk.        }
  191.   VAR
  192.     Regs     : Registers;
  193.     Boot     : PBootSector;
  194.     OldInt24 : POINTER;
  195.   BEGIN
  196.     FatBuf  := NIL;
  197.     DriveNo := Ord(UpCase(Laufwerk)) - Ord('A');
  198.     GetIntVec($24, OldInt24);
  199.     SetIntVec($24, @ErrorHandler);
  200.     REPEAT
  201.       Regs.AH := $36;
  202.       Regs.DL := Succ(DriveNo);
  203.       MsDos(Regs);
  204.       IF Regs.AX <> $FFFF THEN DiskError := dskOk;
  205.     UNTIL (DiskError = dskOk) OR NOT TryAgain;
  206.     SetIntVec($24, OldInt24);
  207.     IF DiskError <> dskOk THEN BEGIN
  208.       Done;
  209.       Fail;
  210.     END;
  211.     SectorsPerCluster := Regs.AX;
  212.     FreeClusters      := Regs.BX;
  213.     BytesPerSector    := Regs.CX;
  214.     TotalClusters     := Regs.DX;
  215.     BytesPerCluster   := BytesPerSector * SectorsPerCluster;
  216.     TotalSectors      := LONGINT(SectorsPerCluster)*
  217.                          TotalClusters;
  218.     Fat16             := TotalClusters >= $0FEF;
  219.     GetMem(Boot, BytesPerSector);
  220.     IF Boot = NIL THEN BEGIN
  221.       DiskError := dskNoMemory;
  222.       Done;
  223.       Fail;
  224.     END;
  225.     FlushDosBuffers;
  226.     ReadSector(Boot^, 0, 1);
  227.     IF DiskError <> dskOk THEN BEGIN
  228.       FreeMem(Boot, BytesPerSector);
  229.       Done;
  230.       Fail;
  231.     END;
  232.     ID              := Boot^.ID;
  233.     MediaDescriptor := Boot^.MediaDescriptor;
  234.     Heads           := Boot^.Heads;
  235.     IF Boot^.TotalSectors <> 0 THEN
  236.       TotalSectors := Boot^.TotalSectors
  237.     ELSE
  238.       TotalSectors := Boot^.TotalSectors32;
  239.     SectorsPerTrack     := Boot^.SectorsPerTrack;
  240.     FatStart            := Boot^.BootSectors;
  241.     Fats                := Boot^.Fats;
  242.     SectorsPerFat       := Boot^.SectorsPerFat;
  243.     RootDirEntries      := Boot^.RootDirEntries;
  244.     RootDirStart        := FatStart+SectorsPerFat*Fats;
  245.     DirEntriesPerSector := BytesPerSector DIV
  246.                            SizeOf(DirEntry);
  247.     RootDirSectors      := Succ(Pred(RootDirEntries) DIV
  248.                            DirEntriesPerSector);
  249.     ClusterStart        := RootDirStart+RootDirSectors;
  250.     VolumeOffset        := Boot^.VolumeOffset;
  251.     IF Boot^.BootBlockType = $29 THEN BEGIN
  252.       VolumeLabel := Boot^.VolumeLabel;
  253.       VolumeNo    := Boot^.VolumeNo;
  254.       FatSystem   := Boot^.FatSystem;
  255.       PhysDrive   := Boot^.PhysDrive;
  256.     END ELSE BEGIN
  257.       VolumeLabel := '           ';
  258.       VolumeNo    := 0;
  259.       FatSystem   := '        ';
  260.       PhysDrive   := 0;
  261.     END;
  262.     FreeMem(Boot, BytesPerSector);
  263.     GetMem(FatBuf, BytesPerSector);
  264.     IF FatBuf = NIL THEN BEGIN
  265.       DiskError := dskNoMemory;
  266.       Done;
  267.       Fail;
  268.     END;
  269.     FatChanged := FALSE;
  270.     FatSector  := FatStart;
  271.     ReadSector(FatBuf^, FatSector, 1);
  272.     IF DiskError <> dskOk THEN BEGIN
  273.       Done;
  274.       Fail;
  275.     END;
  276.   END; { DiskManager.Init }
  277.  
  278.   DESTRUCTOR DiskManager.Done;
  279.     { Gibt den FAT-Puffer frei; falls dessen Inhalt geändert }
  280.     { wurde, wird er auf den Datenträger geschrieben.        }
  281.   BEGIN
  282.     IF FatBuf <> NIL THEN BEGIN
  283.       IF FatChanged AND SaveFat THEN WriteFat;
  284.       FreeMem(FatBuf, BytesPerSector);
  285.       FatBuf := NIL;
  286.     END;
  287.   END; { DiskManager.Done }
  288.  
  289.   PROCEDURE DiskManager.FlushDosBuffers;
  290.     { Setzt die DOS-Sektorpuffer zurück. }
  291.   VAR
  292.     Regs : Registers;
  293.   BEGIN
  294.     Regs.AH := $0D;
  295.     MsDos(Regs);
  296.   END; { DiskManager.FlushDosBuffers }
  297.  
  298.   PROCEDURE DiskManager.GetDiskInfo(VAR Info : DiskInfo);
  299.     { Liefert Informationen über den Datenträger zurück. }
  300.   BEGIN
  301.     Info := Self;
  302.   END; { DiskManager.GetDiskInfo }
  303.  
  304.   FUNCTION DiskManager.GetFatEntry(ClusterNr : WORD) : WORD;
  305.     { Liest einen Eintrag aus der FAT. Einträge in           }
  306.     { 12-Bit-FATs werden automatisch auf 16-Bit-Format       }
  307.     { erweitert.                                             }
  308.   VAR
  309.     Eintrag : WORD;
  310.   BEGIN
  311.     IF ClusterNr > SUCC(TotalClusters) THEN
  312.       DiskError := dskAccessDenied
  313.     ELSE BEGIN
  314.       DiskError := dskOk;
  315.       IF Fat16 THEN
  316.         Eintrag := GetFatWord(LONGINT(ClusterNr)*2)
  317.       ELSE BEGIN
  318.         Eintrag := GetFatWord(ClusterNr*3 DIV 2);
  319.         IF ODD(ClusterNr) THEN
  320.           Eintrag := Eintrag SHR 4
  321.         ELSE
  322.           Eintrag := Eintrag AND $0FFF;
  323.         IF Eintrag >= $0FF0 THEN
  324.           Eintrag := Eintrag OR $F000;
  325.       END;
  326.     END;
  327.     IF DiskError = dskOk THEN
  328.       GetFatEntry := Eintrag
  329.     ELSE
  330.       GetFatEntry := 1;
  331.   END; { DiskManager.GetFatEntry }
  332.  
  333.   FUNCTION DiskManager.GetFatWord(ByteNr : LONGINT) : WORD;
  334.     { Liest ein Word aus der FAT. }
  335.   VAR
  336.     Eintrag : WORD;
  337.   BEGIN
  338.     Eintrag := GetFatByte(ByteNr);
  339.     IF DiskError = dskOk THEN
  340.       INC(Eintrag, 256*GetFatByte(Succ(ByteNr)));
  341.     GetFatWord := Eintrag;
  342.   END; { DiskManager.GetFatWord }
  343.  
  344.   FUNCTION DiskManager.GetFatByte(ByteNr : LONGINT) : BYTE;
  345.     { Liest ein Byte aus der FAT. }
  346.   VAR
  347.     SektorNr : LONGINT;
  348.   BEGIN
  349.     SektorNr := ByteNr DIV BytesPerSector+FatStart;
  350.     IF SektorNr <> FatSector THEN BEGIN
  351.       IF FatChanged AND SaveFat THEN WriteFat;
  352.       ReadSector(FatBuf^, SektorNr, 1);
  353.       FatSector  := SektorNr;
  354.       FatChanged := FALSE;
  355.     END;
  356.     GetFatByte := FatBuf^[ByteNr MOD BytesPerSector];
  357.   END; { DiskManager.GetFatByte }
  358.  
  359.   PROCEDURE DiskManager.PutFatEntry(ClusterNr, Eintrag : WORD);
  360.     { Schreibt einen Eintrag in die FAT. Angaben im          }
  361.     { 16-Bit-Format werden automatisch konvertiert, wenn es  }
  362.     { sich um eine 12-Bit-FAT handelt.                       }
  363.   VAR
  364.     ByteNr : LONGINT;
  365.   BEGIN
  366.     IF ClusterNr > SUCC(TotalClusters) THEN
  367.       DiskError := dskAccessDenied
  368.     ELSE BEGIN
  369.       DiskError := dskOk;
  370.       IF Fat16 THEN
  371.         ByteNr := LONGINT(ClusterNr)*2
  372.       ELSE BEGIN
  373.         Eintrag := Eintrag AND $0FFF;
  374.         IF ODD(ClusterNr) THEN
  375.           Eintrag := Eintrag SHL 4+
  376.                      GetFatEntry(PRED(ClusterNr)) SHR 8 AND $000F
  377.         ELSE
  378.           Eintrag := Eintrag+
  379.                      GetFatEntry(SUCC(ClusterNr)) SHL 12;
  380.         ByteNr := ClusterNr*3 DIV 2;
  381.       END;
  382.       PutFatWord(ByteNr, Eintrag);
  383.     END;
  384.   END; { DiskManager.PutFatEntry }
  385.  
  386.   PROCEDURE DiskManager.PutFatWord(ByteNr  : LONGINT;
  387.                                    Eintrag : WORD);
  388.     { Schreibt ein Word in die FAT. }
  389.   BEGIN
  390.     PutFatByte(ByteNr, Lo(Eintrag));
  391.     IF DiskError = dskOk THEN
  392.       PutFatByte(Succ(ByteNr), Hi(Eintrag));
  393.   END; { DiskManager.PutFatWord }
  394.  
  395.   PROCEDURE DiskManager.PutFatByte(ByteNr  : LONGINT;
  396.                                    Eintrag : BYTE);
  397.     { Schreibt ein Byte in die FAT. }
  398.   VAR
  399.     SektorNr : LONGINT;
  400.     Index    : WORD;
  401.   BEGIN
  402.     SektorNr := ByteNr DIV BytesPerSector+FatStart;
  403.     IF SektorNr <> FatSector THEN BEGIN
  404.       IF FatChanged AND SaveFat THEN WriteFat;
  405.       ReadSector(FatBuf^, SektorNr, 1);
  406.       FatSector  := SektorNr;
  407.       FatChanged := FALSE;
  408.     END;
  409.     Index := ByteNr MOD BytesPerSector;
  410.     IF FatBuf^[Index] <> Eintrag THEN BEGIN
  411.       FatBuf^[Index] := Eintrag;
  412.       FatChanged     := TRUE;
  413.     END;
  414.   END; { DiskManager.PutFatByte }
  415.  
  416.   PROCEDURE DiskManager.WriteFat;
  417.     { Schreibt den Inhalt des FAT-Puffers auf den }
  418.     { Datenträger.                                }
  419.   VAR
  420.     SektorNr : LONGINT;
  421.     FatNr    : BYTE;
  422.   BEGIN
  423.     SektorNr := FatSector;
  424.     FatNr    := 0;
  425.     REPEAT
  426.       WriteSector(FatBuf^, SektorNr, 1);
  427.       INC(SektorNr, SectorsPerFat);
  428.       INC(FatNr);
  429.     UNTIL (DiskError <> dskOk) OR (FatNr = Fats);
  430.   END; { DiskManager.WriteFat }
  431.  
  432.   FUNCTION DiskManager.SaveFat : BOOLEAN;
  433.     { Wenn diese Funktion den Wert TRUE zurückliefert,       }
  434.     { werden Änderungen im FAT-Puffer auf den Datenträger    }
  435.     { geschrieben, ansonsten unterbleibt die Speicherung.    }
  436.   BEGIN
  437.     SaveFat := TRUE;
  438.   END; { DiskManager.SaveFat }
  439.  
  440.   PROCEDURE DiskManager.ReadSector(VAR Buffer;
  441.                                        SektorNr   : LONGINT;
  442.                                        SektorZahl : WORD);
  443.     { Liest einen oder mehrere Sektoren vom Datenträger in   }
  444.     { den angegebenen Puffer ein.                            }
  445.     { (Benutzer von Turbo-Pascal 6.0 können die inline-      }
  446.     { Anweisung durch den in Kommentarklammern gesetzten     }
  447.     { asm-Block ersetzen.)                                   }
  448.   VAR
  449.     Data32   : DataBlock32;
  450.     BufPtr   : POINTER;
  451.     Laufwerk : BYTE;
  452.   BEGIN
  453.     IF TotalSectors <= $FFFF THEN
  454.       BufPtr := @Buffer
  455.     ELSE BEGIN
  456.       Data32.SektorNr   := SektorNr;
  457.       Data32.SektorZahl := SektorZahl;
  458.       Data32.BufPtr     := @Buffer;
  459.       BufPtr            := @Data32;
  460.       SektorZahl        := $FFFF;
  461.     END;
  462.     Laufwerk := DriveNo;
  463.     REPEAT
  464.       INLINE(                     { asm                         }
  465.         $1E/                      {   push ds                   }
  466.         $55/                      {   push bp                   }
  467.         $C5/$9E/BufPtr/           {   lds  bx,BufPtr            }
  468.         $8B/$96/SektorNr/         {   mov  dx,word ptr SektorNr }
  469.         $8B/$8E/SektorZahl/       {   mov  cx,SektorZahl        }
  470.         $8A/$86/Laufwerk/         {   mov  al,Laufwerk          }
  471.         $CD/$25/                  {   int  $25                  }
  472.         $5D/                      {   pop  bp                   }
  473.         $5D/                      {   pop  bp                   }
  474.         $1F/                      {   pop  ds                   }
  475.         $72/$02/                  {   jc   @Ende                }
  476.         $31/$C0/                  {   xor  ax,ax                }
  477.         { @Ende:                      }
  478.         $A3/DiskError             {   mov  DiskError,ax         }
  479.         );                        { end;                        }
  480.     UNTIL (DiskError = dskOk) OR NOT TryAgain;
  481.   END; { DiskManager.ReadSector }
  482.  
  483.   PROCEDURE DiskManager.WriteSector(VAR Buffer;
  484.                                     SektorNr : LONGINT;
  485.                                     SektorZahl : WORD);
  486.     { Schreibt einen oder mehrere Sektoren aus dem           }
  487.     { angegebenen Puffer auf den Datenträger.                }
  488.   VAR
  489.     Data32   : DataBlock32;
  490.     BufPtr   : POINTER;
  491.     Laufwerk : BYTE;
  492.   BEGIN
  493.     IF TotalSectors <= $FFFF THEN
  494.       BufPtr := @Buffer
  495.     ELSE BEGIN
  496.       Data32.SektorNr   := SektorNr;
  497.       Data32.SektorZahl := SektorZahl;
  498.       Data32.BufPtr     := @Buffer;
  499.       BufPtr            := @Data32;
  500.       SektorZahl        := $FFFF;
  501.     END;
  502.     Laufwerk := DriveNo;
  503.     REPEAT
  504.       INLINE(                     { asm                         }
  505.         $1E/                      {   push ds                   }
  506.         $55/                      {   push bp                   }
  507.         $C5/$9E/BufPtr/           {   lds  bx,BufPtr            }
  508.         $8B/$96/SektorNr/         {   mov  dx,word ptr SektorNr }
  509.         $8B/$8E/SektorZahl/       {   mov  cx,SektorZahl        }
  510.         $8A/$86/Laufwerk/         {   mov  al,Laufwerk          }
  511.         $CD/$26/                  {   int  $26                  }
  512.         $5D/                      {   pop  bp                   }
  513.         $5D/                      {   pop  bp                   }
  514.         $1F/                      {   pop  ds                   }
  515.         $72/$02/                  {   jc   @Ende                }
  516.         $31/$C0/                  {   xor  ax,ax                }
  517.         { @Ende:                      }
  518.         $A3/DiskError             {   mov  DiskError,ax         }
  519.         );                        { end;                        }
  520.     UNTIL (DiskError = dskOk) OR NOT TryAgain;
  521.   END;                            { DiskManager.WriteSector }
  522.  
  523.   FUNCTION DiskManager.TryAgain : BOOLEAN;
  524.     { Wird von ReadSector/WriteSector beim Auftreten eines   }
  525.     { Fehlers aufgerufen. Wenn diese Funktion den Wert True  }
  526.     { zurückgibt, wird die Schreib-/Leseoperation            }
  527.     { wiederholt.                                            }
  528.   BEGIN
  529.     TryAgain := FALSE;
  530.   END;                            { DiskManager.TryAgain }
  531.  
  532. END.
  533. (* ------------------------------------------------------ *)
  534. (*             Ende von DISKMAN.PAS                       *)
  535.