/* * 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 #include #include #include #include /* Дата/время файла по хендлу. 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; }