vfs_import: implement write loop for copy_file
This is required to allow import of large file. Fixes #3655
This commit is contained in:
parent
46fa8197a2
commit
9da428dccf
|
@ -119,6 +119,7 @@ class Vfs_import::File_system : public Vfs::File_system
|
||||||
bool overwrite)
|
bool overwrite)
|
||||||
{
|
{
|
||||||
using Genode::Readonly_file;
|
using Genode::Readonly_file;
|
||||||
|
using Genode::size_t;
|
||||||
|
|
||||||
Readonly_file src_file(src, path);
|
Readonly_file src_file(src, path);
|
||||||
Vfs_handle *dst_handle = nullptr;
|
Vfs_handle *dst_handle = nullptr;
|
||||||
|
@ -139,34 +140,55 @@ class Vfs_import::File_system : public Vfs::File_system
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vfs_handle::Guard guard(dst_handle);
|
char buf[4096];
|
||||||
|
Vfs_handle::Guard guard { dst_handle };
|
||||||
|
Flush_guard flush { env, *dst_handle };
|
||||||
|
Readonly_file::At at { };
|
||||||
|
|
||||||
{
|
while (true) {
|
||||||
char buf[4096];
|
|
||||||
Flush_guard flush(env, *dst_handle);
|
|
||||||
|
|
||||||
Readonly_file::At at { };
|
file_size bytes_from_source { src_file.read(at, buf, sizeof(buf)) };
|
||||||
|
|
||||||
while (true) {
|
if (!bytes_from_source) break;
|
||||||
file_size wn = 0;
|
|
||||||
file_size rn = src_file.read(at, buf, sizeof(buf));
|
|
||||||
if (!rn) break;
|
|
||||||
|
|
||||||
auto wres = dst_handle->fs().write(dst_handle, buf, rn, wn);
|
bool stalled { false };
|
||||||
switch (wres) {
|
bool write_error { false };
|
||||||
case WRITE_OK:
|
Vfs::file_size remaining_bytes { bytes_from_source };
|
||||||
case WRITE_ERR_AGAIN:
|
char const *src { buf };
|
||||||
case WRITE_ERR_WOULD_BLOCK:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Genode::error("failed to write to ", path, ", ", wres);
|
|
||||||
env.root_dir().unlink(path.string());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst_handle->advance_seek(wn);
|
while (remaining_bytes > 0 && !write_error) {
|
||||||
at.value += wn;
|
|
||||||
|
try {
|
||||||
|
Vfs::file_size out_count { 0 };
|
||||||
|
switch (dst_handle->fs().write(dst_handle, src,
|
||||||
|
remaining_bytes,
|
||||||
|
out_count)) {
|
||||||
|
case WRITE_ERR_AGAIN:
|
||||||
|
case WRITE_ERR_WOULD_BLOCK:
|
||||||
|
stalled = true;
|
||||||
|
break;
|
||||||
|
case Write_result::WRITE_ERR_INVALID:
|
||||||
|
case Write_result::WRITE_ERR_IO:
|
||||||
|
case Write_result::WRITE_ERR_INTERRUPT:
|
||||||
|
env.root_dir().unlink(path.string());
|
||||||
|
write_error = true;
|
||||||
|
break;
|
||||||
|
case WRITE_OK:
|
||||||
|
out_count = min(remaining_bytes, out_count);
|
||||||
|
remaining_bytes -= out_count;
|
||||||
|
src += out_count;
|
||||||
|
at.value += out_count;
|
||||||
|
dst_handle->advance_seek(out_count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Vfs::File_io_service::Insufficient_buffer) {
|
||||||
|
stalled = true; }
|
||||||
|
|
||||||
|
if (stalled)
|
||||||
|
env.env().ep().wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
|
if (write_error)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user