Files
Sprinter-SDCC/libc/io/open.c
T
snark13 057dd615ba libc: квирки DSS — возврат WRITE и лимит манипуляторов; тесты fdmax/fbench
- ESTEX WRITE ($14) на успехе возвращает DE=0, а НЕ счётчик записанного
  (вопреки докам; solid-c в своём fflush тоже отключил сравнение по
  счётчику) — write() теперь судит по CF/A: CF=0&A=0 → n,
  CF=0&A!=0 → ENOSPC/-1
- DSS выдаёт 8 манипуляторов (fd 2..9; fd 1 держит шелл под запущенный
  exe), а 9-й OPEN не возвращает 06h — ВЕШАЕТ систему; предохранитель
  _fd_guard: счётчик в open()/close(), отказ EMFILE без захода в DSS
- tests/fdmax — эмпирика лимита (8 хендлов, затем EMFILE=6);
  tests/fbench — бенчмарк буферизации (floor 512-байтными read,
  оценка небуферизованного по 1-байтным, fgetc/fgets/fputc)
- filetest расширен: raw-probe возврата write, сценарий r+
  (чтение-запись-чтение с инвалидацией буфера), ungetc, fprintf

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:09:29 +03:00

142 lines
4.1 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.
/*
* open — открыть/создать файл по POSIX-флагам.
*
* Машина состояний флагов: экспонируем POSIX-биты (O_RDONLY/O_WRONLY/
* O_RDWR + O_CREAT/O_EXCL/O_TRUNC/O_APPEND) и диспетчеризуем на три
* входа ESTEX:
*
* $11 OPEN — открыть существующий файл
* $0A CREATE — создать (усечь, если существует), вернуть хендл
* $0B CREATE_NEW — создать, только если файла нет
*
* Три приватных __naked-обёртки делают сырые RST 10h; публичный open()
* — обычный C-оркестратор. IX сохраняется через каждый RST.
* При ошибке errno установлен, возврат -1.
*/
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "_fd_guard.h"
/* ---- сырые ESTEX-обёртки ---------------------------------------------- */
/* ESTEX $11 OPEN: A=режим (1=R, 2=W, 0=R/W), HL=путь → A=хендл, CF=err. */
static int _estex_open_raw(const char *path, int posix_mode) __naked
{
(void)path; (void)posix_mode;
__asm
push ix
;; HL = путь, DE = posix_mode. Перевести в нумерацию ESTEX.
ld a, e
and a, #0x03
ld c, #1
or a, a
jr Z, _oopen_real
ld c, #2
dec a
jr Z, _oopen_real
ld c, #0
_oopen_real:
ld a, c
ld c, #0x11 ; ESTEX OPEN
rst #0x10
pop ix
jr c, _oopen_err
ld e, a
ld d, #0
ret
_oopen_err:
call __errno_set
ld de, #-1
ret
__endasm;
}
/* ESTEX $0A CREATE: A=атрибут, HL=путь → A=хендл, CF=err.
* Усекает существующий файл. */
static int _estex_create_raw(const char *path) __naked
{
(void)path;
__asm
push ix
xor a, a ; A = 0 (обычный атрибут)
ld c, #0x0A
rst #0x10
pop ix
jr c, _ocreat_err
ld e, a
ld d, #0
ret
_ocreat_err:
call __errno_set
ld de, #-1
ret
__endasm;
}
/* ESTEX $0B CREATE_NEW: A=атрибут, HL=путь → A=хендл, CF=err.
* Падает (errno=EEXIST), если файл уже существует. */
static int _estex_create_new_raw(const char *path) __naked
{
(void)path;
__asm
push ix
xor a, a
ld c, #0x0B
rst #0x10
pop ix
jr c, _ocreatn_err
ld e, a
ld d, #0
ret
_ocreatn_err:
call __errno_set
ld de, #-1
ret
__endasm;
}
/* ---- публичная поверхность --------------------------------------------- */
int open(const char *path, int flags)
{
int fd;
/* Предохранитель: 9-й OPEN вешает DSS (см. _fd_guard.h) —
* отказать самим, не доводя до syscall. */
if (_fd_open_count >= _FD_OPEN_MAX) {
errno = EMFILE;
return -1;
}
if (flags & O_CREAT) {
if (flags & O_EXCL) {
/* Не должен существовать. */
fd = _estex_create_new_raw(path);
} else if (flags & O_TRUNC) {
/* Всегда создать или усечь. */
fd = _estex_create_raw(path);
} else {
/* Открыть, если есть, иначе создать. */
fd = _estex_open_raw(path, flags);
if (fd < 0 && errno == ENOENT) {
fd = _estex_create_raw(path);
}
}
} else {
fd = _estex_open_raw(path, flags);
}
if (fd < 0) {
return -1;
}
_fd_open_count++;
if (flags & O_APPEND) {
/* Встать на конец файла — дальнейшие записи дописывают. */
(void)lseek(fd, 0L, SEEK_END);
}
return fd;
}