mirror of
https://github.com/usatiuk/backup.git
synced 2025-10-26 09:27:48 +01:00
Compare commits
8 Commits
a14eb1c501
...
cleaning
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c1e9fe4bf | |||
| 1dad7d1501 | |||
| 0b2040603e | |||
| 476904b5aa | |||
| 061e164c6a | |||
| e996e93431 | |||
| 8e9ed2b715 | |||
| 0095f9ff69 |
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@@ -1,4 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
<component name="CidrRootsConfiguration">
|
||||||
|
<excludeRoots>
|
||||||
|
<file path="$PROJECT_DIR$/cmake-build-debug" />
|
||||||
|
<file path="$PROJECT_DIR$/cmake-build-relwithdebinfo" />
|
||||||
|
<file path="$PROJECT_DIR$/cmake-build-relwithsan" />
|
||||||
|
</excludeRoots>
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
add_subdirectory(change_detectors)
|
add_subdirectory(change_detectors)
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ ComparableFile::ComparableFile(const File &file, const Repository *repo)
|
|||||||
contents([file, repo]() { return std::make_unique<FileBuffer>(repo, file.id); }) {}
|
contents([file, repo]() { return std::make_unique<FileBuffer>(repo, file.id); }) {}
|
||||||
|
|
||||||
ComparableFile::ComparableFile(const std::filesystem::path &p, const std::filesystem::path &base)
|
ComparableFile::ComparableFile(const std::filesystem::path &p, const std::filesystem::path &base)
|
||||||
: path(p.lexically_relative(base).u8string()), type(File::getFileType(p)), bytes(File::getFileSize(p)),
|
: path(p.lexically_relative(base).string()), type(File::getFileType(p)), bytes(File::getFileSize(p)),
|
||||||
mtime(File::getFileMtime(p)),
|
mtime(File::getFileMtime(p)),
|
||||||
contents([p, path = this->path, type = this->type]() -> std::unique_ptr<std::streambuf> {
|
contents([p, path = this->path, type = this->type]() -> std::unique_ptr<std::streambuf> {
|
||||||
if (type == File::Type::Normal) {
|
if (type == File::Type::Normal) {
|
||||||
auto fb = std::make_unique<std::filebuf>();
|
auto fb = std::make_unique<std::filebuf>();
|
||||||
fb->open(p, std::ios::in | std::ios::binary);
|
fb->open(p, std::ios::in | std::ios::binary);
|
||||||
if (!fb->is_open()) throw Exception("Can't open " + p.u8string() + " for reading!");
|
if (!fb->is_open()) throw Exception("Can't open " + p.string() + " for reading!");
|
||||||
return fb;
|
return fb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
add_library(commands srcs/CommandDiff.cpp srcs/CommandList.cpp srcs/CommandListFiles.cpp srcs/CommandRestore.cpp srcs/CommandRun.cpp srcs/CommandsCommon.cpp srcs/Diff.cpp srcs/CommandMount.cpp)
|
add_library(commands
|
||||||
|
srcs/CommandDiff.cpp
|
||||||
|
srcs/CommandList.cpp
|
||||||
|
srcs/CommandListFiles.cpp
|
||||||
|
srcs/CommandRestore.cpp
|
||||||
|
srcs/CommandRun.cpp
|
||||||
|
srcs/CommandsCommon.cpp
|
||||||
|
srcs/Diff.cpp
|
||||||
|
srcs/CommandMount.cpp
|
||||||
|
srcs/CommandDelete.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(commands PUBLIC includes)
|
target_include_directories(commands PUBLIC includes)
|
||||||
|
|
||||||
|
|||||||
18
src/commands/includes/CommandDelete.h
Normal file
18
src/commands/includes/CommandDelete.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by Stepan Usatiuk on 06.08.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BACKUP_COMMANDDELETE_H
|
||||||
|
#define BACKUP_COMMANDDELETE_H
|
||||||
|
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
class CommandDelete : public Command {
|
||||||
|
public:
|
||||||
|
CommandDelete();
|
||||||
|
void run(Context ctx) override;
|
||||||
|
static constexpr std::string_view name{"delete"};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif//BACKUP_COMMANDDELETE_H
|
||||||
15
src/commands/srcs/CommandDelete.cpp
Normal file
15
src/commands/srcs/CommandDelete.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by Stepan Usatiuk on 06.08.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "CommandDelete.h"
|
||||||
|
|
||||||
|
#include "CommandsCommon.h"
|
||||||
|
|
||||||
|
using namespace CommandsCommon;
|
||||||
|
|
||||||
|
CommandDelete::CommandDelete() {}
|
||||||
|
|
||||||
|
void CommandDelete::run(Context ctx) {
|
||||||
|
ctx.repo->deleteObjects({static_cast<unsigned long long>(ctx.repo->getConfig().getInt("aid"))});
|
||||||
|
}
|
||||||
@@ -38,12 +38,12 @@ void CommandDiff::run(Context ctx) {
|
|||||||
ctx.repo->getConfig().exists("threads") ? ctx.repo->getConfig().getInt("threads")
|
ctx.repo->getConfig().exists("threads") ? ctx.repo->getConfig().getInt("threads")
|
||||||
: std::thread::hardware_concurrency());
|
: std::thread::hardware_concurrency());
|
||||||
|
|
||||||
auto archiveO1 = Serialize::deserialize<Archive>(ctx.repo->getObject(archive1));
|
auto archiveO1 = Serialize::deserialize<Archive>(ctx.repo->getObjectRaw(archive1));
|
||||||
std::mutex filesLock;
|
std::mutex filesLock;
|
||||||
std::map<std::filesystem::path, File> files;///< Files in the first archive
|
std::map<std::filesystem::path, File> files;///< Files in the first archive
|
||||||
for (auto id: archiveO1.files) {
|
for (auto id: archiveO1.files) {
|
||||||
auto file = Serialize::deserialize<File>(ctx.repo->getObject(id));
|
auto file = Serialize::deserialize<File>(ctx.repo->getObjectRaw(id));
|
||||||
auto path = std::filesystem::u8path(file.name);
|
auto path = std::filesystem::path(file.name);
|
||||||
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), path)) files.emplace(file.getKey(), std::move(file));
|
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), path)) files.emplace(file.getKey(), std::move(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,14 +76,14 @@ void CommandDiff::run(Context ctx) {
|
|||||||
/// If a second archive is given, run the task for each of its files, otherwise use the "from" config option
|
/// If a second archive is given, run the task for each of its files, otherwise use the "from" config option
|
||||||
if (ctx.repo->getConfig().exists("aid2")) {
|
if (ctx.repo->getConfig().exists("aid2")) {
|
||||||
archiveO2.emplace(
|
archiveO2.emplace(
|
||||||
Serialize::deserialize<Archive>(ctx.repo->getObject(ctx.repo->getConfig().getInt("aid2"))));
|
Serialize::deserialize<Archive>(ctx.repo->getObjectRaw(ctx.repo->getConfig().getInt("aid2"))));
|
||||||
|
|
||||||
threadPool.push([&]() {
|
threadPool.push([&]() {
|
||||||
for (auto id: archiveO2.value().files) {
|
for (auto id: archiveO2.value().files) {
|
||||||
/// Exit when asked to
|
/// Exit when asked to
|
||||||
if (Signals::shouldQuit) throw Exception("Quitting");
|
if (Signals::shouldQuit) throw Exception("Quitting");
|
||||||
auto file = Serialize::deserialize<File>(ctx.repo->getObject(id));
|
auto file = Serialize::deserialize<File>(ctx.repo->getObjectRaw(id));
|
||||||
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), std::filesystem::u8path(file.name)))
|
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), std::filesystem::path(file.name)))
|
||||||
threadPool.push([&, file]() { processFile(ComparableFile{file, ctx.repo}); });
|
threadPool.push([&, file]() { processFile(ComparableFile{file, ctx.repo}); });
|
||||||
if (Signals::shouldQuit) break;
|
if (Signals::shouldQuit) break;
|
||||||
}
|
}
|
||||||
@@ -111,11 +111,11 @@ void CommandDiff::run(Context ctx) {
|
|||||||
|
|
||||||
if (ctx.repo->getConfig().exists("aid2")) {
|
if (ctx.repo->getConfig().exists("aid2")) {
|
||||||
archiveO2.emplace(
|
archiveO2.emplace(
|
||||||
Serialize::deserialize<Archive>(ctx.repo->getObject(ctx.repo->getConfig().getInt("aid2"))));
|
Serialize::deserialize<Archive>(ctx.repo->getObjectRaw(ctx.repo->getConfig().getInt("aid2"))));
|
||||||
std::map<std::filesystem::path, File> files2;///< Files in the first archive
|
std::map<std::filesystem::path, File> files2;///< Files in the first archive
|
||||||
for (auto id: archiveO2->files) {
|
for (auto id: archiveO2->files) {
|
||||||
auto file = Serialize::deserialize<File>(ctx.repo->getObject(id));
|
auto file = Serialize::deserialize<File>(ctx.repo->getObjectRaw(id));
|
||||||
auto path = std::filesystem::u8path(file.name);
|
auto path = std::filesystem::path(file.name);
|
||||||
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), path))
|
if (isSubpath(ctx.repo->getConfig().getStr("prefix"), path))
|
||||||
files2.emplace(file.getKey(), std::move(file));
|
files2.emplace(file.getKey(), std::move(file));
|
||||||
}
|
}
|
||||||
@@ -144,5 +144,5 @@ void CommandDiff::run(Context ctx) {
|
|||||||
std::unique_lock finishedLock(threadPool.finishedLock);
|
std::unique_lock finishedLock(threadPool.finishedLock);
|
||||||
threadPool.finished.wait(finishedLock, [&threadPool] { return threadPool.empty(); });
|
threadPool.finished.wait(finishedLock, [&threadPool] { return threadPool.empty(); });
|
||||||
if (diffMode == "normal")
|
if (diffMode == "normal")
|
||||||
for (auto const &s: files) { ctx.logger->write(s.first.u8string() + " is removed\n", 0); }
|
for (auto const &s: files) { ctx.logger->write(s.first.string() + " is removed\n", 0); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
CommandListFiles::CommandListFiles() : Command() {}
|
CommandListFiles::CommandListFiles() : Command() {}
|
||||||
|
|
||||||
void CommandListFiles::run(Context ctx) {
|
void CommandListFiles::run(Context ctx) {
|
||||||
auto archive = Serialize::deserialize<Archive>(ctx.repo->getObject(ctx.repo->getConfig().getInt("aid")));
|
auto archive = Serialize::deserialize<Archive>(ctx.repo->getObjectRaw(ctx.repo->getConfig().getInt("aid")));
|
||||||
for (auto const &fid: archive.files) {
|
for (auto const &fid: archive.files) {
|
||||||
auto file = Serialize::deserialize<File>(ctx.repo->getObject(fid));
|
auto file = Serialize::deserialize<File>(ctx.repo->getObjectRaw(fid));
|
||||||
std::cout << "Name: " << file.name << " type: " << File::TypeToStr.at(file.fileType)
|
std::cout << "Name: " << file.name << " type: " << File::TypeToStr.at(file.fileType)
|
||||||
<< " size: " << BytesFormatter::formatStr(file.bytes) << std::endl;
|
<< " size: " << BytesFormatter::formatStr(file.bytes) << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ CommandRestore::CommandRestore() : Command() {}
|
|||||||
|
|
||||||
void CommandRestore::run(Context ctx) {
|
void CommandRestore::run(Context ctx) {
|
||||||
Object::idType archive = ctx.repo->getConfig().getInt("aid");
|
Object::idType archive = ctx.repo->getConfig().getInt("aid");
|
||||||
std::filesystem::path to = std::filesystem::u8path(ctx.repo->getConfig().getStr("to"));
|
std::filesystem::path to = std::filesystem::path(ctx.repo->getConfig().getStr("to"));
|
||||||
|
|
||||||
std::atomic<unsigned long long> filesToRestoreCount = 0;
|
std::atomic<unsigned long long> filesToRestoreCount = 0;
|
||||||
std::atomic<unsigned long long> bytesToRestore = 0;
|
std::atomic<unsigned long long> bytesToRestore = 0;
|
||||||
@@ -68,14 +68,14 @@ void CommandRestore::run(Context ctx) {
|
|||||||
/// Add the main restore task
|
/// Add the main restore task
|
||||||
threadPool.push([&, this]() {
|
threadPool.push([&, this]() {
|
||||||
/// Get the archive and its file IDs
|
/// Get the archive and its file IDs
|
||||||
auto archiveO = Serialize::deserialize<Archive>(ctx.repo->getObject(archive));
|
auto archiveO = Serialize::deserialize<Archive>(ctx.repo->getObjectRaw(archive));
|
||||||
std::vector<Object::idType> files = archiveO.files;
|
std::vector<Object::idType> files = archiveO.files;
|
||||||
/// For each file...
|
/// For each file...
|
||||||
for (const auto fid: files) {
|
for (const auto fid: files) {
|
||||||
/// Stop when asked to
|
/// Stop when asked to
|
||||||
if (Signals::shouldQuit) break;
|
if (Signals::shouldQuit) break;
|
||||||
|
|
||||||
auto file = Serialize::deserialize<File>(ctx.repo->getObject(fid));
|
auto file = Serialize::deserialize<File>(ctx.repo->getObjectRaw(fid));
|
||||||
filesToRestoreCount++;
|
filesToRestoreCount++;
|
||||||
bytesToRestore += file.bytes;
|
bytesToRestore += file.bytes;
|
||||||
/// Spawn a restore task
|
/// Spawn a restore task
|
||||||
@@ -95,28 +95,28 @@ void CommandRestore::run(Context ctx) {
|
|||||||
|
|
||||||
std::string CommandRestore::backupRestoreFile(const File &file, const std::filesystem::path &baseDir,
|
std::string CommandRestore::backupRestoreFile(const File &file, const std::filesystem::path &baseDir,
|
||||||
workerStatsFunction &callback, Context ctx) {
|
workerStatsFunction &callback, Context ctx) {
|
||||||
auto fullpath = baseDir / std::filesystem::u8path(file.name);
|
auto fullpath = baseDir / std::filesystem::path(file.name);
|
||||||
|
|
||||||
std::filesystem::create_directories(fullpath.parent_path());
|
std::filesystem::create_directories(fullpath.parent_path());
|
||||||
|
|
||||||
if (file.fileType == File::Type::Directory) {
|
if (file.fileType == File::Type::Directory) {
|
||||||
std::filesystem::create_directory(fullpath);
|
std::filesystem::create_directory(fullpath);
|
||||||
callback(0, 0, 1);
|
callback(0, 0, 1);
|
||||||
return fullpath.u8string();
|
return fullpath.string();
|
||||||
}
|
}
|
||||||
if (file.fileType == File::Type::Symlink) {
|
if (file.fileType == File::Type::Symlink) {
|
||||||
auto dest = Serialize::deserialize<Chunk>(ctx.repo->getObject(file.chunks.at(0)));
|
auto dest = Serialize::deserialize<Chunk>(ctx.repo->getObjectRaw(file.chunks.at(0)));
|
||||||
std::filesystem::create_symlink(std::filesystem::u8path(std::string{dest.data.begin(), dest.data.end()}),
|
std::filesystem::create_symlink(std::filesystem::path(std::string{dest.data.begin(), dest.data.end()}),
|
||||||
fullpath);
|
fullpath);
|
||||||
callback(0, 0, 1);
|
callback(0, 0, 1);
|
||||||
return fullpath.u8string();
|
return fullpath.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream ostream(fullpath, std::ios::binary | std::ios::out | std::ios::trunc);
|
std::ofstream ostream(fullpath, std::ios::binary | std::ios::out | std::ios::trunc);
|
||||||
for (const auto cid: file.chunks) {
|
for (const auto cid: file.chunks) {
|
||||||
if (Signals::shouldQuit) throw Exception("Quitting!");
|
if (Signals::shouldQuit) throw Exception("Quitting!");
|
||||||
|
|
||||||
Chunk c = Serialize::deserialize<Chunk>(ctx.repo->getObject(cid.second));
|
Chunk c = Serialize::deserialize<Chunk>(ctx.repo->getObjectRaw(cid.second));
|
||||||
if (!c.data.empty()) {
|
if (!c.data.empty()) {
|
||||||
ostream.rdbuf()->sputn(c.data.data(), c.data.size());
|
ostream.rdbuf()->sputn(c.data.data(), c.data.size());
|
||||||
callback(c.data.size(), 0, 0);
|
callback(c.data.size(), 0, 0);
|
||||||
@@ -124,5 +124,5 @@ std::string CommandRestore::backupRestoreFile(const File &file, const std::files
|
|||||||
}
|
}
|
||||||
callback(0, 0, 1);
|
callback(0, 0, 1);
|
||||||
|
|
||||||
return fullpath.u8string();
|
return fullpath.string();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,17 +79,17 @@ void CommandRun::run(Context ctx) {
|
|||||||
File::getFileType(absPath) == File::Type::Normal ? std::filesystem::file_size(absPath) : 0;
|
File::getFileType(absPath) == File::Type::Normal ? std::filesystem::file_size(absPath) : 0;
|
||||||
runnerStats.filesToSaveCount++;
|
runnerStats.filesToSaveCount++;
|
||||||
threadPool.push([&, relPath, absPath]() {
|
threadPool.push([&, relPath, absPath]() {
|
||||||
addFile(backupChunkFile(absPath, relPath.u8string(), workerCallback, ctx));
|
addFile(backupChunkFile(absPath, relPath.string(), workerCallback, ctx));
|
||||||
progress.print("Copied: " + relPath.u8string(), 1);
|
progress.print("Copied: " + relPath.string(), 1);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Task to process an individual file in the backup
|
/// Task to process an individual file in the backup
|
||||||
std::function<void(std::filesystem::path)> processFile = [&, this](const std::filesystem::path &p) {
|
std::function<void(std::filesystem::path)> processFile = [&, this](const std::filesystem::path &p) {
|
||||||
auto relPath = p.lexically_relative(from).u8string();
|
auto relPath = p.lexically_relative(from).string();
|
||||||
|
|
||||||
if (ctx.repo->exists(Object::ObjectType::File, relPath) != 0) {
|
if (ctx.repo->exists(Object::ObjectType::File, relPath) != 0) {
|
||||||
File repoFile = Serialize::deserialize<File>(ctx.repo->getObject(Object::ObjectType::File, relPath));
|
File repoFile = Serialize::deserialize<File>(ctx.repo->getObjectRaw(Object::ObjectType::File, relPath));
|
||||||
if (!changeDetector.check({repoFile, ctx.repo}, {p, from})) {
|
if (!changeDetector.check({repoFile, ctx.repo}, {p, from})) {
|
||||||
addFile(repoFile.id);
|
addFile(repoFile.id);
|
||||||
progress.print("Skipped: " + relPath, 1);
|
progress.print("Skipped: " + relPath, 1);
|
||||||
@@ -144,10 +144,10 @@ Object::idType CommandRun::backupChunkFile(const std::filesystem::path &orig, co
|
|||||||
ctx.repo->putObject(f);
|
ctx.repo->putObject(f);
|
||||||
return f.id;
|
return f.id;
|
||||||
}
|
}
|
||||||
if (!std::filesystem::is_regular_file(orig)) throw Exception(orig.u8string() + "is a special file, not saving");
|
if (!std::filesystem::is_regular_file(orig)) throw Exception(orig.string() + "is a special file, not saving");
|
||||||
|
|
||||||
std::ifstream ifstream(orig, std::ios::in | std::ios::binary);
|
std::ifstream ifstream(orig, std::ios::in | std::ios::binary);
|
||||||
if (!ifstream) throw Exception("Couldn't open " + orig.u8string() + " for reading");
|
if (!ifstream) throw Exception("Couldn't open " + orig.string() + " for reading");
|
||||||
std::unique_ptr<Chunker> chunker = ChunkerFactory::getChunker(ctx.repo->getConfig(), ifstream.rdbuf());
|
std::unique_ptr<Chunker> chunker = ChunkerFactory::getChunker(ctx.repo->getConfig(), ifstream.rdbuf());
|
||||||
|
|
||||||
SHA fileHash;
|
SHA fileHash;
|
||||||
@@ -179,7 +179,7 @@ Object::idType CommandRun::backupChunkFile(const std::filesystem::path &orig, co
|
|||||||
/// We might have exited in the loop before, so we don't save an incomplete file
|
/// We might have exited in the loop before, so we don't save an incomplete file
|
||||||
if (Signals::shouldQuit) throw Exception("Quitting!");
|
if (Signals::shouldQuit) throw Exception("Quitting!");
|
||||||
if (size != File::getFileSize(orig)) {
|
if (size != File::getFileSize(orig)) {
|
||||||
throw Exception("Something really bad happened or file " + orig.u8string() + " changed during backup");
|
throw Exception("Something really bad happened or file " + orig.string() + " changed during backup");
|
||||||
}
|
}
|
||||||
File f(ctx.repo->getId(), saveAs, size, File::getFileMtime(orig), fileHash.getHash(), fileChunks,
|
File f(ctx.repo->getId(), saveAs, size, File::getFileMtime(orig), fileHash.getHash(), fileChunks,
|
||||||
File::getFileType(orig));
|
File::getFileType(orig));
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ void CommandsCommon::workerCallback(unsigned long long int bytesWritten, unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CommandsCommon::isSubpath(const std::filesystem::path &prefix, const std::filesystem::path &p) {
|
bool CommandsCommon::isSubpath(const std::filesystem::path &prefix, const std::filesystem::path &p) {
|
||||||
if (prefix.u8string().size() > p.u8string().size()) return false;
|
if (prefix.string().size() > p.string().size()) return false;
|
||||||
for (int i = 0; i < prefix.u8string().size(); i++)
|
for (int i = 0; i < prefix.string().size(); i++)
|
||||||
if (p.u8string()[i] != prefix.u8string()[i]) return false;
|
if (p.string()[i] != prefix.string()[i]) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandsCommon::processDirWithIgnore(const std::filesystem::path &dir, std::vector<std::string> ignore,
|
void CommandsCommon::processDirWithIgnore(const std::filesystem::path &dir, std::vector<std::string> ignore,
|
||||||
const std::function<void(std::function<void()>)> &spawner,
|
const std::function<void(std::function<void()>)> &spawner,
|
||||||
std::function<void(std::filesystem::directory_entry)> processFile) {
|
std::function<void(std::filesystem::directory_entry)> processFile) {
|
||||||
if (!std::filesystem::is_directory(dir)) throw Exception(dir.u8string() + " is not a directory!");
|
if (!std::filesystem::is_directory(dir)) throw Exception(dir.string() + " is not a directory!");
|
||||||
|
|
||||||
/// Don't process the directory if it has a ".nobackup" file
|
/// Don't process the directory if it has a ".nobackup" file
|
||||||
if (std::filesystem::exists(dir / ".nobackup")) return;
|
if (std::filesystem::exists(dir / ".nobackup")) return;
|
||||||
@@ -47,7 +47,7 @@ void CommandsCommon::processDirWithIgnore(const std::filesystem::path &dir, std:
|
|||||||
/// Don't process the entry if it matches any of the ignore rules
|
/// Don't process the entry if it matches any of the ignore rules
|
||||||
if (std::any_of(ignore.begin(), ignore.end(), [dirEntry](auto pred) {
|
if (std::any_of(ignore.begin(), ignore.end(), [dirEntry](auto pred) {
|
||||||
std::smatch m;
|
std::smatch m;
|
||||||
auto s = dirEntry.path().filename().u8string();
|
auto s = dirEntry.path().filename().string();
|
||||||
return std::regex_match(s, m, std::regex(pred));
|
return std::regex_match(s, m, std::regex(pred));
|
||||||
}))
|
}))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ FilterContainer &FilterContainer::addFilter(std::unique_ptr<Filter> &&f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FilterContainer::filterWrite(std::vector<char> from) const {
|
std::vector<char> FilterContainer::filterWrite(std::vector<char> from) const {
|
||||||
for (auto const &f: filters) from = f->filterWrite(std::move(from));
|
for (auto const &f: filters) from = std::move(f->filterWrite(std::move(from)));
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FilterContainer::filterRead(std::vector<char> from) const {
|
std::vector<char> FilterContainer::filterRead(std::vector<char> from) const {
|
||||||
for (auto f = filters.crbegin(); f != filters.crend(); f++) from = (*f)->filterRead(std::move(from));
|
for (auto f = filters.crbegin(); f != filters.crend(); f++) from = std::move((*f)->filterRead(std::move(from)));
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "objects/Chunk.h"
|
#include "objects/Chunk.h"
|
||||||
|
|
||||||
DirEntry *getf(std::string path) {
|
DirEntry *getf(std::string path) {
|
||||||
auto p = std::filesystem::relative(std::filesystem::u8path(path), "/");
|
auto p = std::filesystem::relative(std::filesystem::path(path), "/");
|
||||||
DirEntry *entry = RepoFS::root.get();
|
DirEntry *entry = RepoFS::root.get();
|
||||||
if (p != ".")
|
if (p != ".")
|
||||||
for (auto const &subp: p) { entry = entry->children.at(subp).get(); }
|
for (auto const &subp: p) { entry = entry->children.at(subp).get(); }
|
||||||
@@ -101,7 +101,7 @@ static int rfsRead(const char *path, char *buf, size_t size, off_t offset, struc
|
|||||||
size_t curInBuf = 0;
|
size_t curInBuf = 0;
|
||||||
size_t curInChunk = offset - curchunk->first;
|
size_t curInChunk = offset - curchunk->first;
|
||||||
while (curInBuf < size) {
|
while (curInBuf < size) {
|
||||||
auto chunk = Serialize::deserialize<Chunk>(RepoFS::repo->getObject(curchunk->second));
|
auto chunk = Serialize::deserialize<Chunk>(RepoFS::repo->getObjectRaw(curchunk->second));
|
||||||
size_t read = std::min((size_t) chunk.length - curInChunk, size - curInBuf);
|
size_t read = std::min((size_t) chunk.length - curInChunk, size - curInBuf);
|
||||||
memcpy(buf + curInBuf, chunk.data.data() + curInChunk, read);
|
memcpy(buf + curInBuf, chunk.data.data() + curInChunk, read);
|
||||||
curInBuf += read;
|
curInBuf += read;
|
||||||
@@ -121,7 +121,7 @@ static int rfsReadlink(const char *path, char *buf, size_t size) {
|
|||||||
} catch (...) { return -ENOENT; }
|
} catch (...) { return -ENOENT; }
|
||||||
|
|
||||||
if (entry->file->fileType != File::Type::Symlink) return -ENOENT;
|
if (entry->file->fileType != File::Type::Symlink) return -ENOENT;
|
||||||
auto dst = Serialize::deserialize<Chunk>(RepoFS::repo->getObject(entry->file->chunks.at(0)));
|
auto dst = Serialize::deserialize<Chunk>(RepoFS::repo->getObjectRaw(entry->file->chunks.at(0)));
|
||||||
strncpy(buf, dst.data.data(), std::min(dst.data.size(), size));
|
strncpy(buf, dst.data.data(), std::min(dst.data.size(), size));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -139,10 +139,10 @@ void RepoFS::start(Repository *repo, std::string path) {
|
|||||||
RepoFS::repo = repo;
|
RepoFS::repo = repo;
|
||||||
auto ars = repo->getObjects(Object::ObjectType::Archive);
|
auto ars = repo->getObjects(Object::ObjectType::Archive);
|
||||||
for (auto const &r: ars) {
|
for (auto const &r: ars) {
|
||||||
auto a = Serialize::deserialize<Archive>(repo->getObject(r.second));
|
auto a = Serialize::deserialize<Archive>(repo->getObjectRaw(r.second));
|
||||||
for (auto const &f: a.files) {
|
for (auto const &f: a.files) {
|
||||||
auto file = Serialize::deserialize<File>(repo->getObject(f));
|
auto file = Serialize::deserialize<File>(repo->getObjectRaw(f));
|
||||||
auto path = std::filesystem::u8path(file.name);
|
auto path = std::filesystem::path(file.name);
|
||||||
DirEntry *entry = root->children[std::to_string(a.id)].get()
|
DirEntry *entry = root->children[std::to_string(a.id)].get()
|
||||||
? root->children[std::to_string(a.id)].get()
|
? root->children[std::to_string(a.id)].get()
|
||||||
: (root->children[std::to_string(a.id)] = std::make_unique<DirEntry>()).get();
|
: (root->children[std::to_string(a.id)] = std::make_unique<DirEntry>()).get();
|
||||||
@@ -153,7 +153,7 @@ void RepoFS::start(Repository *repo, std::string path) {
|
|||||||
: (entry->children[subp] = std::make_unique<DirEntry>()).get();
|
: (entry->children[subp] = std::make_unique<DirEntry>()).get();
|
||||||
}
|
}
|
||||||
entry->file.emplace(file);
|
entry->file.emplace(file);
|
||||||
entry->name = std::filesystem::u8path(file.name).filename().u8string();
|
entry->name = std::filesystem::path(file.name).filename().string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "BytesFormatter.h"
|
#include "BytesFormatter.h"
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
|
#include "CommandDelete.h"
|
||||||
#include "CommandDiff.h"
|
#include "CommandDiff.h"
|
||||||
#include "CommandList.h"
|
#include "CommandList.h"
|
||||||
#include "CommandListFiles.h"
|
#include "CommandListFiles.h"
|
||||||
@@ -109,6 +110,7 @@ int main(int argc, char *argv[]) {
|
|||||||
commands.emplace(CommandListFiles::name, std::make_unique<CommandListFiles>());
|
commands.emplace(CommandListFiles::name, std::make_unique<CommandListFiles>());
|
||||||
commands.emplace(CommandList::name, std::make_unique<CommandList>());
|
commands.emplace(CommandList::name, std::make_unique<CommandList>());
|
||||||
commands.emplace(CommandMount::name, std::make_unique<CommandMount>());
|
commands.emplace(CommandMount::name, std::make_unique<CommandMount>());
|
||||||
|
commands.emplace(CommandDelete::name, std::make_unique<CommandDelete>());
|
||||||
|
|
||||||
if (commands.count(opt) == 0) {
|
if (commands.count(opt) == 0) {
|
||||||
std::cerr << "Unknown argument" << std::endl;
|
std::cerr << "Unknown argument" << std::endl;
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ public:
|
|||||||
bool init() override;
|
bool init() override;
|
||||||
bool flush() override;
|
bool flush() override;
|
||||||
|
|
||||||
std::vector<char> getObject(Object::idType id) const override;
|
std::vector<char> getObjectRaw(Object::idType id) const override;
|
||||||
bool putObject(const Object &obj) override;
|
bool putObject(const Object &obj) override;
|
||||||
bool deleteObject(const Object &obj) override;
|
bool deleteObjects(const std::vector<Object::idType> &objs) override;
|
||||||
|
|
||||||
std::vector<char> getObject(Object::ObjectType type, const std::string &key) const override;
|
std::vector<char> getObjectRaw(Object::ObjectType type, const std::string &key) const override;
|
||||||
Object::idType getObjectId(Object::ObjectType type, const std::string &key) const override;
|
Object::idType getObjectId(Object::ObjectType type, const std::string &key) const override;
|
||||||
std::vector<std::pair<std::string, Object::idType>> getObjects(Object::ObjectType type) const override;
|
std::vector<std::pair<std::string, Object::idType>> getObjects(Object::ObjectType type) const override;
|
||||||
|
|
||||||
@@ -104,6 +104,8 @@ private:
|
|||||||
|
|
||||||
unsigned long long maxFileId = 1; ///< Largest ID of object storage file
|
unsigned long long maxFileId = 1; ///< Largest ID of object storage file
|
||||||
std::unordered_map<Object::idType, OffsetEntry> offsetIndex;///< Used to locate Object%s in the filesystem
|
std::unordered_map<Object::idType, OffsetEntry> offsetIndex;///< Used to locate Object%s in the filesystem
|
||||||
|
std::unordered_map<Object::idType, std::set<Object::idType>>
|
||||||
|
fileToObjs;///< Used to locate Object%s in the filesystem
|
||||||
|
|
||||||
std::mutex writeCacheLock; ///< Write cache lock
|
std::mutex writeCacheLock; ///< Write cache lock
|
||||||
std::map<Object::idType, std::vector<char>> writeCache;///< Write cache, map of Object ids and their serialized data
|
std::map<Object::idType, std::vector<char>> writeCache;///< Write cache, map of Object ids and their serialized data
|
||||||
@@ -116,9 +118,12 @@ private:
|
|||||||
/// \param lockW Write cache lock
|
/// \param lockW Write cache lock
|
||||||
void flushWriteCache(std::unique_lock<std::mutex> &&lockW);
|
void flushWriteCache(std::unique_lock<std::mutex> &&lockW);
|
||||||
|
|
||||||
Object::idType largestUnusedId = 1;///< Largest available objectID
|
Object::idType largestUnusedId = 1; ///< Largest available objectID
|
||||||
|
std::vector<Object::idType> unusedIds;///< Vector of unused IDs
|
||||||
std::unordered_map<Object::ObjectType, std::unordered_map<std::string, Object::idType>>
|
std::unordered_map<Object::ObjectType, std::unordered_map<std::string, Object::idType>>
|
||||||
keyIndex;///< Maps Object%'s keys to their ID's
|
keyIndex;///< Maps Object%'s keys to their ID's
|
||||||
|
|
||||||
|
std::unordered_map<Object::idType, uint64_t> refCounts;///< Count of references to an object per its id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,16 @@ public:
|
|||||||
/// All derived objects should implement this method
|
/// All derived objects should implement this method
|
||||||
virtual std::string getKey() const = 0;
|
virtual std::string getKey() const = 0;
|
||||||
|
|
||||||
|
/// Returns the keys of that this object refers to
|
||||||
|
virtual const std::vector<idType> &getRefs() const;
|
||||||
|
|
||||||
const idType id; ///< Unique numerical of the object
|
const idType id; ///< Unique numerical of the object
|
||||||
const ObjectType type;///< Type of the object
|
const ObjectType type;///< Type of the object
|
||||||
|
|
||||||
|
static std::unique_ptr<Object> deserialize(const std::vector<char> &src);
|
||||||
|
static std::unique_ptr<Object> deserialize(std::vector<char>::const_iterator &in,
|
||||||
|
const std::vector<char>::const_iterator &end);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
/// \param id Object ID
|
/// \param id Object ID
|
||||||
|
|||||||
@@ -45,7 +45,13 @@ public:
|
|||||||
/// \param id ID of object to return
|
/// \param id ID of object to return
|
||||||
/// \return Serialized object
|
/// \return Serialized object
|
||||||
/// \throws Exception on any error or if object doesn't exist
|
/// \throws Exception on any error or if object doesn't exist
|
||||||
virtual std::vector<char> getObject(Object::idType id) const = 0;
|
virtual std::vector<char> getObjectRaw(Object::idType id) const = 0;
|
||||||
|
|
||||||
|
/// Returns the Object with id \p id
|
||||||
|
/// \param id ID of object to return
|
||||||
|
/// \return Serialized object
|
||||||
|
/// \throws Exception on any error or if object doesn't exist
|
||||||
|
std::unique_ptr<Object> getObject(Object::idType id) const;
|
||||||
|
|
||||||
/// Adds the Object \p obj to the Repository
|
/// Adds the Object \p obj to the Repository
|
||||||
/// \param obj Constant reference to the object
|
/// \param obj Constant reference to the object
|
||||||
@@ -54,17 +60,17 @@ public:
|
|||||||
virtual bool putObject(const Object &obj) = 0;
|
virtual bool putObject(const Object &obj) = 0;
|
||||||
|
|
||||||
/// Deletes Object \p obj from the Repository
|
/// Deletes Object \p obj from the Repository
|
||||||
/// \param obj Constant reference to the object
|
/// \param obj Constant reference to the vector with ids of objects to delete
|
||||||
/// \return True if successful, False if it didn't exist
|
/// \return True if successful, False if it didn't exist
|
||||||
/// \throws Exception on any error
|
/// \throws Exception on any error
|
||||||
virtual bool deleteObject(const Object &obj) = 0;
|
virtual bool deleteObjects(const std::vector<Object::idType> &objs) = 0;
|
||||||
|
|
||||||
/// Returns the Object of type \p type and with key \p key
|
/// Returns the Object of type \p type and with key \p key
|
||||||
/// \param type Type of the object
|
/// \param type Type of the object
|
||||||
/// \param key Constant reference to the key of the object
|
/// \param key Constant reference to the key of the object
|
||||||
/// \return Serialized object
|
/// \return Serialized object
|
||||||
/// \throws Exception on any error or if object doesn't exist
|
/// \throws Exception on any error or if object doesn't exist
|
||||||
virtual std::vector<char> getObject(Object::ObjectType type, const std::string &key) const = 0;
|
virtual std::vector<char> getObjectRaw(Object::ObjectType type, const std::string &key) const = 0;
|
||||||
|
|
||||||
/// Returns the id of an Object of type \p type and with key \p key
|
/// Returns the id of an Object of type \p type and with key \p key
|
||||||
/// \param type Type of the object
|
/// \param type Type of the object
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "../Object.h"
|
#include "../Object.h"
|
||||||
|
|
||||||
/// Object representing a backup
|
/// Object representing a backup
|
||||||
class Archive : public Object {
|
class Archive final : public Object {
|
||||||
public:
|
public:
|
||||||
Archive(Object::idType id, std::string name, unsigned long long mtime, std::vector<idType> files);
|
Archive(Object::idType id, std::string name, unsigned long long mtime, std::vector<idType> files);
|
||||||
|
|
||||||
@@ -22,6 +22,9 @@ public:
|
|||||||
/// Returns the name of the archive
|
/// Returns the name of the archive
|
||||||
std::string getKey() const override;
|
std::string getKey() const override;
|
||||||
|
|
||||||
|
/// Returns the files in this archive
|
||||||
|
const std::vector<Object::idType> &getRefs() const override;
|
||||||
|
|
||||||
const std::string name; ///< Archive name
|
const std::string name; ///< Archive name
|
||||||
const unsigned long long mtime; ///< Time of creation
|
const unsigned long long mtime; ///< Time of creation
|
||||||
const std::vector<idType> files;///< List of ids of File objects in the Archive
|
const std::vector<idType> files;///< List of ids of File objects in the Archive
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "../Object.h"
|
#include "../Object.h"
|
||||||
|
|
||||||
/// Object representing a part of a File
|
/// Object representing a part of a File
|
||||||
class Chunk : public Object {
|
class Chunk final : public Object {
|
||||||
public:
|
public:
|
||||||
Chunk(idType id, std::string, std::vector<char> data);
|
Chunk(idType id, std::string, std::vector<char> data);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "../Object.h"
|
#include "../Object.h"
|
||||||
|
|
||||||
/// Object representing a saved file
|
/// Object representing a saved file
|
||||||
class File : public Object {
|
class File final : public Object {
|
||||||
public:
|
public:
|
||||||
enum class Type { Normal, Symlink, Directory, END };
|
enum class Type { Normal, Symlink, Directory, END };
|
||||||
|
|
||||||
@@ -68,6 +68,12 @@ public:
|
|||||||
/// List of the chunks in file
|
/// List of the chunks in file
|
||||||
/// Normal file has normal chunks as its contents, for Directory it's empty, Symlink has a chunk with its target path
|
/// Normal file has normal chunks as its contents, for Directory it's empty, Symlink has a chunk with its target path
|
||||||
const std::map<size_t, idType> chunks;
|
const std::map<size_t, idType> chunks;
|
||||||
|
|
||||||
|
const std::vector<idType> &getRefs() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void makeChunksList() const;
|
||||||
|
mutable std::optional<std::vector<idType>> chunksList{std::nullopt};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
#include "FileRepository.h"
|
#include "FileRepository.h"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "CheckFilter.h"
|
#include "CheckFilter.h"
|
||||||
#include "FilterFactory.h"
|
#include "FilterFactory.h"
|
||||||
@@ -45,6 +47,9 @@ bool FileRepository::open() {
|
|||||||
std::tie(keyIndex, largestUnusedId) =
|
std::tie(keyIndex, largestUnusedId) =
|
||||||
Serialize::deserialize<std::pair<decltype(keyIndex), decltype(largestUnusedId)>>(
|
Serialize::deserialize<std::pair<decltype(keyIndex), decltype(largestUnusedId)>>(
|
||||||
filters.filterRead(readFile(root / "index")));
|
filters.filterRead(readFile(root / "index")));
|
||||||
|
refCounts = Serialize::deserialize<decltype(refCounts)>(filters.filterRead(readFile(root / "refcounts")));
|
||||||
|
unusedIds = Serialize::deserialize<decltype(unusedIds)>(filters.filterRead(readFile(root / "unusedIds")));
|
||||||
|
fileToObjs = Serialize::deserialize<decltype(fileToObjs)>(filters.filterRead(readFile(root / "fileToObjs")));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
ready = false;
|
ready = false;
|
||||||
throw;
|
throw;
|
||||||
@@ -58,7 +63,7 @@ bool FileRepository::init() {
|
|||||||
if (exists()) throw Exception("Trying to initialize already existing repository!");
|
if (exists()) throw Exception("Trying to initialize already existing repository!");
|
||||||
|
|
||||||
if (!std::filesystem::is_directory(root) && !std::filesystem::create_directories(root))
|
if (!std::filesystem::is_directory(root) && !std::filesystem::create_directories(root))
|
||||||
throw Exception("Can't create directory " + root.u8string());
|
throw Exception("Can't create directory " + root.string());
|
||||||
|
|
||||||
writeFile(root / "info", CheckFilter::filterWriteStatic(Serialize::serialize(config)));
|
writeFile(root / "info", CheckFilter::filterWriteStatic(Serialize::serialize(config)));
|
||||||
|
|
||||||
@@ -79,10 +84,13 @@ FileRepository::~FileRepository() {
|
|||||||
|
|
||||||
writeFile(root / "offsets", filters.filterWrite(Serialize::serialize(std::make_pair(maxFileId, offsetIndex))));
|
writeFile(root / "offsets", filters.filterWrite(Serialize::serialize(std::make_pair(maxFileId, offsetIndex))));
|
||||||
writeFile(root / "index", filters.filterWrite(Serialize::serialize(std::make_pair(keyIndex, largestUnusedId))));
|
writeFile(root / "index", filters.filterWrite(Serialize::serialize(std::make_pair(keyIndex, largestUnusedId))));
|
||||||
|
writeFile(root / "unusedIds", filters.filterWrite(Serialize::serialize(unusedIds)));
|
||||||
|
writeFile(root / "refcounts", filters.filterWrite(Serialize::serialize(refCounts)));
|
||||||
|
writeFile(root / "fileToObjs", filters.filterWrite(Serialize::serialize(fileToObjs)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FileRepository::getObject(Object::idType id) const {
|
std::vector<char> FileRepository::getObjectRaw(Object::idType id) const {
|
||||||
if (!ready) throw Exception("Tried working with uninitialized repo!");
|
if (!ready) throw Exception("Tried working with uninitialized repo!");
|
||||||
|
|
||||||
std::unique_lock lock(repoLock);
|
std::unique_lock lock(repoLock);
|
||||||
@@ -133,6 +141,7 @@ void FileRepository::flushWriteCache(std::unique_lock<std::mutex> &&lockW) {
|
|||||||
{
|
{
|
||||||
std::lock_guard lockI(repoLock);
|
std::lock_guard lockI(repoLock);
|
||||||
offsetIndex.emplace(i.first, OffsetEntry(currentFileId, offset, i.second.size()));
|
offsetIndex.emplace(i.first, OffsetEntry(currentFileId, offset, i.second.size()));
|
||||||
|
fileToObjs[currentFileId].emplace(i.first);
|
||||||
}
|
}
|
||||||
offset += i.second.size();
|
offset += i.second.size();
|
||||||
ofstream.rdbuf()->sputn(i.second.data(), i.second.size());
|
ofstream.rdbuf()->sputn(i.second.data(), i.second.size());
|
||||||
@@ -144,36 +153,103 @@ bool FileRepository::putObject(const Object &obj) {
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(repoLock);
|
std::lock_guard lock(repoLock);
|
||||||
keyIndex[obj.type][obj.getKey()] = obj.id;
|
keyIndex[obj.type][obj.getKey()] = obj.id;
|
||||||
|
for (auto const &i: obj.getRefs()) refCounts[i]++;
|
||||||
}
|
}
|
||||||
writeObject(obj);
|
writeObject(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileRepository::deleteObject(const Object &obj) {
|
bool FileRepository::deleteObjects(const std::vector<Object::idType> &objs) {
|
||||||
if (!ready) throw Exception("Tried working with uninitialized repo!");
|
if (!ready) throw Exception("Tried working with uninitialized repo!");
|
||||||
throw Exception("Deletion not implemented!");
|
|
||||||
|
std::queue<Object::idType> toVisit;
|
||||||
|
std::set<Object::idType> toDelete;
|
||||||
|
|
||||||
|
for (auto const &o: objs) {
|
||||||
|
toVisit.emplace(o);
|
||||||
|
toDelete.emplace(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Scanning for objects" << std::endl;
|
||||||
|
|
||||||
|
while (!toVisit.empty()) {
|
||||||
|
auto o = toVisit.back();
|
||||||
|
toVisit.pop();
|
||||||
|
|
||||||
|
auto obj = getObject(o);
|
||||||
|
for (const auto &id: obj->getRefs()) {
|
||||||
|
std::unique_lock lock(repoLock);
|
||||||
|
refCounts[id]--;
|
||||||
|
if (refCounts.at(id) == 0) {
|
||||||
|
toDelete.emplace(id);
|
||||||
|
toVisit.emplace(id);
|
||||||
|
refCounts.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Found " << toDelete.size() << " to delete " << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
std::unordered_map<uint64_t, Object::idType> fileToObj;
|
||||||
|
std::set<uint64_t> touchedFiles;
|
||||||
|
|
||||||
|
for (auto const &id: toDelete) {
|
||||||
|
fileToObj.emplace(offsetIndex.at(id).fileId, id);
|
||||||
|
touchedFiles.emplace(offsetIndex.at(id).fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Will rewrite " << touchedFiles.size() << " files" << std::endl;
|
||||||
|
|
||||||
|
for (auto const &f: touchedFiles) {
|
||||||
|
std::cout << "Rewriting file " << f << std::endl;
|
||||||
|
const auto &objs = fileToObjs.at(f);
|
||||||
|
std::vector<std::unique_ptr<Object>> objects;
|
||||||
|
for (auto const &o: objs) {
|
||||||
|
auto obj = getObject(o);
|
||||||
|
{
|
||||||
|
std::unique_lock lock(repoLock);
|
||||||
|
offsetIndex.erase(o);
|
||||||
|
}
|
||||||
|
if (toDelete.find(o) == toDelete.end()) putObject(*obj);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::unique_lock lock(repoLock);
|
||||||
|
fileToObjs.erase(f);
|
||||||
|
}
|
||||||
|
std::filesystem::remove(root / std::to_string(f));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::unique_lock lock(repoLock);
|
||||||
|
for (auto const &id: toDelete) {
|
||||||
|
unusedIds.emplace_back(id);
|
||||||
|
// FIXME: this is a bit inefficient
|
||||||
|
for (auto &m: keyIndex) erase_if(m.second, [&](const auto &t) { return toDelete.contains(t.second); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FileRepository::readFile(const std::filesystem::path &file, unsigned long long offset,
|
std::vector<char> FileRepository::readFile(const std::filesystem::path &file, unsigned long long offset,
|
||||||
unsigned long long size) const {
|
unsigned long long size) const {
|
||||||
if (size > absoluteMaxFileLimit)
|
if (size > absoluteMaxFileLimit)
|
||||||
throw Exception("Tried to read " + std::to_string(size) + " bytes from " + file.u8string() +
|
throw Exception("Tried to read " + std::to_string(size) + " bytes from " + file.string() +
|
||||||
" which is more than absoluteMaxFileLimit");
|
" which is more than absoluteMaxFileLimit");
|
||||||
|
|
||||||
std::ifstream ifstream(file, std::ios::binary | std::ios::in);
|
std::ifstream ifstream(file, std::ios::binary | std::ios::in);
|
||||||
if (!ifstream.is_open()) throw Exception("Can't open file " + file.u8string() + " for reading!");
|
if (!ifstream.is_open()) throw Exception("Can't open file " + file.string() + " for reading!");
|
||||||
|
|
||||||
std::vector<char> buf(size);
|
std::vector<char> buf(size);
|
||||||
|
|
||||||
if (ifstream.rdbuf()->pubseekpos(offset) == std::streampos(std::streamoff(-1)))
|
if (ifstream.rdbuf()->pubseekpos(offset) == std::streampos(std::streamoff(-1)))
|
||||||
throw Exception("Unexpected end of file " + file.u8string());
|
throw Exception("Unexpected end of file " + file.string());
|
||||||
if (ifstream.rdbuf()->sgetn(buf.data(), size) != size) throw Exception("Unexpected end of file " + file.u8string());
|
if (ifstream.rdbuf()->sgetn(buf.data(), size) != size) throw Exception("Unexpected end of file " + file.string());
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FileRepository::readFile(const std::filesystem::path &file) const {
|
std::vector<char> FileRepository::readFile(const std::filesystem::path &file) const {
|
||||||
if (!std::filesystem::is_regular_file(file)) throw Exception("File " + file.u8string() + " is not a regular file!");
|
if (!std::filesystem::is_regular_file(file)) throw Exception("File " + file.string() + " is not a regular file!");
|
||||||
auto fileSize = std::filesystem::file_size(file);
|
auto fileSize = std::filesystem::file_size(file);
|
||||||
if (fileSize == 0) return {};
|
if (fileSize == 0) return {};
|
||||||
return readFile(file, 0, fileSize);
|
return readFile(file, 0, fileSize);
|
||||||
@@ -181,15 +257,15 @@ std::vector<char> FileRepository::readFile(const std::filesystem::path &file) co
|
|||||||
|
|
||||||
bool FileRepository::writeFile(const std::filesystem::path &file, const std::vector<char> &data) {
|
bool FileRepository::writeFile(const std::filesystem::path &file, const std::vector<char> &data) {
|
||||||
std::ofstream ofstream(file, std::ios::binary | std::ios::trunc | std::ios::out);
|
std::ofstream ofstream(file, std::ios::binary | std::ios::trunc | std::ios::out);
|
||||||
if (!ofstream.is_open()) throw Exception("Can't open file " + file.u8string() + " for writing!");
|
if (!ofstream.is_open()) throw Exception("Can't open file " + file.string() + " for writing!");
|
||||||
|
|
||||||
if (ofstream.rdbuf()->sputn(data.data(), data.size()) != data.size())
|
if (ofstream.rdbuf()->sputn(data.data(), data.size()) != data.size())
|
||||||
throw Exception("Couldn't write all the data for " + file.u8string());
|
throw Exception("Couldn't write all the data for " + file.string());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> FileRepository::getObject(Object::ObjectType type, const std::string &key) const {
|
std::vector<char> FileRepository::getObjectRaw(Object::ObjectType type, const std::string &key) const {
|
||||||
return getObject(getObjectId(type, key));
|
return getObjectRaw(getObjectId(type, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::idType FileRepository::getObjectId(Object::ObjectType type, const std::string &key) const {
|
Object::idType FileRepository::getObjectId(Object::ObjectType type, const std::string &key) const {
|
||||||
@@ -214,6 +290,11 @@ bool FileRepository::exists(Object::ObjectType type, const std::string &key) con
|
|||||||
|
|
||||||
Object::idType FileRepository::getId() {
|
Object::idType FileRepository::getId() {
|
||||||
std::lock_guard lock(repoLock);
|
std::lock_guard lock(repoLock);
|
||||||
|
if (!unusedIds.empty()) {
|
||||||
|
auto ret = unusedIds.back();
|
||||||
|
unusedIds.pop_back();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return largestUnusedId++;
|
return largestUnusedId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "Serialize.h"
|
#include "Serialize.h"
|
||||||
|
|
||||||
|
#include "objects/Archive.h"
|
||||||
|
#include "objects/Chunk.h"
|
||||||
|
#include "objects/File.h"
|
||||||
|
|
||||||
Object::Object(idType id, ObjectType type) : id(id), type(type) {}
|
Object::Object(idType id, ObjectType type) : id(id), type(type) {}
|
||||||
|
|
||||||
Object::Object(std::vector<char>::const_iterator &in, const std::vector<char>::const_iterator &end)
|
Object::Object(std::vector<char>::const_iterator &in, const std::vector<char>::const_iterator &end)
|
||||||
@@ -17,3 +21,32 @@ void Object::serialize(std::vector<char> &out) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object::~Object() = default;
|
Object::~Object() = default;
|
||||||
|
|
||||||
|
static std::vector<Object::idType> emptyRef{};
|
||||||
|
|
||||||
|
const std::vector<Object::idType> &Object::getRefs() const { return emptyRef; }
|
||||||
|
|
||||||
|
std::unique_ptr<Object> Object::deserialize(std::vector<char>::const_iterator &in,
|
||||||
|
const std::vector<char>::const_iterator &end) {
|
||||||
|
auto inCpy = in;
|
||||||
|
auto id = Serialize::deserialize<idType>(in, end);
|
||||||
|
auto type = Serialize::deserialize<ObjectType>(in, end);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ObjectType::Archive:
|
||||||
|
return std::make_unique<Archive>(Serialize::deserialize<Archive>(inCpy, end));
|
||||||
|
case ObjectType::File:
|
||||||
|
return std::make_unique<File>(Serialize::deserialize<File>(inCpy, end));
|
||||||
|
case ObjectType::Chunk:
|
||||||
|
return std::make_unique<Chunk>(Serialize::deserialize<Chunk>(inCpy, end));
|
||||||
|
case ObjectType::END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception("Bad object!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Object> Object::deserialize(const std::vector<char> &src) {
|
||||||
|
auto srcIterator = src.cbegin();
|
||||||
|
return deserialize(srcIterator, src.end());
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,3 +8,7 @@ Repository::~Repository() = default;
|
|||||||
Repository::Repository(Config config) : config(std::move(config)) {}
|
Repository::Repository(Config config) : config(std::move(config)) {}
|
||||||
|
|
||||||
const Config &Repository::getConfig() const { return config; }
|
const Config &Repository::getConfig() const { return config; }
|
||||||
|
|
||||||
|
std::unique_ptr<Object> Repository::getObject(Object::idType id) const {
|
||||||
|
return Object::deserialize(this->getObjectRaw(id));
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,3 +28,5 @@ void Archive::serialize(std::vector<char> &out) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string Archive::getKey() const { return name; }
|
std::string Archive::getKey() const { return name; }
|
||||||
|
|
||||||
|
const std::vector<Object::idType> &Archive::getRefs() const { return files; }
|
||||||
|
|||||||
@@ -42,20 +42,20 @@ File::Type File::getFileType(const std::filesystem::path &p) {
|
|||||||
if (std::filesystem::is_symlink(p)) return Type::Symlink;
|
if (std::filesystem::is_symlink(p)) return Type::Symlink;
|
||||||
if (std::filesystem::is_directory(p)) return Type::Directory;
|
if (std::filesystem::is_directory(p)) return Type::Directory;
|
||||||
if (std::filesystem::is_regular_file(p)) return Type::Normal;
|
if (std::filesystem::is_regular_file(p)) return Type::Normal;
|
||||||
throw Exception("Unsupported file type! " + p.u8string());
|
throw Exception("Unsupported file type! " + p.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> File::getFileContents(const std::filesystem::path &p) {
|
std::vector<char> File::getFileContents(const std::filesystem::path &p) {
|
||||||
auto type = getFileType(p);
|
auto type = getFileType(p);
|
||||||
if (type == Type::Normal) throw Exception(p.u8string() + " is a normal file!");
|
if (type == Type::Normal) throw Exception(p.string() + " is a normal file!");
|
||||||
if (type == Type::Directory) { return {}; }
|
if (type == Type::Directory) { return {}; }
|
||||||
if (type == Type::Symlink) {
|
if (type == Type::Symlink) {
|
||||||
auto target = std::filesystem::read_symlink(p).u8string();
|
auto target = std::filesystem::read_symlink(p).string();
|
||||||
std::vector<char> target_null_term = {target.begin(), target.end()};
|
std::vector<char> target_null_term = {target.begin(), target.end()};
|
||||||
target_null_term.emplace_back('\0');
|
target_null_term.emplace_back('\0');
|
||||||
return target_null_term;
|
return target_null_term;
|
||||||
}
|
}
|
||||||
throw Exception("Error with file " + p.u8string());
|
throw Exception("Error with file " + p.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long File::getFileMtime(const std::filesystem::path &p) {
|
unsigned long long File::getFileMtime(const std::filesystem::path &p) {
|
||||||
@@ -65,16 +65,16 @@ unsigned long long File::getFileMtime(const std::filesystem::path &p) {
|
|||||||
std::chrono::duration_cast<std::chrono::seconds>(std::filesystem::last_write_time(p).time_since_epoch())
|
std::chrono::duration_cast<std::chrono::seconds>(std::filesystem::last_write_time(p).time_since_epoch())
|
||||||
.count());
|
.count());
|
||||||
else if (type == Type::Symlink) {
|
else if (type == Type::Symlink) {
|
||||||
auto path = p.u8string();
|
auto path = p.string();
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
if (lstat(path.c_str(), &sb) != 0) throw Exception("Error reading mtime for " + p.u8string());
|
if (lstat(path.c_str(), &sb) != 0) throw Exception("Error reading mtime for " + p.string());
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
return sb.st_mtimespec.tv_sec;
|
return sb.st_mtimespec.tv_sec;
|
||||||
#else
|
#else
|
||||||
return sb.st_mtime;
|
return sb.st_mtime;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
throw Exception("Error with file " + p.u8string());
|
throw Exception("Error with file " + p.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long File::getFileSize(const std::filesystem::path &p) {
|
unsigned long long File::getFileSize(const std::filesystem::path &p) {
|
||||||
@@ -83,3 +83,16 @@ unsigned long long File::getFileSize(const std::filesystem::path &p) {
|
|||||||
else
|
else
|
||||||
return getFileContents(p).size();
|
return getFileContents(p).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void File::makeChunksList() const {
|
||||||
|
if (chunksList) return;
|
||||||
|
chunksList.emplace();
|
||||||
|
|
||||||
|
chunksList->reserve(chunks.size());
|
||||||
|
for (auto const &c: chunks) chunksList->emplace_back(c.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Object::idType> &File::getRefs() const {
|
||||||
|
if (!chunksList) makeChunksList();
|
||||||
|
return *chunksList;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "Serialize.h"
|
#include "Serialize.h"
|
||||||
|
|
||||||
FileBuffer::FileBuffer(const Repository *repo, Object::idType fileId)
|
FileBuffer::FileBuffer(const Repository *repo, Object::idType fileId)
|
||||||
: repo(repo), file(Serialize::deserialize<File>(repo->getObject(fileId))), chunksQueue() {
|
: repo(repo), file(Serialize::deserialize<File>(repo->getObjectRaw(fileId))), chunksQueue() {
|
||||||
for (auto const &id: file.chunks) chunksQueue.emplace(id.second);
|
for (auto const &id: file.chunks) chunksQueue.emplace(id.second);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ int FileBuffer::underflow() {
|
|||||||
if (getBuf.empty() || curGetBufPos == getBuf.size()) {
|
if (getBuf.empty() || curGetBufPos == getBuf.size()) {
|
||||||
if (chunksQueue.empty()) return traits_type::eof();
|
if (chunksQueue.empty()) return traits_type::eof();
|
||||||
else {
|
else {
|
||||||
auto chunk = Serialize::deserialize<Chunk>(repo->getObject(chunksQueue.front()));
|
auto chunk = Serialize::deserialize<Chunk>(repo->getObjectRaw(chunksQueue.front()));
|
||||||
getBuf = chunk.data;
|
getBuf = chunk.data;
|
||||||
chunksQueue.pop();
|
chunksQueue.pop();
|
||||||
curGetBufPos = 0;
|
curGetBufPos = 0;
|
||||||
|
|||||||
@@ -8,16 +8,17 @@ ThreadPool::ThreadPool(std::function<void(std::string)> onError, std::size_t wor
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThreadPool::~ThreadPool() {
|
ThreadPool::~ThreadPool() {
|
||||||
stop = true;
|
{
|
||||||
somethingNew.notify_all();
|
std::lock_guard lock(queueLock);
|
||||||
|
stop = true;
|
||||||
|
somethingNew.notify_all();
|
||||||
|
}
|
||||||
for (auto &t: threads) { t.join(); }
|
for (auto &t: threads) { t.join(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPool::push(std::function<void()> &&func) {
|
void ThreadPool::push(std::function<void()> &&func) {
|
||||||
{
|
std::lock_guard lock(queueLock);
|
||||||
std::lock_guard lock(queueLock);
|
queue.push(std::move(func));
|
||||||
queue.push(std::move(func));
|
|
||||||
}
|
|
||||||
somethingNew.notify_one();
|
somethingNew.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,16 +44,13 @@ void ThreadPool::loop() {
|
|||||||
queue.pop();
|
queue.pop();
|
||||||
|
|
||||||
qLock.unlock();
|
qLock.unlock();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
task();
|
task();
|
||||||
} catch (std::exception &e) { onError(std::string(e.what())); }
|
} catch (std::exception &e) { onError(std::string(e.what())); }
|
||||||
|
qLock.lock();
|
||||||
|
|
||||||
{
|
running--;
|
||||||
std::lock_guard qLock(queueLock);
|
if (queue.empty() && running == 0) { finished.notify_all(); }
|
||||||
running--;
|
|
||||||
if (queue.empty() && running == 0) { finished.notify_all(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
# GoogleTest requires at least C++14
|
# GoogleTest requires at least C++14
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ TEST(BuzhashTest, SimpleTest) {
|
|||||||
for (int i = 0; i < loremipsum.length(); i++) {
|
for (int i = 0; i < loremipsum.length(); i++) {
|
||||||
b2.feed((uint8_t) loremipsum[i]);
|
b2.feed((uint8_t) loremipsum[i]);
|
||||||
if (b2.get() == h1) {
|
if (b2.get() == h1) {
|
||||||
EXPECT_EQ(i, loremipsum.find("e eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p"));
|
ASSERT_EQ(i, loremipsum.find("e eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p"));
|
||||||
h1found = true;
|
h1found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPECT_EQ(h1found, true);
|
ASSERT_EQ(h1found, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@
|
|||||||
|
|
||||||
TEST(CLITest, Backup) {
|
TEST(CLITest, Backup) {
|
||||||
int ret = system("../../../tests/clitests/scripts/backup.sh");
|
int ret = system("../../../tests/clitests/scripts/backup.sh");
|
||||||
EXPECT_EQ(WEXITSTATUS(ret), 0);
|
ASSERT_EQ(WEXITSTATUS(ret), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CLITest, Ignore) {
|
TEST(CLITest, Ignore) {
|
||||||
int ret = system("../../../tests/clitests/scripts/ignore.sh");
|
int ret = system("../../../tests/clitests/scripts/ignore.sh");
|
||||||
EXPECT_EQ(WEXITSTATUS(ret), 0);
|
ASSERT_EQ(WEXITSTATUS(ret), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CLITest, Diff) {
|
TEST(CLITest, Diff) {
|
||||||
int ret = system("../../../tests/clitests/scripts/diff.sh");
|
int ret = system("../../../tests/clitests/scripts/diff.sh");
|
||||||
EXPECT_EQ(WEXITSTATUS(ret), 0);
|
ASSERT_EQ(WEXITSTATUS(ret), 0);
|
||||||
}
|
}
|
||||||
@@ -11,32 +11,32 @@ TEST(CryptoTests, AES) {
|
|||||||
std::string in = "hello1";
|
std::string in = "hello1";
|
||||||
auto enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
auto enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
auto dec = AES::decrypt(enc, "p1", "e");
|
auto dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
|
|
||||||
in = "";
|
in = "";
|
||||||
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
dec = AES::decrypt(enc, "p1", "e");
|
dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
|
|
||||||
in = "1234567890asdfg";
|
in = "1234567890asdfg";
|
||||||
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
dec = AES::decrypt(enc, "p1", "e");
|
dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
|
|
||||||
in = "1234567890asdfgh";
|
in = "1234567890asdfgh";
|
||||||
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
dec = AES::decrypt(enc, "p1", "e");
|
dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
|
|
||||||
in = "1234567890asdfghe";
|
in = "1234567890asdfghe";
|
||||||
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
dec = AES::decrypt(enc, "p1", "e");
|
dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
|
|
||||||
in = "1234567890asdfgheq";
|
in = "1234567890asdfgheq";
|
||||||
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
|
||||||
dec = AES::decrypt(enc, "p1", "e");
|
dec = AES::decrypt(enc, "p1", "e");
|
||||||
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
|
ASSERT_EQ(in, std::string(dec.begin(), dec.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CryptoTests, SHA) {
|
TEST(CryptoTests, SHA) {
|
||||||
@@ -47,6 +47,6 @@ TEST(CryptoTests, SHA) {
|
|||||||
|
|
||||||
auto out = SHA::calculate(data);
|
auto out = SHA::calculate(data);
|
||||||
|
|
||||||
EXPECT_EQ(out.size(), 32);
|
ASSERT_EQ(out.size(), 32);
|
||||||
for (int i = 0; i < out.size(); i++) { EXPECT_EQ(static_cast<uint8_t>(out[i]), excepted[i]); }
|
for (int i = 0; i < out.size(); i++) { ASSERT_EQ(static_cast<uint8_t>(out[i]), excepted[i]); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ TEST(FullTest, Simple) {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
EXPECT_EQ(std::filesystem::is_directory("Simple/testtores/testdir"), true);
|
ASSERT_EQ(std::filesystem::is_directory("Simple/testtores/testdir"), true);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cerr << "Empty directory doesn't exist!" << std::endl;
|
std::cerr << "Empty directory doesn't exist!" << std::endl;
|
||||||
throw;
|
throw;
|
||||||
@@ -71,11 +71,11 @@ TEST(FullTest, Simple) {
|
|||||||
std::ifstream o(std::filesystem::path("Simple/testtores") / ("f" + std::to_string(i)),
|
std::ifstream o(std::filesystem::path("Simple/testtores") / ("f" + std::to_string(i)),
|
||||||
std::ios::binary | std::ios::in);
|
std::ios::binary | std::ios::in);
|
||||||
try {
|
try {
|
||||||
EXPECT_EQ(o.is_open(), true);
|
ASSERT_EQ(o.is_open(), true);
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
char c;
|
char c;
|
||||||
EXPECT_EQ(o.get(c).operator bool(), true);
|
ASSERT_EQ(o.get(c).operator bool(), true);
|
||||||
EXPECT_EQ(static_cast<char>(j % 256), c);
|
ASSERT_EQ(static_cast<char>(j % 256), c);
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cerr << "Error comparing file " << i << std::endl;
|
std::cerr << "Error comparing file " << i << std::endl;
|
||||||
@@ -150,16 +150,16 @@ TEST(FullTest, SimpleWithIgnore) {
|
|||||||
cmd.run(Context{&logger, repo.get()});
|
cmd.run(Context{&logger, repo.get()});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
EXPECT_EQ(std::filesystem::is_directory("SimpleWithIgnore/testtores/testdir"), true);
|
ASSERT_EQ(std::filesystem::is_directory("SimpleWithIgnore/testtores/testdir"), true);
|
||||||
|
|
||||||
for (int i = 0; i < 257; i++) {
|
for (int i = 0; i < 257; i++) {
|
||||||
std::ifstream o(std::filesystem::path("SimpleWithIgnore/testtores") / ("f" + std::to_string(i)),
|
std::ifstream o(std::filesystem::path("SimpleWithIgnore/testtores") / ("f" + std::to_string(i)),
|
||||||
std::ios::binary | std::ios::in);
|
std::ios::binary | std::ios::in);
|
||||||
EXPECT_EQ(o.is_open(), true);
|
ASSERT_EQ(o.is_open(), true);
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
char c;
|
char c;
|
||||||
EXPECT_EQ(o.get(c).operator bool(), true);
|
ASSERT_EQ(o.get(c).operator bool(), true);
|
||||||
EXPECT_EQ(static_cast<char>(j % 256), c);
|
ASSERT_EQ(static_cast<char>(j % 256), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,31 +167,31 @@ TEST(FullTest, SimpleWithIgnore) {
|
|||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/.ignore");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/.ignore");
|
||||||
std::string s;
|
std::string s;
|
||||||
file >> s;
|
file >> s;
|
||||||
EXPECT_EQ(s, "hello.txt");
|
ASSERT_EQ(s, "hello.txt");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/.ignore");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/.ignore");
|
||||||
std::string s;
|
std::string s;
|
||||||
file >> s;
|
file >> s;
|
||||||
EXPECT_EQ(s, ".*\\.txt");
|
ASSERT_EQ(s, ".*\\.txt");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/hello.txt");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/hello.txt");
|
||||||
EXPECT_EQ(!file, true);
|
ASSERT_EQ(!file, true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/hello.txt");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/hello.txt");
|
||||||
EXPECT_EQ(!file, true);
|
ASSERT_EQ(!file, true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/asdf.txt");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir3/asdf.txt");
|
||||||
EXPECT_EQ(!file, true);
|
ASSERT_EQ(!file, true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir4/asdf.txt");
|
std::ifstream file("SimpleWithIgnore/testtores/testdir2/testdir4/asdf.txt");
|
||||||
std::string s;
|
std::string s;
|
||||||
file >> s;
|
file >> s;
|
||||||
EXPECT_EQ(s, "asdf2");
|
ASSERT_EQ(s, "asdf2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,16 +237,16 @@ TEST(FullTest, SimpleWithCompress) {
|
|||||||
cmd.run(Context{&logger, repo.get()});
|
cmd.run(Context{&logger, repo.get()});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
EXPECT_EQ(std::filesystem::is_directory("SimpleWithCompress/testtores/testdir"), true);
|
ASSERT_EQ(std::filesystem::is_directory("SimpleWithCompress/testtores/testdir"), true);
|
||||||
|
|
||||||
for (int i = 0; i < 257; i++) {
|
for (int i = 0; i < 257; i++) {
|
||||||
std::ifstream o(std::filesystem::path("SimpleWithCompress/testtores") / ("f" + std::to_string(i)),
|
std::ifstream o(std::filesystem::path("SimpleWithCompress/testtores") / ("f" + std::to_string(i)),
|
||||||
std::ios::binary | std::ios::in);
|
std::ios::binary | std::ios::in);
|
||||||
EXPECT_EQ(o.is_open(), true);
|
ASSERT_EQ(o.is_open(), true);
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
char c;
|
char c;
|
||||||
EXPECT_EQ(o.get(c).operator bool(), true);
|
ASSERT_EQ(o.get(c).operator bool(), true);
|
||||||
EXPECT_EQ(static_cast<char>(j % 256), c);
|
ASSERT_EQ(static_cast<char>(j % 256), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,10 +290,10 @@ TEST(FullTest, SimpleWithCompEnd) {
|
|||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
try {
|
try {
|
||||||
EXPECT_EQ(repo->open(), false);
|
ASSERT_EQ(repo->open(), false);
|
||||||
ok = false;
|
ok = false;
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
EXPECT_EQ(ok, true);
|
ASSERT_EQ(ok, true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
@@ -312,16 +312,16 @@ TEST(FullTest, SimpleWithCompEnd) {
|
|||||||
cmd.run(Context{&logger, repo.get()});
|
cmd.run(Context{&logger, repo.get()});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
EXPECT_EQ(std::filesystem::is_directory("SimpleWithCompEnd/testtores/testdir"), true);
|
ASSERT_EQ(std::filesystem::is_directory("SimpleWithCompEnd/testtores/testdir"), true);
|
||||||
|
|
||||||
for (int i = 0; i < 257; i++) {
|
for (int i = 0; i < 257; i++) {
|
||||||
std::ifstream o(std::filesystem::path("SimpleWithCompEnd/testtores") / ("f" + std::to_string(i)),
|
std::ifstream o(std::filesystem::path("SimpleWithCompEnd/testtores") / ("f" + std::to_string(i)),
|
||||||
std::ios::binary | std::ios::in);
|
std::ios::binary | std::ios::in);
|
||||||
EXPECT_EQ(o.is_open(), true);
|
ASSERT_EQ(o.is_open(), true);
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
char c;
|
char c;
|
||||||
EXPECT_EQ(o.get(c).operator bool(), true);
|
ASSERT_EQ(o.get(c).operator bool(), true);
|
||||||
EXPECT_EQ(static_cast<char>(j % 256), c);
|
ASSERT_EQ(static_cast<char>(j % 256), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ TEST(FullTest, Fuzz) {
|
|||||||
auto outstr = runnerout.str();
|
auto outstr = runnerout.str();
|
||||||
if (outstr.find("Error") == std::string::npos) ok = false;
|
if (outstr.find("Error") == std::string::npos) ok = false;
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
EXPECT_EQ(ok, true);
|
ASSERT_EQ(ok, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ TEST(Chunk, Deserialize) {
|
|||||||
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
||||||
Chunk o2e(777, {1}, data2);
|
Chunk o2e(777, {1}, data2);
|
||||||
|
|
||||||
EXPECT_EQ(o1.id, o1e.id);
|
ASSERT_EQ(o1.id, o1e.id);
|
||||||
EXPECT_EQ(o2.id, o2e.id);
|
ASSERT_EQ(o2.id, o2e.id);
|
||||||
EXPECT_EQ((int) o1.type, (int) o1e.type);
|
ASSERT_EQ((int) o1.type, (int) o1e.type);
|
||||||
EXPECT_EQ((int) o2.type, (int) o2e.type);
|
ASSERT_EQ((int) o2.type, (int) o2e.type);
|
||||||
|
|
||||||
EXPECT_EQ(o1.data.size(), o1e.data.size());
|
ASSERT_EQ(o1.data.size(), o1e.data.size());
|
||||||
EXPECT_EQ(o2.data.size(), o2e.data.size());
|
ASSERT_EQ(o2.data.size(), o2e.data.size());
|
||||||
for (int i = 0; i < o1.data.size(); i++) { EXPECT_EQ(o1.data[i], o1e.data[i]); }
|
for (int i = 0; i < o1.data.size(); i++) { ASSERT_EQ(o1.data[i], o1e.data[i]); }
|
||||||
for (int i = 0; i < o2.data.size(); i++) { EXPECT_EQ(o2.data[i], o2e.data[i]); }
|
for (int i = 0; i < o2.data.size(); i++) { ASSERT_EQ(o2.data[i], o2e.data[i]); }
|
||||||
|
|
||||||
for (int i = 0; i < o1.SHA.size(); i++) { EXPECT_EQ(o1.SHA[i], o1e.SHA[i]); }
|
for (int i = 0; i < o1.SHA.size(); i++) { ASSERT_EQ(o1.SHA[i], o1e.SHA[i]); }
|
||||||
for (int i = 0; i < o2.SHA.size(); i++) { EXPECT_EQ(o2.SHA[i], o2e.SHA[i]); }
|
for (int i = 0; i < o2.SHA.size(); i++) { ASSERT_EQ(o2.SHA[i], o2e.SHA[i]); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ TEST(FileRepository, Deserialize) {
|
|||||||
repo.putObject(o2);
|
repo.putObject(o2);
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
@@ -45,11 +45,11 @@ TEST(FileRepository, Deserialize) {
|
|||||||
std::string o2k(16, '\0');
|
std::string o2k(16, '\0');
|
||||||
o2k[0] = 1;
|
o2k[0] = 1;
|
||||||
o2k[1] = 2;
|
o2k[1] = 2;
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
||||||
|
|
||||||
auto o1o = repo.getObject(666);
|
auto o1o = repo.getObjectRaw(666);
|
||||||
auto o2o = repo.getObject(777);
|
auto o2o = repo.getObjectRaw(777);
|
||||||
|
|
||||||
auto o1ob = o1o.cbegin();
|
auto o1ob = o1o.cbegin();
|
||||||
auto o2ob = o2o.cbegin();
|
auto o2ob = o2o.cbegin();
|
||||||
@@ -61,18 +61,18 @@ TEST(FileRepository, Deserialize) {
|
|||||||
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
|
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
|
||||||
Chunk o2e(777, o2k, data2);
|
Chunk o2e(777, o2k, data2);
|
||||||
|
|
||||||
EXPECT_EQ(o1.id, o1e.id);
|
ASSERT_EQ(o1.id, o1e.id);
|
||||||
EXPECT_EQ(o2.id, o2e.id);
|
ASSERT_EQ(o2.id, o2e.id);
|
||||||
EXPECT_EQ((int) o1.type, (int) o1e.type);
|
ASSERT_EQ((int) o1.type, (int) o1e.type);
|
||||||
EXPECT_EQ((int) o2.type, (int) o2e.type);
|
ASSERT_EQ((int) o2.type, (int) o2e.type);
|
||||||
auto o1d = o1.data;
|
auto o1d = o1.data;
|
||||||
auto o1ed = o1e.data;
|
auto o1ed = o1e.data;
|
||||||
auto o2d = o2.data;
|
auto o2d = o2.data;
|
||||||
auto o2ed = o2e.data;
|
auto o2ed = o2e.data;
|
||||||
EXPECT_EQ(o1.data.size(), o1e.data.size());
|
ASSERT_EQ(o1.data.size(), o1e.data.size());
|
||||||
EXPECT_EQ(o2.data.size(), o2e.data.size());
|
ASSERT_EQ(o2.data.size(), o2e.data.size());
|
||||||
for (int i = 0; i < o1.data.size(); i++) { EXPECT_EQ(o1.data[i], o1e.data[i]); }
|
for (int i = 0; i < o1.data.size(); i++) { ASSERT_EQ(o1.data[i], o1e.data[i]); }
|
||||||
for (int i = 0; i < o2.data.size(); i++) { EXPECT_EQ(o2.data[i], o2e.data[i]); }
|
for (int i = 0; i < o2.data.size(); i++) { ASSERT_EQ(o2.data[i], o2e.data[i]); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +103,8 @@ TEST(FileRepository, Filters) {
|
|||||||
repo.putObject(o2);
|
repo.putObject(o2);
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
@@ -126,7 +126,7 @@ TEST(FileRepository, Filters) {
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto o1o = repo.getObject(666);
|
auto o1o = repo.getObjectRaw(666);
|
||||||
auto o1ob = o1o.cbegin();
|
auto o1ob = o1o.cbegin();
|
||||||
|
|
||||||
Chunk o1(o1ob, o1o.cend());
|
Chunk o1(o1ob, o1o.cend());
|
||||||
@@ -134,7 +134,7 @@ TEST(FileRepository, Filters) {
|
|||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto o2o = repo.getObject(777);
|
auto o2o = repo.getObjectRaw(777);
|
||||||
auto o2ob = o2o.cbegin();
|
auto o2ob = o2o.cbegin();
|
||||||
|
|
||||||
Chunk o2(o2ob, o2o.cend());
|
Chunk o2(o2ob, o2o.cend());
|
||||||
@@ -160,11 +160,11 @@ TEST(FileRepository, Filters) {
|
|||||||
std::string o2k(16, '\0');
|
std::string o2k(16, '\0');
|
||||||
o2k[0] = 1;
|
o2k[0] = 1;
|
||||||
o2k[1] = 2;
|
o2k[1] = 2;
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
|
||||||
|
|
||||||
auto o1o = repo.getObject(666);
|
auto o1o = repo.getObjectRaw(666);
|
||||||
auto o2o = repo.getObject(777);
|
auto o2o = repo.getObjectRaw(777);
|
||||||
|
|
||||||
auto o1ob = o1o.cbegin();
|
auto o1ob = o1o.cbegin();
|
||||||
auto o2ob = o2o.cbegin();
|
auto o2ob = o2o.cbegin();
|
||||||
@@ -176,23 +176,22 @@ TEST(FileRepository, Filters) {
|
|||||||
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
||||||
Chunk o2e(777, o2k, data2);
|
Chunk o2e(777, o2k, data2);
|
||||||
|
|
||||||
EXPECT_EQ(o1.id, o1e.id);
|
ASSERT_EQ(o1.id, o1e.id);
|
||||||
EXPECT_EQ(o2.id, o2e.id);
|
ASSERT_EQ(o2.id, o2e.id);
|
||||||
EXPECT_EQ((int) o1.type, (int) o1e.type);
|
ASSERT_EQ((int) o1.type, (int) o1e.type);
|
||||||
EXPECT_EQ((int) o2.type, (int) o2e.type);
|
ASSERT_EQ((int) o2.type, (int) o2e.type);
|
||||||
auto o1d = o1.data;
|
auto o1d = o1.data;
|
||||||
auto o1ed = o1e.data;
|
auto o1ed = o1e.data;
|
||||||
auto o2d = o2.data;
|
auto o2d = o2.data;
|
||||||
auto o2ed = o2e.data;
|
auto o2ed = o2e.data;
|
||||||
EXPECT_EQ(o1.data.size(), o1e.data.size());
|
ASSERT_EQ(o1.data.size(), o1e.data.size());
|
||||||
EXPECT_EQ(o2.data.size(), o2e.data.size());
|
ASSERT_EQ(o2.data.size(), o2e.data.size());
|
||||||
for (int i = 0; i < o1.data.size(); i++) { EXPECT_EQ(o1.data[i], o1e.data[i]); }
|
for (int i = 0; i < o1.data.size(); i++) { ASSERT_EQ(o1.data[i], o1e.data[i]); }
|
||||||
for (int i = 0; i < o2.data.size(); i++) { EXPECT_EQ(o2.data[i], o2e.data[i]); }
|
for (int i = 0; i < o2.data.size(); i++) { ASSERT_EQ(o2.data[i], o2e.data[i]); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileRepository, IDsDisabled) {
|
TEST(FileRepository, IDsDisabled) {
|
||||||
GTEST_SKIP();
|
|
||||||
Cleaner c({"IDS/testrepo"});
|
Cleaner c({"IDS/testrepo"});
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
@@ -209,23 +208,23 @@ TEST(FileRepository, IDsDisabled) {
|
|||||||
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
||||||
Chunk o2(repo.getId(), o2k, data2);
|
Chunk o2(repo.getId(), o2k, data2);
|
||||||
|
|
||||||
EXPECT_EQ(o1.id, 1);
|
ASSERT_EQ(o1.id, 1);
|
||||||
EXPECT_EQ(o2.id, 2);
|
ASSERT_EQ(o2.id, 2);
|
||||||
|
|
||||||
repo.putObject(o1);
|
repo.putObject(o1);
|
||||||
repo.putObject(o2);
|
repo.putObject(o2);
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
conf.add("repo", "IDS/testrepo");
|
conf.add("repo", "IDS/testrepo");
|
||||||
FileRepository repo(conf);
|
FileRepository repo(conf);
|
||||||
repo.open();
|
repo.open();
|
||||||
auto o1o = repo.getObject(1);
|
auto o1o = repo.getObjectRaw(1);
|
||||||
auto o2o = repo.getObject(2);
|
auto o2o = repo.getObjectRaw(2);
|
||||||
|
|
||||||
auto o1ob = o1o.cbegin();
|
auto o1ob = o1o.cbegin();
|
||||||
auto o2ob = o2o.cbegin();
|
auto o2ob = o2o.cbegin();
|
||||||
@@ -239,25 +238,25 @@ TEST(FileRepository, IDsDisabled) {
|
|||||||
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
|
||||||
Chunk o2e(2, o2k, data2);
|
Chunk o2e(2, o2k, data2);
|
||||||
|
|
||||||
EXPECT_EQ(o1.id, o1e.id);
|
ASSERT_EQ(o1.id, o1e.id);
|
||||||
EXPECT_EQ(o2.id, o2e.id);
|
ASSERT_EQ(o2.id, o2e.id);
|
||||||
EXPECT_EQ((int) o1.type, (int) o1e.type);
|
ASSERT_EQ((int) o1.type, (int) o1e.type);
|
||||||
EXPECT_EQ((int) o2.type, (int) o2e.type);
|
ASSERT_EQ((int) o2.type, (int) o2e.type);
|
||||||
auto o1d = o1.data;
|
auto o1d = o1.data;
|
||||||
auto o1ed = o1e.data;
|
auto o1ed = o1e.data;
|
||||||
auto o2d = o2.data;
|
auto o2d = o2.data;
|
||||||
auto o2ed = o2e.data;
|
auto o2ed = o2e.data;
|
||||||
EXPECT_EQ(o1.data.size(), o1e.data.size());
|
ASSERT_EQ(o1.data.size(), o1e.data.size());
|
||||||
EXPECT_EQ(o2.data.size(), o2e.data.size());
|
ASSERT_EQ(o2.data.size(), o2e.data.size());
|
||||||
for (int i = 0; i < o1.data.size(); i++) { EXPECT_EQ(o1.data[i], o1e.data[i]); }
|
for (int i = 0; i < o1.data.size(); i++) { ASSERT_EQ(o1.data[i], o1e.data[i]); }
|
||||||
for (int i = 0; i < o2.data.size(); i++) { EXPECT_EQ(o2.data[i], o2e.data[i]); }
|
for (int i = 0; i < o2.data.size(); i++) { ASSERT_EQ(o2.data[i], o2e.data[i]); }
|
||||||
|
|
||||||
|
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
||||||
|
|
||||||
|
|
||||||
repo.deleteObject(o1);
|
repo.deleteObjects({o1.id});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Config conf;
|
Config conf;
|
||||||
@@ -267,12 +266,12 @@ TEST(FileRepository, IDsDisabled) {
|
|||||||
|
|
||||||
std::string o2k(16, '\0');
|
std::string o2k(16, '\0');
|
||||||
o2k[0] = 1;
|
o2k[0] = 1;
|
||||||
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
ASSERT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
|
||||||
|
|
||||||
auto id = repo.getId();
|
auto id = repo.getId();
|
||||||
EXPECT_EQ(id, 1);
|
ASSERT_EQ(id, 1);
|
||||||
std::vector<char> data1{'a', 'b', 'c', 'e'};
|
std::vector<char> data1{'a', 'b', 'c', 'e'};
|
||||||
Chunk o1(id, o2k, data1);
|
Chunk o1(id, o2k, data1);
|
||||||
EXPECT_EQ(repo.getId(), 3);
|
ASSERT_EQ(repo.getId(), 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user