057dd615ba
- 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>
142 lines
4.1 KiB
C
142 lines
4.1 KiB
C
/*
|
||
* 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;
|
||
}
|