Files
pmt-renovated/src/functions/BackupFunction.cpp

172 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <fcntl.h>
#include <private/android_filesystem_config.h>
#include <unistd.h>
#include <PartitionManager/PartitionManager.hpp>
#include <cerrno>
#include <chrono>
#include <cstdlib>
#include <future>
#include "functions.hpp"
#define BFUN "backupFunction"
#define FUNCTION_CLASS backupFunction
namespace PartitionManager {
RUN_ASYNC(const std::string& partitionName, const std::string& outputName,
const uint64_t bufferSize) {
if (!PART_MAP.hasPartition(partitionName))
return {Helper::format("Couldn't find partition: %s", partitionName.data()),
false};
LOGN(BFUN, INFO) << "Back upping " << partitionName << " as " << outputName
<< std::endl;
if (VARS.onLogical && !PART_MAP.isLogical(partitionName)) {
if (VARS.forceProcess)
LOGN(BFUN, WARNING)
<< "Partition " << partitionName
<< " is exists but not logical. Ignoring (from --force, -f)."
<< std::endl;
else
return {Helper::format(
"Used --logical (-l) flag but is not logical partition: %s",
partitionName.data()),
false};
}
if (Helper::fileIsExists(outputName) && !VARS.forceProcess)
return {Helper::format("%s is exists. Remove it, or use --force (-f) flag.",
outputName.data()),
false};
LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName
<< "): " << bufferSize << std::endl;
// Automatically close file descriptors and delete allocated memories (arrays)
Helper::garbageCollector collector;
const int pfd = Helper::openAndAddToCloseList(
PART_MAP.getRealPathOf(partitionName), collector, O_RDONLY);
if (pfd < 0)
return {Helper::format("Can't open partition: %s: %s", partitionName.data(),
strerror(errno)),
false};
const int ffd = Helper::openAndAddToCloseList(
outputName, collector, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0)
return {Helper::format("Can't create/open output file %s: %s",
outputName.data(), strerror(errno)),
false};
LOGN(BFUN, INFO) << "Writing partition " << partitionName
<< " to file: " << outputName << std::endl;
auto* buffer = new (std::nothrow) char[bufferSize];
collector.delAfterProgress(buffer);
memset(buffer, 0x00, bufferSize);
ssize_t bytesRead;
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
if (const ssize_t bytesWritten = write(ffd, buffer, bytesRead);
bytesWritten != bytesRead)
return {Helper::format("Can't write partition to output file %s: %s",
outputName.data(), strerror(errno)),
false};
}
if (!Helper::changeOwner(outputName, AID_EVERYBODY, AID_EVERYBODY))
LOGN(BFUN, WARNING) << "Failed to change owner of output file: "
<< outputName
<< ". Access problems maybe occur in non-root mode"
<< std::endl;
if (!Helper::changeMode(outputName, 0664))
LOGN(BFUN, WARNING) << "Failed to change mode of output file as 660: "
<< outputName
<< ". Access problems maybe occur in non-root mode"
<< std::endl;
return {Helper::format("%s partition successfully back upped to %s",
partitionName.data(), outputName.data()),
true};
}
INIT {
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")
->required();
cmd->add_option("output(s)", rawOutputNames,
"File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-O,--output-directory", outputDirectory,
"Directory to save the partition image(s)")
->check(CLI::ExistingDirectory);
cmd->add_option("-b,--buffer-size", bufferSize,
"Buffer size for reading partition(s) and writing to file(s)")
->transform(CLI::AsSizeValue(false))
->default_val("4KB");
return true;
}
RUN {
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames,
',', true);
if (!outputNames.empty() && partitions.size() != outputNames.size())
throw CLI::ValidationError(
"You must provide an output name(s) as long as the partition name(s)");
std::vector<std::future<pair>> futures;
for (size_t i = 0; i < partitions.size(); i++) {
uint64_t buf = bufferSize;
std::string partitionName = partitions[i];
std::string outputName =
outputNames.empty() ? partitionName + ".img" : outputNames[i];
if (!outputDirectory.empty()) outputName.insert(0, outputDirectory + '/');
setupBufferSize(buf, partitionName);
futures.push_back(std::async(std::launch::async, runAsync, partitionName,
outputName, buf));
LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName
<< std::endl;
}
std::string end;
bool endResult = true;
for (auto& future : futures) {
auto [fst, snd] = future.get();
if (!snd) {
end += fst + '\n';
endResult = false;
} else
println("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
IS_USED_COMMON_BODY
NAME { return BFUN; }
} // namespace PartitionManager