Open3
Rustでファイルシステムに触れる【MikanOS/Day17】
今までとは実装方法を変えて先にテストケースを書くようにしてみます。
#[test_case]
fn it_exists_kernel_elf() {
let mut dir = kernel_lib::fs::read_dir(&Path::new("/")).unwrap();
assert!(dir.any(|entry| entry.file_name() == "kernel.elf"));
}
FATボリュームを読み込むための最低限の機能を実装したライブラリを作り、カーネル側でそれを使うようにしました。
#[test_case]
fn it_read_root_dir() {
let mut dir = fs::root_dir().unwrap();
dir.next();
let hello_txt_file = dir
.next()
.unwrap()
.into_regular_file()
.unwrap()
.name()
.unwrap();
assert_eq!(
hello_txt_file
.to_str()
.unwrap(),
"HELLO.TXT"
);
}
#[test_case]
fn it_exists_hlt_elf() {
let hlt = fs::open_file("HLT.ELF")
.unwrap()
.name()
.unwrap();
let name = hlt.to_str().unwrap();
assert_eq!(name, "HLT.ELF");
}
本家MikanOSだと起動メディア全体を読み込めるようにしていますが、uefi-rs(version=0.24.0)だとBlockIOProtocolがNotSupportedのよう?なためfat_diskという名前のボリュームファイルをdisk.img内に入れておいてそのファイルのバッファを読み込むようにしています。
ただしファイル全体を読み込むメソッドしかないようで、読み込みにかなり時間が掛かってしまっているため修正予定です。
let mut disk_buff = system_table
.boot_services()
.get_image_file_system(handle)
.unwrap()
.read(Path::new(&CString16::try_from("fat_disk").unwrap()))
.unwrap();
対応方法として今のところ次の2点を考えています。
- uefi-rsのファイルの取り扱い周りは、バージョンによってかなり違うようなのでバージョンを変えてみる。
- open_volumeから返されるディレクトリのファイルハンドルを取得し、FileImpl にキャスト、そのあとにread関数使って読み込む
let loaded_image = system_table
.boot_services().open_protocol_exclusive::<LoadedImage>(image_handle)?;
let device_path = system_table
.boot_services().open_protocol_exclusive::<DevicePath>(loaded_image.device())?;
let device_handle = system_table
.boot_services().locate_device_path::<SimpleFileSystem>(&mut &*device_path)?;
let protocol = system_table
.boot_services().open_protocol_exclusive::<SimpleFileSystem>(device_handle)?;
let handle = protocol.open_volume().unwrap()
.handle();
#[repr(C)]
pub(super) struct FileImpl {
revision: u64,
open: unsafe extern "efiapi" fn(
this: &mut FileImpl,
new_handle: &mut *mut FileImpl,
filename: *const Char16,
open_mode: FileMode,
attributes: FileAttribute,
) -> Status,
close: extern "efiapi" fn(this: &mut FileImpl) -> Status,
delete: extern "efiapi" fn(this: &mut FileImpl) -> Status,
/// # Read from Regular Files
/// If `self` is not a directory, the function reads the requested
/// number of bytes from the file at the file’s current position
/// and returns them in `buffer`. If the read goes beyond the end
/// of the file, the read length is truncated to the end of the file.
/// The file’s current position is increased by the number of
/// bytes returned.
///
/// # Read from Directory
/// If `self` is a directory, the function reads the directory entry at
/// the file’s current position and returns the entry in
/// `buffer`. If the `buffer` is not large enough to hold the
/// current directory entry, then `EFI_BUFFER_TOO_SMALL` is returned and
/// the current file position is not updated. `buffer_size` is
/// set to be the size of the buffer needed to read the entry.
/// On success, the current position is updated to the next directory
/// entry. If there are no more directory entries, the read
/// returns a zero-length buffer.
read: unsafe extern "efiapi" fn(
this: &mut FileImpl,
buffer_size: &mut usize,
buffer: *mut u8,
) -> Status,
write: unsafe extern "efiapi" fn(
this: &mut FileImpl,
buffer_size: &mut usize,
buffer: *const u8,
) -> Status,
get_position: extern "efiapi" fn(this: &mut FileImpl, position: &mut u64) -> Status,
set_position: extern "efiapi" fn(this: &mut FileImpl, position: u64) -> Status,
get_info: unsafe extern "efiapi" fn(
this: &mut FileImpl,
information_type: &Guid,
buffer_size: &mut usize,
buffer: *mut u8,
) -> Status,
set_info: unsafe extern "efiapi" fn(
this: &mut FileImpl,
information_type: &Guid,
buffer_size: usize,
buffer: *const c_void,
) -> Status,
flush: extern "efiapi" fn(this: &mut FileImpl) -> Status,
}