1
0
mirror of https://github.com/cc65/cc65.git synced 2026-04-25 22:18:27 +00:00

Apple2: implement stat(2) and statvfs(3)

This commit is contained in:
Colin Leroy-Mira
2023-12-28 21:50:13 +01:00
committed by Oliver Schmidt
parent 4343eebe67
commit 75461e1319
23 changed files with 999 additions and 124 deletions
+8 -18
View File
@@ -5,8 +5,8 @@
;
.export _exec
.import pushname, popname
.import popax, done, _exit
.import mli_file_info_direct
.import pushname, popname, popax, done, _exit
.include "zeropage.inc"
.include "errno.inc"
@@ -17,13 +17,12 @@
typerr: lda #$4A ; "Incompatible file format"
; Cleanup name
oserr: jsr popname ; Preserves A
; Set ___oserror
jmp ___mappederrno
mlierr: jsr popname
oserr: jmp ___mappederrno
_exec:
; Save cmdline
; Store cmdline
sta ptr4
stx ptr4+1
@@ -32,6 +31,9 @@ _exec:
jsr pushname
bne oserr
jsr mli_file_info_direct
bcs mlierr
; ProDOS TechRefMan, chapter 5.1.5.1:
; "The complete or partial pathname of the system program
; is stored at $280, starting with a length byte."
@@ -46,18 +48,6 @@ _exec:
dey
bpl :-
; Set pushed name
lda sp
ldx sp+1
sta mliparam + MLI::INFO::PATHNAME
stx mliparam + MLI::INFO::PATHNAME+1
; Get file_type and aux_type
lda #GET_INFO_CALL
ldx #GET_INFO_COUNT
jsr callmli
bcs oserr
; If we get here the program file at least exists so we copy
; the loader stub right now and patch it later to set params
ldx #size - 1
+6 -5
View File
@@ -8,6 +8,7 @@
.import subysp, addysp, decsp1
.include "zeropage.inc"
.include "apple2.inc"
.include "mli.inc"
pushname:
@@ -15,7 +16,7 @@ pushname:
stx ptr1+1
; Alloc pathname buffer
ldy #64+1 ; Max pathname length + zero
ldy #FILENAME_MAX
jsr subysp
; Check for full pathname
@@ -71,14 +72,14 @@ copy: lda (ptr1),y
sta (sp),y
beq setlen
iny
cpy #64+1 ; Max pathname length + zero
cpy #FILENAME_MAX
bcc copy
; Load oserror code
lda #$40 ; "Invalid pathname"
; Free pathname buffer
addsp65:ldy #64+1
addsp65:ldy #FILENAME_MAX
bne addsp ; Branch always
; Alloc and set length byte
@@ -93,5 +94,5 @@ setlen: tya
popname:
; Cleanup stack
ldy #1 + 64+1 ; Length byte + max pathname length + zero
addsp: jmp addysp ; Preserves A
ldy #1 + FILENAME_MAX
addsp: jmp addysp ; Preserves A and X
+7 -49
View File
@@ -4,7 +4,8 @@
; int __fastcall__ clock_gettime (clockid_t clk_id, struct timespec *tp);
;
.import pushax, steaxspidx, incsp1, incsp3, return0
.import pushax, incsp1, incsp3, steaxspidx, return0
.import _mktime_dt
.include "time.inc"
.include "zeropage.inc"
@@ -29,42 +30,12 @@ _clock_gettime:
jsr callmli
bcs oserr
; Get date
lda DATELO+1
lsr
php ; Save month msb
cmp #70 ; Year < 70?
bcs :+ ; No, leave alone
adc #100 ; Move 19xx to 20xx
: sta TM + tm::tm_year
lda DATELO
tax ; Save day
plp ; Restore month msb
ror
lsr
lsr
lsr
lsr
beq erange ; [1..12] allows for validity check
tay
dey ; Move [1..12] to [0..11]
sty TM + tm::tm_mon
txa ; Restore day
and #%00011111
sta TM + tm::tm_mday
; Convert DATELO/TIMELO to time_t
lda #<DATELO
ldx #>DATELO
jsr _mktime_dt
; Get time
lda TIMELO+1
sta TM + tm::tm_hour
lda TIMELO
sta TM + tm::tm_min
; Make time_t
lda #<TM
ldx #>TM
jsr _mktime
; Store tv_sec
; Store
ldy #timespec::tv_sec
jsr steaxspidx
@@ -74,21 +45,8 @@ _clock_gettime:
; Return success
jmp return0
; Load errno code
erange: lda #ERANGE
; Cleanup stack
jsr incsp3 ; Preserves A
; Set __errno
jmp ___directerrno
; Cleanup stack
oserr: jsr incsp3 ; Preserves A
; Set ___oserror
jmp ___mappederrno
.bss
TM: .tag tm
+73
View File
@@ -0,0 +1,73 @@
;
; Oliver Schmidt, 14.08.2018
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
; struct tm * __fastcall__ gmtime_dt(const struct datetime *dt)
;
.export _gmtime_dt, tm_buf
.include "time.inc"
.include "zeropage.inc"
.include "errno.inc"
.include "mli.inc"
; Convert ProDOS date/time to a struct tm
; source date address in AX
; on stack:
; destination struct
_gmtime_dt:
sta ptr1
stx ptr1+1
; Get time
ldy #$03
lda (ptr1),y
sta tm_buf + tm::tm_hour
dey
lda (ptr1),y
sta tm_buf + tm::tm_min
; Get date
dey
lda (ptr1),y
lsr
php ; Save month msb
cmp #70 ; Year < 70?
bcs :+ ; No, leave alone
adc #100 ; Move 19xx to 20xx
: sta tm_buf + tm::tm_year
dey
lda (ptr1),y
tax ; Save day
plp ; Restore month msb
ror
lsr
lsr
lsr
lsr
beq erange ; [1..12] allows for validity check
tay
dey ; Move [1..12] to [0..11]
sty tm_buf + tm::tm_mon
txa ; Restore day
and #%00011111
sta tm_buf + tm::tm_mday
lda #<tm_buf ; Return pointer to tm_buf
ldx #>tm_buf
rts
; Load errno code and return NULL
erange: lda #ERANGE
sta ___errno
lda #$00
tax
rts
.bss
tm_buf:
.tag tm
+37
View File
@@ -0,0 +1,37 @@
;
; Oliver Schmidt, 14.08.2018
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
; time_t __fastcall__ mktime_dt(const struct datetime *dt)
;
.import steaxspidx, pushax, incsp2, _gmtime_dt
.import tm_buf
.export _mktime_dt
.include "time.inc"
.include "zeropage.inc"
.include "errno.inc"
.include "mli.inc"
; Convert ProDOS date/time to UNIX timestamp
; source date address in AX
_mktime_dt:
; Convert to internal tm
jsr _gmtime_dt
cpx #$00
bne :+
cmp #$00
beq err
; Make time_t
: lda #<tm_buf
ldx #>tm_buf
jmp _mktime
err: lda #$00
tax
sta sreg
sta sreg+1
rts
+5 -2
View File
@@ -83,8 +83,8 @@ EOF_COUNT = 2
AUX_TYPE .word
STORAGE_TYPE .byte
BLOCKS .word
MODE_DATE .word
MODE_TIME .word
MOD_DATE .word
MOD_TIME .word
CREATE_DATE .word
CREATE_TIME .word
.endstruct
@@ -139,3 +139,6 @@ LEVEL := $BF94 ; File level: used in open, flush, close
MACHID := $BF98 ; Machine identification
PFIXPTR := $BF9A ; If = 0, no prefix active
KVERSION:= $BFFF ; Kernel version number
; Max filename length
FILENAME_MAX = 64+1
+33
View File
@@ -0,0 +1,33 @@
;
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
.export mli_file_info
.import pushname, popname, mli_file_info_direct
.import popax
.include "zeropage.inc"
.include "errno.inc"
.include "mli.inc"
; Calls ProDOS MLI GET_FILE_INFO on the filename
; stored as C string in AX at top of stack
; Returns with carry set on error, and sets errno
mli_file_info:
; Get pathname
jsr popax
jsr pushname
bne oserr
jsr mli_file_info_direct
php ; Save return status
jsr popname ; Preserves A
plp
bcs oserr
rts
oserr:
jsr ___mappederrno
sec
rts
+22
View File
@@ -0,0 +1,22 @@
;
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
.export mli_file_info_direct
.include "zeropage.inc"
.include "mli.inc"
; Calls ProDOS MLI GET_FILE_INFO on the ProDOS style
; filename stored on top of stack
; Returns with carry set on error, and sets errno
mli_file_info_direct:
; Set pushed name
lda sp
ldx sp+1
sta mliparam + MLI::INFO::PATHNAME
stx mliparam + MLI::INFO::PATHNAME+1
; Get file information
lda #GET_INFO_CALL
ldx #GET_INFO_COUNT
jmp callmli
+1
View File
@@ -18,6 +18,7 @@
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
.include "time.inc"
.segment "ONCE"
+129
View File
@@ -0,0 +1,129 @@
;
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
; int __fastcall__ stat(const char *pathname, struct stat *statbuf);
;
.export _stat
.import __errno, _open,_close
.import mli_file_info
.import popax, pushax, pusha0, incsp2
.include "zeropage.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "filedes.inc"
.include "mli.inc"
.include "stat.inc"
_stat:
; Store statbuf pointer
sta ptr4
sta stbuf
stx ptr4+1
stx stbuf+1
; Clear statbuf
lda #$00
ldy #.sizeof(stat)-1
: sta (ptr4),y
dey
bpl :-
; Reset errno
sta ___errno
; Store pathname
jsr popax
jsr pushax ; Push it back for mli_file_info
jsr pushax ; and for open
jsr mli_file_info
bcc got_info
jmp incsp2 ; Drop filename copy for open
got_info:
; st_dev
lda DEVNUM
lsr ; Shift right to cc65 representation
lsr
lsr
lsr
ldy #stat::st_dev
sta (ptr4),y
; st_mode (S_IFDIR/S_IFREG only)
lda mliparam + MLI::INFO::FILE_TYPE
ldy #stat::st_mode
cmp #$0f
bne is_reg
lda #S_IFDIR
bne set_st_mode
is_reg: lda #S_IFREG
set_st_mode:
sta (ptr4),y
; st_access through st_create_time
ldx #MLI::INFO::ACCESS
ldy #stat::st_access
: lda mliparam,x
sta (ptr4),y
inx
iny
cpy #stat::st_create_time + .sizeof(stat::st_create_time)
bne :-
; st_size
lda #O_RDONLY
jsr pusha0
ldy #$04
jsr _open
cmp #$FF
beq done
pha ; Save file descriptor for closing
; Get ProDOS's REF_NUM from file descriptor
jsr getfd
; Get file information
sta mliparam + MLI::EOF::REF_NUM
lda #GET_EOF_CALL
ldx #EOF_COUNT
jsr callmli
bcs eoferr
; Get struct stat in ptr4 back, open destroyed it
lda stbuf
ldx stbuf+1
sta ptr4
stx ptr4+1
; Store size
ldy #stat::st_size
lda mliparam + MLI::EOF::EOF
sta (ptr4),y
lda mliparam + MLI::EOF::EOF+1
iny
sta (ptr4),y
lda mliparam + MLI::EOF::EOF+2
iny
sta (ptr4),y
; Close file
eoferr:
pla
ldx #$00
jsr _close
; Set return value if we had an error
lda ___errno
beq done
lda #$FF
done:
tax
rts
.bss
stbuf: .res 2
+125
View File
@@ -0,0 +1,125 @@
;
; Colin Leroy-Mira, 2023 <colin@colino.net>
;
; int __fastcall__ statvfs(const char *pathname, struct statvfs *statvfsbuf);
;
.export _statvfs
.import _dio_query_sectsize
.import mli_file_info, pushax, popax, popptr1
.include "zeropage.inc"
.include "apple2.inc"
.include "errno.inc"
.include "mli.inc"
.include "statvfs.inc"
_statvfs:
; Store statbuf
sta ptr4
stx ptr4+1
; Clear statbuf
lda #$00
ldy #.sizeof(statvfs)-1
: sta (ptr4),y
dey
bpl :-
; Store pathname, keeping only volume name
jsr popptr1
ldy #$00
sty vol_sep
lda (ptr1),y
cmp #'/' ; Is the path absolute?
beq :+
lda #EINVAL
jmp ___directerrno
: iny
lda (ptr1),y
beq :+ ; End of string, no other /
cpy #FILENAME_MAX
beq :+ ; Max filename length reached
cmp #'/'
bne :- ; Not a slash, keep looking
sty vol_sep ; Register '/' index
lda #$00
sta (ptr1),y ; Cut pathname at first slash
: lda ptr1
ldx ptr1+1
jsr pushax
jsr mli_file_info
php
ldy vol_sep ; Put slash back in pathname
lda #'/'
sta (ptr1),y
plp
bcc got_info
jmp ___mappederrno
got_info:
; f_fsid
lda DEVNUM
lsr ; Shift right to cc65 representation
lsr
lsr
lsr
ldy #statvfs::f_fsid
sta (ptr4),y
; total number of blocks
lda mliparam + MLI::INFO::AUX_TYPE
ldy #statvfs::f_blocks
sta (ptr4),y
lda mliparam + MLI::INFO::AUX_TYPE+1
iny
sta (ptr4),y
; blocks free & avail
sec
lda mliparam + MLI::INFO::AUX_TYPE
sbc mliparam + MLI::INFO::BLOCKS
ldy #statvfs::f_bfree
sta (ptr4),y
ldy #statvfs::f_bavail
sta (ptr4),y
lda mliparam + MLI::INFO::AUX_TYPE+1
sbc mliparam + MLI::INFO::BLOCKS+1
iny
sta (ptr4),y
ldy #statvfs::f_bfree+1
sta (ptr4),y
; block sizes
jsr _dio_query_sectsize
; low bytes
ldy #statvfs::f_bsize
sta (ptr4),y
ldy #statvfs::f_frsize
sta (ptr4),y
; f_frsize high byte
iny
txa
sta (ptr4),y
; f_bsize high byte
ldy #statvfs::f_bsize+1
sta (ptr4),y
; f_namemax
lda #FILENAME_MAX
ldy #statvfs::f_namemax
sta (ptr4),y
lda #$00
sta ___errno
tax
rts
.bss
vol_sep:.res 1
+1 -1
View File
@@ -108,7 +108,7 @@ static unsigned get_dir_entry(char* p_name)
}
/* Field header_pointer directly follows field last_mod */
cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
cur_addr = *(unsigned*)(&dirent->d_mtime.time.hour + 1);
dhandle = dio_open(getcurrentdevice());
if (!dhandle) {