diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 1ddfb7600..218cfde66 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -463,13 +463,41 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t
     return true;
 }
 
-bool VfsRawCopy(VirtualFile src, VirtualFile dest) {
-    if (src == nullptr || dest == nullptr)
+bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size) {
+    if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
         return false;
     if (!dest->Resize(src->GetSize()))
         return false;
-    std::vector<u8> data = src->ReadAllBytes();
-    return dest->WriteBytes(data, 0) == data.size();
+
+    std::vector<u8> temp(std::min(block_size, src->GetSize()));
+    for (size_t i = 0; i < src->GetSize(); i += block_size) {
+        const auto read = std::min(block_size, src->GetSize() - i);
+        const auto block = src->Read(temp.data(), read, i);
+
+        if (dest->Write(temp.data(), read, i) != read)
+            return false;
+    }
+
+    return true;
+}
+
+bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size) {
+    if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
+        return false;
+
+    for (const auto& file : src->GetFiles()) {
+        const auto out = dest->CreateFile(file->GetName());
+        if (!VfsRawCopy(file, out, block_size))
+            return false;
+    }
+
+    for (const auto& dir : src->GetSubdirectories()) {
+        const auto out = dest->CreateSubdirectory(dir->GetName());
+        if (!VfsRawCopyD(dir, out, block_size))
+            return false;
+    }
+
+    return true;
 }
 
 VirtualDir GetOrCreateDirectoryRelative(const VirtualDir& rel, std::string_view path) {
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 828e87f38..6aec4c164 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -316,12 +316,14 @@ public:
 };
 
 // Compare the two files, byte-for-byte, in increments specificed by block_size
-bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size = 0x200);
+bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x1000);
 
 // A method that copies the raw data between two different implementations of VirtualFile. If you
 // are using the same implementation, it is probably better to use the Copy method in the parent
 // directory of src/dest.
-bool VfsRawCopy(VirtualFile src, VirtualFile dest);
+bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000);
+
+bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000);
 
 // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not
 // it attempts to create it and returns the new dir or nullptr on failure.