Add support for rename
continuous-integration/drone the build was successful Details

This commit is contained in:
Olivier 'reivilibre' 2022-02-08 07:56:42 +00:00
parent 926a29fa47
commit 1fb63833c5
5 changed files with 135 additions and 12 deletions

View File

@ -390,7 +390,7 @@ impl Filesystem for OliveFilesystem {
reply.error(ENOENT);
return;
}
.to_owned();
.to_owned();
let link = if let Some(link) = link.to_str() {
link
@ -400,7 +400,7 @@ impl Filesystem for OliveFilesystem {
reply.error(ENOENT);
return;
}
.to_owned();
.to_owned();
let requester = self.requester.clone();
@ -419,7 +419,10 @@ impl Filesystem for OliveFilesystem {
reply.entry(&Duration::from_secs(5), &file_attr, 42);
}
DataResponse::Error { code, message } => {
warn!("symlink(parent: {:#x?}) failed: {:?}", parent_vnode, message);
warn!(
"symlink(parent: {:#x?}) failed: {:?}",
parent_vnode, message
);
reply.error(code as c_int);
}
}
@ -441,12 +444,62 @@ impl Filesystem for OliveFilesystem {
flags: u32,
reply: ReplyEmpty,
) {
debug!(
"[Not Implemented] rename(parent: {:#x?}, name: {:?}, newparent: {:#x?}, \
newname: {:?}, flags: {})",
parent, name, newparent, newname, flags,
let name = if let Some(name) = name.to_str() {
name
} else {
// If we can't decode the filename, pretend it doesn't exist.
error!("rename: Old Filename not convertible.");
reply.error(ENOENT);
return;
}
.to_owned();
let newname = if let Some(newname) = newname.to_str() {
newname
} else {
// If we can't decode the filename, pretend it doesn't exist.
error!("rename: New 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.")?,
);
let newparent_vnode = VnodeId(
newparent
.try_into()
.context("Converting u64 inode to u32 VnodeId.")?,
);
match requester
.rename(parent_vnode, name, newparent_vnode, newname)
.await?
{
DataResponse::Success(()) => {
reply.ok();
}
DataResponse::Error { code, message } => {
warn!(
"rename(parent: {:#x?}, newparent: {:#?}) failed: {:?}",
parent_vnode, newparent_vnode, message
);
reply.error(code as c_int);
}
}
Ok(())
},
"rename",
);
reply.error(ENOSYS);
}
/// Create a hard link.

View File

@ -226,10 +226,14 @@ impl Requester {
&self,
dir_vnode: VnodeId,
name: String,
link: String
link: String,
) -> anyhow::Result<DataResponse<FileMetadata>> {
self.internal
.command(&DataCommand::MakeSymlink { dir_vnode, name, link })
.command(&DataCommand::MakeSymlink {
dir_vnode,
name,
link,
})
.await
}
@ -253,6 +257,23 @@ impl Requester {
.await
}
pub async fn rename(
&self,
old_dir_vnode: VnodeId,
old_name: String,
new_dir_vnode: VnodeId,
new_name: String,
) -> anyhow::Result<DataResponse<()>> {
self.internal
.command(&DataCommand::Rename {
old_dir_vnode,
old_name,
new_dir_vnode,
new_name,
})
.await
}
pub async fn open(&self, vnode: VnodeId, mode: OpenMode) -> anyhow::Result<DataResponse<u32>> {
self.internal
.command(&DataCommand::OpenFile { vnode, mode })

View File

@ -108,6 +108,12 @@ pub enum DataCommand {
name: String,
link: String,
},
Rename {
old_dir_vnode: VnodeId,
old_name: String,
new_dir_vnode: VnodeId,
new_name: String,
},
}
#[derive(Serialize, Deserialize, Debug, Clone)]

View File

@ -166,7 +166,11 @@ pub async fn handle_command_stream(
)
.await?;
}
DataCommand::MakeSymlink { dir_vnode, name, link } => {
DataCommand::MakeSymlink {
dir_vnode,
name,
link,
} => {
send_bare_message(
&mut tx,
&file_access
@ -174,7 +178,22 @@ pub async fn handle_command_stream(
.await
.unwrap_or_else(error_to_response),
)
.await?;
.await?;
}
DataCommand::Rename {
old_dir_vnode,
old_name,
new_dir_vnode,
new_name,
} => {
send_bare_message(
&mut tx,
&file_access
.rename(old_dir_vnode, old_name, new_dir_vnode, new_name)
.await
.unwrap_or_else(error_to_response),
)
.await?;
}
}
}

View File

@ -815,4 +815,28 @@ impl FileAccess {
let metadata = self.read_metadata(&target_path, vnode).await?;
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 rename(
&self,
old_dir_vnode: VnodeId,
old_name: String,
new_dir_vnode: VnodeId,
new_name: String,
) -> anyhow::Result<DataResponse<()>> {
let old_parent_dir_resolved = self
.resolve_vnode_including_follow_symlinks_safely_best_effort(old_dir_vnode)
.await?;
let source_path = old_parent_dir_resolved.join(old_name);
let new_parent_dir_resolved = self
.resolve_vnode_including_follow_symlinks_safely_best_effort(new_dir_vnode)
.await?;
let target_path = new_parent_dir_resolved.join(new_name);
tokio::fs::rename(source_path, target_path).await?;
Ok(DataResponse::Success(()))
}
}