385 lines
6.9 KiB
ArmAsm
385 lines
6.9 KiB
ArmAsm
|
|
;
|
|
; Hypervisor virtual filesystem - reading directory
|
|
;
|
|
|
|
|
|
; XXX optimize the flow; we do not need 256-byte SD_DIRENT buffer, directory entries can be constructed directly
|
|
|
|
|
|
fs_hvsr_read_dir_open:
|
|
|
|
; Open the directory
|
|
|
|
lda #$12 ; dos_opendir
|
|
sta HTRAP00
|
|
+nop
|
|
|
|
; XXX handle read errors
|
|
|
|
sta SD_DESC ; store directory descriptor XXX invent better name
|
|
|
|
; Reset status to OK
|
|
|
|
lda #$00
|
|
sta PAR_TRACK
|
|
sta PAR_SECTOR
|
|
jsr util_status_SD
|
|
|
|
; Provide pointer to the header
|
|
|
|
lda #$20
|
|
sta SD_ACPTR_LEN+0
|
|
lda #$00
|
|
sta SD_ACPTR_LEN+1
|
|
|
|
lda #<dir_hdr_sd
|
|
sta SD_ACPTR_PTR+0
|
|
lda #>dir_hdr_sd
|
|
sta SD_ACPTR_PTR+1
|
|
|
|
; Set directory phase to 'file name'
|
|
|
|
lda #$01
|
|
sta SD_DIR_PHASE
|
|
|
|
; End
|
|
|
|
jmp dos_EXIT
|
|
|
|
fs_hvsr_read_dir:
|
|
|
|
; Read dirent structure into $1000 and then copy it to SD_DIRENT
|
|
; Starting at $1000 VIC sees chargen, so this should be a safe place
|
|
; Content of the original memory location will be preserved
|
|
|
|
jsr fs_hvsr_dirent_prepare
|
|
|
|
ldx SD_DESC ; directory descriptor
|
|
ldy #$10 ; target page number
|
|
|
|
lda #$14 ; dos_readdir
|
|
sta HTRAP00
|
|
+nop
|
|
|
|
jsr fs_hvsr_dirent_swap ; processor status is preserved
|
|
|
|
; If nothing to read, output 'blocks free'
|
|
|
|
+bcc fs_hvsr_read_dir_blocksfree
|
|
|
|
; Dirent structure - important fields:
|
|
; - $00-$3F - file name
|
|
; - $40 - file name length
|
|
; - $52-$55 - file length
|
|
; - $56-$57 - file type ($10 = dir, $20 = regular) and attributes ($01 for read-only)
|
|
|
|
; Retrieve read-only status, store mark in SD_DIRENT+$FE
|
|
|
|
lda SD_DIRENT+$56
|
|
and #$01
|
|
bne @rdonly
|
|
lda #$00
|
|
+skip_2_bytes_trash_nvz
|
|
|
|
@rdonly:
|
|
|
|
lda #'<'
|
|
sta SD_DIRENT+$FE
|
|
|
|
; Validate/fix characters in file name
|
|
|
|
ldx SD_DIRENT+$40
|
|
dex
|
|
|
|
@lp1:
|
|
|
|
lda SD_DIRENT,x
|
|
cmp #$22
|
|
beq fs_hvsr_read_dir ; quotation mark is illegal
|
|
cmp #$2A
|
|
beq fs_hvsr_read_dir ; asterisk is illegal, it is used for filtering
|
|
cmp #$3F
|
|
beq fs_hvsr_read_dir ; the question mark - in the MS-DOS world it is illegal
|
|
cmp #$20
|
|
bcc fs_hvsr_read_dir ; control characters are not allowed
|
|
cmp #$5B
|
|
bcc @lp1_next ; up to PETSCII 'Z' is OK
|
|
cmp #$61
|
|
bcc fs_hvsr_read_dir ; some characters are not allowed
|
|
cmp #$7E
|
|
bne @lp1_1
|
|
lda #$A6 ; replace tilde / pi with something more sane
|
|
bra @lp1_store_next
|
|
@lp1_1:
|
|
cmp #$7B
|
|
bcs fs_hvsr_read_dir ; PETSCII-art and control characters are illegal
|
|
clc
|
|
sbc #$20 ; make everything the same case
|
|
|
|
@lp1_store_next:
|
|
|
|
sta SD_DIRENT,x
|
|
|
|
@lp1_next:
|
|
|
|
dex
|
|
bpl @lp1
|
|
|
|
; Determine type (file/directory), store marker offset in SD_DIRENT+$FF
|
|
|
|
lda SD_DIRENT+$56
|
|
and #$FE
|
|
beq @cklen_file ; workaround for older hypervisors
|
|
|
|
and #$20
|
|
bne @cklen_file ; branch on file
|
|
|
|
lda SD_DIRENT+$56
|
|
and #$10
|
|
beq fs_hvsr_read_dir ; this type is unknown
|
|
|
|
@cklen_dir:
|
|
|
|
; Validate file name length (directories)
|
|
|
|
lda SD_DIRENT+$40
|
|
beq fs_hvsr_read_dir
|
|
cmp #$11
|
|
bcs fs_hvsr_read_dir
|
|
|
|
; Set type offset for directory in SD_DIRENT+$FF
|
|
|
|
lda #$10
|
|
bra @all_prepared
|
|
|
|
@cklen_file:
|
|
|
|
; Validate file name length (regular files)
|
|
|
|
lda SD_DIRENT+$40
|
|
sec
|
|
sbc #$04 ; strip 4 bytes - for dot and extension
|
|
sta SD_DIRENT+$40
|
|
+bmi fs_hvsr_read_dir ; if name too short, try next entry
|
|
+beq fs_hvsr_read_dir ; if name too short, try next entry
|
|
cmp #$11
|
|
+bcs fs_hvsr_read_dir ; if stripped name is 17 characters or longer, try the next entry
|
|
sta SD_DIRENT+$40 ; store corrected file name length
|
|
tax
|
|
|
|
; Detect file type
|
|
|
|
lda SD_DIRENT, x
|
|
cmp #$2E
|
|
+bne fs_hvsr_read_dir ; 3-character extension is required!
|
|
|
|
inx
|
|
ldy #$00
|
|
|
|
@lpdetect:
|
|
|
|
lda SD_DIRENT+0, x
|
|
cmp dir_types+0, y
|
|
bne @lpdetect_next
|
|
|
|
lda SD_DIRENT+1, x
|
|
cmp dir_types+1, y
|
|
bne @lpdetect_next
|
|
|
|
lda SD_DIRENT+2, x
|
|
cmp dir_types+2, y
|
|
beq @lpdetect_found
|
|
|
|
@lpdetect_next:
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
cpy #(dir_types__end - dir_types)
|
|
bcc @lpdetect
|
|
|
|
jmp fs_hvsr_read_dir ; file extension not detected
|
|
|
|
@lpdetect_found:
|
|
|
|
cpy #$10
|
|
+beq fs_hvsr_read_dir ; file extension 'DIR' does not mean this is a directory
|
|
tya
|
|
|
|
@all_prepared:
|
|
|
|
sta SD_DIRENT+$FF ; store offset to file type in SD_DIRENT+$FF
|
|
cmp #$14
|
|
bcc @noforcedro
|
|
lda #'<' ; for some file types, force the read-only flag
|
|
sta SD_DIRENT+$FE
|
|
|
|
@noforcedro:
|
|
|
|
; Prepare output entry, starting from SD_DIRENT+$80
|
|
|
|
lda #$01 ; link to the next line - dummy, will be regenerated by BASIC
|
|
sta SD_DIRENT+$80
|
|
sta SD_DIRENT+$81
|
|
|
|
ldx SD_DIRENT+$40 ; make sure file name is terminated by 0
|
|
lda #$00
|
|
sta SD_DIRENT, x
|
|
|
|
lda SD_DIRENT+$52 ; calculate file length in blocks to display
|
|
sta PAR_FSIZE_BYTES+0
|
|
lda SD_DIRENT+$53
|
|
sta PAR_FSIZE_BYTES+1
|
|
lda SD_DIRENT+$54
|
|
sta PAR_FSIZE_BYTES+2
|
|
lda SD_DIRENT+$55
|
|
sta PAR_FSIZE_BYTES+3
|
|
|
|
jsr util_dir_filesize_bytes
|
|
|
|
lda PAR_FSIZE_BLOCKS+0
|
|
sta SD_DIRENT+$82
|
|
lda PAR_FSIZE_BLOCKS+1
|
|
sta SD_DIRENT+$83
|
|
|
|
lda #' '
|
|
ldx #$04 ; indent number of blocks
|
|
@lpindent1:
|
|
dey
|
|
bmi @lpindent1_done
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
bra @lpindent1
|
|
|
|
@lpindent1_done:
|
|
|
|
lda #$22 ; opening quote
|
|
sta SD_DIRENT+$80, x
|
|
|
|
ldy #$FF ; put file name
|
|
|
|
@lp2:
|
|
|
|
inx
|
|
iny
|
|
lda SD_DIRENT, y
|
|
sta SD_DIRENT+$80,x
|
|
bne @lp2
|
|
|
|
lda #$22 ; closing quote
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
|
|
lda #' ' ; put spaces for indentation
|
|
ldy SD_DIRENT+$40
|
|
|
|
@lp3:
|
|
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
iny
|
|
cpy #$11
|
|
bcc @lp3
|
|
|
|
; No 'damaged' mark make sense for this filesystem
|
|
|
|
ldy SD_DIRENT+$FF ; put file type
|
|
|
|
@lp4:
|
|
|
|
lda dir_types, y
|
|
beq @lp4_done
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
iny
|
|
bra @lp4
|
|
|
|
@lp4_done:
|
|
|
|
lda SD_DIRENT+$FE ; read-only mark (if needed)
|
|
beq @skipro
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
|
|
@skipro:
|
|
|
|
lda #$00
|
|
sta SD_DIRENT+$80, x
|
|
inx
|
|
|
|
stx SD_ACPTR_LEN+0
|
|
sta SD_ACPTR_LEN+1
|
|
|
|
lda #<(SD_DIRENT+$80)
|
|
sta SD_ACPTR_PTR+0
|
|
lda #>(SD_DIRENT+$80)
|
|
sta SD_ACPTR_PTR+1
|
|
|
|
clc
|
|
rts
|
|
|
|
fs_hvsr_read_dir_blocksfree:
|
|
|
|
; Set pointer to 'BLOCKS FREE.' line
|
|
|
|
; XXX determine free space
|
|
|
|
lda #$13
|
|
sta SD_ACPTR_LEN+0
|
|
lda #$00
|
|
sta SD_ACPTR_LEN+1
|
|
|
|
lda #<dir_end
|
|
sta SD_ACPTR_PTR+0
|
|
lda #>dir_end
|
|
sta SD_ACPTR_PTR+1
|
|
|
|
; Mark end of directory
|
|
|
|
lda #$00
|
|
sta SD_DIR_PHASE
|
|
|
|
; Close the directory within the hypervisor XXX maybe move it to close routine
|
|
|
|
ldx SD_DESC
|
|
lda #$16 ; dos_closedir
|
|
sta HTRAP00
|
|
+nop
|
|
|
|
clc
|
|
rts
|
|
|
|
;
|
|
; Helper routines
|
|
;
|
|
|
|
fs_hvsr_dirent_prepare:
|
|
|
|
ldx #$00
|
|
txa
|
|
@1:
|
|
ldy $1000, x
|
|
sty SD_DIRENT, x
|
|
sta $1000, x
|
|
inx
|
|
bne @1
|
|
|
|
rts
|
|
|
|
fs_hvsr_dirent_swap:
|
|
|
|
php
|
|
ldx #$00
|
|
@1:
|
|
lda $1000, x
|
|
ldy SD_DIRENT, x
|
|
sta SD_DIRENT, x
|
|
sty $1000, x
|
|
inx
|
|
bne @1
|
|
|
|
plp
|
|
rts
|