diff --git a/kinode/src/vfs.rs b/kinode/src/vfs.rs index 65fc22a6..d292dfb5 100644 --- a/kinode/src/vfs.rs +++ b/kinode/src/vfs.rs @@ -287,14 +287,12 @@ async fn handle_request( .. }) = km.message else { - return Err(VfsError::BadRequest { - error: "not a request".into(), - }); + // we got a response -- safe to ignore + return Ok(()); }; - let request: VfsRequest = serde_json::from_slice(&body).map_err(|e| VfsError::BadJson { - error: e.to_string(), - })?; + let request: VfsRequest = + serde_json::from_slice(&body).map_err(|_| VfsError::MalformedRequest)?; // special case for root reading list of all drives. if request.action == VfsAction::ReadDir && request.path == "/" { @@ -336,10 +334,7 @@ async fn handle_request( .await; return Ok(()); } else { - return Err(VfsError::NoCap { - action: request.action.to_string(), - path: request.path, - }); + return Err(VfsError::NoReadCap); } } @@ -348,7 +343,6 @@ async fn handle_request( // must have prepended `/` here or else it messes up caps downstream, e.g. in run-tests let drive = format!("/{package_id}/{drive}"); let action = request.action; - let path = PathBuf::from(&request.path); if km.source.process != *KERNEL_PROCESS_ID { check_caps( @@ -356,7 +350,6 @@ async fn handle_request( &km.source, &send_to_caps_oracle, &action, - &path, &drive, &package_id, vfs_path, @@ -406,9 +399,7 @@ async fn handle_request( VfsAction::WriteAll => { // doesn't create a file, writes at exact cursor. let Some(blob) = km.lazy_load_blob else { - return Err(VfsError::BadRequest { - error: "blob needs to exist for WriteAll".into(), - }); + return Err(VfsError::NoBlob); }; let file = files.open_file(&path, false, false).await?; let mut file = file.lock().await; @@ -417,18 +408,14 @@ async fn handle_request( } VfsAction::Write => { let Some(blob) = km.lazy_load_blob else { - return Err(VfsError::BadRequest { - error: "blob needs to exist for Write".into(), - }); + return Err(VfsError::NoBlob); }; fs::write(&path, &blob.bytes).await?; (VfsResponse::Ok, None) } VfsAction::Append => { let Some(blob) = km.lazy_load_blob else { - return Err(VfsError::BadRequest { - error: "blob needs to exist for Append".into(), - }); + return Err(VfsError::NoBlob); }; let file = files.open_file(&path, false, false).await?; let mut file = file.lock().await; @@ -526,29 +513,16 @@ async fn handle_request( } VfsAction::Rename { new_path } => { let new_path = join_paths_safely(vfs_path, &new_path); - fs::rename(&path, new_path) - .await - .map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path, - })?; + fs::rename(&path, new_path).await?; (VfsResponse::Ok, None) } VfsAction::CopyFile { new_path } => { let new_path = join_paths_safely(vfs_path, &new_path); - fs::copy(&path, new_path) - .await - .map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path, - })?; + fs::copy(&path, new_path).await?; (VfsResponse::Ok, None) } VfsAction::Metadata => { - let metadata = fs::metadata(&path).await.map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path, - })?; + let metadata = fs::metadata(&path).await?; let file_type = get_file_type(&metadata); let meta = FileMetadata { len: metadata.len(), @@ -559,23 +533,13 @@ async fn handle_request( VfsAction::Len => { let file = files.open_file(&path, false, false).await?; let file = file.lock().await; - let len = file - .metadata() - .await - .map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path, - })? - .len(); + let len = file.metadata().await?.len(); (VfsResponse::Len(len), None) } VfsAction::SetLen(len) => { let file = files.open_file(&path, false, false).await?; let file = file.lock().await; - file.set_len(len).await.map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path, - })?; + file.set_len(len).await?; (VfsResponse::Ok, None) } VfsAction::Hash => { @@ -597,9 +561,7 @@ async fn handle_request( } VfsAction::AddZip => { let Some(blob) = km.lazy_load_blob else { - return Err(VfsError::BadRequest { - error: "blob needs to exist for AddZip".into(), - }); + return Err(VfsError::NoBlob); }; let file = std::io::Cursor::new(&blob.bytes); let mut zip = match zip::ZipArchive::new(file) { @@ -620,10 +582,7 @@ async fn handle_request( // Before any `.await`s are called since ZipFile is not // Send and so does not play nicely with await let (is_file, is_dir, local_path, file_contents) = { - let mut file = zip.by_index(i).map_err(|e| VfsError::IOError { - error: e.to_string(), - path: request.path.clone(), - })?; + let mut file = zip.by_index(i).map_err(|_| VfsError::UnzipError)?; let is_file = file.is_file(); let is_dir = file.is_dir(); let mut file_contents = Vec::new(); @@ -638,10 +597,7 @@ async fn handle_request( } else if is_dir { fs::create_dir_all(&local_path).await?; } else { - return Err(VfsError::CreateDirError { - path: path.display().to_string(), - error: "vfs: zip with non-file non-dir".into(), - }); + return Err(VfsError::UnzipError); }; } (VfsResponse::Ok, None) @@ -684,17 +640,13 @@ fn parse_package_and_drive( // sanitize path.. let normalized_path = normalize_path(&joined_path); if !normalized_path.starts_with(vfs_path) { - return Err(VfsError::BadRequest { - error: format!("input path tries to escape parent vfs directory: {path}"), - })?; + return Err(VfsError::MalformedRequest); } // extract original path. let path = normalized_path .strip_prefix(vfs_path) - .map_err(|_| VfsError::BadRequest { - error: format!("input path tries to escape parent vfs directory: {path}"), - })? + .map_err(|_| VfsError::MalformedRequest)? .display() .to_string(); @@ -707,19 +659,13 @@ fn parse_package_and_drive( parts.remove(0); } if parts.len() < 2 { - return Err(VfsError::ParseError { - error: "malformed path".into(), - path, - }); + return Err(VfsError::MalformedRequest); } let package_id = match parts[0].parse::() { Ok(id) => id, - Err(e) => { - return Err(VfsError::ParseError { - error: e.to_string(), - path, - }) + Err(_) => { + return Err(VfsError::MalformedRequest); } }; @@ -774,7 +720,6 @@ async fn check_caps( source: &Address, send_to_caps_oracle: &CapMessageSender, action: &VfsAction, - path: &PathBuf, drive: &str, package_id: &PackageId, vfs_path: &PathBuf, @@ -809,10 +754,7 @@ async fn check_caps( if read_capability("", "", true, our_node, source, send_to_caps_oracle).await { return Ok(()); } - return Err(VfsError::NoCap { - action: action.to_string(), - path: path.display().to_string(), - }); + return Err(VfsError::NoWriteCap); } Ok(()) } @@ -835,10 +777,7 @@ async fn check_caps( if read_capability("", "", true, our_node, source, send_to_caps_oracle).await { return Ok(()); } - return Err(VfsError::NoCap { - action: action.to_string(), - path: path.display().to_string(), - }); + return Err(VfsError::NoReadCap); } Ok(()) } @@ -867,10 +806,7 @@ async fn check_caps( if read_capability("", "", true, our_node, source, send_to_caps_oracle).await { return Ok(()); } - return Err(VfsError::NoCap { - action: action.to_string(), - path: path.display().to_string(), - }); + return Err(VfsError::NoWriteCap); } // if they're within the same drive, no need for 2 caps checks @@ -892,10 +828,7 @@ async fn check_caps( if read_capability("", "", true, our_node, source, send_to_caps_oracle).await { return Ok(()); } - return Err(VfsError::NoCap { - action: action.to_string(), - path: path.display().to_string(), - }); + return Err(VfsError::NoWriteCap); } Ok(()) } @@ -903,10 +836,7 @@ async fn check_caps( if &src_package_id != package_id { // check for root cap if !read_capability("", "", true, our_node, source, send_to_caps_oracle).await { - return Err(VfsError::NoCap { - action: action.to_string(), - path: path.display().to_string(), - }); + return Err(VfsError::NoWriteCap); } } add_capability("read", &drive, &our_node, &source, send_to_caps_oracle).await?; @@ -958,20 +888,20 @@ async fn add_capability( format!("{{\"kind\": \"{kind}\", \"drive\": \"{drive}\"}}"), ); let (send_cap_bool, recv_cap_bool) = tokio::sync::oneshot::channel(); - send_to_caps_oracle + let Ok(()) = send_to_caps_oracle .send(CapMessage::Add { on: source.process.clone(), caps: vec![cap], responder: Some(send_cap_bool), }) - .await?; - match recv_cap_bool.await? { - true => Ok(()), - false => Err(VfsError::NoCap { - action: "add_capability".to_string(), - path: drive.to_string(), - }), - } + .await + else { + return Err(VfsError::AddCapFailed); + }; + let Ok(true) = recv_cap_bool.await else { + return Err(VfsError::AddCapFailed); + }; + Ok(()) } fn get_file_type(metadata: &std::fs::Metadata) -> FileType { diff --git a/lib/src/state.rs b/lib/src/state.rs index 82b62c23..5f5e8822 100644 --- a/lib/src/state.rs +++ b/lib/src/state.rs @@ -2,6 +2,8 @@ use crate::types::core::ProcessId; use serde::{Deserialize, Serialize}; use thiserror::Error; +// state:distro:sys is INTERNAL -- this interface is NEVER EXPOSED TO USERSPACE + /// IPC Requests for the state:distro:sys runtime module. #[derive(Serialize, Deserialize, Debug)] pub enum StateAction { diff --git a/lib/src/vfs.rs b/lib/src/vfs.rs index 200e98d7..991d2bbc 100644 --- a/lib/src/vfs.rs +++ b/lib/src/vfs.rs @@ -1,4 +1,3 @@ -use crate::types::core::CapMessage; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -81,72 +80,26 @@ pub enum VfsResponse { #[derive(Error, Debug, Serialize, Deserialize)] pub enum VfsError { - #[error("No capability for action {action} at path {path}")] - NoCap { action: String, path: String }, - #[error("Bytes blob required for {action} at path {path}")] - BadBytes { action: String, path: String }, - #[error("bad request error: {error}")] - BadRequest { error: String }, + #[error("no write capability for requested drive")] + NoWriteCap, + #[error("no read capability for requested drive")] + NoReadCap, + #[error("failed to generate capability for new drive")] + AddCapFailed, + #[error("request could not be deserialized to valid VfsRequest")] + MalformedRequest, + #[error("request type used requires a blob")] + NoBlob, #[error("error parsing path: {path}: {error}")] ParseError { error: String, path: String }, - #[error("IO error: {error}, at path {path}")] - IOError { error: String, path: String }, - #[error("kernel capability channel error: {error}")] - CapChannelFail { error: String }, - #[error("Bad JSON blob: {error}")] - BadJson { error: String }, - #[error("File not found at path {path}")] - NotFound { path: String }, - #[error("Creating directory failed at path: {path}: {error}")] - CreateDirError { path: String, error: String }, - #[error("Other error: {error}")] - Other { error: String }, -} - -impl VfsError { - pub fn kind(&self) -> &str { - match *self { - VfsError::NoCap { .. } => "NoCap", - VfsError::BadBytes { .. } => "BadBytes", - VfsError::BadRequest { .. } => "BadRequest", - VfsError::ParseError { .. } => "ParseError", - VfsError::IOError { .. } => "IOError", - VfsError::CapChannelFail { .. } => "CapChannelFail", - VfsError::BadJson { .. } => "NoJson", - VfsError::NotFound { .. } => "NotFound", - VfsError::CreateDirError { .. } => "CreateDirError", - VfsError::Other { .. } => "Other", - } - } -} - -impl From for VfsError { - fn from(err: tokio::sync::oneshot::error::RecvError) -> Self { - VfsError::CapChannelFail { - error: err.to_string(), - } - } -} - -impl From> for VfsError { - fn from(err: tokio::sync::mpsc::error::SendError) -> Self { - VfsError::CapChannelFail { - error: err.to_string(), - } - } + #[error("IO error: {0}")] + IOError(String), + #[error("non-file non-dir in zip")] + UnzipError, } impl From for VfsError { fn from(err: std::io::Error) -> Self { - VfsError::IOError { - path: "".into(), - error: err.to_string(), - } - } -} - -impl std::fmt::Display for VfsAction { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) + VfsError::IOError(err.to_string()) } }