Add support for unlink
All checks were successful
continuous-integration/drone the build was successful

This commit is contained in:
Olivier 'reivilibre' 2022-02-07 23:21:20 +00:00
parent fecdaaecdf
commit 59dba8a2e1
5 changed files with 74 additions and 9 deletions

View File

@ -281,10 +281,6 @@ impl Filesystem for OliveFilesystem {
match requester.mkdir(parent_vnode, name).await? { match requester.mkdir(parent_vnode, name).await? {
DataResponse::Success(metadata) => { DataResponse::Success(metadata) => {
// Use the direct I/O flag so that we can be in control of when EOF happens
// rather than letting the kernel assume the getattr size is valid
// and caching up to that point.
// We might wind up wanting to do our own buffering...
let file_attr: FileAttr = metadata.into(); let file_attr: FileAttr = metadata.into();
// TODO generation should be generated client-side // TODO generation should be generated client-side
reply.entry(&Duration::from_secs(5), &file_attr, 42); reply.entry(&Duration::from_secs(5), &file_attr, 42);
@ -303,11 +299,40 @@ impl Filesystem for OliveFilesystem {
/// Remove a file. /// Remove a file.
fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) {
debug!( let name = if let Some(name) = name.to_str() {
"[Not Implemented] unlink(parent: {:#x?}, name: {:?})", name
parent, name, } else {
// If we can't decode the filename, pretend it doesn't exist.
error!("unlink: Filename not convertible.");
reply.error(ENOENT);
return;
}
.to_owned();
let requester = self.requester.clone();
self.spawn_with_error_handler(
async move {
let parent_vnode = VnodeId(
parent
.try_into()
.context("Converting u64 inode to u32 VnodeId.")?,
);
match requester.unlink(parent_vnode, name).await? {
DataResponse::Success(()) => {
reply.ok();
}
DataResponse::Error { code, message } => {
warn!("unlink(parent: {:#x?}) failed: {:?}", parent_vnode, message);
reply.error(code as c_int);
}
}
Ok(())
},
"unlink",
); );
reply.error(ENOSYS);
} }
/// Remove a directory. /// Remove a directory.

View File

@ -222,6 +222,16 @@ impl Requester {
.await .await
} }
pub async fn unlink(
&self,
dir_vnode: VnodeId,
name: String,
) -> anyhow::Result<DataResponse<()>> {
self.internal
.command(&DataCommand::Unlink { dir_vnode, name })
.await
}
pub async fn open(&self, vnode: VnodeId, mode: OpenMode) -> anyhow::Result<DataResponse<u32>> { pub async fn open(&self, vnode: VnodeId, mode: OpenMode) -> anyhow::Result<DataResponse<u32>> {
self.internal self.internal
.command(&DataCommand::OpenFile { vnode, mode }) .command(&DataCommand::OpenFile { vnode, mode })

View File

@ -95,6 +95,10 @@ pub enum DataCommand {
dir_vnode: VnodeId, dir_vnode: VnodeId,
name: String, name: String,
}, },
Unlink {
dir_vnode: VnodeId,
name: String,
},
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]

View File

@ -146,6 +146,16 @@ pub async fn handle_command_stream(
) )
.await?; .await?;
} }
DataCommand::Unlink { dir_vnode, name } => {
send_bare_message(
&mut tx,
&file_access
.unlink(dir_vnode, name)
.await
.unwrap_or_else(error_to_response),
)
.await?;
}
} }
} }

View File

@ -762,4 +762,20 @@ impl FileAccess {
let metadata = self.read_metadata(&target_path, vnode).await?; let metadata = self.read_metadata(&target_path, vnode).await?;
Ok(DataResponse::Success(metadata)) Ok(DataResponse::Success(metadata))
} }
/// Symlink safety:
/// Makes an attempt to safely resolve symlinks, but there is a possibility of a TOCTOU race.
/// TODO Revisit later for safety.
pub async fn unlink(
&self,
dir_vnode: VnodeId,
name: String,
) -> anyhow::Result<DataResponse<()>> {
let parent_dir_resolved = self
.resolve_vnode_including_follow_symlinks_safely_best_effort(dir_vnode)
.await?;
let target_path = parent_dir_resolved.join(name);
tokio::fs::remove_file(&target_path).await?;
Ok(DataResponse::Success(()))
}
} }