diff --git a/cleonos/c/apps/cat_main.c b/cleonos/c/apps/cat_main.c index 67e7f9d..b2c685a 100644 --- a/cleonos/c/apps/cat_main.c +++ b/cleonos/c/apps/cat_main.c @@ -3,10 +3,8 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { char path[USH_PATH_MAX]; - char buf[USH_CAT_MAX + 1ULL]; - u64 size; - u64 req; - u64 got; + char buf[1024]; + u64 fd; if (arg == (const char *)0 || arg[0] == '\0') { if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) { @@ -28,36 +26,38 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { return 0; } - size = cleonos_sys_fs_stat_size(path); - - if (size == (u64)-1) { - (void)puts("cat: failed to stat file"); + fd = cleonos_sys_fd_open(path, CLEONOS_O_RDONLY, 0ULL); + if (fd == (u64)-1) { + (void)puts("cat: open failed"); return 0; } - if (size == 0ULL) { - return 1; - } - - req = (size < USH_CAT_MAX) ? size : USH_CAT_MAX; - got = cleonos_sys_fs_read(path, buf, req); - - if (got == 0ULL) { - (void)puts("cat: read failed"); - return 0; - } - - if (got > USH_CAT_MAX) { - got = USH_CAT_MAX; - } - - buf[got] = '\0'; - (void)puts(buf); - - if (size > got) { - (void)puts("[cat] output truncated"); + for (;;) { + u64 got = cleonos_sys_fd_read(fd, buf, (u64)sizeof(buf)); + u64 written_total = 0ULL; + + if (got == (u64)-1) { + (void)cleonos_sys_fd_close(fd); + (void)puts("cat: read failed"); + return 0; + } + + if (got == 0ULL) { + break; + } + + while (written_total < got) { + u64 written = cleonos_sys_fd_write(1ULL, buf + written_total, got - written_total); + if (written == (u64)-1 || written == 0ULL) { + (void)cleonos_sys_fd_close(fd); + (void)puts("cat: write failed"); + return 0; + } + written_total += written; + } } + (void)cleonos_sys_fd_close(fd); return 1; } diff --git a/cleonos/c/apps/cp_main.c b/cleonos/c/apps/cp_main.c index 6681ea9..120787f 100644 --- a/cleonos/c/apps/cp_main.c +++ b/cleonos/c/apps/cp_main.c @@ -1,45 +1,60 @@ #include "cmd_runtime.h" static int ush_copy_file(const char *src_path, const char *dst_path) { - static char copy_buf[USH_COPY_MAX]; - u64 src_type; - u64 src_size; - u64 got; + static char copy_buf[4096]; + u64 src_fd; + u64 dst_fd; - src_type = cleonos_sys_fs_stat_type(src_path); - - if (src_type != 1ULL) { + if (cleonos_sys_fs_stat_type(src_path) != 1ULL) { ush_writeln("cp: source file not found"); return 0; } - src_size = cleonos_sys_fs_stat_size(src_path); - - if (src_size == (u64)-1) { - ush_writeln("cp: failed to stat source"); + src_fd = cleonos_sys_fd_open(src_path, CLEONOS_O_RDONLY, 0ULL); + if (src_fd == (u64)-1) { + ush_writeln("cp: failed to open source"); return 0; } - if (src_size > (u64)USH_COPY_MAX) { - ush_writeln("cp: source too large for user shell buffer"); + dst_fd = cleonos_sys_fd_open(dst_path, CLEONOS_O_WRONLY | CLEONOS_O_CREAT | CLEONOS_O_TRUNC, 0ULL); + if (dst_fd == (u64)-1) { + (void)cleonos_sys_fd_close(src_fd); + ush_writeln("cp: failed to open destination"); return 0; } - if (src_size == 0ULL) { - got = 0ULL; - } else { - got = cleonos_sys_fs_read(src_path, copy_buf, src_size); + for (;;) { + u64 got = cleonos_sys_fd_read(src_fd, copy_buf, (u64)sizeof(copy_buf)); - if (got == 0ULL || got != src_size) { - ush_writeln("cp: failed to read source"); + if (got == (u64)-1) { + (void)cleonos_sys_fd_close(dst_fd); + (void)cleonos_sys_fd_close(src_fd); + ush_writeln("cp: read failed"); return 0; } + + if (got == 0ULL) { + break; + } + + { + u64 written_total = 0ULL; + while (written_total < got) { + u64 written = cleonos_sys_fd_write(dst_fd, + copy_buf + written_total, + got - written_total); + if (written == (u64)-1 || written == 0ULL) { + (void)cleonos_sys_fd_close(dst_fd); + (void)cleonos_sys_fd_close(src_fd); + ush_writeln("cp: write failed"); + return 0; + } + written_total += written; + } + } } - if (cleonos_sys_fs_write(dst_path, copy_buf, got) == 0ULL) { - ush_writeln("cp: failed to write destination"); - return 0; - } - + (void)cleonos_sys_fd_close(dst_fd); + (void)cleonos_sys_fd_close(src_fd); return 1; } diff --git a/cleonos/c/apps/wavplay_main.c b/cleonos/c/apps/wavplay_main.c index 97d605e..7a9a424 100644 --- a/cleonos/c/apps/wavplay_main.c +++ b/cleonos/c/apps/wavplay_main.c @@ -1,6 +1,5 @@ #include "cmd_runtime.h" -#define USH_WAVPLAY_FILE_MAX 65536ULL #define USH_WAVPLAY_DEFAULT_STEPS 256ULL #define USH_WAVPLAY_MAX_STEPS 4096ULL #define USH_WAVPLAY_DEFAULT_TICKS 1ULL @@ -8,7 +7,6 @@ #define USH_WAVPLAY_RUN_TICK_MAX 512ULL typedef struct ush_wav_info { - const unsigned char *data; u64 data_size; u64 frame_count; u64 sample_rate; @@ -17,8 +15,6 @@ typedef struct ush_wav_info { u64 block_align; } ush_wav_info; -static unsigned char ush_wavplay_file_buf[USH_WAVPLAY_FILE_MAX + 1ULL]; - static unsigned int ush_wav_le16(const unsigned char *ptr) { return (unsigned int)ptr[0] | ((unsigned int)ptr[1] << 8U); } @@ -43,6 +39,50 @@ static int ush_wav_tag_eq(const unsigned char *tag, const char *lit4) { : 0; } +static int ush_wav_read_exact(u64 fd, unsigned char *out, u64 size) { + u64 done = 0ULL; + + if (out == (unsigned char *)0 || size == 0ULL) { + return 0; + } + + while (done < size) { + u64 got = cleonos_sys_fd_read(fd, out + done, size - done); + + if (got == (u64)-1 || got == 0ULL) { + return 0; + } + + done += got; + } + + return 1; +} + +static int ush_wav_skip_bytes(u64 fd, u64 size) { + unsigned char scratch[256]; + u64 remaining = size; + + while (remaining > 0ULL) { + u64 req = remaining; + u64 got; + + if (req > (u64)sizeof(scratch)) { + req = (u64)sizeof(scratch); + } + + got = cleonos_sys_fd_read(fd, scratch, req); + + if (got == (u64)-1 || got == 0ULL) { + return 0; + } + + remaining -= got; + } + + return 1; +} + static void ush_wavplay_write_u64_dec(u64 value) { char rev[32]; u64 len = 0ULL; @@ -84,70 +124,79 @@ static void ush_wavplay_print_meta(const char *path, const ush_wav_info *info, u ush_write_char('\n'); } -static int ush_wav_parse(const unsigned char *buffer, u64 size, ush_wav_info *out_info) { - u64 offset = 12ULL; +static int ush_wav_parse_stream(u64 fd, ush_wav_info *out_info) { + unsigned char riff_header[12]; + unsigned char chunk_header[8]; + unsigned char fmt_min[16]; int found_fmt = 0; int found_data = 0; u64 sample_rate = 0ULL; u64 channels = 0ULL; u64 bits = 0ULL; u64 block_align = 0ULL; - const unsigned char *data = (const unsigned char *)0; u64 data_size = 0ULL; - if (buffer == (const unsigned char *)0 || out_info == (ush_wav_info *)0) { + if (out_info == (ush_wav_info *)0) { return 0; } - if (size < 12ULL) { + if (ush_wav_read_exact(fd, riff_header, (u64)sizeof(riff_header)) == 0) { return 0; } - if (ush_wav_tag_eq(&buffer[0], "RIFF") == 0 || ush_wav_tag_eq(&buffer[8], "WAVE") == 0) { + if (ush_wav_tag_eq(&riff_header[0], "RIFF") == 0 || ush_wav_tag_eq(&riff_header[8], "WAVE") == 0) { return 0; } - while (offset + 8ULL <= size) { - const unsigned char *chunk_tag = &buffer[offset]; - u64 chunk_size = (u64)ush_wav_le32(&buffer[offset + 4ULL]); - u64 chunk_data = offset + 8ULL; - u64 next_offset; + while (found_data == 0) { + const unsigned char *chunk_tag; + u64 chunk_size; - if (chunk_data > size || chunk_size > (size - chunk_data)) { + if (ush_wav_read_exact(fd, chunk_header, (u64)sizeof(chunk_header)) == 0) { return 0; } + chunk_tag = &chunk_header[0]; + chunk_size = (u64)ush_wav_le32(&chunk_header[4]); + if (ush_wav_tag_eq(chunk_tag, "fmt ") != 0) { if (chunk_size < 16ULL) { return 0; } - if (ush_wav_le16(&buffer[chunk_data + 0ULL]) != 1U) { + if (ush_wav_read_exact(fd, fmt_min, (u64)sizeof(fmt_min)) == 0) { return 0; } - channels = (u64)ush_wav_le16(&buffer[chunk_data + 2ULL]); - sample_rate = (u64)ush_wav_le32(&buffer[chunk_data + 4ULL]); - block_align = (u64)ush_wav_le16(&buffer[chunk_data + 12ULL]); - bits = (u64)ush_wav_le16(&buffer[chunk_data + 14ULL]); + if (ush_wav_le16(&fmt_min[0]) != 1U) { + return 0; + } + + channels = (u64)ush_wav_le16(&fmt_min[2]); + sample_rate = (u64)ush_wav_le32(&fmt_min[4]); + block_align = (u64)ush_wav_le16(&fmt_min[12]); + bits = (u64)ush_wav_le16(&fmt_min[14]); found_fmt = 1; + + if (chunk_size > 16ULL) { + if (ush_wav_skip_bytes(fd, chunk_size - 16ULL) == 0) { + return 0; + } + } } else if (ush_wav_tag_eq(chunk_tag, "data") != 0) { - data = &buffer[chunk_data]; data_size = chunk_size; found_data = 1; + } else { + if (ush_wav_skip_bytes(fd, chunk_size) == 0) { + return 0; + } } - next_offset = chunk_data + chunk_size; - - if ((chunk_size & 1ULL) != 0ULL) { - next_offset++; + if ((chunk_size & 1ULL) != 0ULL && found_data == 0) { + if (ush_wav_skip_bytes(fd, 1ULL) == 0) { + return 0; + } } - - if (next_offset <= offset || next_offset > size) { - break; - } - - offset = next_offset; } if (found_fmt == 0 || found_data == 0) { @@ -166,7 +215,6 @@ static int ush_wav_parse(const unsigned char *buffer, u64 size, ush_wav_info *ou return 0; } - out_info->data = data; out_info->data_size = data_size; out_info->sample_rate = sample_rate; out_info->channels = channels; @@ -177,19 +225,11 @@ static int ush_wav_parse(const unsigned char *buffer, u64 size, ush_wav_info *ou return (out_info->frame_count > 0ULL) ? 1 : 0; } -static u64 ush_wav_sample_deviation(const ush_wav_info *info, u64 frame_index) { - const unsigned char *frame; - - if (info == (const ush_wav_info *)0 || info->data == (const unsigned char *)0 || info->frame_count == 0ULL) { +static u64 ush_wav_frame_deviation(const ush_wav_info *info, const unsigned char *frame) { + if (info == (const ush_wav_info *)0 || frame == (const unsigned char *)0) { return 0ULL; } - if (frame_index >= info->frame_count) { - frame_index = info->frame_count - 1ULL; - } - - frame = &info->data[frame_index * info->block_align]; - if (info->bits_per_sample == 8ULL) { unsigned int left = (unsigned int)frame[0]; unsigned int dev_left = (left >= 128U) ? (left - 128U) : (128U - left); @@ -309,12 +349,13 @@ static int ush_wavplay_parse_args(const char *arg, static int ush_cmd_wavplay(const ush_state *sh, const char *arg) { char path_arg[USH_PATH_MAX]; char abs_path[USH_PATH_MAX]; + unsigned char frame_buf[8]; ush_wav_info info; - u64 file_size; - u64 got; + u64 fd; u64 steps; u64 ticks_per_step; u64 stride; + u64 current_frame = 0ULL; u64 i; u64 run_freq = 0ULL; u64 run_ticks = 0ULL; @@ -351,35 +392,30 @@ static int ush_cmd_wavplay(const ush_state *sh, const char *arg) { return 0; } - file_size = cleonos_sys_fs_stat_size(abs_path); - - if (file_size == (u64)-1 || file_size == 0ULL) { - ush_writeln("wavplay: empty or unreadable file"); + fd = cleonos_sys_fd_open(abs_path, CLEONOS_O_RDONLY, 0ULL); + if (fd == (u64)-1) { + ush_writeln("wavplay: open failed"); return 0; } - if (file_size > USH_WAVPLAY_FILE_MAX) { - ush_writeln("wavplay: file too large (max 65536 bytes)"); - return 0; - } - - got = cleonos_sys_fs_read(abs_path, (char *)ush_wavplay_file_buf, file_size); - - if (got != file_size) { - ush_writeln("wavplay: read failed"); - return 0; - } - - if (ush_wav_parse(ush_wavplay_file_buf, got, &info) == 0) { + if (ush_wav_parse_stream(fd, &info) == 0) { + (void)cleonos_sys_fd_close(fd); ush_writeln("wavplay: unsupported wav (need PCM 8/16-bit, mono/stereo)"); return 0; } + if (info.block_align > (u64)sizeof(frame_buf)) { + (void)cleonos_sys_fd_close(fd); + ush_writeln("wavplay: unsupported block align"); + return 0; + } + if (steps > info.frame_count) { steps = info.frame_count; } if (steps == 0ULL) { + (void)cleonos_sys_fd_close(fd); ush_writeln("wavplay: nothing to play"); return 0; } @@ -403,12 +439,42 @@ static int ush_cmd_wavplay(const ush_state *sh, const char *arg) { u64 frame_index = i * stride; u64 deviation; u64 freq; + u64 skip_frames; if (frame_index >= info.frame_count) { frame_index = info.frame_count - 1ULL; } - deviation = ush_wav_sample_deviation(&info, frame_index); + if (frame_index < current_frame) { + (void)cleonos_sys_fd_close(fd); + ush_writeln("wavplay: internal frame order error"); + return 0; + } + + skip_frames = frame_index - current_frame; + if (skip_frames > 0ULL) { + if (skip_frames > (0xFFFFFFFFFFFFFFFFULL / info.block_align)) { + (void)cleonos_sys_fd_close(fd); + ush_writeln("wavplay: frame skip overflow"); + return 0; + } + + if (ush_wav_skip_bytes(fd, skip_frames * info.block_align) == 0) { + (void)cleonos_sys_fd_close(fd); + ush_writeln("wavplay: seek/read failed"); + return 0; + } + current_frame = frame_index; + } + + if (ush_wav_read_exact(fd, frame_buf, info.block_align) == 0) { + (void)cleonos_sys_fd_close(fd); + ush_writeln("wavplay: read failed"); + return 0; + } + current_frame++; + + deviation = ush_wav_frame_deviation(&info, frame_buf); if (deviation < 4ULL) { freq = 0ULL; @@ -428,6 +494,7 @@ static int ush_cmd_wavplay(const ush_state *sh, const char *arg) { } if (cleonos_sys_audio_play_tone(run_freq, run_ticks) == 0ULL) { + (void)cleonos_sys_fd_close(fd); ush_writeln("wavplay: playback failed"); (void)cleonos_sys_audio_stop(); return 0; @@ -439,12 +506,14 @@ static int ush_cmd_wavplay(const ush_state *sh, const char *arg) { if (run_ticks > 0ULL) { if (cleonos_sys_audio_play_tone(run_freq, run_ticks) == 0ULL) { + (void)cleonos_sys_fd_close(fd); ush_writeln("wavplay: playback failed"); (void)cleonos_sys_audio_stop(); return 0; } } + (void)cleonos_sys_fd_close(fd); (void)cleonos_sys_audio_stop(); ush_writeln("wavplay: done"); return 1; @@ -492,4 +561,4 @@ int cleonos_app_main(void) { } return (success != 0) ? 0 : 1; -} \ No newline at end of file +} diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index c38e1d8..0306f35 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -20,7 +20,7 @@ #define CLKS_SYSCALL_PATH_MAX 192U #define CLKS_SYSCALL_NAME_MAX 96U #define CLKS_SYSCALL_TTY_MAX_LEN 2048U -#define CLKS_SYSCALL_FS_IO_MAX_LEN 65536U +#define CLKS_SYSCALL_FS_IO_CHUNK_LEN 65536U #define CLKS_SYSCALL_JOURNAL_MAX_LEN 256U #define CLKS_SYSCALL_ARG_LINE_MAX 256U #define CLKS_SYSCALL_ENV_LINE_MAX 512U @@ -1457,44 +1457,62 @@ static u64 clks_syscall_fs_mkdir(u64 arg0) { static u64 clks_syscall_fs_write_common(u64 arg0, u64 arg1, u64 arg2, clks_bool append_mode) { char path[CLKS_SYSCALL_PATH_MAX]; - void *heap_copy = CLKS_NULL; - const void *payload = CLKS_NULL; + const u8 *src = (const u8 *)arg1; + u64 remaining = arg2; + clks_bool first_chunk = CLKS_TRUE; clks_bool ok; if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { return 0ULL; } - if (arg2 > CLKS_SYSCALL_FS_IO_MAX_LEN) { + if (arg2 == 0ULL) { + if (append_mode == CLKS_TRUE) { + ok = clks_fs_append(path, CLKS_NULL, 0ULL); + } else { + ok = clks_fs_write_all(path, CLKS_NULL, 0ULL); + } + + return (ok == CLKS_TRUE) ? 1ULL : 0ULL; + } + + if (arg1 == 0ULL) { return 0ULL; } - if (arg2 > 0ULL) { - if (arg1 == 0ULL) { - return 0ULL; + while (remaining > 0ULL) { + u64 chunk_len = remaining; + void *heap_copy; + + if (chunk_len > CLKS_SYSCALL_FS_IO_CHUNK_LEN) { + chunk_len = CLKS_SYSCALL_FS_IO_CHUNK_LEN; } - heap_copy = clks_kmalloc((usize)arg2); - + heap_copy = clks_kmalloc((usize)chunk_len); if (heap_copy == CLKS_NULL) { return 0ULL; } - clks_memcpy(heap_copy, (const void *)arg1, (usize)arg2); - payload = (const void *)heap_copy; - } + clks_memcpy(heap_copy, (const void *)src, (usize)chunk_len); - if (append_mode == CLKS_TRUE) { - ok = clks_fs_append(path, payload, arg2); - } else { - ok = clks_fs_write_all(path, payload, arg2); - } + if (append_mode == CLKS_TRUE || first_chunk == CLKS_FALSE) { + ok = clks_fs_append(path, heap_copy, chunk_len); + } else { + ok = clks_fs_write_all(path, heap_copy, chunk_len); + } - if (heap_copy != CLKS_NULL) { clks_kfree(heap_copy); + + if (ok == CLKS_FALSE) { + return 0ULL; + } + + src += chunk_len; + remaining -= chunk_len; + first_chunk = CLKS_FALSE; } - return (ok == CLKS_TRUE) ? 1ULL : 0ULL; + return 1ULL; } static u64 clks_syscall_fs_write(u64 arg0, u64 arg1, u64 arg2) { diff --git a/docs/syscall.md b/docs/syscall.md index bffabd0..b9e27f4 100644 --- a/docs/syscall.md +++ b/docs/syscall.md @@ -66,7 +66,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 日志写入 `LOG_WRITE`:最大拷贝 `191` 字节。 - TTY 文本写入 `TTY_WRITE`:最大拷贝 `512` 字节。 - 文件读取 `FS_READ`:最多读取 `min(file_size, buffer_size)` 字节。 -- 文件写入 `FS_WRITE` / `FS_APPEND`:单次最大 `65536` 字节。 +- 文件写入 `FS_WRITE` / `FS_APPEND`:内核按 `65536` 字节分块搬运;这是实现分块大小,不是文件大小上限。 - log journal 行读取缓冲:`256` 字节。 - 路径缓冲上限:`192` 字节(包含 `\0`)。 - 文件名输出上限:`96` 字节(与 `CLEONOS_FS_NAME_MAX` 对齐)。 @@ -634,7 +634,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。 - `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`。 -- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。 +- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`;大数据写入由内核自动分块处理。 - `/proc` 由 syscall 层虚拟导出,不占用 RAMDISK 节点,也不能通过写入类 syscall 修改。 ## 7. Wine 兼容说明 diff --git a/ramdisk/test.wav b/ramdisk/test.wav index 44d8638..3179e0e 100644 Binary files a/ramdisk/test.wav and b/ramdisk/test.wav differ