From 75461e13190976534eec4a1b8ce89f6ed03773ac Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Thu, 28 Dec 2023 21:50:13 +0100 Subject: [PATCH] Apple2: implement stat(2) and statvfs(3) --- asminc/stat.inc | 64 ++++++++++ asminc/statvfs.inc | 46 +++++++ doc/apple2.sgml | 37 +++++- doc/apple2enh.sgml | 39 +++++- doc/funcref.sgml | 171 +++++++++++++++++++++++++++ include/apple2.h | 42 +++++-- include/dirent.h | 36 ++---- include/sys/stat.h | 37 +++++- include/sys/statvfs.h | 74 ++++++++++++ include/sys/types.h | 43 ++++++- include/time.h | 12 +- libsrc/apple2/exec.s | 26 ++-- libsrc/apple2/filename.s | 11 +- libsrc/apple2/gettime.s | 56 ++------- libsrc/apple2/gmtime_dt.s | 73 ++++++++++++ libsrc/apple2/mktime_dt.s | 37 ++++++ libsrc/apple2/mli.inc | 7 +- libsrc/apple2/mli_file_info.s | 33 ++++++ libsrc/apple2/mli_file_info_direct.s | 22 ++++ libsrc/apple2/open.s | 1 + libsrc/apple2/stat.s | 129 ++++++++++++++++++++ libsrc/apple2/statvfs.s | 125 ++++++++++++++++++++ libsrc/apple2/targetutil/convert.c | 2 +- 23 files changed, 999 insertions(+), 124 deletions(-) create mode 100644 asminc/stat.inc create mode 100644 asminc/statvfs.inc create mode 100644 include/sys/statvfs.h create mode 100644 libsrc/apple2/gmtime_dt.s create mode 100644 libsrc/apple2/mktime_dt.s create mode 100644 libsrc/apple2/mli_file_info.s create mode 100644 libsrc/apple2/mli_file_info_direct.s create mode 100644 libsrc/apple2/stat.s create mode 100644 libsrc/apple2/statvfs.s diff --git a/asminc/stat.inc b/asminc/stat.inc new file mode 100644 index 000000000..e5248f06d --- /dev/null +++ b/asminc/stat.inc @@ -0,0 +1,64 @@ +;**************************************************************************** +;* * +;* stat.inc * +;* * +;* Stat struct * +;* * +;* * +;* * +;*(C) 2023 Colin Leroy-Mira * +;* * +;* * +;*This software is provided 'as-is', without any expressed or implied * +;*warranty. In no event will the authors be held liable for any damages * +;*arising from the use of this software. * +;* * +;*Permission is granted to anyone to use this software for any purpose, * +;*including commercial applications, and to alter it and redistribute it * +;*freely, subject to the following restrictions: * +;* * +;*1. The origin of this software must not be misrepresented; you must not * +;* claim that you wrote the original software. If you use this software * +;* in a product, an acknowledgment in the product documentation would be * +;* appreciated but is not required. * +;*2. Altered source versions must be plainly marked as such, and must not * +;* be misrepresented as being the original software. * +;*3. This notice may not be removed or altered from any source * +;* distribution. * +;* * +;**************************************************************************** + + .include "time.inc" + +;------------------------------------------------------------------------------ +; st_mode values + +S_IFDIR = $01 +S_IFREG = $02 + +;------------------------------------------------------------------------------ +; struct stat + +.struct stat + st_dev .dword + st_ino .dword + st_mode .byte + st_nlink .dword + st_uid .byte + st_gid .byte + st_size .dword + st_atim .tag timespec + st_ctim .tag timespec + st_mtim .tag timespec + .ifdef __APPLE2__ + st_access .byte + st_type .byte + st_auxtype .word + st_storagetype .byte + st_blocks .word + st_mod_date .word + st_mod_time .word + st_create_date .word + st_create_time .word + .endif +.endstruct diff --git a/asminc/statvfs.inc b/asminc/statvfs.inc new file mode 100644 index 000000000..8674b045d --- /dev/null +++ b/asminc/statvfs.inc @@ -0,0 +1,46 @@ +;**************************************************************************** +;* * +;* statvfs.inc * +;* * +;* Statvfs struct * +;* * +;* * +;* * +;*(C) 2023 Colin Leroy-Mira * +;* * +;* * +;*This software is provided 'as-is', without any expressed or implied * +;*warranty. In no event will the authors be held liable for any damages * +;*arising from the use of this software. * +;* * +;*Permission is granted to anyone to use this software for any purpose, * +;*including commercial applications, and to alter it and redistribute it * +;*freely, subject to the following restrictions: * +;* * +;*1. The origin of this software must not be misrepresented; you must not * +;* claim that you wrote the original software. If you use this software * +;* in a product, an acknowledgment in the product documentation would be * +;* appreciated but is not required. * +;*2. Altered source versions must be plainly marked as such, and must not * +;* be misrepresented as being the original software. * +;*3. This notice may not be removed or altered from any source * +;* distribution. * +;* * +;**************************************************************************** + +;------------------------------------------------------------------------------ +; struct statvfs + +.struct statvfs + f_bsize .dword + f_frsize .dword + f_blocks .dword + f_bfree .dword + f_bavail .dword + f_files .dword + f_ffree .dword + f_favail .dword + f_fsid .dword + f_flag .dword + f_namemax .dword +.endstruct diff --git a/doc/apple2.sgml b/doc/apple2.sgml index 97724c147..f1603c428 100644 --- a/doc/apple2.sgml +++ b/doc/apple2.sgml @@ -321,14 +321,15 @@ Programs containing Apple ][ specific code may use the Apple ][ specific functions

-The functions listed below are special for the Apple ][. See -the for declaration and +The functions and variables listed below are special for the Apple ][. +See the for declaration and usage. _auxtype _dos_type _filetype +_datetime get_ostype rebootafterexit ser_apple2_slot @@ -569,6 +570,28 @@ program. See the discussion of the . +ProDOS date/time manipulation

+ + +The readdir and stat function return ProDOS timestamps in their file +creation/modification time attributes. You can convert them to more portable +time representations using either: + + + + DIO

@@ -630,6 +653,16 @@ url="ca65.html" name="assembler manual">. that can be used to set these variables. It is included in + + extern struct datetime _datetime; + + + Example A text file cannot be created with just the diff --git a/doc/apple2enh.sgml b/doc/apple2enh.sgml index 11d4feb7e..e27501577 100644 --- a/doc/apple2enh.sgml +++ b/doc/apple2enh.sgml @@ -322,14 +322,15 @@ Programs containing enhanced Apple //e specific code may use the Enhanced Apple //e specific functions

-The functions listed below are special for the enhanced Apple //e. See -the for declaration and +The functions and variables listed below are special for the Apple ][. +See the for declaration and usage. _auxtype _dos_type _filetype +_datetime get_ostype rebootafterexit ser_apple2_slot @@ -575,6 +576,28 @@ program. See the discussion of the . +ProDOS date/time manipulation

+ + +The readdir and stat function return ProDOS timestamps in their file +creation/modification time attributes. You can convert them to more portable +time representations using either: + + + + DIO

@@ -619,7 +642,7 @@ url="ca65.html" name="assembler manual">. auxiliary type. Therefore, some additional mechanism for specifying the file types is needed. - Specifying the File Type and Auxiliary Type + Specifying the File Type, Auxiliary Type and creation date There are two global variables provided that allow the file type and auxiliary type to be specified before a call to . that can be used to set these variables. It is included in + + extern struct datetime _datetime; + + + Example A text file cannot be created with just the diff --git a/doc/funcref.sgml b/doc/funcref.sgml index 524818b19..c8a818295 100644 --- a/doc/funcref.sgml +++ b/doc/funcref.sgml @@ -93,6 +93,8 @@ function. _dos_type + + rebootafterexit @@ -846,6 +848,20 @@ communication, see also testcode/lib/ser-test.c. (incomplete) +

+ + + + + + +

+ + + + + +

(incomplete) @@ -2851,6 +2867,79 @@ setting the time may not work. See also the platform-specific information. +gmtime_dt

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. +This function is only available on Apple II. +On Apple II, you can't stat() an opened file. stat() before opening. + + + +#include +#include +#include +int main(void) +{ + struct stat st; + struct tm* tm; + if (stat ("/disk/file", &st) == 0) { + tm = gmtime_dt (&st.st_ctime); + if (tm) + printf ("File created on %s\n", asctime(tm)); + } +} + + + + + +mktime_dt

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. +This function is only available on Apple II. + + + +#include +#include +#include +int main(void) +{ + struct stat st; + if (stat ("/disk/file", &st) == 0) { + printf ("File created on %s\n", + localtime (mktime_dt (&st.st_ctime))); + } +} + + + + + clrscr

@@ -6229,6 +6318,9 @@ be used in presence of a prototype. The returned pointer may point to a statically allocated instance of On the Apple II platform, the d_ctime and d_mtime returned are in the +ProDOS format. You can convert them to more portable time representations using +the ProDOS datetime conversion functions. On several platforms, namely the CBMs and the Atari, the disk drives get confused when opening/closing files between directory reads. So for example a program that reads the list of files on a disk, and after each call to @@ -7075,6 +7167,85 @@ be used in presence of a prototype. +stat

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. +On the Apple II platform, the st_ctim, st_mtim and st_atim members are left +to zero, for size and performance reasons. The ProDOS creation and modification dates +are returned in the ProDOS format in st_ctime and st_mtime. The access date does +not exist. You can convert them to POSIX-style time representations using +the . + + + +#include <sys/stat.h> + +#define FILENAME "helloworld" +struct stat stbuf; +if (stat (FILENAME, &stbuf) == 0) { + printf ("%s size is %lu bytes (created on %s)\n", FILENAME, stbuf.st_size, +#ifndef __APPLE2__ + localtime (&stbuf.st_ctim.tv_sec) +#else + localtime (mktime_dt (&stbuf.st_ctime)) +#endif + ); +} else { + printf ("There was a problem stat'ing %s: %d\n", FILENAME, errno); +} + + + + + +statvfs

+ + + +/ + +The function is only available as fastcall function, so it may only +be used in presence of a prototype. +The function requires an absolute pathname. + + + +#include <sys/statvfs.h> + +#define FILENAME "/disk/helloworld" +struct statvfs stvbuf; +if (statvfs (FILENAME, &stvbuf) == 0) { + printf ("%s filesystem has %u blocks of %u size, %u of them free.\n", FILENAME, stvbuf.f_blocks, stvbuf.f_bsize, stvbuf.f_bfree); +} else { + printf ("There was a problem statvfs'ing %s: %d\n", FILENAME, errno); +} + + + + + strcasecmp

diff --git a/include/apple2.h b/include/apple2.h index 8b9a3e0ea..25995eec2 100644 --- a/include/apple2.h +++ b/include/apple2.h @@ -41,6 +41,7 @@ # error This module may only be used when compiling for the Apple ][! #endif +#include #include @@ -142,6 +143,27 @@ extern unsigned char _dos_type; ** ProDOS 8 2.4.x - 0x24 */ +/* struct stat.st_mode values */ +#define S_IFDIR 0x01 +#define S_IFREG 0x02 +#define S_IFBLK 0xFF +#define S_IFCHR 0xFF +#define S_IFIFO 0xFF +#define S_IFLNK 0xFF +#define S_IFSOCK 0xFF + +struct datetime { + struct { + unsigned day :5; + unsigned mon :4; + unsigned year :7; + } date; + struct { + unsigned char min; + unsigned char hour; + } time; +}; + /*****************************************************************************/ @@ -151,20 +173,10 @@ extern unsigned char _dos_type; /* The file stream implementation and the POSIX I/O functions will use the -** following struct to set the date and time stamp on files. This specificially +** following struct to set the date and time stamp on files. This specifically ** applies to the open and fopen functions. */ -extern struct { - struct { - unsigned day :5; - unsigned mon :4; - unsigned year :7; - } createdate; /* Current date: 0 */ - struct { - unsigned char min; - unsigned char hour; - } createtime; /* Current time: 0 */ -} _datetime; +extern struct datetime _datetime; /* The addresses of the static drivers */ #if !defined(__APPLE2ENH__) @@ -211,6 +223,12 @@ void rebootafterexit (void); #define _cpeekcolor() COLOR_WHITE #define _cpeekrevers() 0 +struct tm* __fastcall__ gmtime_dt (const struct datetime* dt); +/* Converts a ProDOS date/time structure to a struct tm */ + +time_t __fastcall__ mktime_dt (const struct datetime* dt); +/* Converts a ProDOS date/time structure to a time_t UNIX timestamp */ + /* End of apple2.h */ diff --git a/include/dirent.h b/include/dirent.h index 124c7f224..b95646833 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -33,6 +33,8 @@ #ifndef _DIRENT_H #define _DIRENT_H +#include + /*****************************************************************************/ @@ -46,31 +48,15 @@ typedef struct DIR DIR; #if defined(__APPLE2__) struct dirent { - char d_name[16]; - unsigned d_ino; - unsigned d_blocks; - unsigned long d_size; - unsigned char d_type; - struct { - unsigned day :5; - unsigned mon :4; - unsigned year :7; - } d_cdate; - struct { - unsigned char min; - unsigned char hour; - } d_ctime; - unsigned char d_access; - unsigned d_auxtype; - struct { - unsigned day :5; - unsigned mon :4; - unsigned year :7; - } d_mdate; - struct { - unsigned char min; - unsigned char hour; - } d_mtime; + char d_name[16]; + unsigned d_ino; + unsigned d_blocks; + unsigned long d_size; + unsigned char d_type; + struct datetime d_ctime; + unsigned char d_access; + unsigned d_auxtype; + struct datetime d_mtime; }; #define _DE_ISREG(t) ((t) != 0x0F) diff --git a/include/sys/stat.h b/include/sys/stat.h index d8fc09c75..0e1589d52 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -2,7 +2,7 @@ /* */ /* stat.h */ /* */ -/* Constants for the mode argument of open and creat */ +/* stat(2) definition */ /* */ /* */ /* */ @@ -11,6 +11,9 @@ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ +/* (C) 2023 Colin Leroy-Mira */ +/* EMail: colin@colino.net */ +/* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ /* warranty. In no event will the authors be held liable for any damages */ @@ -36,6 +39,10 @@ #ifndef _STAT_H #define _STAT_H +#include +#include +#include + /*****************************************************************************/ @@ -47,6 +54,30 @@ #define S_IREAD 0x01 #define S_IWRITE 0x02 +#define S_IFMT 0x03 + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + off_t st_size; + struct timespec st_atim; + struct timespec st_ctim; + struct timespec st_mtim; + #ifdef __APPLE2__ + unsigned char st_access; + unsigned char st_type; + unsigned int st_auxtype; + unsigned char st_storagetype; + unsigned int st_blocks; + struct datetime st_mtime; + struct datetime st_ctime; + #endif +}; + /*****************************************************************************/ @@ -55,5 +86,9 @@ +int __fastcall__ stat (const char* pathname, struct stat* statbuf); + + + /* End of stat.h */ #endif diff --git a/include/sys/statvfs.h b/include/sys/statvfs.h new file mode 100644 index 000000000..d9edc2f23 --- /dev/null +++ b/include/sys/statvfs.h @@ -0,0 +1,74 @@ +/*****************************************************************************/ +/* */ +/* statvfs.h */ +/* */ +/* statvfs(3) definition */ +/* */ +/* */ +/* */ +/* (C) 2023 Colin Leroy-Mira */ +/* EMail: colin@colino.net */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STATVFS_H +#define _STATVFS_H + +#include + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +int __fastcall__ statvfs (const char* pathname, struct statvfs* buf); + + + +/* End of statvfs.h */ +#endif diff --git a/include/sys/types.h b/include/sys/types.h index e75dd7d46..89b91c5b4 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -50,6 +50,46 @@ typedef long int off_t; #endif +#ifndef _HAVE_dev_t +#define _HAVE_dev_t +typedef unsigned long int dev_t; +#endif + +#ifndef _HAVE_ino_t +#define _HAVE_ino_t +typedef unsigned long int ino_t; +#endif + +#ifndef _HAVE_nlink_t +#define _HAVE_nlink_t +typedef unsigned long int nlink_t; +#endif + +#ifndef _HAVE_uid_t +#define _HAVE_uid_t +typedef unsigned char uid_t; +#endif + +#ifndef _HAVE_gid_t +#define _HAVE_gid_t +typedef unsigned char gid_t; +#endif + +#ifndef _HAVE_mode_t +#define _HAVE_mode_t +typedef unsigned char mode_t; +#endif + +#ifndef _HAVE_fsblkcnt_t +#define _HAVE_fsblkcnt_t +typedef unsigned long int fsblkcnt_t; +#endif + +#ifndef _HAVE_fsfilcnt_t +#define _HAVE_fsfilcnt_t +typedef unsigned long int fsfilcnt_t; +#endif + /*****************************************************************************/ @@ -60,6 +100,3 @@ typedef long int off_t; /* End of types.h */ #endif - - - diff --git a/include/time.h b/include/time.h index bfc2ac435..6cd0c8068 100644 --- a/include/time.h +++ b/include/time.h @@ -37,6 +37,15 @@ #define _TIME_H +/* Forward declaration for target.h */ +typedef unsigned long time_t; +typedef unsigned long clock_t; + + + +#include + + /* NULL pointer */ #ifndef NULL @@ -49,9 +58,6 @@ typedef unsigned size_t; #endif -typedef unsigned long time_t; -typedef unsigned long clock_t; - /* Structure for broken down time */ struct tm { int tm_sec; diff --git a/libsrc/apple2/exec.s b/libsrc/apple2/exec.s index b8875e9ca..ec90f19bb 100644 --- a/libsrc/apple2/exec.s +++ b/libsrc/apple2/exec.s @@ -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 diff --git a/libsrc/apple2/filename.s b/libsrc/apple2/filename.s index aaef6ec2d..0d4b6bedd 100644 --- a/libsrc/apple2/filename.s +++ b/libsrc/apple2/filename.s @@ -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 diff --git a/libsrc/apple2/gettime.s b/libsrc/apple2/gettime.s index 7467b0189..829aaab3b 100644 --- a/libsrc/apple2/gettime.s +++ b/libsrc/apple2/gettime.s @@ -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 + 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 - 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 diff --git a/libsrc/apple2/gmtime_dt.s b/libsrc/apple2/gmtime_dt.s new file mode 100644 index 000000000..a0b8e9f4d --- /dev/null +++ b/libsrc/apple2/gmtime_dt.s @@ -0,0 +1,73 @@ +; +; Oliver Schmidt, 14.08.2018 +; Colin Leroy-Mira, 2023 +; +; 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 + rts + + ; Load errno code and return NULL +erange: lda #ERANGE + sta ___errno + lda #$00 + tax + rts + + .bss + +tm_buf: + .tag tm diff --git a/libsrc/apple2/mktime_dt.s b/libsrc/apple2/mktime_dt.s new file mode 100644 index 000000000..415f52b9e --- /dev/null +++ b/libsrc/apple2/mktime_dt.s @@ -0,0 +1,37 @@ +; +; Oliver Schmidt, 14.08.2018 +; Colin Leroy-Mira, 2023 +; +; 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 + jmp _mktime + +err: lda #$00 + tax + sta sreg + sta sreg+1 + rts diff --git a/libsrc/apple2/mli.inc b/libsrc/apple2/mli.inc index 42363d9c9..382a071b0 100644 --- a/libsrc/apple2/mli.inc +++ b/libsrc/apple2/mli.inc @@ -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 diff --git a/libsrc/apple2/mli_file_info.s b/libsrc/apple2/mli_file_info.s new file mode 100644 index 000000000..16e01c07f --- /dev/null +++ b/libsrc/apple2/mli_file_info.s @@ -0,0 +1,33 @@ +; +; Colin Leroy-Mira, 2023 +; + + .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 diff --git a/libsrc/apple2/mli_file_info_direct.s b/libsrc/apple2/mli_file_info_direct.s new file mode 100644 index 000000000..c15ebc28f --- /dev/null +++ b/libsrc/apple2/mli_file_info_direct.s @@ -0,0 +1,22 @@ +; +; Colin Leroy-Mira, 2023 +; + + .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 diff --git a/libsrc/apple2/open.s b/libsrc/apple2/open.s index 68c203cd6..38793a13e 100644 --- a/libsrc/apple2/open.s +++ b/libsrc/apple2/open.s @@ -18,6 +18,7 @@ .include "fcntl.inc" .include "mli.inc" .include "filedes.inc" + .include "time.inc" .segment "ONCE" diff --git a/libsrc/apple2/stat.s b/libsrc/apple2/stat.s new file mode 100644 index 000000000..f655b3e3f --- /dev/null +++ b/libsrc/apple2/stat.s @@ -0,0 +1,129 @@ +; +; Colin Leroy-Mira, 2023 +; +; 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 diff --git a/libsrc/apple2/statvfs.s b/libsrc/apple2/statvfs.s new file mode 100644 index 000000000..6274bb52b --- /dev/null +++ b/libsrc/apple2/statvfs.s @@ -0,0 +1,125 @@ +; +; Colin Leroy-Mira, 2023 +; +; 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 diff --git a/libsrc/apple2/targetutil/convert.c b/libsrc/apple2/targetutil/convert.c index ea9273fc3..52dffa745 100644 --- a/libsrc/apple2/targetutil/convert.c +++ b/libsrc/apple2/targetutil/convert.c @@ -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) {