Skip to content

Commit

Permalink
Merge pull request #5315 from wasmerio/fix/cross-fs-rename
Browse files Browse the repository at this point in the history
Implement cross-FS file rename
  • Loading branch information
Arshia001 authored Dec 25, 2024
2 parents 3c32c74 + 196f81d commit 5d31e03
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 8 deletions.
35 changes: 27 additions & 8 deletions lib/virtual-fs/src/mem_fs/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ impl crate::FileSystem for FileSystem {
}

fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> {
Box::pin(async {
Box::pin(async move {
let name_of_to;

// Read lock.
Expand Down Expand Up @@ -493,6 +493,7 @@ impl crate::FileSystem for FileSystem {
};

match (inode_of_from_parent, inode_of_to_parent) {
// Rename within this MemFS instance
(Either::Left(inode_of_from_parent), Either::Left(inode_of_to_parent)) => {
let fs = self.inner.read().map_err(|_| FsError::Lock)?;

Expand Down Expand Up @@ -572,16 +573,34 @@ impl crate::FileSystem for FileSystem {

Ok(())
}
(Either::Right((from_fs, from_path)), Either::Right((to_fs, to_path))) => {
if Arc::ptr_eq(&from_fs, &to_fs) {
let same_fs = from_fs;

same_fs.rename(&from_path, &to_path).await
} else {
Err(FsError::InvalidInput)
// Rename within the same mounted FS instance
(Either::Right((from_fs, from_path)), Either::Right((to_fs, to_path)))
if Arc::ptr_eq(&from_fs, &to_fs) =>
{
let same_fs = from_fs;
same_fs.rename(&from_path, &to_path).await
}

// Rename across file systems; we need to do a create and a delete
_ => {
let mut from_file = self.new_open_options().read(true).open(from)?;
let mut to_file = self
.new_open_options()
.create_new(true)
.write(true)
.open(to)?;
tokio::io::copy(from_file.as_mut(), to_file.as_mut()).await?;
if let Err(error) = self.remove_file(from) {
tracing::warn!(
?from,
?to,
?error,
"Failed to remove file after cross-FS rename"
);
}
Ok(())
}
_ => Err(FsError::InvalidInput),
}
})
}
Expand Down
89 changes: 89 additions & 0 deletions tests/wasix/cross-fs-rename/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

void error_exit(const char *desc, const char *call)
{
const char *err_desc = strerror(errno);
printf("Test \"%s\" failed at %s: %s\n", desc, call, err_desc);
// Make it visible in the output log as well
fprintf(stderr, "Test \"%s\" failed at %s: %s\n", desc, call, err_desc);
exit(-1);
}

void create_and_move_file(const char *from_path, const char *to_path)
{
char test_description[1024] = {0};
sprintf(test_description, "%s -> %s", from_path, to_path);

FILE *f = fopen(from_path, "wb");
if (!f)
{
error_exit(test_description, "fopen");
}

char *txt = "hello";
if (!fwrite(txt, 1, 6, f))
{
error_exit(test_description, "fwrite");
}

if (fclose(f))
{
error_exit(test_description, "fclose");
}

// /home is a host FS mount
if (rename(from_path, to_path))
{
error_exit(test_description, "rename");
}

f = fopen(to_path, "rb");
if (!f)
{
error_exit(test_description, "fopen 2");
}

char buffer[7] = {0};
if (!fread(buffer, 1, 7, f))
{
error_exit(test_description, "fread");
}

if (strcmp(buffer, txt))
{
fprintf(stderr, "Expected %s to be equal to %s", buffer, txt);
exit(-1);
}

if (fclose(f))
{
error_exit(test_description, "fclose 2");
}
}

int main()
{
// /tmp is on the MemFS, /temp1 and /temp2 are on separate HostFS instances

// Move file within MemFS
create_and_move_file("/tmp/old", "/tmp/new");

// Move file within single mounted FS
create_and_move_file("/temp1/old", "/temp1/new");

// Move file from MemFS to mounted FS
create_and_move_file("/tmp/file", "/temp1/file");

// Move file from mounted FS to MemFS
create_and_move_file("/temp1/file2", "/tmp/file2");

// Move file between different mounted FS's
create_and_move_file("/temp1/file3", "/temp2/file3");

printf("0");
return 0;
}
6 changes: 6 additions & 0 deletions tests/wasix/cross-fs-rename/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TEMP_DIR1=$(mktemp -d)
TEMP_DIR2=$(mktemp -d)

$WASMER -q run main.wasm --mapdir /temp1:$TEMP_DIR1 --mapdir /temp2:$TEMP_DIR2 > output

printf "0" | diff -u output - 1>/dev/null

0 comments on commit 5d31e03

Please sign in to comment.