; ============================================================================
;
; MicroDOS - Files
;
; ============================================================================
MAXFILES EQU 20 ; total maximum number of open files
NAMELEN EQU 8 ; file name length
EXTLEN EQU 3 ; file extension length
FILENAMELEN EQU NAMELEN+EXTLEN ; file name length with extension
DELETED EQU 0E5h ; flag - deleted file
; ------------- Device handles
DEV_CON EQU 0 ; CON
DEV_AUX EQU 1 ; AUX, COM1
DEV_PRN EQU 2 ; PRN, LPT1
DEV_NUL EQU 3 ; NUL
; ------------- Unopen File Control Block, UFCB
struc UFCB
UFCB_Disk: resb 1 ; 0: disk number (0=default, 1=A:, ...)
UFCB_Name: resb NAMELEN ; 1: blank-padded file name
UFCB_Ext: resb EXTLEN ; 9: blank-padded file extension
UFCB_Cluster: resw 1 ; 0ch: current cluster number
UFCB_RecSize: resw 1 ; 0eh: logical record size
endstruc
UFCB_SIZE EQU UFCB_size ; 10h = 16 bytes
; ------------- File Control Block, FCB
struc FCB
FCB_Disk: resb 1 ; 0: disk number (0=default, 1=A:, ...)
FCB_Name: resb NAMELEN ; 1: blank-padded file name
FCB_Ext: resb EXTLEN ; 9: blank-padded file extension
FCB_Block: resw 1 ; 0Ch: current data block (128 records)
FCB_RecSize: resw 1 ; 0Eh: logical record size
FCB_Size: resd 1 ; 10h: file size
FCB_Date: resw 1 ; 14h: date of last write
; bit 0-4: day
; bit 5-8: month
; bit 9-15: year - 1980
FCB_OpenPar: ; - for devices it contains device ID
; - for files it contains Root index
FCB_Time: resw 1 ; 16h: time of last write (unused)
; bit 0-4: second/2
; bit 5-10: minute
; bit 11-15: hour
FCB_Start: resw 1 ; 18h: internal,starting cluster number
FCB_Current: resw 1 ; 1Ah: internal,current custer number
FCB_CurRel: resw 1 ; 1Ch: internal, relat. cluster in file
FCB_Modi: resb 1 ; 1Eh: internal, 1=file modified
resb 1
FCB_RecBlock: resb 1 ; 20h: record within current data block
; 0 to 127
endstruc
FCB_SIZE EQU FCB_size ; 21h = 33 bytes
; ------------- Extended File Control Block, XFCB
struc XFCB
XFCB_Sign: resb 1 ; 0: 0ffh signature to XFCB
resb 5 ; 1: ...reserved
XFCB_Attr: resb 1 ; 6: file attributes
XFCB_FCB: resb FCB_SIZE ; 7: standard FCB
endstruc
XFCB_SIZE EQU XFCB_size ; 28h = 40 bytes
; ------------- Open mode
OPEN_MASK EQU B0+B1+B2 ; access mode mask
OPEN_RO EQU 0 ; read only
OPEN_WO EQU 1 ; write only
OPEN_RW EQU 2 ; read/write
; ------------- DOS Directory Entry, DIR
struc DIR
DIR_Name: resb NAMELEN ; 0: blank-padded file name
; first character is set to:
; - 0e5h for deleted entry
; - 0 for unused entry
DIR_Ext: resb EXTLEN ; 8: blank-padded file extension
DIR_Attrib: resb 1 ; 0Bh: attributes (see File attributes)
resb 10 ; 0Ch: ...reserved
DIR_Time: resw 1 ; 16h: time of last write
; bit 0-4: second/2
; bit 5-10: minute
; bit 11-15: hour
DIR_Date: resw 1 ; 18h: date of last write
; bit 0-4: day
; bit 5-8: month
; bit 9-15: year - 1980
DIR_Cluster: resw 1 ; 1Ah: starting cluster number
DIR_Size: resd 1 ; 1Ch: file size
endstruc
DIR_SIZE EQU DIR_size ; 20h = 32 bytes
; ------------- File attributes
ATR_RO EQU B0 ; read-only
ATR_HID EQU B1 ; hidden
ATR_SYS EQU B2 ; system
ATR_VOL EQU B3 ; volume label
;ATR_DIR EQU B4 ; directory (unused)
;ATR_ARC EQU B5 ; archive (unused)
; ----------------------------------------------------------------------------
; Open FCB file
; ----------------------------------------------------------------------------
; INPUT: SS:BP = disk DDPB
; BL = flag, 0=first file, 1=next file
; OUTPUT: CY = error
; DS = data segment
; BX = device file handle, if BH = 0ffh
; else pointer to Root directory entry
; DS:SI = file starting cluste number
; ----------------------------------------------------------------------------
; ------------- Push registers
OpenFCB: push ax ; push AX
push cx ; push CX
push di ; push DI
push es ; push ES
; ------------- Prepare registers
push cs ; push CS
pop ds ; DS <- CS
push cs ; push CS
pop es ; ES <- CS
; ------------- Find next file
or bl,bl ; find next file?
jnz OpenFCB2 ; find next file
; ------------- Check if it is reserved device (-> BX device handle)
call CheckDev ; check device
jnc OpenFCB8 ; it is device
; ------------- Read FAT table from disk
call ReadFAT ; read FAT table
; ------------- Prepare first Root entry
mov word [RootIndex],-1 ; index of current Root entry
OpenFCB2: call GetNextRoot ; get next Root entry
jc OpenFCB8 ; no Root entry
; ------------- Is this entry deleted?
cmp byte [bx],DELETED ; is this entry deleted?
je OpenFCB2 ; delete entry
; ------------- Compare filename
mov si,bx ; SI <- filename in Root entry
mov di,CurFilename ; DI <- FCB filename
mov cx,FILENAMELEN ; CX <- length of filename
cld ; direction up
OpenFCB3: repe cmpsb ; compare filename
je OpenFCB4 ; filename equals
cmp byte [di-1],"?" ; substitute character?
je OpenFCB3 ; this character is OK
jmp short OpenFCB2 ; next Root entry
; ------------- Check file attributes
OpenFCB4: mov al,[CurAttrib] ; AL <- required attributes
not al ; AL <- attribute mask
and al,[si] ; test attribute
add si,DIR_Cluster-DIR_Attrib ; skip to cluster number
and ah,ATR_HID | ATR_SYS ; system file?
jz OpenFCB8 ; no system file, ok
cmp byte [OpenHidSys],0 ; open HID and SYS files?
je OpenFCB2 ; no, search next file
; ------------- Pop registers
OpenFCB8: pop es ; pop ES
pop di ; pop DI
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Parse and open FCB file
; ----------------------------------------------------------------------------
; INPUT: DS:DX = FCB or XFCB
; OUTPUT: CY = error
; SS:BP = DDPB of the disk
; DS = data segment
; BX = device file handle, if BH = 0ffh
; else pointer to Root directory entry
; DS:SI = starting cluster number
; ----------------------------------------------------------------------------
; ------------- Check and parse FCB
ParseOpenFCB: call LoadFCB ; check and parse FCB
jc ParseOpenFCB4 ; error
; ------------- Read FCB from directory
mov bl,0 ; flag, open first FCB
call OpenFCB ; open FCB file
ParseOpenFCB4: ret
; ----------------------------------------------------------------------------
; Parse and open FCB file with ES:DI
; ----------------------------------------------------------------------------
; INPUT: DS:DX = FCB or XFCB
; OUTPUT: CY = error
; ES:DI = original FCB (not XFCB)
; SS:BP = DDPB of the disk
; DS = data segment
; BX = device file handle, if BH = 0ffh
; else pointer to Root directory entry
; DS:SI = starting cluster number
; ----------------------------------------------------------------------------
ParseOpenFCBX: push dx ; push DX
push ds ; push DS
call ParseOpenFCB ; parse and open FCB
pop es ; ES <- original DS
pop di ; DI <- original DI
ParseOpenKorig: pushf ; push flags
cmp byte [es:di],0ffh ; is it extended FCB?
jne ParseOpenFCBX2 ; it is not extended FCB
add di,byte 7 ; DI <- normal FCB
ParseOpenFCBX2: popf ; pop flags
ret
; ----------------------------------------------------------------------------
; Int 21h, function 0Fh - open file using FCB
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 0Fh (function code)
; DS:DX = unopened FCB
; INT21 OUTPUT: AL = status
; 00h: successful
; 0ffh: file not found
; ----------------------------------------------------------------------------
; ------------- Find file FCB
Int210F: call ParseOpenFCBX ; parse and open FCB file
jc Int210F9 ; error, file not found
; ------------- Check if it is a device
Int210FNew: cmp bh,0ffh ; is it a device?
jne Int210F2 ; it is not device
mov [es:di+FCB_OpenPar],bx ; store device ID
mov al,0 ; AL <- 0, status OK
ret
; ------------- Filling up file informations
Int210F2: cld ; direction up
mov al,[bp+DDPB_disk] ; AL <- disk drive
stosb ; store disk drive
add di,FILENAMELEN ; skip filename
xor ax,ax ; AX <- 0
stosw ; clear current cluster number
mov al,80h ; AX <- 80h, default record size
stosw ; set default record size
lodsw ; AX <- starting cluster number
push ax ; push starting cluster number
movsw ; file size LOW
movsw ; file size HIGH
mov ax,[si-8] ; AX <- date of last write
stosw ; set date of last write
mov ax,[RootIndex] ; AX <- index of Root entry
stosw ; set index of Root entry
pop ax ; AX <- starting cluster number
stosw ; set starting cluster number
stosw ; set current cluster number
xor ax,ax ; AX <- 0
stosw ; set current cluster in file
stosb ; flag, file not modified
ret
Int210F9: mov al,0ffh ; error flag
ret
; ----------------------------------------------------------------------------
; Int 21h, function 10h - close file using FCB
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 10h (function code)
; DS:DX = opened FCB
; INT21 OUTPUT: AL = status
; 00h: successful
; 0ffh: failed
; ----------------------------------------------------------------------------
; ------------- Skip extended header
Int2110: mov di,dx ; DI <- FCB
cmp byte [di],0ffh ; is it extended FCB?
jne Int21102 ; it is not extended FCB
add di,byte 7 ; skip extended header
; ------------- Check if it is device
Int21102: cmp byte [di+FCB_OpenPar+1],0ffh ; is it device?
je Int21107 ; it is device
; ------------- Check if the file is modified
cmp byte [di+FCB_Modi],0 ; is file modified?
je Int21107 ; it is not modified
; ------------- Get DDPB disk table (-> SS:BP)
mov al,[di+FCB_Disk]; AL <- disk number
call GetDDPB ; get DDPB disk table
jc Int21109 ; error, invalid disk drive
; ------------- Check if data buffer is modified
mov al,[bp+DDPB_disk] ; AL <- disk
mov ah,1 ; flag - buffer is modified
cmp ax,[cs:DataDiskModi] ; is buffer modified?
jne Int21104 ; buffer is not modified
; ------------- Write data buffer to disk
call WriteData ; write data buffer to disk
; ------------- Open file Root entry
Int21104: call ParseOpenFCBX ; open file Root entry
jc Int21108 ; error
; ------------- Check Root index (if file is property opened)
mov ax,[es:di+FCB_OpenPar] ; Root index
cmp ax,[cs:RootIndex] ; check Root index
jne Int21108 ; invalid Root index
; ------------- Transfer new parameters
mov ax,[es:di+FCB_Start] ; AX <- starting cluster number
mov [si],ax ; store starting cluster number
mov ax,[es:di+FCB_Size] ; AX <- file size LOW
mov [si+2],ax ; store file size LOW
mov ax,[es:di+FCB_Size+2] ; AX <- file size HIGH
mov [si+4],ax ; store file size LOW
mov ax,[es:di+FCB_Date] ; AX <- date of last write
mov [si-2],ax ; store date of last write
; ------------- Write Root buffer to disk
call ModiWriteRoot ; modify and write Root to disk
; ------------- Write FAT table to disk
call WriteFAT ; write FAT table to disk
; ------------- Result OK
Int21107: mov al,0 ; status OK
ret
; ------------- Error, clear FAT modified flag
Int21108: mov byte [bp+DDPB_modi],0 ; clear FAT buffer modified flag
Int21109: mov al,0ffh ; error flag
ret
; ----------------------------------------------------------------------------
; Int 21h, function 13h - delete file using FCB
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 13h (function code)
; DS:DX = unopened FCB ('?' wildcards allowed)
; INT21 OUTPUT: AL = status
; 00h: one or more files successfully deleted
; 0ffh: no matching files or all were read-only
; ----------------------------------------------------------------------------
; ------------- Find file FCB
Int2113: call ParseOpenFCB ; parse and open FCB file
mov al,0ffh ; AL <- 0ffh error flag
jc Int21138 ; error
; ------------- Check if it is device file (CON, AUX, ...)
cmp al,bh ; is it device file?
je Int21138 ; it is device file
; ------------- Delete directory entry
Int21132: mov byte [bx],DELETED ; delete directory entry
; ------------- Prepare first cluster number
mov bx,[si] ; BX <- first cluster number
or bx,bx ; is it free cluster?
jz Int21136 ; it is free cluster
cmp bx,[bp+DDPB_maxclust] ; check cluster number
ja Int21136 ; invalid cluster, end of chain
; ------------- Free cluster chain
call FreeChain ; free cluster chain
; ------------- Find next FCB file
Int21136: mov bl,1 ; flag, open next FCB
call OpenFCB ; open next FCB file
jnc Int21132 ; next file OK
; ------------- Write FAT to disk
call WriteFAT ; write FAT to disk
; ------------- Modify and write Root to disk
call ModiWriteRoot ; modify and write Root to disk
mov al,0 ; AL <- 0 status, operation OK
Int21138: ret
; ----------------------------------------------------------------------------
; Get record number from opened FCB
; ----------------------------------------------------------------------------
; INPUT: DS:DX = opened FCB
; OUTPUT: CX = 1 (number of records)
; DX:AX = record number
; DS:DI = normal FCB (not extended)
; ----------------------------------------------------------------------------
; ------------- Skip extended FCB header
GetRecord: mov di,dx ; DI <- FCB
cmp byte [di],0ffh ; is it extended FCB?
jne GetRecord2 ; it is not extended FCB
add di,7 ; skip to normal FCB
; ------------- Prepare record number
GetRecord2: mov al,[di+FCB_RecBlock] ; AL <- record within data block
mov dx,[di+FCB_Block]; DX <- current data block
shl al,1 ; AL << 1 (prerotate, *2)
shr dx,1 ; DX / 2, low bit -> CF
rcr al,1 ; transfer low bit from DX >> AL
mov ah,dl ; AH <- DL
mov dl,dh ; DL <- DH
mov dh,0 ; DH <- 0
ret
; ----------------------------------------------------------------------------
; Prepare for file read/write
; ----------------------------------------------------------------------------
; INPUT: CX = number of records
; DX:AX = record number
; DS:DI = normal FCB (not extended)
; OUTPUT: CY = error
; SS:BP = DDPB of the disk
; DS = data segment
; ES:DI = normal FCB (not extended)
; CX = number of bytes
; DESTROYS: AX, BX, DX, SI
; ----------------------------------------------------------------------------
; ------------- Prepare record size (-> BX)
PrepRW: mov bx,[di+FCB_RecSize] ; BX <- record size
or bx,bx ; use default record size?
jnz PrepRW1 ; record size known
mov bl,80h ; BX <- 80h default record size
mov [di+FCB_RecSize],bx ; set default record size
; ------------- Prepare segment registers
PrepRW1: push ax ; push AX (record LOW)
mov al,[di+FCB_Disk] ; AL <- disk number
push ds ; push DS
pop es ; ES <- FCB segment
push cs ; push CS
pop ds ; DS <- CS
; ------------- Prepare DDPB disk table
call GetDDPB ; get DDPB disk table
pop ax ; pop AX
jnc PrepRW3 ; disk is OK
; ------------- Error, invalid disk
mov byte [RWResult],4 ; error, invalid disk
PrepRW2: xor cx,cx ; CX <- 0 no data transfered
stc ; set error flag
ret
; ------------- Ignore highest byte of record number if record size >= 64
PrepRW3: cmp bx,byte 64 ; is small record size?
jb PrepRW4 ; small record size
mov dh,0 ; else ignore highest byte of record
; ------------- Store parameters for operation
PrepRW4: mov byte [RWResult],0 ; set operation result OK
mov [RWRecords],cx ; store number of records
mov [RWRecord],ax ; store record number LOW
mov [RWRecord+2],dx ; store record number HIGH
mov [RWFCB],di ; store address of FCB
mov si,[DTA] ; offset of DTA
mov [RWAddr],si ; store offset of DTA address
mov byte [RWDataOn],0 ; flag, don't transfer data
; ------------- Recalc record number to offset in file
mov si,dx ; SI <- record number HIGH
mul bx ; offset in file LOW
mov [RWFileOff],ax ; store offset in file LOW
push dx ; push offet in file HIGH
xchg ax,si ; AX <- record number HIGH
mul bx ; offset in file HIGH
pop si ; SI <- carry from offset LOW
add ax,si ; add carry from offset LOW
mov [RWFileOff+2],ax ; offset in file HIGH
adc dx,byte 0 ; carry HIGH
jz PrepRW7 ; data OK
; ------------- Error, no data
PrepRW5: mov byte [RWResult],1 ; error, no data
PrepRW6: jmp short PrepRW2
; ------------- Recalc offset in file to sector in file
PrepRW7: xchg ax,dx ; DX <- offset in file HIGH
mov ax,[RWFileOff] ; AX <- offset in file LOW
mov si,[bp+DDPB_sector] ; SI <- sector size
cmp dx,si ; would be overflow?
jae PrepRW5 ; error, overflow
div si ; recalc to sector number
mov [RWFileSect],ax ; store sector in file
mov [RWSectOff],dx ; store offset in sector
; ------------- Recalc sector in file to cluster in file
mov si,ax ; SI <- sector in file
and al,[bp+DDPB_maxsect] ; mask sector in cluster
mov [RWClustSect],al ; sector in cluster
mov ax,cx ; AX <- number of records
mov cl,[bp+DDPB_shifts] ; CL <- shift count
shr si,cl ; SI <- cluster in file
mov [RWFileClust],si ; store cluster in file
; ------------- Check DTA address
mul bx ; recalc records to bytes
mov cx,ax ; CX <- store lenght of data
mov si,[DTA] ; SI <- offset in DTA buffer
add ax,si ; add offset in DTA buffer
adc dx,byte 0 ; overflow
jz PrepRW9 ; no overflow over segment boundary
mov byte [RWResult],2 ; error, segment overflow
; ------------- Limit data to segment boundary
xchg ax,si ; AX <- offset in DTA buffer
neg ax ; rest to 64 KB
jnz PrepRW8 ; no overflow
dec ax ; limit data to 0ffffh
PrepRW8: xor dx,dx ; DX <- 0
div bx ; recalc data to records
mov [RWRecords],ax ; new number of records
mul bx ; recalc back to data size
xchg ax,cx ; CX <- number of bytes
jcxz PrepRW6 ; error, no data remains
PrepRW9: clc ; operation OK
ret
; ----------------------------------------------------------------------------
; Read from file
; ----------------------------------------------------------------------------
; INPUT: CX = number of records
; DX:AX = record number
; DS:DI = normal FCB (not extended)
; OUTPUT:
; ----------------------------------------------------------------------------
; ------------- Prepare for operation
ReadFile: call PrepRW ; prepare for operation
jnc ReadFile1 ; ok
ret ; error
; ------------- Check if it is a device
ReadFile1: mov bx,[es:di+FCB_OpenPar] ; BX <- device ID
cmp bh,0ffh ; is it device?
jne ReadFile2 ; it is not device
jmp ReadDev ; read from device
ReadFile2:
ReadFileDevRet:
ret
; ------------- Prepare to read from device
ReadDev: push es ; push ES (FCB segment)
les di,[DTA] ; ES:DI <- DTA address
and bx,byte 7fh ; is it console?
jnz ReadDev3 ; it is not console
; ------------- Check if there are next data to read from console buffer
mov si,[RWConAddr] ; SI <- console buffer
or si,si ; there are next data?
jnz ReadDev25 ; there are next data to read
; ------------- Initialize console input buffer
cmp byte [ConBuff],80h ; is console buffer initialized?
je ReadDev22 ; buffer is initialized
mov word [ConBuff],0ff80h ; initialize buffer
; ------------- Read next line from console to buffer
ReadDev22: push cx ; push CX (number of bytes)
push di ; push DI (offset of buffer)
push es ; push ES (segment of buffer)
mov dx,ConBuff ; DX <- console input buffer
call Int210A ; read from console
pop es ; pop ES
pop di ; pop DI
pop cx ; pop CX
; ------------- Check if there any data in console buffer
mov si,ConBuff ; SI <- console buffer
mov al,EOF ; AL <- EOF
cmp [si],al ; any valid data in buffer?
jne ReadDev25 ; read data from console buffer
; ------------- Mark end of text
cld ; direction up
stosb ; store EOF character
mov al,LF ; AL <- LF character
call ConOutChar ; display character on console
xor si,si ; SI <- 0, no other data
jmp short ReadDev28
; ------------- Read next data from console buffer (ending with CR/LF)
ReadDev25: cld ; direction up
ReadDev26: lodsb ; AL <- load next character
stosb ; store this character
cmp al,CR ; is it CR character?
jne ReadDev27 ; it is not CR character
mov byte [si],LF ; next character will be LF
ReadDev27: cmp al,LF ; is it end of line?
loopne ReadDev26 ; next character
jnz ReadDev28 ; any data remain
; ------------- Prepare next data from konzole
call ConOutChar ; display character on console
xor si,si ; SI <- 0 no data left
or cx,cx ; any other data required?
jnz ReadDev22 ; read next line from console
inc ax ; clear ZF
ReadDev28: mov [RWConAddr],si ; store new address of buffer
jmp short ReadDev4
; ------------- Read from AUX (COM1) port
ReadDev3: dec bx ; is it AUX device?
jnz ReadDev4 ; it is not AUX device
ReadDev32: call Int2103 ; read character from AUX/COM1
cld ; direction up
stosb ; store character
cmp al,EOF ; end of file?
loopne ReadDev32 ; next character
; ------------- Read data from PRN and NUL (=no data to read)
ReadDev4: mov [RWAddr],di ; next store address
pop es ; pop ES (FCB segment)
jnz ReadDev42 ; there left any data
mov di,[RWFCB] ; DI <- FCB offset
or byte [es:di+FCB_OpenPar],80h ; change to NUL device
ReadDev42: jmp ReadFileDevRet
; ----------------------------------------------------------------------------
; Int 21h, function 14h - sequential read from FCB file
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 14h (function code)
; DS:DX = opened FCB
; INT21 OUTPUT: AL = status
; 00h: successful
; 01h: end of file, no data
; 02h: segment wrap in DTA
; 03h: end of file, partial record read
; 04h: invalid disk
; DTA (Disk Transfer Area) filled with record read from file
; ----------------------------------------------------------------------------
; NOTES: - If a partial record was read, it is zero-padded to full size
; ----------------------------------------------------------------------------
; ------------- Get current record number
Int2114: call GetRecord ; get current record number
; ------------- Read from file
call ReadFile ; read from file
; ----------------------------------------------------------------------------
; Int 21h, function 15h - sequential write to FCB file
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 15h (function code)
; DS:DX = opened FCB
; DTA (Disk Transfer Area) contains record to be written
; INT21 OUTPUT: AL = status
; 00h: successful
; 01h: disk full
; 02h: segment wrap in DTA
; 04h: invalid disk
; ----------------------------------------------------------------------------
; ------------- Get current record number
Int2115: call GetRecord ; get current record number
; ----------------------------------------------------------------------------
; Int 21h, function 16h - create or truncate file using FCB
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 16h (function code)
; DS:DX = unopened FCB
; INT21 OUTPUT: AL = status
; 00h: successful
; 0ffh: directory full or existing file is read-only
; ----------------------------------------------------------------------------
; ------------- Check and parse FCB
Int2116: call LoadFCB ; check and parse FCB
jc Int21165 ; error
; ------------- Check if filename contains wildcars
push cs ; push CS
pop es ; ES <- CS
mov al,"?" ; search wildcard character
mov di,CurFilename ; DI <- current filename
mov cx,FILENAMELEN ; CX <- length of filename
repne scasb ; find wildcard character
je Int21165 ; error, no wildcards allowed
; ------------- Push original FCB
push dx ; push DX (FCB offset)
push ds ; push DS (FCB segment)
; ------------- Open existing file
mov byte [cs:OpenHidSys],1 ; open HID and SYS files
mov bl,0 ; flag, open first FCB
call OpenFCB ; open FCB file
jnc Int21166 ; file found, truncate it
; ------------- Read FAT table from disk
call ReadFAT ; read FAT table
; ------------- Find free Root entry
mov word [RootIndex],-1 ; index of current Root entry
Int21162: call GetNextRoot ; get next Root entry
jc Int21164 ; error, no next entry
cmp byte [bx],0 ; unused entry?
je Int21167 ; found unused directory entry
cmp byte [bx],DELETED ; find free directory entry?
jne Int21162 ; no free entry
jmp short Int21167
; ------------- Error
Int21164: pop ds ; pop DS
pop dx ; pop DX
Int21165: mov al,0ffh ; error flag
ret
; ------------- Check if existing file is valid
Int21166: cmp bh,0ffh ; is it device?
je Int21168 ; it is device, reopen it
test byte [bx+DIR_Attrib],ATR_RO ; is it read-only?
jnz Int21164 ; file is read-only
; ------------- Truncate existing file
mov ax,[si] ; AX <- starting cluster
or ax,ax ; is any clulster?
jz Int21167 ; file has no data
cmp ax,[bp+DDPB_maxclust] ; is it valid cluster?
ja Int21167 ; end of file
push bx ; push BX
xchg ax,bx ; BX <- starting cluster
call FreeChain ; free cluster chain
call WriteFAT ; write FAT table to disk
pop bx ; pop BX
; ------------- Fill directory entry
Int21167: mov di,bx ; DI <- directory entry
mov si,CurFilename ; SI <- current filename
mov cx,FILENAMELEN ; CX <- length of filename
rep movsb ; copy filename
mov al,[CurAttrib] ; AL <- attributes
stosb ; set attributes
mov al,0 ; AL <- 0
mov cl,12 ; CX <- 12 unused data
rep stosb ; clear unused data + time
mov ax,[FileDate] ; AX <- current date
stosw ; set current date
mov al,0 ; AL <- 0
mov cl,6 ; CX <- 6
rep stosb ; clear cluster and file size
; ------------- Modify and write Root to disk
call ModiWriteRoot ; modify and write Root to disk
; ------------- Result OK - open file
Int21168: pop es ; pop ES (FCB segment)
pop di ; pop DI (FCB offset)
call ParseOpenKorig ; korig ED:DI (skip XFCB header)
jmp Int210FNew ; reopen new file
; ----------------------------------------------------------------------------
; Int 21h, function 17h - rename file using FCB
; ----------------------------------------------------------------------------
; INT21 INPUT: AH = 17h (function code)
; DS:DX = modified FCB ('?' wildcards allowed)
; - old filename is in the standard location
; - new filename is on the 11h offset
; INT21 OUTPUT: AL = status
; 00h: successfully renamed
; 0ffh: no matching files, read-only or already exists
; ----------------------------------------------------------------------------
; ------------- Check and parse FCB
Int2117: call LoadFCB ; check and parse FCB
jc Int21176 ; error
; ------------- Parse second FCB
add si,5 ; SI <- second filename in FCB
mov di,SecFilename ; DI <- buffer of second filename
call Load2FCB ; parse second FCB
jc Int21176 ; error, invalid filename
; ------------- Find first FCB
mov bl,0 ; flag, open first FCB
call OpenFCB ; open FCB file
jc Int21176 ; error, file not found
cmp bh,0ffh ; is it device?
je Int21176 ; error, it is device
; ------------- Push filename into temporary buffer
push cs ; push CS
pop es ; ES <- CS
mov cx,FILENAMELEN ; CX <- length of filename
mov si,CurFilename ; SI <- current filename
mov di,PushFilename ; DI <- push filename
cld ; direction up
rep movsb ; store filename
; ------------- Assemble new filename
Int21172: mov cx,FILENAMELEN ; CX <- length of filename
mov di,CurFilename ; DI <- current filename
mov si,SecFilename ; SI <- second filename
Int21174: lodsb ; load character
cmp al,"?" ; is it wildcard?
jne Int21175 ; it is not wildcard
mov al,[bx] ; AL <- character of found filename
Int21175: inc bx ; increase filename pointer
stosb ; store new character
loop Int21174 ; next character
; ------------- Check, if it is now device name
call CheckDev ; check reserved device name
jnc Int21176 ; error, it is device name
; ------------- Check, if such filename already exists
push word [RootIndex] ; push current Root index
mov word [RootIndex],-1 ; index of current Root entry
mov bl,1 ; flag, open next FCB
call OpenFCB ; open FCB file
pop ax ; AX <- old Root index
jc Int21178 ; ok, file not found
; ------------- Error
Int21176: mov al,0ffh ; AL <- 0ffh, error flag
jmp short Int21179
; ------------- Return old root entry
Int21178: dec ax ; previous Root index
mov [RootIndex],ax ; return old index
call GetNextRoot ; return old root entry
; ------------- Store new filename into entry
mov cx,FILENAMELEN ; CX <- length of filename
mov si,CurFilename ; SI <- new filename
mov di,bx ; DI <- directory entry
rep movsb ; store new filename
call SetRootModi ; set Root modified flag
; ------------- Restore filename from temporary buffer
mov cx,FILENAMELEN ; CX <- length of filename
mov si,PushFilename ; SI <- pushed filename
mov di,CurFilename ; DI <- current filename
rep movsb ; restore filename
; ------------- Find next FCB file
mov bl,1 ; flag, open next FCB
call OpenFCB ; open next FCB file
jnc Int21172 ; next file OK
; ------------- OK
mov al,0 ; AL <- 0, OK flag
Int21179: call WriteRoot ; write Root sector
ret
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
RootIndex: dw 0 ; index of current Root entry
RootSectDisk:
RootSect: db -1 ; current Root sector in Root buffer
RootDisk: db -1 ; current disk in Root buffer
RootModi: db 0 ; flag, 0ffh=Root buffer modified, 0=no
; ------------- Read/write file operation
RWResult: db 0 ; result of file operation
RWRecords: dw 0 ; number of required records
RWRecord: dd 0 ; record number
RWFCB: dw 0 ; offset of original FCB
RWAddr: dw 0 ; address of buffer (offset in DTA)
RWDataOn: db 0 ; 1=transfer data, 0=don't transfer
RWFileOff: dd 0 ; offset in file
RWFileSect: dw 0 ; sector in file
RWSectOff: dw 0 ; offset in sector
RWFileClust: dw 0 ; cluster in file
RWDiskClust: dw 0 ; cluster in disk
RWClustSect: dw 0 ; sector in cluster
RWConAddr: dw 0 ; address for reading from console
; ------------- Current file
CurFilename: times FILENAMELEN db SPACE ; current filename
SecFilename: times FILENAMELEN db SPACE ; second filename
PushFilename: times FILENAMELEN db SPACE ; push filename
CurExtFlag: db 0 ; flag, 0ffh = use extended FCB
CurAttrib: db 0 ; current attributes
OpenHidSys: db 0 ; flag, 0ffh = open HID and SYS files
|