Files
FS/src/CopyStream.cpp
T
2024-07-10 13:31:12 +02:00

86 lines
2.9 KiB
C++

#include "StdAfx.h"
#include "fs/CopyStream.h"
#include "fs/IStreamSink.h"
#include "fs/IStreamSource.h"
#include <tl/functional.h>
#include "fs/IFilesystem.h"
namespace fs
{
static constexpr size_t k_defaultBufferSize = 100 * 1024;
CopyStreamResult copyStream(IStreamSink& sink, IStreamSource& source, size_t bufferSize)
{
return copyStream(sink, source, nullptr, bufferSize);
}
CopyStreamResult copyStream(IStreamSink& sink, IStreamSource& source, const ProcessDataCallback& dataCallback, size_t bufferSize)
{
if (bufferSize == 0)
bufferSize = source.getPreferredBufferSize();
if (bufferSize == 0)
bufferSize = sink.getPreferredBufferSize();
if (bufferSize == 0)
bufferSize = k_defaultBufferSize;
tl::memory_buffer buffer;
buffer.resize_uninitialized(bufferSize);
uint64_t size = 0;
do
{
const uint64_t read = source.read(buffer);
tl::optional<Error> optLastError = source.getLastError();
if (optLastError.has_value())
return *optLastError;
if (read == 0)
return size;
if (dataCallback)
dataCallback({ buffer.data(), static_cast<size_t>(read) });
const uint64_t written = sink.write({ buffer.data(), static_cast<size_t>(read) });
if (written != read)
return tl::make_error<Error>(ErrorCode::SystemError, "Failed to write {} bytes. Only {} went through", read, written);
size += written;
optLastError = sink.getLastError();
if (optLastError.has_value())
return *optLastError;
} while (!source.isEOS());
return size;
}
//////////////////////////////////////////////////////////////////////////
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return copyStream(sink, *source, bufferSize);
}
//////////////////////////////////////////////////////////////////////////
CopyStreamResult copyFile(IStreamSink& sink, const IFilesystem& filesystem, AbsPathView filePath, const ProcessDataCallback& dataCallback, size_t bufferSize)
{
OUTCOME_TRY(const auto source, filesystem.openStreamSource(filePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return copyStream(sink, *source, dataCallback, bufferSize);
}
CopyStreamResult copyFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, const IFilesystem& srcFilesystem, AbsPathView srcFilePath, size_t bufferSize)
{
OUTCOME_TRY(const auto sink, dstFilesystem.openStreamSink(dstFilePath, fs::Mode::CreateOrOpenAndClear));
OUTCOME_TRY(const auto source, srcFilesystem.openStreamSource(srcFilePath, IFilesystem::SourceFlags(IFilesystem::SourceFlag::SequentialHint, IFilesystem::SourceFlag::Unbuffered)));
return copyStream(*sink, *source, nullptr, bufferSize);
}
//////////////////////////////////////////////////////////////////////////
}