use crate::{
fsemul::{
filesystem::ResolvedLocation,
pcfs::sata::{
proto::{
SataFileDescriptorResult, SataOpenFolderPacketBody, SataRequest, SataResponse,
},
server::PcfsServerState,
},
},
net::{
additions::StreamID,
server::requestable::{Body, State},
},
};
use tracing::debug;
const FS_ERROR: u32 = 0xFFF0_FFE0;
const PATH_NOT_EXIST_ERROR: u32 = 0xFFF0_FFE9;
pub async fn handle_open_folder(
stream: StreamID,
State(state): State<PcfsServerState>,
Body(request): Body<SataRequest<SataOpenFolderPacketBody>>,
) -> SataResponse<SataFileDescriptorResult> {
let packet = request.body();
let request_header = request.header().clone();
let Ok(final_location) = state.host_filesystem().resolve_path(packet.path()).await else {
debug!(
packet.path = packet.path(),
packet.typ = "PcfsSrvOpenFolder",
"Failed to resolve path!",
);
return SataResponse::new(
state.pid(),
request_header,
SataFileDescriptorResult::error(PATH_NOT_EXIST_ERROR),
);
};
let resolved_path = match final_location {
ResolvedLocation::Filesystem(fs_location) => fs_location.resolved_path().clone(),
ResolvedLocation::Network(()) => todo!("network shares not yet implemented"),
#[cfg(feature = "nus")]
ResolvedLocation::NUSLocation(_, _, disk_path) => disk_path,
};
let fd = match state
.host_filesystem()
.open_folder(&resolved_path, Some(stream.to_raw()))
.await
{
Ok(f) => f,
Err(cause) => {
debug!(
?cause,
packet.path = packet.path(),
packet.typ = "PcfsSrvOpenFolder",
"Failed to open folder!",
);
return SataResponse::new(
state.pid(),
request_header,
SataFileDescriptorResult::error(FS_ERROR),
);
}
};
debug!(
result.fd = fd,
packet.path = packet.path(),
packet.typ = "PcfsSrvOpenFolder",
"Successfully opened directory!",
);
SataResponse::new(
state.pid(),
request_header,
SataFileDescriptorResult::success(fd),
)
}
#[cfg(test)]
mod unit_tests {
use super::*;
use crate::fsemul::{
filesystem::host::test_helpers::{create_temporary_host_filesystem, join_many},
pcfs::sata::proto::{SataCommandInfo, SataPacketHeader},
};
use bytes::Bytes;
#[tokio::test]
pub async fn simple_open_folder_request() {
let (tempdir, fs) = create_temporary_host_filesystem().await;
let request = SataOpenFolderPacketBody::new("/%SLC_EMU_DIR/to-query/".to_owned())
.expect("Failed to create open folder packet!");
let mocked_header = SataPacketHeader::new(0);
let mocked_ci = SataCommandInfo::new((0, 0), (0, 0), 0);
let base_dir = join_many(tempdir.path(), ["data", "slc", "to-query"]);
tokio::fs::create_dir(&base_dir)
.await
.expect("Failed to create temporary directory for test!");
let mut response: Bytes = handle_open_folder(
StreamID::from_existing(1),
State(PcfsServerState::new(true, fs.clone(), 0)),
Body(SataRequest::new(mocked_header, mocked_ci, request)),
)
.await
.try_into()
.expect("Failed to serialize open file response!");
assert_eq!(response.len(), 8 + 0x20, "Packet is not correct size!");
_ = response.split_to(0x20);
assert_eq!(
&response[..4],
&[0x00, 0x00, 0x00, 0x00], );
assert_ne!(
&response[4..],
&[0x00, 0x00, 0x00, 0x00], );
fs.close_folder(
i32::from_be_bytes([response[4], response[5], response[6], response[7]]),
Some(1),
)
.await;
}
}