;; GetFileDevName returns a pointer to the file or device name associated
;; with an open file handle.
;;
;; Call with: BX - File handle
;;            ES - PSP segment address
;;
;; Returns:   Carry clear - Address of file or device name in ES:DI
;;            Carry set   - File handle does not correspond to an open
;;                          file or device (handle invalid)
;;
;; Note: This function is valid in MS-DOS versions 2.x, 3.x, 4.0, 5,
;;       and 6, but it is not guaranteed to work in subsequent versions
;;       of MS-DOS. Also, it does not verify that the file handle does
;;       not exceed the JFT length.

FNOffset        equ     word ptr [bp]
SFTEntryLength  equ     byte ptr [bp+2]

GetFileDevName  proc    near
                push    bp                      ;Save BP
                sub     sp,4                    ;Allocate space on the stack
                mov     bp,sp                   ;Copy SP to BP

                push    bx                      ;Save BX
                mov     ah,30h                  ;Get MS-DOS version number
                int     21h
                pop     bx                      ;Restore BX

                mov     FNOffset,04h            ;Set FNOffset to 04h and
                mov     SFTEntryLength,28h      ;SFTEntryLength to 28h
                cmp     al,2                    ;Branch if MS-DOS 2.x
                je      GFDN1

                mov     FNOffset,20h            ;Set FNOffset to 20h and
                mov     SFTEntryLength,35h      ;SFTEntryLength to 35h
                cmp     al,3                    ;Branch if MS-DOS 3.x
                je      GFDN1

                mov     SFTEntryLength,3Bh      ;Set SFTEntryLength to 3Bh
                                                ;(MS-DOS 4.0, 5, or 6)
;
; Locate the Job File Table (JFT) and retrieve the SFT entry number.
;
GFDN1:          cmp     al,2                    ;Branch if MS-DOS version
                je      GFDN3                   ;is 2.x
                cmp     al,3                    ;Branch if MS-DOS version
                jne     GFDN2                   ;is 4.0 or higher
                cmp     ah,3                    ;Branch if MS-DOS version
                jb      GFDN3                   ;is lower than 3.3

GFDN2:          les     di,es:[34h]             ;Get JFT address for MS-DOS
                jmp     short GFDN4             ;3.3 or higher

GFDN3:          mov     di,18h                  ;Get JFT address for MS-DOS
                                                ;versions preceding 3.3
GFDN4:          mov     cl,es:[di+bx]           ;Get SFT entry number in CL
                cmp     cl,0FFh                 ;Branch if the file handle 
                je      GFDNError               ;is invalid (FFh)
                inc     cl                      ;Increment the entry number
;
; Walk the SFT chain and locate the specified entry.
;
                mov     ah,52h                  ;Get SFT address
                int     21h
                les     di,es:[bx+4]            ;Copy address to ES:DI

GFDN5:          cmp     cl,byte ptr es:[di+4]   ;Branch if this block contains
                jbe     GFDN6                   ;the specified SFT entry
                sub     cl,byte ptr es:[di+4]   ;Subtract block length
                les     di,es:[di]              ;Get next SFT block address
                jmp     GFDN5                   ;Loop back for another try

GFDN6:          dec     cl                      ;Decrement entry number
                mov     al,cl                   ;Multiply entry number by
                mul     SFTEntryLength          ;entry length
                add     di,ax                   ;Add result to offset in DI
                add     di,6                    ;Add 6 to skip SFT header

                cmp     byte ptr es:[di],0      ;Error if the first byte in
                je      GFDNError               ;the entry is set to 0

                add     di,FNOffset             ;Compute file name offset
;
; Clean up and exit.
;
                add     sp,4                    ;Deallocate stack space,
                pop     bp                      ;restore BP, and exit with
                clc                             ;carry clear
                ret

GFDNError:      add     sp,4                    ;Deallocate stack space,
                pop     bp                      ;restore BP, and exit with
                stc                             ;carry set
                ret
GetFileDevName  endp

