dont preview by default, Vault::delete_file
This commit is contained in:
@@ -1 +1 @@
|
||||
Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-pro-type-reinterpret-cast,-*-owning-memory,-concurrency-mt-unsafe,-cert-env33-c'
|
||||
Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-pro-type-reinterpret-cast,-*-owning-memory,-concurrency-mt-unsafe,-cert-env33-c,-*-avoid-do-while'
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
/.cache
|
||||
/build
|
||||
/build
|
||||
*.py
|
||||
*.dull
|
||||
@@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(BOTAN REQUIRED botan-3)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
13
src/common.h
13
src/common.h
@@ -5,11 +5,14 @@
|
||||
#include <string>
|
||||
|
||||
#define ASSERT(cond) \
|
||||
if (!(cond)) { \
|
||||
std::cerr << "ASSERTION FAILED at " << __FILE__ << ":" << __LINE__ << "\n" \
|
||||
<< #cond << std::endl; \
|
||||
abort(); \
|
||||
}
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
std::cerr << "ASSERTION FAILED at " << __FILE__ << ":" << __LINE__ \
|
||||
<< "\n" \
|
||||
<< #cond << std::endl; \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
using u8 = unsigned char;
|
||||
using i16 = int16_t;
|
||||
|
||||
@@ -15,6 +15,8 @@ encrypt_xchacha20_poly1305(const Botan::secure_vector<u8> &plaintext,
|
||||
ASSERT(key.size() == 32);
|
||||
ASSERT(nonce.size() == 24);
|
||||
|
||||
// XChaCha20 is selected automatically based on the nonce size
|
||||
// https://github.com/randombit/botan/blob/master/src/lib/stream/chacha/chacha.cpp#L375
|
||||
auto cipher = Botan::AEAD_Mode::create_or_throw(
|
||||
"ChaCha20Poly1305", Botan::Cipher_Dir::Encryption);
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
#include <QTemporaryFile>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||
: QMainWindow(parent), ui(std::make_unique<Ui::MainWindow>()) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->filePreview->setVisible(false);
|
||||
|
||||
connect(ui->actionNew, &QAction::triggered, this, [this]() {
|
||||
QString path = QFileDialog::getSaveFileName(this, "Choose vault location",
|
||||
QDir::currentPath(),
|
||||
@@ -33,10 +35,9 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
reload_fs_tree();
|
||||
});
|
||||
|
||||
connect(ui->fsTreeWidget, &QTreeWidget::itemClicked,
|
||||
[this](QTreeWidgetItem *item, int column) {
|
||||
preview_file(item->text(column).toStdString());
|
||||
});
|
||||
connect(
|
||||
ui->fsTreeWidget, &QTreeWidget::itemClicked,
|
||||
[this](QTreeWidgetItem *, int) { ui->filePreview->setVisible(false); });
|
||||
|
||||
connect(ui->fsTreeWidget, &QTreeWidget::customContextMenuRequested, this,
|
||||
&MainWindow::file_context_menu);
|
||||
@@ -54,7 +55,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
m_vault->write_file(path_to_filename(path.toStdString()), content);
|
||||
m_vault->create_file(path_to_filename(path.toStdString()), content);
|
||||
}
|
||||
|
||||
reload_fs_tree();
|
||||
@@ -62,6 +63,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
}
|
||||
|
||||
void MainWindow::reload_fs_tree() {
|
||||
ui->menuFiles->setEnabled(true);
|
||||
ui->fsTreeWidget->clear();
|
||||
|
||||
auto headers = m_vault->read_file_headers();
|
||||
@@ -69,11 +71,14 @@ void MainWindow::reload_fs_tree() {
|
||||
auto *item = new QTreeWidgetItem(ui->fsTreeWidget);
|
||||
item->setText(0, QString::fromStdString(header.name));
|
||||
item->setText(1, QString::number(header.size));
|
||||
item->setText(2, QString::number(header.offset));
|
||||
}
|
||||
ui->fsTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
void MainWindow::preview_file(const std::string &filename) {
|
||||
ui->filePreview->setVisible(true);
|
||||
|
||||
auto content = m_vault->read_file(filename);
|
||||
if (content) {
|
||||
ui->filePreview->setText(QString::fromStdString(content.value()));
|
||||
@@ -102,6 +107,8 @@ void MainWindow::edit_file(const std::string &filename) {
|
||||
QTextStream in(&temp_file);
|
||||
m_vault->update_file(filename, in.readAll().toStdString());
|
||||
reload_fs_tree();
|
||||
|
||||
// QTemporaryFile gets deleted when it goes out of scope
|
||||
} else {
|
||||
qWarning() << "File to edit not found";
|
||||
}
|
||||
@@ -115,6 +122,11 @@ void MainWindow::file_context_menu(const QPoint &pos) {
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
QAction *preview_action = menu.addAction(
|
||||
style()->standardIcon(QStyle::SP_FileDialogContentsView), "Preview");
|
||||
connect(preview_action, &QAction::triggered, this,
|
||||
[this, item]() { preview_file(item->text(0).toStdString()); });
|
||||
|
||||
QAction *edit_action = menu.addAction(
|
||||
style()->standardIcon(QStyle::SP_FileDialogDetailedView), "Edit");
|
||||
connect(edit_action, &QAction::triggered, this,
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
std::unique_ptr<Ui::MainWindow> ui;
|
||||
|
||||
std::unique_ptr<Vault> m_vault;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<width>900</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -33,6 +33,11 @@
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -46,10 +51,10 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>30</height>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<widget class="QMenu" name="menuVault">
|
||||
<property name="title">
|
||||
<string>Vault</string>
|
||||
</property>
|
||||
@@ -57,12 +62,15 @@
|
||||
<addaction name="actionOpen"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuFiles">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Files</string>
|
||||
</property>
|
||||
<addaction name="actionAddFiles"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuVault"/>
|
||||
<addaction name="menuFiles"/>
|
||||
</widget>
|
||||
<action name="actionNew">
|
||||
|
||||
108
src/vault.cc
108
src/vault.cc
@@ -19,7 +19,7 @@ Vault::Vault(std::string path) : m_path(std::move(path)) {
|
||||
ASSERT(static_cast<bool>(m_file.read(header.data(), header.size())));
|
||||
ASSERT(std::string_view(header.data(), header.size()) == "DULL");
|
||||
|
||||
std::int16_t version = 0;
|
||||
i16 version = 0;
|
||||
ASSERT(m_file.read(reinterpret_cast<char *>(&version), sizeof(version)));
|
||||
ASSERT(version == VERSION);
|
||||
}
|
||||
@@ -31,19 +31,13 @@ std::vector<FileHeader> Vault::read_file_headers() {
|
||||
m_file.seekg(AFTER_HEADER_OFFSET, std::ios::beg);
|
||||
|
||||
while (true) {
|
||||
u64 name_size = 0;
|
||||
if (!m_file.read(reinterpret_cast<char *>(&name_size), sizeof(u64))) {
|
||||
auto header = read_file_header(m_file);
|
||||
if (header) {
|
||||
headers.push_back(header.value());
|
||||
m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
FileHeader header{};
|
||||
header.name.resize(name_size);
|
||||
m_file.read(header.name.data(), static_cast<i64>(name_size));
|
||||
|
||||
m_file.read(reinterpret_cast<char *>(&header.size), sizeof(u64));
|
||||
m_file.seekg(static_cast<i64>(header.size), std::ios::cur);
|
||||
|
||||
headers.push_back(header);
|
||||
}
|
||||
|
||||
return headers;
|
||||
@@ -54,46 +48,42 @@ std::optional<std::string> Vault::read_file(const std::string &filename) {
|
||||
m_file.seekg(AFTER_HEADER_OFFSET, std::ios::beg);
|
||||
|
||||
while (true) {
|
||||
u64 name_size = 0;
|
||||
if (!m_file.read(reinterpret_cast<char *>(&name_size), sizeof(u64))) {
|
||||
auto header = read_file_header(m_file);
|
||||
if (!header) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
name.resize(name_size);
|
||||
m_file.read(name.data(), static_cast<i64>(name_size));
|
||||
|
||||
u64 content_size = 0;
|
||||
m_file.read(reinterpret_cast<char *>(&content_size), sizeof(u64));
|
||||
|
||||
if (name == filename) {
|
||||
std::string content(content_size, '\0');
|
||||
m_file.read(content.data(), static_cast<i64>(content_size));
|
||||
if (header->name == filename) {
|
||||
std::string content(header->size, '\0');
|
||||
if (!m_file.read(content.data(), static_cast<i64>(header->size))) {
|
||||
break;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
m_file.seekg(static_cast<i64>(content_size), std::ios::cur);
|
||||
m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Vault::write_file(const std::string &filename,
|
||||
const std::string &content) {
|
||||
void Vault::create_file(const std::string &filename,
|
||||
const std::string &content) {
|
||||
m_file.clear();
|
||||
m_file.seekp(0, std::ios::end);
|
||||
|
||||
u64 filename_size = filename.size();
|
||||
u64 content_size = content.size();
|
||||
m_file.write(reinterpret_cast<const char *>(&filename_size), sizeof(u64));
|
||||
m_file.write(filename.data(), static_cast<i64>(filename_size));
|
||||
m_file.write(reinterpret_cast<const char *>(&content_size), sizeof(u64));
|
||||
m_file.write(content.data(), static_cast<i64>(content_size));
|
||||
ASSERT(m_file.write(reinterpret_cast<const char *>(&filename_size),
|
||||
sizeof(u64)));
|
||||
ASSERT(m_file.write(filename.data(), static_cast<i64>(filename_size)));
|
||||
ASSERT(
|
||||
m_file.write(reinterpret_cast<const char *>(&content_size), sizeof(u64)));
|
||||
ASSERT(m_file.write(content.data(), static_cast<i64>(content_size)));
|
||||
m_file.flush();
|
||||
}
|
||||
|
||||
void Vault::update_file(const std::string &filename,
|
||||
const std::string &content) {
|
||||
void Vault::delete_file(const std::string &filename) {
|
||||
m_file.clear();
|
||||
m_file.seekg(AFTER_HEADER_OFFSET, std::ios::beg);
|
||||
|
||||
@@ -103,26 +93,20 @@ void Vault::update_file(const std::string &filename,
|
||||
while (true) {
|
||||
i64 current_pos = m_file.tellg();
|
||||
|
||||
u64 name_size = 0;
|
||||
if (!m_file.read(reinterpret_cast<char *>(&name_size), sizeof(u64))) {
|
||||
auto header = read_file_header(m_file);
|
||||
if (!header) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
name.resize(name_size);
|
||||
m_file.read(name.data(), static_cast<i64>(name_size));
|
||||
|
||||
u64 content_size = 0;
|
||||
m_file.read(reinterpret_cast<char *>(&content_size), sizeof(u64));
|
||||
|
||||
if (name == filename) {
|
||||
if (header->name == filename) {
|
||||
entry_start = current_pos;
|
||||
entry_total_size = sizeof(u64) + name_size + sizeof(u64) + content_size;
|
||||
m_file.seekg(static_cast<i64>(content_size), std::ios::cur);
|
||||
entry_total_size =
|
||||
sizeof(u64) + header->name.length() + sizeof(u64) + header->size;
|
||||
m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
|
||||
break;
|
||||
}
|
||||
|
||||
m_file.seekg(static_cast<i64>(content_size), std::ios::cur);
|
||||
m_file.seekg(static_cast<i64>(header->size), std::ios::cur);
|
||||
}
|
||||
|
||||
if (entry_start != -1) {
|
||||
@@ -136,7 +120,7 @@ void Vault::update_file(const std::string &filename,
|
||||
|
||||
m_file.clear();
|
||||
m_file.seekp(entry_start, std::ios::beg);
|
||||
m_file.write(remaining.data(), static_cast<i64>(remaining.size()));
|
||||
ASSERT(m_file.write(remaining.data(), static_cast<i64>(remaining.size())));
|
||||
|
||||
i64 new_size = entry_start + static_cast<i64>(remaining.size());
|
||||
m_file.flush();
|
||||
@@ -147,6 +131,32 @@ void Vault::update_file(const std::string &filename,
|
||||
m_file.open(m_path, std::ios::in | std::ios::out | std::ios::binary);
|
||||
ASSERT(m_file.good());
|
||||
}
|
||||
}
|
||||
|
||||
write_file(filename, content);
|
||||
}
|
||||
void Vault::update_file(const std::string &filename,
|
||||
const std::string &content) {
|
||||
delete_file(filename);
|
||||
create_file(filename, content);
|
||||
}
|
||||
|
||||
std::optional<FileHeader> Vault::read_file_header(std::fstream &file) {
|
||||
FileHeader header{};
|
||||
header.offset = file.tellg();
|
||||
|
||||
u64 name_size = 0;
|
||||
if (!file.read(reinterpret_cast<char *>(&name_size), sizeof(u64))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ASSERT(name_size < 10000);
|
||||
|
||||
header.name.resize(name_size);
|
||||
if (!file.read(header.name.data(), static_cast<i64>(name_size))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!file.read(reinterpret_cast<char *>(&header.size), sizeof(u64))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ constexpr u64 AFTER_HEADER_OFFSET = 6;
|
||||
struct FileHeader {
|
||||
std::string name;
|
||||
u64 size;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
class Vault {
|
||||
@@ -19,9 +20,12 @@ public:
|
||||
|
||||
std::vector<FileHeader> read_file_headers();
|
||||
std::optional<std::string> read_file(const std::string &name);
|
||||
void write_file(const std::string &name, const std::string &content);
|
||||
void create_file(const std::string &name, const std::string &content);
|
||||
void delete_file(const std::string &name);
|
||||
void update_file(const std::string &name, const std::string &content);
|
||||
|
||||
static std::optional<FileHeader> read_file_header(std::fstream &file);
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
std::fstream m_file;
|
||||
|
||||
Reference in New Issue
Block a user