init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
140
Telegram/SourceFiles/export/output/export_output_file.cpp
Normal file
140
Telegram/SourceFiles/export/output/export_output_file.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "export/output/export_output_file.h"
|
||||
|
||||
#include "export/output/export_output_result.h"
|
||||
#include "export/output/export_output_stats.h"
|
||||
#include "base/qt/qt_string_view.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include <gsl/util>
|
||||
|
||||
namespace Export {
|
||||
namespace Output {
|
||||
|
||||
File::File(const QString &path, Stats *stats) : _path(path), _stats(stats) {
|
||||
}
|
||||
|
||||
int64 File::size() const {
|
||||
return _offset;
|
||||
}
|
||||
|
||||
bool File::empty() const {
|
||||
return !_offset;
|
||||
}
|
||||
|
||||
Result File::writeBlock(const QByteArray &block) {
|
||||
const auto result = writeBlockAttempt(block);
|
||||
if (!result) {
|
||||
_file.reset();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Result File::writeBlockAttempt(const QByteArray &block) {
|
||||
if (_stats && !_inStats) {
|
||||
_inStats = true;
|
||||
_stats->incrementFiles();
|
||||
}
|
||||
if (const auto result = reopen(); !result) {
|
||||
return result;
|
||||
}
|
||||
const auto size = block.size();
|
||||
if (!size) {
|
||||
return Result::Success();
|
||||
}
|
||||
if (_file->write(block) == size && _file->flush()) {
|
||||
_offset += size;
|
||||
if (_stats) {
|
||||
_stats->incrementBytes(size);
|
||||
}
|
||||
return Result::Success();
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
||||
Result File::reopen() {
|
||||
if (_file && _file->isOpen()) {
|
||||
return Result::Success();
|
||||
}
|
||||
_file.emplace(_path);
|
||||
if (_file->exists()) {
|
||||
if (_file->size() < _offset) {
|
||||
return fatalError();
|
||||
} else if (!_file->resize(_offset)) {
|
||||
return error();
|
||||
}
|
||||
} else if (_offset > 0) {
|
||||
return fatalError();
|
||||
}
|
||||
if (_file->open(QIODevice::Append)) {
|
||||
return Result::Success();
|
||||
}
|
||||
const auto info = QFileInfo(_path);
|
||||
const auto dir = info.absoluteDir();
|
||||
return (!dir.exists()
|
||||
&& dir.mkpath(dir.absolutePath())
|
||||
&& _file->open(QIODevice::Append))
|
||||
? Result::Success()
|
||||
: error();
|
||||
}
|
||||
|
||||
Result File::error() const {
|
||||
return Result(Result::Type::Error, _path);
|
||||
}
|
||||
|
||||
Result File::fatalError() const {
|
||||
return Result(Result::Type::FatalError, _path);
|
||||
}
|
||||
|
||||
QString File::PrepareRelativePath(
|
||||
const QString &folder,
|
||||
const QString &suggested) {
|
||||
if (!QFile::exists(folder + suggested)) {
|
||||
return suggested;
|
||||
}
|
||||
|
||||
// Not lastIndexOf('.') so that "file.tar.xz" won't be messed up.
|
||||
const auto position = suggested.indexOf('.');
|
||||
const auto base = suggested.mid(0, position);
|
||||
const auto extension = (position >= 0)
|
||||
? base::StringViewMid(suggested, position)
|
||||
: QStringView();
|
||||
const auto relativePart = [&](int attempt) {
|
||||
auto result = base + QString(" (%1)").arg(attempt);
|
||||
result.append(extension);
|
||||
return result;
|
||||
};
|
||||
auto attempt = 0;
|
||||
while (true) {
|
||||
const auto relativePath = relativePart(++attempt);
|
||||
if (!QFile::exists(folder + relativePath)) {
|
||||
return relativePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result File::Copy(
|
||||
const QString &source,
|
||||
const QString &path,
|
||||
Stats *stats) {
|
||||
QFile f(source);
|
||||
if (!f.exists() || !f.open(QIODevice::ReadOnly)) {
|
||||
return Result(Result::Type::FatalError, source);
|
||||
}
|
||||
const auto bytes = f.readAll();
|
||||
if (bytes.size() != f.size()) {
|
||||
return Result(Result::Type::FatalError, source);
|
||||
}
|
||||
return File(path, stats).writeBlock(bytes);
|
||||
}
|
||||
|
||||
} // namespace Output
|
||||
} // namespace File
|
||||
Reference in New Issue
Block a user