DOSSEG .MODEL LARGE include partit.inc .DATA? public PartitionList PartitionList dd ? public PartitionListCount PartitionListCount dw ? .CODE ASSUME ds:NOTHING extrn _InitializeDiskList:far extrn _OpenDisk:far extrn _CloseDisk:far extrn _ReadDisk:far extrn _WriteDisk:far extrn _malloc:far extrn _free:far .386 ;++ ; ; UINT ; _far ; InitializePartitionList( ; VOID ; ); ; ; Routine Description: ; ; This routine initializes internal data structures necessary so that ; other partition-related routines in this module can be called. ; ; All int13 disks are enumerated to find all primary and extended ; partitions. A data structure is build for each partition/logical drive ; and relevent information is saved away. ; ; Arguments: ; ; None. ; ; Return Value: ; ; Total count of all partitions on all disks that we can deal with. ; 0 if an error occurs. ; ;-- SectorBufferh equ word ptr [bp-2] SectorBufferl equ word ptr [bp-4] CurrentSectorh equ word ptr [bp-6] CurrentSectorl equ word ptr [bp-8] NextSectorh equ word ptr [bp-10] NextSectorl equ word ptr [bp-12] ExtStarth equ word ptr [bp-14] ExtStartl equ word ptr [bp-16] DiskHandleh equ word ptr [bp-18] DiskHandlel equ word ptr [bp-20] PartCount equ word ptr [bp-22] InMbr equ byte ptr [bp-24] public _InitializePartitionList _InitializePartitionList proc far push bp mov bp,sp sub sp,24 push ds push es push bx push si push di mov PartCount,0 ; ; Allocate a sector buffer. Note that we havn'e overwritten ds ; so it is addressing _DATA, which is required by the crt. ; push 512 call _malloc add sp,2 mov cx,ax or cx,dx jz exit ; ax already 0 for error exit mov SectorBufferl,ax mov SectorBufferh,dx ; ; _InitializeDiskList could return 0 in case of ; failure but the code below will then simply execute ; zero iterations of its loop. ; call _InitializeDiskList mov si,ax ; si is limit of disk ids mov di,0 ; di is current disk id nextdisk: cmp si,di je done ; ; Open this disk. ; push di call _OpenDisk add sp,2 mov cx,ax or cx,dx jz exit ; open failed, bail out mov DiskHandlel,ax mov DiskHandleh,dx ; save disk handle ; ; Read partition table for this disk ; xor ax,ax mov NextSectorl,ax mov NextSectorh,ax mov ExtStartl,ax mov ExtStarth,ax mov InMbr,1 nextptable: ; ; Read current mbr/ebr ; push SectorBufferh push SectorBufferl push 1 mov ax,NextSectorh mov CurrentSectorh,ax push ax mov ax,NextSectorl mov CurrentSectorl,ax push ax push DiskHandleh push DiskHandlel call _ReadDisk add sp,14 cmp ax,0 jz exit ; ax already 0 for error exit mov NextSectorl,0 mov NextSectorh,0 mov bx,SectorBufferl add bx,1beh mov ax,SectorBufferh mov es,ax ; es:bx -> first partition table entry mov cx,4 nextent: cmp byte ptr es:[bx+4],0 jz nextent1 ; unused entry cmp byte ptr es:[bx+4],5 je gotlink cmp byte ptr es:[bx+4],0fh jnz gotentry gotlink: ; ; Link-type partition, track next ebr location ; mov ax,ExtStartl add ax,es:[bx+8] mov NextSectorl,ax mov ax,ExtStarth adc ax,es:[bx+10] mov NextSectorh,ax cmp InMbr,1 jne nextent1 mov ax,es:[bx+8] mov ExtStartl,ax mov ax,es:[bx+10] mov ExtStarth,ax jmp nextent1 gotentry: mov ax,CurrentSectorl add ax,es:[bx+8] mov dx,CurrentSectorh adc dx,es:[bx+10] push cx push bx push es ; ; Before calling crt ensure that ds addresses _DATA ; push ds mov ax,DGROUP mov ds,ax push SIZE PART_INFO call _malloc add sp,2 pop ds pop es pop bx mov cx,ax or cx,dx pop cx ; does not affect flags jz exit ; ax already 0 for error exit push si push ds mov ds,dx mov si,ax ; ds:si -> new partition record mov ax,PartCount mov [si].PartInfoOrdinal,ax inc PartCount mov ax,CurrentSectorl add ax,es:[bx+8] mov [si].PartInfoStartSectorl,ax mov ax,CurrentSectorh adc ax,es:[bx+10] mov [si].PartInfoStartSectorh,ax mov ax,es:[bx+12] mov [si].PartInfoSectorCountl,ax mov ax,es:[bx+14] mov [si].PartInfoSectorCounth,ax mov al,es:[bx+4] mov [si].PartInfoSystemId,al mov [si].PartInfoDiskId,di mov [si].PartInfoPartOpen,0 mov [si].PartInfoDiskHandlel,0 mov [si].PartInfoDiskHandleh,0 ; ; Insert at head of linked list ; push es push di mov ax,DGROUP mov es,ax mov di,OFFSET DGROUP:[PartitionList] ; es:di = &PartitionList mov ax,es:[di] mov [si].PartInfoNextl,ax mov ax,es:[di+2] mov [si].PartInfoNexth,ax ; Record->Next = PartitionList mov es:[di],si mov es:[di+2],dx ; PartitionList = Record pop di pop es pop ds pop si ; restore int13 unit limit nextent1: add bx,16 dec cx jz @f jmp nextent @@: mov InMbr,0 ; ; If we found a link entry, follow it. Otherwise we're done ; with this disk. ; cmp NextSectorl,0 jnz nextptable cmp NextSectorh,0 jnz nextptable push DiskHandleh push DiskHandlel call _CloseDisk add sp,4 inc di jmp nextdisk done: push DGROUP pop ds ; address DGROUP for crt push SectorBufferh push SectorBufferl call _free add sp,4 mov ax,PartCount mov si,OFFSET DGROUP:PartitionListCount mov [si],ax ; save count in global var exit: pop di pop si pop bx pop es pop ds leave retf _InitializePartitionList endp ;++ ; ; BOOL ; _far ; GetPartitionInfoById( ; IN UINT PartitionId, ; IN UINT Reserved, ; OUT FPUINT DiskId, ; OUT FPBYTE SystemId, ; OUT FPULONG StartSector, ; OUT FPULONG SectorCount ; ); ; ; BOOL ; _far ; GetPartitionInfoByHandle( ; IN HPARTITION PartitionHandle, ; OUT FPUINT DiskId, ; OUT FPBYTE SystemId, ; OUT FPULONG StartSector, ; OUT FPULONG SectorCount ; ); ; ; Routine Description: ; ; These routines retrieve information about a particular partition, ; either by an ordinal id (range: 0 - n-1 where n is the value returned ; by InitializePartitionList()), or by a handle returned from ; OpenPartition(). ; ; Arguments: ; ; PartitionId/PartitionHandle - supplies ordinal id or handle that ; identifies the partition whose information is of interest. ; ; Reserved - unused. ; ; DiskId - receives the disk id of the disk where the partition is. ; ; SystemId - receives the system id of the partition from the ; partition table, if known, or 0 if not. ; ; StartSector - recieves the absolute physical start sector on the ; drive where the partition lives. ; ; SectorCount - recieves the number of sectors in the partition. ; ; Return Value: ; ; 0 - failure ; non-0 - success and caller's variables filled in ; ;-- PartitionId equ word ptr [bp+6] PartitionHandle equ dword ptr [bp+6] DiskId equ dword ptr [bp+10] SystemId equ dword ptr [bp+14] StartSector equ dword ptr [bp+18] SectorCount equ dword ptr [bp+22] public _GetPartitionInfoById _GetPartitionInfoById proc far push bp mov bp,sp push ds push es push si push di ; ; Locate the partition record for the requested partition. ; The far pointer comes back in dx:si and ds:si. ; mov ax,PartitionId call far ptr pLocatePartitionRecord cmp dx,0 jnz get_p_id cmp si,0 jz error1 ; ; Transfer the relevent fields to the caller's variables. ; get_p_id: les di,DiskId mov ax,[si].PartInfoDiskId mov es:[di],ax les di,SystemId mov al,[si].PartInfoSystemId mov es:[di],al les di,StartSector mov ax,[si].PartInfoStartSectorl mov es:[di],ax mov ax,[si].PartInfoStartSectorh mov es:[di+2],ax les di,SectorCount mov ax,[si].PartInfoSectorCountl mov es:[di],ax mov ax,[si].PartInfoSectorCounth mov es:[di+2],ax mov ax,1 jmp short exit1 error1: xor ax,ax exit1: pop di pop si pop es pop ds leave retf _GetPartitionInfoById endp public _GetPartitionInfoByHandle _GetPartitionInfoByHandle label far push bp mov bp,sp push ds push es push si push di ; ; Make sure it's open, if not give error. ; lds si,PartitionHandle cmp [si].PartInfoPartOpen,0 jne short get_p_id je error1 ;++ ; ; HPARTITION ; _far ; OpenPartition( ; IN UINT PartitionId ; ); ; ; Routine Description: ; ; This routine 'opens' a partition so that subsequent io may be ; performed on it. ; ; Note that a partition can be open only once at a time. ; ; Note that this routine also opens the underlying disk. ; Disks can be opened only once at a time, thus this routine will ; fail if the disk is already open. ; ; Arguments: ; ; PartitionId - supplies an ordinal value identifying the partition. ; Valid range is 0 - n-1, where n is the number returned ; from InitializePartitionList(). ; ; Return Value: ; ; If successful, returns a value to be used as a handle to the ; partition for subsequent i/o with other routines in this module. ; If failure, returns 0. ; ;-- PartitionId equ word ptr [bp+6] public _OpenPartition _OpenPartition proc far push bp mov bp,sp push ds push si ; ; Locate the partition record for the requested partition. ; The far pointer comes back in dx:si and ds:si. ; mov ax,PartitionId call far ptr pLocatePartitionRecord mov cx,si or cx,dx jnz @f mov ax,cx ; dx:ax = 0 jz o_p_3 ; ; Make sure the partition is not already open. ; @@: cmp [si].PartInfoPartOpen,0 je @f mov ax,0 mov dx,ax jne o_p_3 ; ; Open the underlying disk. ; @@: push [si].PartInfoDiskId call _OpenDisk add sp,2 mov cx,ax or cx,dx jz o_p_3 ; ; Remember disk handle, that the partition is open, ; and return the pointer to the partition record as the handle. ; mov [si].PartInfoDiskHandlel,ax mov [si].PartInfoDiskHandleh,dx inc [si].PartInfoPartOpen mov dx,ds mov ax,si o_p_3: pop si pop ds leave retf _OpenPartition endp ;++ ; ; VOID ; _far ; ClosePartition( ; IN HPARTITION PartitionHandle ; ); ; ; Routine Description: ; ; This routine 'closes' a partition previously opened by ; OpenPartition. ; ; This routine also releases its handle to the disk that ; contains the partition. ; ; Arguments: ; ; PartitionHandle - supplies a handle previously returned by ; OpenPartition(). ; ; Return Value: ; ; None. ; ;-- PartitionHandle equ dword ptr [bp+6] public _ClosePartition _ClosePartition proc far push bp mov bp,sp push ds push si ; ; If not open, nothing to do. ; lds si,PartitionHandle cmp [si].PartInfoPartOpen,0 je c_p_3 ; ; Close the disk. ; push [si].PartInfoDiskHandleh push [si].PartInfoDiskHandlel call _CloseDisk add sp,4 ; ; Indicate partition closed ; mov cx,0 mov [si].PartInfoPartOpen,cl mov [si].PartInfoDiskHandlel,cx mov [si].PartInfoDiskHandleh,cx c_p_3: pop si pop ds leave retf _ClosePartition endp ;++ ; ; BOOL ; _far ; ReadPartition( ; IN HPARTITION PartitionHandle, ; IN ULONG StartSector, ; IN BYTE SectorCount, ; OUT FPVOID Buffer ; ); ; ; BOOL ; _far ; WritePartition( ; IN HPARTITION PartitionHandle, ; IN ULONG StartSector, ; IN BYTE SectorCount, ; IN FPVOID Buffer ; ); ; ; Routine Description: ; ; These routines read from or write to a partition previously opened by ; OpenPartition. I/Os use the proper method for the disk, ; ie, int13, xint13, etc. This routine also ensures that ; I/O doesn't cross a track boundary. ; ; This routine does NOT however, worry about DMA boundaries. ; The caller must take care of this. ; ; Arguments: ; ; StartSector - supplies the 0-based sector relative to the start ; of the partition where I/O is to start. ; ; SectorCount - supplies the number of sectors to be transferred. ; ; Return Value: ; ; 0 - failure ; non-0 - success ; ;-- PartitionHandle equ dword ptr [bp+6] StartSector equ dword ptr [bp+10] StartSectorl equ word ptr [bp+10] StartSectorh equ word ptr [bp+12] SectorCount equ [bp+14] Buffer equ dword ptr [bp+16] Bufferh equ word ptr [bp+18] IoRoutine equ dword ptr [bp-4] IoRoutinel equ word ptr [bp-4] IoRoutineh equ word ptr [bp-2] public _ReadPartition _ReadPartition label far mov dx,SEG _ReadDisk mov ax,OFFSET _ReadDisk jmp short PartitionIo public _WritePartition _WritePartition label far mov dx,SEG _WriteDisk mov ax,OFFSET _WriteDisk PartitionIo proc far push bp mov bp,sp sub sp,4 push ds push es push bx push si push di ; ; The partition handle is actually a far pointer to ; the partition data record. Make sure it's open. ; lds si,PartitionHandle ; ds:si -> partition record cmp [si].PartInfoPartOpen,0 jne @f xor ax,ax jmp short iodone ; ; Store the i/o routine pointer, passed to us in dx:ax. ; @@: mov IoRoutineh,dx mov IoRoutinel,ax ; ; Adjust the start sector to be disk-based instead of ; partition-based. ; mov ax,[si].PartInfoStartSectorl add StartSectorl,ax mov ax,[si].PartInfoStartSectorh adc StartSectorh,ax ; StartSector is physical sector# ; ; Call the disk routine to do the read. ; push Buffer push SectorCount push StartSector push [si].PartInfoDiskHandleh push [si].PartInfoDiskHandlel call IoRoutine add sp,14 iodone: pop di pop si pop bx pop es pop ds leave retf PartitionIo endp ;++ ; ; PVOID ; _far ; pLocatePartitionRecord( ; IN UINT PartitionId ; ); ; ; Routine Description: ; ; ; Internal routine. ; ; This routine locates a partition record in the linked list ; of all partition records as prepared by InitializePartitionList(). ; ; Arguments: ; ; PartitionId - supplies an ordinal value identifying the partition. ; Valid range is 0 - n-1, where n is the number returned ; from InitializePartitionList(). ; ; This parameter is passed in ax, not on the stack. ; ; Return Value: ; ; NULL if record not located. ; Otherwise fills ds:si and dx:si with a far pointer to the ; partition record. ; ;-- pLocatePartitionRecord proc far mov dx,DGROUP mov ds,dx mov si,OFFSET PartitionList ; ds:si = &PartitionList ; ; Note that this code depends on the link field in the ; partition record structure being first! ; .errnz PartInfoNext lpr_loop: lds si,[si].PartInfoNext mov dx,ds cmp dx,0 jz lpr_done ; end of list, we're done cmp [si].PartInfoOrdinal,ax jz lpr_done jmp short lpr_loop lpr_done: ret pLocatePartitionRecord endp end