Skip to content

Commit

Permalink
Handle new lite dir
Browse files Browse the repository at this point in the history
  • Loading branch information
netheril96 committed Mar 6, 2024
1 parent 8a9db80 commit 83b4051
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 43 deletions.
130 changes: 121 additions & 9 deletions sources/lite_format.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
#include "lite_format.h"
#include "exceptions.h"
#include "lite_long_name_lookup_table.h"
#include "logger.h"
#include "macro.h"
#include "platform.h"

#include <absl/base/thread_annotations.h>
#include <absl/strings/str_cat.h>
#include <absl/strings/string_view.h>

#include <absl/utility/utility.h>
#include <cerrno>
#include <memory>
#include <utility>

namespace securefs
{
Expand Down Expand Up @@ -75,15 +84,16 @@ namespace lite_format
{
public:
INJECT(NoOpNameTranslator()) {}
bool is_no_op() const noexcept override { return true; }
std::string encrypt_full_path(absl::string_view path,
std::string* out_encrypted_last_component) override
{
return {path.data(), path.size()};
}

std::string decrypt_path_component(absl::string_view path) override
absl::optional<std::string> decrypt_path_component(absl::string_view path) override
{
return {path.data(), path.size()};
return absl::optional<std::string>{absl::in_place, path.data(), path.size()};
}

std::string encrypt_path_for_symlink(absl::string_view path) override
Expand All @@ -104,19 +114,121 @@ namespace lite_format
class DirectoryImpl : public Directory
{
public:
INJECT(DirectoryImpl(std::string dir_abs_path,
std::unique_ptr<DirectoryTraverser> underlying_traverser,
StreamOpener& opener,
NameTranslator& name_trans));
DirectoryImpl(std::string dir_abs_path,
NameTranslator& name_trans,
StreamOpener& opener,
bool readdir_plus)
: dir_abs_path_(std::move(dir_abs_path))
, name_trans_(name_trans)
, opener_(opener)
, readdir_plus_(readdir_plus)
{
if (readdir_plus && !opener_.can_compute_virtual_size())
{
throw_runtime_error("Readdir plus should only be used without padding");
}
under_traverser_ = OSService::get_default().create_traverser(dir_abs_path);
}

void fstat(fuse_stat* stat) override ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
OSService().get_default().stat(dir_abs_path_, stat);
}

bool next(std::string* name, fuse_stat* stbuf) override
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
std::string under_name;

while (true)
{
if (under_traverser_->next(&under_name, stbuf))
return false;
if (!name)
return true;

if (under_name.empty())
continue;
if (under_name == "." || under_name == "..")
{
if (name)
name->swap(under_name);
return true;
}
if (stbuf && readdir_plus_ && (stbuf->st_mode & S_IFMT) == S_IFREG)
{
stbuf->st_size = opener_.compute_virtual_size(stbuf->st_size);
}
if (name_trans_.is_no_op())
{
// Plain text name mode
if (name)
name->swap(under_name);
return true;
}
if (under_name[0] == '.')
continue;
try
{
auto decoded = name_trans_.decrypt_path_component(under_name);
if (decoded.has_value())
{
decoded->swap(*name);
}
else
{
decoded = name_trans_.decrypt_path_component(lazy_get_table().transact(
[&](LongNameLookupTable& table) -> std::string
{ return table.lookup(under_name); }));
decoded.value().swap(*name);
}
}
catch (const std::exception& e)
{
WARN_LOG("Skipping filename %s/%s due to exception in decoding: %s",
dir_abs_path_,
under_name,
e.what());
continue;
}
return true;
}
}
void rewind() override ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
under_traverser_->rewind();
}

private:
LongNameLookupTable& lazy_get_table() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
if (long_table_.has_value())
{
return *long_table_;
}
long_table_.emplace(absl::StrCat(dir_abs_path_, "/.long_names.db"), true);
return *long_table_;
}

private:
absl::optional<LongNameLookupTable> long_table_ ABSL_GUARDED_BY(*this);
std::string dir_abs_path_;
std::unique_ptr<DirectoryTraverser> under_traverser_ ABSL_GUARDED_BY(*this);
NameTranslator& name_trans_;
StreamOpener& opener_;
bool readdir_plus_;
};
} // namespace

void FuseHighLevelOps::initialize(fuse_conn_info* info)
{
(void)info;
#ifdef FSP_FUSE_CAP_READDIR_PLUS
info->want |= (info->capable & FSP_FUSE_CAP_READDIR_PLUS);
read_dir_plus_ = true;
if (opener_.can_compute_virtual_size() && (info->capable & FSP_FUSE_CAP_READDIR_PLUS))
{
info->want |= FSP_FUSE_CAP_READDIR_PLUS;
read_dir_plus_ = true;
}
#endif
}

Expand Down Expand Up @@ -147,7 +259,7 @@ namespace lite_format
if (link_size != buf->st_size && link_size != (buf->st_size - 8) / 2)
throwVFSException(EIO);

if (dynamic_cast<NoOpNameTranslator*>(&name_trans_) == nullptr)
if (!name_trans_.is_no_op())
{
// Resize to actual size
buffer.resize(static_cast<size_t>(link_size));
Expand Down
26 changes: 15 additions & 11 deletions sources/lite_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,14 @@ namespace lite_format
class File;
class Directory;

class Base : public Object
class ABSL_LOCKABLE Base : public Object
{
public:
virtual File* as_file() noexcept { return nullptr; }
virtual Directory* as_dir() noexcept { return nullptr; }
virtual void lock(bool exclusive) ABSL_EXCLUSIVE_LOCK_FUNCTION() = 0;
virtual void unlock() noexcept ABSL_UNLOCK_FUNCTION() = 0;
virtual void fstat(fuse_stat* stat) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this) = 0;
};

class ABSL_LOCKABLE Directory : public Base, public DirectoryTraverser
Expand All @@ -77,13 +80,10 @@ namespace lite_format
securefs::Mutex m_lock;

public:
void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { m_lock.lock(); }
void unlock() noexcept ABSL_UNLOCK_FUNCTION() { m_lock.unlock(); }
void lock(bool exclusive) override ABSL_EXCLUSIVE_LOCK_FUNCTION() { m_lock.lock(); }
void unlock() noexcept override ABSL_UNLOCK_FUNCTION() { m_lock.unlock(); }
Directory* as_dir() noexcept override { return this; }

// Obtains the (virtual) path of the directory.
virtual absl::string_view path() const = 0;

// Redeclare the methods in `DirectoryTraverser` to add thread safe annotations.
bool next(std::string* name, fuse_stat* st) override ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
= 0;
Expand Down Expand Up @@ -130,13 +130,17 @@ namespace lite_format
{
return m_crypt_stream->write(input, off, len);
}
void fstat(fuse_stat* stat) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);
void fstat(fuse_stat* stat) override ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
m_file_stream->fstat(stat);
stat->st_size = m_crypt_stream->size();
}
void fsync() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this) { m_file_stream->fsync(); }
void utimens(const fuse_timespec ts[2]) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this)
{
m_file_stream->utimens(ts);
}
void lock(bool exclusive = true) ABSL_EXCLUSIVE_LOCK_FUNCTION()
void lock(bool exclusive) override ABSL_EXCLUSIVE_LOCK_FUNCTION()
{
m_lock.lock();
try
Expand All @@ -149,7 +153,7 @@ namespace lite_format
throw;
}
}
void unlock() noexcept ABSL_UNLOCK_FUNCTION()
void unlock() noexcept override ABSL_UNLOCK_FUNCTION()
{
m_file_stream->unlock();
m_lock.unlock();
Expand All @@ -159,7 +163,7 @@ namespace lite_format

struct NameTranslator : public Object
{

virtual bool is_no_op() const noexcept { return false; }
/// @brief Encrypt the full path.
/// @param path The original path.
/// @param out_encrypted_last_component If it is not null, and the last path component is a
Expand All @@ -171,7 +175,7 @@ namespace lite_format

/// @brief Decrypt a component of an encrypted path.
/// If a long component, then the result is empty.
virtual std::string decrypt_path_component(absl::string_view path) = 0;
virtual absl::optional<std::string> decrypt_path_component(absl::string_view path) = 0;

virtual std::string encrypt_path_for_symlink(absl::string_view path) = 0;
virtual std::string decrypt_path_from_symlink(absl::string_view path) = 0;
Expand Down
25 changes: 12 additions & 13 deletions sources/lite_long_name_lookup_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,52 +31,51 @@ LongNameLookupTable::LongNameLookupTable(const std::string& filename, bool reado
{
db_.exec(R"(
create table if not exists encrypted_mappings (
encrypted_hash blob not null primary key,
encrypted_name blob not null
encrypted_hash text not null primary key,
encrypted_name text not null
);
)");
}
}

LongNameLookupTable::~LongNameLookupTable() {}

std::vector<unsigned char>
LongNameLookupTable::lookup(absl::Span<const unsigned char> encrypted_hash)
std::string LongNameLookupTable::lookup(absl::string_view encrypted_hash)
{
SQLiteStatement q(db_,
"select encrypted_name from encrypted_mappings where encrypted_hash = ?;");
q.reset();
q.bind_blob(1, encrypted_hash);
q.bind_text(1, encrypted_hash);
if (!q.step())
{
return {};
}
auto span = q.get_blob(0);
return std::vector<unsigned char>(span.begin(), span.end());
auto view = q.get_text(0);
return {view.begin(), view.end()};
}

void LongNameLookupTable::insert_or_update(absl::Span<const unsigned char> encrypted_hash,
absl::Span<const unsigned char> encrypted_long_name)
void LongNameLookupTable::insert_or_update(absl::string_view encrypted_hash,
absl::string_view encrypted_long_name)
{
SQLiteStatement q(db_, R"(
insert or ignore into encrypted_mappings
(encrypted_hash, encrypted_name)
values (?, ?);
)");
q.reset();
q.bind_blob(1, encrypted_hash);
q.bind_blob(2, encrypted_long_name);
q.bind_text(1, encrypted_hash);
q.bind_text(2, encrypted_long_name);
q.step();
}

void LongNameLookupTable::delete_once(absl::Span<const unsigned char> encrypted_hash)
void LongNameLookupTable::delete_once(absl::string_view encrypted_hash)
{
SQLiteStatement q(db_, R"(
delete from encrypted_mappings
where encrypted_hash = ?;
)");
q.reset();
q.bind_blob(1, encrypted_hash);
q.bind_text(1, encrypted_hash);
q.step();
}

Expand Down
15 changes: 6 additions & 9 deletions sources/lite_long_name_lookup_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <absl/strings/str_cat.h>
#include <absl/strings/string_view.h>

#include <vector>
#include <string>

namespace securefs
{
Expand All @@ -18,19 +18,16 @@ class ABSL_LOCKABLE LongNameLookupTable
LongNameLookupTable(const std::string& filename, bool readonly);
~LongNameLookupTable();

std::vector<unsigned char> lookup(absl::Span<const unsigned char> encrypted_hash)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);
void insert_or_update(absl::Span<const unsigned char> encrypted_hash,
absl::Span<const unsigned char> encrypted_long_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);
void delete_once(absl::Span<const unsigned char> encrypted_hash)
std::string lookup(absl::string_view encrypted_hash) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);
void insert_or_update(absl::string_view encrypted_hash, absl::string_view encrypted_long_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);
void delete_once(absl::string_view encrypted_hash) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*this);

template <typename Callback>
auto transact(Callback&& callback) -> decltype(callback(this))
auto transact(Callback&& callback) -> decltype(callback(*this))
{
LockGuard<LongNameLookupTable> lg(*this);
return callback(this);
return callback(*this);
}

void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(*this) ABSL_NO_THREAD_SAFETY_ANALYSIS
Expand Down
2 changes: 1 addition & 1 deletion sources/sqlite_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace securefs
class SQLiteDB
{
public:
SQLiteDB() {}
SQLiteDB() = default;
SQLiteDB(const char* filename, int flags, const char* vfs);

void exec(const char* sql);
Expand Down

0 comments on commit 83b4051

Please sign in to comment.