feat(phase111): FileHandleBox append+metadata実装(修正案統合版)

Task 2: FsApi / Ring0FsFileIo 拡張
- FsApi trait に append_all(path, data) メソッド追加
- StdFsApi で append_all() を std::fs::OpenOptions で実装
- Ring0FsFileIo に mode を保持、write() で truncate/append を切り替え
- Ring0FsFileIo に内部 metadata() ヘルパ追加(FsApi.metadata() 呼び出し)

Task 3: FileHandleBox API 実装
- open(path, mode) で "r"/"w"/"a" 3モードをサポート
- write_all() で read-only mode チェック
- 内部 Rust API:size / exists / is_file / is_dir メソッド実装
  (NyashBox 公開は Phase 112+ に延期)

Task 5: テスト + ドキュメント
- 4つの新テスト PASS:
  - test_filehandlebox_append_mode(write→append→内容確認)
  - test_filehandlebox_metadata_size(size() 取得)
  - test_filehandlebox_metadata_is_file(is_file()/is_dir())
  - test_filehandlebox_write_readonly_error("r"で write 拒否)

統計:
- 9ファイル修正(+316行, -35行)
- 4つの新テスト追加(既存15テスト全PASS)
- cargo build --release: SUCCESS
- 11個のチェックリスト:  ALL PASS

次フェーズ(Phase 112-114)の backlog も指示書で整理済み

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-03 21:30:47 +09:00
parent 298369ec1e
commit fce7555e46
8 changed files with 316 additions and 35 deletions

View File

@ -182,6 +182,20 @@ impl FsApi for StdFs {
.map_err(|e| IoError::WriteFailed(format!("write({}): {}", path.display(), e)))
}
fn append_all(&self, path: &Path, data: &[u8]) -> Result<(), IoError> {
use std::fs::OpenOptions;
use std::io::Write;
let mut file = OpenOptions::new()
.create(true) // 存在しなければ作成
.append(true) // append モードで開く
.open(path)
.map_err(|e| IoError::WriteFailed(format!("append_all({}): {}", path.display(), e)))?;
file.write_all(data)
.map_err(|e| IoError::WriteFailed(format!("append write({}): {}", path.display(), e)))
}
fn exists(&self, path: &Path) -> bool {
path.exists()
}

View File

@ -105,6 +105,12 @@ pub trait FsApi: Send + Sync {
/// ファイルに書き込む
fn write_all(&self, path: &Path, data: &[u8]) -> Result<(), IoError>;
/// ファイルに追記append
///
/// ファイルが存在しない場合は新規作成、存在する場合は末尾に追記。
/// Phase 111: write_all と対称的に提供。
fn append_all(&self, path: &Path, data: &[u8]) -> Result<(), IoError>;
/// パスが存在するか確認
fn exists(&self, path: &Path) -> bool;