Files
Sprinter-SDCC/libc/io/stat.c
T
snark13 4a081501d8 libc: сплит «1 функция = 1 модуль» — вся библиотека, wildcard-сборка
- 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>
2026-07-06 16:08:58 +03:00

109 lines
3.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* stat — POSIX stat() поверх метаданных ESTEX.
*
* stat(path, &st) -> open(O_RDONLY) + fstat() + close. Работает для
* любого обычного файла; для директорий — fallback
* через F_FIRST (и перебор "*.*" для "."/"..").
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <dir.h>
/* Конвертация DOS-формата даты+времени ESTEX в time_t (используется
* на пути через F_FIRST для записей директорий). */
static time_t dos_to_epoch(uint16_t date, uint16_t dtime)
{
struct tm tm;
tm.tm_sec = (unsigned char)((dtime & 0x1F) << 1);
tm.tm_min = (unsigned char)((dtime >> 5) & 0x3F);
tm.tm_hour = (unsigned char)((dtime >> 11) & 0x1F);
tm.tm_mday = (unsigned char)(date & 0x1F);
tm.tm_mon = (unsigned char)(((date >> 5) & 0x0F) - 1);
tm.tm_year = (int)((date >> 9) & 0x7F) + 80; /* DOS year base = 1980 */
tm.tm_isdst = 0;
tm.tm_hundredth = 0;
return mktime(&tm);
}
/* Возвращает 1, если path — "." или "..", иначе 0. Читает максимум
* 3 байта; NULL-безопасно. ~28 байт / 34–117 тактов от входа. */
static char is_dot_or_dotdot(const char *path) __naked
{
(void)path;
__asm
ld a, h
or a, l
jr Z, _idd_fail ; NULL 0
ld a, (hl)
sub a, #0x2E
jr NZ, _idd_fail ; path[0] != '.'
inc hl
ld a, (hl)
or a, a
jr Z, _idd_ok ; ".\0" 1
sub a, #0x2E
jr NZ, _idd_fail ; path[1] not '.' and not '\0'
inc hl
ld a, (hl)
or a, a
jr Z, _idd_ok ; "..\0" 1
_idd_fail:
xor a, a
ret
_idd_ok:
ld a, #1
ret
__endasm;
}
int stat(const char *path, struct stat *buf)
{
/* Обычный файл: open + fstat. */
int fd = open(path, O_RDONLY);
if (fd >= 0) {
int r = fstat(fd, buf);
close(fd);
return r;
}
int saved = errno;
/* Пробуем ffirst напрямую — работает для обычных подпапок. */
ffblk_t ffb;
if (ffirst(path, &ffb, FA_DIREC) == 0 && (ffb.found_attr & FA_DIREC)) {
buf->st_size = ffb.size;
buf->st_mtime = dos_to_epoch(ffb.date, ffb.time);
buf->st_mode = S_IFDIR | S_IRWXU;
return 0;
}
/* Проверено 2026-05-29: ESTEX F_FIRST отвергает голые "." и ".."
* с EINAME (16), как и open(). Но в листинге "*.*" они ЕСТЬ с
* FA_DIREC — ищем перебором. */
if (is_dot_or_dotdot(path)) {
if (ffirst("*.*", &ffb, FA_DIREC) == 0) {
do {
if (strcmp(ffb.found_name, path) == 0) {
buf->st_size = ffb.size;
buf->st_mtime = dos_to_epoch(ffb.date, ffb.time);
buf->st_mode = S_IFDIR | S_IRWXU;
return 0;
}
} while (fnext(&ffb) == 0);
}
/* Крайний случай — синтетическая запись: ФС их не отдала. */
buf->st_mode = S_IFDIR | S_IRWXU;
buf->st_size = 0;
buf->st_mtime = 0;
return 0;
}
errno = saved;
return -1;
}