wav支持2

This commit is contained in:
2026-04-18 14:29:24 +08:00
parent 6a93335e53
commit 6b3c74f66f
6 changed files with 240 additions and 138 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 兼容说明

Binary file not shown.