(********************************************************************)
(*                            UNIT DRIVExx                          *)
(*                                                                  *)
(*                            Version 3.13                          *)
(*                                                                  *)
(*          Copyright (C) 1991, 1992 by NativSoft Computing         *)
(*                                                                  *)
(*                          1155 College Ave                        *)
(*                          Adrian, MI 49221                        *)
(*                           (517) 265-6080                         *)
(*                          CIS [71160,1045]                        *)
(*                                                                  *)
(*                        ALL RIGHTS RESERVED                       *)
(********************************************************************)

(********************************************************************)
(*      Written by:  Charles B. Little, Ph.D.                       *)
(*         Version:  3.13                                           *)
(*   Revision Date:  28 March 1992                                  *)
(*         Purpose:  To obtain as much useful information as        *)
(*                   possible about block devices without hitting   *)
(*                   any disks.                                     *)
(********************************************************************)


{$F+,S-,R-,B-,O+}

UNIT DRIVExx;

{********************************************************************}
                                   INTERFACE
{********************************************************************}
USES DOS;

type
  SectorArray = array[0..1023] of byte;
      {because DOS allows 1024 byte sectors}

  fakeDPB =      {3.10 revised}
  record
    {start of standard BPB in boot record}
    bytespersex     : word;    {BPB & DPB}
    sexperclust     : byte;    {BPB & DPB}
    FATstart        : word;    {BPB & DPB}
    numFATS         : byte;    {BPB & DPB}
    RootdirEnts     : word;    {BPB & DPB}
    placeholder     : word;    {ignore this}
    mediabyte       : byte;    {BPB & DPB}
    sexperFAT       : word;    {BPB & DPB}
    SexperTrack     : word;    {BPB ONLY}
    NumHeads        : word;    {BPB ONLY}
    HiddenSex       : longint; {BPB ONLY}
    TotSexonDisk    : longint; {BPB ONLY}
    {end of standard BPB - 25 bytes}
    RootdirSex      : word;    {calculated}
    ROOTstart       : word;    {DPB}
    FirstDataSec    : word;    {DPB}
    TotClusts       : word;    {calculated}
    TotDataClusts   : word;    {DPB}
    Tracks          : word;    {calculated}
    Cylinders       : word;    {calculated}
    Size            : longint; {calculated}
    accessflag      : byte;    {DPB}
    ddunitnum       : byte;    {DPB}
    DPBDataValid    : boolean; {evaluated}
  end;

var
  DOSVER            : real;
  DRDOS,
  DevDrvrChainValid,
  NCacheLoaded,                        {3.00}
  NetwareLoaded,                       {3.00}
  StackerLoaded     : boolean;         {3.00}
  DriveError        : longint;
  NumLogicaldrives,
  InternalFloppies,
  PhysicalFixed,
  NumBlockDevs,
  MachineID         : byte;
  AllLogicalDrives,
  BootableDrives,
  Floppies,
  Hards             : string[32]; {3.00 - change length to 32 from 26}
  ProcessorType     : integer;
  BiosDateString    : string[8];


PROCEDURE UpdateDrives;
    { Main procedure in unit.  Updates GLOBAL array DRIVES.  Called in
    unit initialization, but should be called again each time there's a
    chance a user can JOIN or ASSIGN a drive, or if a phantom drive
    might have been accessed while shelled out from the main program
    that USES this unit }

FUNCTION DrivExists(drv:char)          : boolean;

FUNCTION DriveisNormal(drv:char)       : boolean;

FUNCTION DriveisNONDOS(drv:char)       : boolean;

FUNCTION DriveisHard(drv:char)         : boolean;

FUNCTION DriveisRAMDisk(drv:char)      : boolean;

FUNCTION DriveisOtherfixed(drv:char)   : boolean;

FUNCTION DriveisNetwork(drv:char)      : boolean;

FUNCTION DriveisSubsted(drv:char)      : boolean;

FUNCTION DriveisJoined(drv:char)       : boolean;

FUNCTION DriveisAssigned(drv:char)     : boolean;

FUNCTION DriveisIFS(drv:char)          : boolean;

FUNCTION DriveisAliased(drv:char)      : boolean;

FUNCTION DriveisRemovable(drv:char)    : boolean;

FUNCTION DriveisDeviceDriven(drv:char) : boolean;

FUNCTION DriveisSwapped(drv:char)      : boolean;

FUNCTION SwappedWith(drv:char)         : char;

FUNCTION DriveisPhantom(drv:char)      : boolean;

FUNCTION DriveMappedTo(drv:char)       : char;

FUNCTION ChangeLineSupported(drv:char) : boolean;

FUNCTION DiskWasChanged(drv:char)      : boolean;
    {hits the disk only if there's support for Changeline detection}

FUNCTION DiskSyze(drv:char)            : longint;  {3.10 name change}
{ returns:
    0      :  removable drive hasn't been accessed, so no DPB data to use, 
              or size is unreliable
 else      :  disk size IN BYTES; if removable, size of last disk accessed
              in drive}

FUNCTION RemovableDrivetype(drv:char)  : integer;
         { returns:
               -3 : INT $13 fnc $08 failed
               -2 : INT $13 fnc $08 returned value not in range 1-4
               -1 : INT $13 fnc $08 returned 0 for unknown reason
                0 : can't be determined, may not be removable
                1 : 5.25" 360K
                2 : 5.25" 1.2M
                3 : 3.5" 720K
                4 : 3.5" 1.44M
                5 : 3.5" 2.88M
                6 : TAPE
                7 : Bernoulli }

FUNCTION CurrentDir(drv:char)          : pathstr;
    { returns the currently logged directory for the specified drive as
    a complete path, including driveletter, colon and final backslash,
    all in uppercase letters.  If the drive doesn't exist - or NetWare
    is installed - a null string is returned }

FUNCTION DefaultDrive                  : char;
    { identifies the current default drive as an uppercase letter }

FUNCTION WriteDiskSectors
    (drv:char; first:longint; num:word; var Buf) : word;   {3.10}

    { returns 0 if successful, otherwise BIOS error code in high byte
    and DOS error code in low byte. Eg, returns 128:2 for floppy disk
    not ready, or 2:12 for unformatted disk in drive }

FUNCTION ReadDiskSectors
    (drv:char; first:longint; num:word; var Buf) : word;   {3.10}

    { returns 0 if successful, otherwise BIOS error code in high byte
    and DOS error code in low byte. Eg, returns 128:2 for floppy disk
    not ready, or 2:12 for unformatted disk in drive }

FUNCTION ShowBIOSDriveNum(drv:char) : byte;   {3.10}
    { Does not try to figure out DOS redirection commands like JOIN or
    ASSIGN.  Whatever PHYSICAL disk you would hit with a function like
    ReadDiskSectors(drv, 0, 1, buf) is what this returns.  If DRV is not
    a physical disk (eg, RAMDISK) or if DRV is a phantom, the function
    returns 255.  Based on interception of DOS INT 25h call and
    determination of drivenumber passed to BIOS INT 13h Fnc 02h.

    IMPORTANT: DOS INT 25h ignores JOIN, but DOES NOT ignore ASSIGN or
    SUBST!



FUNCTION GETBOOT(drv:char; var S:SectorArray) : word;      {3.10}
    { reads boot sector and puts it directly into byte array S

    THE ONLY CHECKING DONE BY THIS PROCEDURE IS ON PHANTOM DRIVES.  ALL
    OTHERS WILL BE HIT BY INT 25h AND ANY REDIRECTION BY SUBST OR ASSIGN
    WILL AFFECT THE OUTCOME!

   returns         0 : no error, S contains boot sector as read
               $F4F4 : can't allocate buffer to receive boot sector
               $F5F5 : DPB for drive says bytes per sector > 1024
               $F6F6 : drive is phantom
               $F7F7 : drive doesn't exist
               else  : error code generated by INT 25 (Absolute Read):
                       Hi byte = BIOS error code
                       Lo byte = DOS error code
                       (eg, BIOS error 128 means drive not ready or no
                       disk in drive, BIOS error 2,6 or 12 could mean
                       disk isn't formatted). }


FUNCTION GETDPB(drv:char; var F:fakeDPB; HitTheDisk:boolean) : word;
    { Puts useful drive data from DPB into F.  If HITTHEDISK is FALSE,
    the function will just use the DPB data in memory, usually for the
    last disk that was accessed in the drive.

    Please note that some information in the FakeDPB structure F, such
    as sectors-per-track, is located in the disk's boot record and not
    in the DPB in memory.  Therefore, these fields will be filled in
    ONLY if this function is called with HitTheDisk = TRUE since the
    boot sector must be read from the disk.  Only drives that are
    *NORMAL* are allowed to be hit; aliased drives, phantom drives,
    non-DOS drives, etc, will not be hit.

    GETDPB(drv,F,FALSE)  returns
                   0 : no error, F contains only DPB data
               $F7F7 : drive doesn't exist
                     (no other return values possible)

    GETDPB(drv,F,TRUE)   returns
                   0 : no error, F contains DPB data, BPB data
               $F4F4 : can't allocate buffer to receive boot sector
               $F5F5 : DPB says bytes per sector > 1024
               $F6F6 : drive is not normal (may be phantom or aliased)
               $F7F7 : drive doesn't exist
               $FF00 : DOS Fnc $32 (GetDPB) failed
               else  : error code generated by INT 25 (Absolute Read):
                       Hi byte = BIOS error code
                       Lo byte = DOS error code
                       (eg, BIOS error 128 means drive not ready or no
                       disk in drive, BIOS error 2,6 or 12 could mean
                       disk isn't formatted).  All fields of F will be
                       zeroed out. }

PROCEDURE MakeDriveActive(drv:char);
    { makes a phantom drive active so you don't see the obnoxious
     "Insert diskette... " message when you try to access it.
     THIS PROCEDURE CALLS UPDATEDRIVES WHEN IT'S FINISHED!! }
