mirror of
https://github.com/vgough/encfs.git
synced 2024-11-25 01:13:12 +01:00
fuseFhMap: translate FUSE file handles to FileNode pointers
Previously, we used raw pointers to the FileNode as FUSE file handles. With this change, we instead pass an arbitrary value (a uint64 counter) to the kernel as FUSE file handle, and use the "fuseFhMap" look-up table to convert back to the FileNode pointer. This gets rid of a lot of scary void pointer casts. The performance cost is not measurable.
This commit is contained in:
parent
9a4ea2007f
commit
e2f0f8e3c6
@ -34,6 +34,7 @@ EncFS_Context::EncFS_Context() {
|
||||
pthread_mutex_init(&contextMutex, 0);
|
||||
|
||||
usageCount = 0;
|
||||
currentFuseFh = 1;
|
||||
}
|
||||
|
||||
EncFS_Context::~EncFS_Context() {
|
||||
@ -106,17 +107,20 @@ void EncFS_Context::renameNode(const char *from, const char *to) {
|
||||
}
|
||||
}
|
||||
|
||||
FileNode *EncFS_Context::putNode(const char *path,
|
||||
std::shared_ptr<FileNode> &&node) {
|
||||
// putNode stores "node" under key "path" in the "openFiles" map. It
|
||||
// increments the reference count if the key already exists.
|
||||
void EncFS_Context::putNode(const char *path,
|
||||
std::shared_ptr<FileNode> node) {
|
||||
Lock lock(contextMutex);
|
||||
auto &list = openFiles[std::string(path)];
|
||||
list.push_front(std::move(node));
|
||||
return list.front().get();
|
||||
// The length of "list" serves as the reference count.
|
||||
list.push_front(node);
|
||||
fuseFhMap[node->fuseFh] = node;
|
||||
}
|
||||
|
||||
// eraseNode is called by encfs_release in response to the RELEASE
|
||||
// FUSE-command we get from the kernel.
|
||||
void EncFS_Context::eraseNode(const char *path, FileNode *pl) {
|
||||
void EncFS_Context::eraseNode(const char *path, std::shared_ptr<FileNode> fnode) {
|
||||
Lock lock(contextMutex);
|
||||
|
||||
FileMap::iterator it = openFiles.find(std::string(path));
|
||||
@ -130,7 +134,25 @@ void EncFS_Context::eraseNode(const char *path, FileNode *pl) {
|
||||
if (it->second.empty()) {
|
||||
fn->canary = CANARY_RELEASED;
|
||||
openFiles.erase(it);
|
||||
fuseFhMap.erase(fn->fuseFh);
|
||||
}
|
||||
}
|
||||
|
||||
// nextFuseFh returns the next unused uint64 to serve as the FUSE file
|
||||
// handle for the kernel.
|
||||
uint64_t EncFS_Context::nextFuseFh(void) {
|
||||
// This is thread-safe because currentFuseFh is declared as std::atomic
|
||||
return currentFuseFh++;
|
||||
}
|
||||
|
||||
// lookupFuseFh finds "n" in "fuseFhMap" and returns the FileNode.
|
||||
std::shared_ptr<FileNode> EncFS_Context::lookupFuseFh(uint64_t n) {
|
||||
Lock lock(contextMutex);
|
||||
auto it = fuseFhMap.find(n);
|
||||
if (it == fuseFhMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // namespace encfs
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
|
||||
#include "encfs.h"
|
||||
|
||||
@ -46,9 +47,9 @@ class EncFS_Context {
|
||||
|
||||
void getAndResetUsageCounter(int *usage, int *openCount);
|
||||
|
||||
FileNode *putNode(const char *path, std::shared_ptr<FileNode> &&node);
|
||||
void putNode(const char *path, std::shared_ptr<FileNode> node);
|
||||
|
||||
void eraseNode(const char *path, FileNode *fnode);
|
||||
void eraseNode(const char *path, std::shared_ptr<FileNode> fnode);
|
||||
|
||||
void renameNode(const char *oldName, const char *newName);
|
||||
|
||||
@ -69,6 +70,9 @@ class EncFS_Context {
|
||||
pthread_cond_t wakeupCond;
|
||||
pthread_mutex_t wakeupMutex;
|
||||
|
||||
uint64_t nextFuseFh();
|
||||
std::shared_ptr<FileNode> lookupFuseFh(uint64_t);
|
||||
|
||||
private:
|
||||
/* This placeholder is what is referenced in FUSE context (passed to
|
||||
* callbacks).
|
||||
@ -89,6 +93,9 @@ class EncFS_Context {
|
||||
|
||||
int usageCount;
|
||||
std::shared_ptr<DirNode> root;
|
||||
|
||||
std::atomic<std::uint64_t> currentFuseFh;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<FileNode>> fuseFhMap;
|
||||
};
|
||||
|
||||
int remountFS(EncFS_Context *ctx);
|
||||
|
@ -644,8 +644,9 @@ std::shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) {
|
||||
if (!node) {
|
||||
uint64_t iv = 0;
|
||||
string cipherName = naming->encodePath(plainName, &iv);
|
||||
uint64_t fuseFh = ctx->nextFuseFh();
|
||||
node.reset(new FileNode(this, fsConfig, plainName,
|
||||
(rootDir + cipherName).c_str()));
|
||||
(rootDir + cipherName).c_str(), fuseFh));
|
||||
|
||||
if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv);
|
||||
|
||||
|
@ -53,7 +53,8 @@ namespace encfs {
|
||||
*/
|
||||
|
||||
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
|
||||
const char *plaintextName_, const char *cipherName_) {
|
||||
const char *plaintextName_, const char *cipherName_, uint64_t fuseFh) {
|
||||
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
|
||||
Lock _lock(mutex);
|
||||
@ -66,6 +67,8 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
|
||||
|
||||
this->fsConfig = cfg;
|
||||
|
||||
this->fuseFh = fuseFh;
|
||||
|
||||
// chain RawFileIO & CipherFileIO
|
||||
std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
|
||||
io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
|
||||
|
@ -47,13 +47,16 @@ class FileIO;
|
||||
class FileNode {
|
||||
public:
|
||||
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
|
||||
const char *cipherName);
|
||||
const char *cipherName, uint64_t fuseFh);
|
||||
~FileNode();
|
||||
|
||||
// Use an atomic type. The canary is accessed without holding any
|
||||
// locks.
|
||||
std::atomic<std::uint32_t> canary;
|
||||
|
||||
// FUSE file handle that is passed to the kernel
|
||||
uint64_t fuseFh;
|
||||
|
||||
const char *plaintextName() const;
|
||||
const char *cipherName() const;
|
||||
|
||||
|
@ -142,7 +142,7 @@ static int withFileNode(const char *opName, const char *path,
|
||||
|
||||
try {
|
||||
|
||||
auto do_op = [&FSRoot, opName, &op](FileNode *fnode) {
|
||||
auto do_op = [&FSRoot, opName, &op](std::shared_ptr<FileNode> fnode) {
|
||||
rAssert(fnode != nullptr);
|
||||
checkCanary(fnode);
|
||||
VLOG(1) << "op: " << opName << " : " << fnode->cipherName();
|
||||
@ -153,13 +153,19 @@ static int withFileNode(const char *opName, const char *path,
|
||||
<< fnode->cipherName() << "'";
|
||||
return -EIO;
|
||||
}
|
||||
return op(fnode);
|
||||
return op(fnode.get());
|
||||
};
|
||||
|
||||
if (fi != nullptr && fi->fh != 0)
|
||||
res = do_op(reinterpret_cast<FileNode *>(fi->fh));
|
||||
else
|
||||
res = do_op(FSRoot->lookupNode(path, opName).get());
|
||||
if (fi != nullptr && fi->fh != 0) {
|
||||
auto node = ctx->lookupFuseFh(fi->fh);
|
||||
if (node == nullptr) {
|
||||
auto msg = "fh=" + std::to_string(fi->fh) + " not found in fuseFhMap";
|
||||
throw Error(msg.c_str());
|
||||
}
|
||||
res = do_op(node);
|
||||
} else {
|
||||
res = do_op(FSRoot->lookupNode(path, opName));
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res);
|
||||
@ -555,8 +561,8 @@ int encfs_open(const char *path, struct fuse_file_info *file) {
|
||||
<< file->flags;
|
||||
|
||||
if (res >= 0) {
|
||||
file->fh =
|
||||
reinterpret_cast<uintptr_t>(ctx->putNode(path, std::move(fnode)));
|
||||
ctx->putNode(path, fnode);
|
||||
file->fh = fnode->fuseFh;
|
||||
res = ESUCCESS;
|
||||
}
|
||||
}
|
||||
@ -611,7 +617,8 @@ int encfs_release(const char *path, struct fuse_file_info *finfo) {
|
||||
EncFS_Context *ctx = context();
|
||||
|
||||
try {
|
||||
ctx->eraseNode(path, reinterpret_cast<FileNode *>(finfo->fh));
|
||||
auto fnode = ctx->lookupFuseFh(finfo->fh);
|
||||
ctx->eraseNode(path, fnode);
|
||||
return ESUCCESS;
|
||||
} catch (encfs::Error &err) {
|
||||
RLOG(ERROR) << "error caught in release: " << err.what();
|
||||
|
Loading…
Reference in New Issue
Block a user