#include "StdAfx.h" #include "fs/CopyStream.h" #include "fs/IStreamSink.h" #include "fs/IStreamSource.h" #include #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 optLastError = source.getLastError(); if (optLastError.has_value()) return *optLastError; if (read == 0) return size; if (dataCallback) dataCallback({ buffer.data(), static_cast(read) }); const uint64_t written = sink.write({ buffer.data(), static_cast(read) }); if (written != read) return tl::make_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); } ////////////////////////////////////////////////////////////////////////// }