86 lines
2.9 KiB
C++
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, const AbsPath& 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, const AbsPath& 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, const AbsPath& dstFilePath, const IFilesystem& srcFilesystem, const AbsPath& 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);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
}
|