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:
committed by
Oliver Schmidt
parent
4343eebe67
commit
75461e1319
+8
-18
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -18,6 +18,7 @@
|
||||
.include "fcntl.inc"
|
||||
.include "mli.inc"
|
||||
.include "filedes.inc"
|
||||
.include "time.inc"
|
||||
|
||||
.segment "ONCE"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user