4a081501d8
- bios/conio/env/errno/gfx/io/mem/mouse/stdio/stdlib/string/sys/time/ video разложены по модулям: общие статики и helpers — в internal _-модулях (_conio.h/_mouse.h/_gfx.h/_palette.h/_atexit.h/_time.h) - lib/Makefile: LIBC_C = wildcard libc/*/*.c — гранулярность файлов = гранулярность DCE линкера - эффект _CODE: gfx_text 6986→2568 Б, gfx_mous −1745, gfx_demo/d16 −542; ранее timedir −3270, ls −3098, stattest −2995 - комментарии оставшихся модулей переведены на русский; puts: убран мёртвый pchars; videomode_raw разложен на get/set - docs/libc-split-asm-cases.md — правила asm-связок между модулями; docs/libc-roadmap.md — план этапа - восстановлен examples/mdview/SAMPLE.MD (нужен make floppy) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
92 lines
3.2 KiB
C
92 lines
3.2 KiB
C
/*
|
|
* fstat — POSIX fstat() поверх метаданных ESTEX.
|
|
*
|
|
* fstat(fd, &st) -> ESTEX GET_D_T ($17) для mtime + lseek/SEEK_END
|
|
* для размера.
|
|
*
|
|
* Sprinter / DSS не хранит POSIX owner/group/inode, поэтому mode
|
|
* синтезируется минимальный (S_IFREG | rw для пользователя).
|
|
*/
|
|
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
|
|
/* Дата/время файла по хендлу. ESTEX GET_D_T: A=fd, C=$17 → D=day,
|
|
* E=month, IX=year, H=hour, L=min, B=sec. CF=1 + A=errcode при ошибке.
|
|
*
|
|
* Пишет прямо в *out через `ex (sp), hl` (обмен сохранённого out с
|
|
* HL=час:мин после RST) — статический скретч не нужен.
|
|
* `out->dow` не трогается (GET_D_T его не возвращает). */
|
|
static int get_dt_for_handle(int fd, datetime_t *out) __naked
|
|
{
|
|
(void)fd; (void)out;
|
|
__asm
|
|
;; __sdcccall(1): fd in HL (low byte), out in DE.
|
|
push ix ; save caller IX
|
|
push de ; stash out pointer
|
|
ld a, l ; A = fd
|
|
ld c, #0x17 ; ESTEX GET_D_T
|
|
rst #0x10
|
|
jr c, _gdt_err
|
|
;; D=day E=month IX=year H=hour L=min B=sec
|
|
ex (sp), hl ; TOS<->HL: HL=out, TOS=hour:min
|
|
ld (hl), d ; +0 day
|
|
inc hl
|
|
ld (hl), e ; +1 month
|
|
inc hl
|
|
push ix ; year onto stack
|
|
pop de ; DE = year
|
|
ld (hl), e ; +2 year low
|
|
inc hl
|
|
ld (hl), d ; +3 year high
|
|
inc hl
|
|
pop de ; D=hour E=min (from earlier ex (sp))
|
|
ld (hl), d ; +4 hour
|
|
inc hl
|
|
ld (hl), e ; +5 min
|
|
inc hl
|
|
ld (hl), b ; +6 sec (+7 dow left untouched)
|
|
pop ix ; restore caller IX
|
|
ld de, #0
|
|
ret
|
|
_gdt_err:
|
|
pop hl ; discard stashed out pointer
|
|
pop ix ; restore caller IX
|
|
call __errno_set
|
|
ld de, #-1
|
|
ret
|
|
__endasm;
|
|
}
|
|
|
|
int fstat(int fd, struct stat *buf)
|
|
{
|
|
/* Размер — через lseek-трюк. */
|
|
long cur = lseek(fd, 0L, SEEK_CUR);
|
|
if (cur < 0) return -1;
|
|
long end = lseek(fd, 0L, SEEK_END);
|
|
if (end < 0) return -1;
|
|
(void)lseek(fd, cur, SEEK_SET);
|
|
buf->st_size = (uint32_t)end;
|
|
|
|
/* Дата/время — через ESTEX. */
|
|
datetime_t ft;
|
|
if (get_dt_for_handle(fd, &ft) < 0) return -1;
|
|
{
|
|
struct tm tm;
|
|
tm.tm_sec = ft.second;
|
|
tm.tm_min = ft.minute;
|
|
tm.tm_hour = ft.hour;
|
|
tm.tm_mday = ft.day;
|
|
tm.tm_mon = (unsigned char)(ft.month - 1);
|
|
tm.tm_year = (int)ft.year - 1900;
|
|
tm.tm_isdst = 0;
|
|
tm.tm_hundredth = 0;
|
|
buf->st_mtime = mktime(&tm);
|
|
}
|
|
buf->st_mode = S_IFREG | S_IRUSR | S_IWUSR;
|
|
return 0;
|
|
}
|