mirror of
https://github.com/vgough/encfs.git
synced 2024-11-22 16:03:34 +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);
|
pthread_mutex_init(&contextMutex, 0);
|
||||||
|
|
||||||
usageCount = 0;
|
usageCount = 0;
|
||||||
|
currentFuseFh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
EncFS_Context::~EncFS_Context() {
|
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,
|
// putNode stores "node" under key "path" in the "openFiles" map. It
|
||||||
std::shared_ptr<FileNode> &&node) {
|
// increments the reference count if the key already exists.
|
||||||
|
void EncFS_Context::putNode(const char *path,
|
||||||
|
std::shared_ptr<FileNode> node) {
|
||||||
Lock lock(contextMutex);
|
Lock lock(contextMutex);
|
||||||
auto &list = openFiles[std::string(path)];
|
auto &list = openFiles[std::string(path)];
|
||||||
list.push_front(std::move(node));
|
// The length of "list" serves as the reference count.
|
||||||
return list.front().get();
|
list.push_front(node);
|
||||||
|
fuseFhMap[node->fuseFh] = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eraseNode is called by encfs_release in response to the RELEASE
|
// eraseNode is called by encfs_release in response to the RELEASE
|
||||||
// FUSE-command we get from the kernel.
|
// 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);
|
Lock lock(contextMutex);
|
||||||
|
|
||||||
FileMap::iterator it = openFiles.find(std::string(path));
|
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()) {
|
if (it->second.empty()) {
|
||||||
fn->canary = CANARY_RELEASED;
|
fn->canary = CANARY_RELEASED;
|
||||||
openFiles.erase(it);
|
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
|
} // namespace encfs
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "encfs.h"
|
#include "encfs.h"
|
||||||
|
|
||||||
@ -46,9 +47,9 @@ class EncFS_Context {
|
|||||||
|
|
||||||
void getAndResetUsageCounter(int *usage, int *openCount);
|
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);
|
void renameNode(const char *oldName, const char *newName);
|
||||||
|
|
||||||
@ -69,6 +70,9 @@ class EncFS_Context {
|
|||||||
pthread_cond_t wakeupCond;
|
pthread_cond_t wakeupCond;
|
||||||
pthread_mutex_t wakeupMutex;
|
pthread_mutex_t wakeupMutex;
|
||||||
|
|
||||||
|
uint64_t nextFuseFh();
|
||||||
|
std::shared_ptr<FileNode> lookupFuseFh(uint64_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* This placeholder is what is referenced in FUSE context (passed to
|
/* This placeholder is what is referenced in FUSE context (passed to
|
||||||
* callbacks).
|
* callbacks).
|
||||||
@ -89,6 +93,9 @@ class EncFS_Context {
|
|||||||
|
|
||||||
int usageCount;
|
int usageCount;
|
||||||
std::shared_ptr<DirNode> root;
|
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);
|
int remountFS(EncFS_Context *ctx);
|
||||||
|
@ -644,8 +644,9 @@ std::shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) {
|
|||||||
if (!node) {
|
if (!node) {
|
||||||
uint64_t iv = 0;
|
uint64_t iv = 0;
|
||||||
string cipherName = naming->encodePath(plainName, &iv);
|
string cipherName = naming->encodePath(plainName, &iv);
|
||||||
|
uint64_t fuseFh = ctx->nextFuseFh();
|
||||||
node.reset(new FileNode(this, fsConfig, plainName,
|
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);
|
if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv);
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ namespace encfs {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
|
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);
|
pthread_mutex_init(&mutex, 0);
|
||||||
|
|
||||||
Lock _lock(mutex);
|
Lock _lock(mutex);
|
||||||
@ -66,6 +67,8 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
|
|||||||
|
|
||||||
this->fsConfig = cfg;
|
this->fsConfig = cfg;
|
||||||
|
|
||||||
|
this->fuseFh = fuseFh;
|
||||||
|
|
||||||
// chain RawFileIO & CipherFileIO
|
// chain RawFileIO & CipherFileIO
|
||||||
std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
|
std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
|
||||||
io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
|
io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
|
||||||
|
@ -47,13 +47,16 @@ class FileIO;
|
|||||||
class FileNode {
|
class FileNode {
|
||||||
public:
|
public:
|
||||||
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
|
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
|
||||||
const char *cipherName);
|
const char *cipherName, uint64_t fuseFh);
|
||||||
~FileNode();
|
~FileNode();
|
||||||
|
|
||||||
// Use an atomic type. The canary is accessed without holding any
|
// Use an atomic type. The canary is accessed without holding any
|
||||||
// locks.
|
// locks.
|
||||||
std::atomic<std::uint32_t> canary;
|
std::atomic<std::uint32_t> canary;
|
||||||
|
|
||||||
|
// FUSE file handle that is passed to the kernel
|
||||||
|
uint64_t fuseFh;
|
||||||
|
|
||||||
const char *plaintextName() const;
|
const char *plaintextName() const;
|
||||||
const char *cipherName() const;
|
const char *cipherName() const;
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ static int withFileNode(const char *opName, const char *path,
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
auto do_op = [&FSRoot, opName, &op](FileNode *fnode) {
|
auto do_op = [&FSRoot, opName, &op](std::shared_ptr<FileNode> fnode) {
|
||||||
rAssert(fnode != nullptr);
|
rAssert(fnode != nullptr);
|
||||||
checkCanary(fnode);
|
checkCanary(fnode);
|
||||||
VLOG(1) << "op: " << opName << " : " << fnode->cipherName();
|
VLOG(1) << "op: " << opName << " : " << fnode->cipherName();
|
||||||
@ -153,13 +153,19 @@ static int withFileNode(const char *opName, const char *path,
|
|||||||
<< fnode->cipherName() << "'";
|
<< fnode->cipherName() << "'";
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
return op(fnode);
|
return op(fnode.get());
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fi != nullptr && fi->fh != 0)
|
if (fi != nullptr && fi->fh != 0) {
|
||||||
res = do_op(reinterpret_cast<FileNode *>(fi->fh));
|
auto node = ctx->lookupFuseFh(fi->fh);
|
||||||
else
|
if (node == nullptr) {
|
||||||
res = do_op(FSRoot->lookupNode(path, opName).get());
|
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) {
|
if (res < 0) {
|
||||||
RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res);
|
RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res);
|
||||||
@ -555,8 +561,8 @@ int encfs_open(const char *path, struct fuse_file_info *file) {
|
|||||||
<< file->flags;
|
<< file->flags;
|
||||||
|
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
file->fh =
|
ctx->putNode(path, fnode);
|
||||||
reinterpret_cast<uintptr_t>(ctx->putNode(path, std::move(fnode)));
|
file->fh = fnode->fuseFh;
|
||||||
res = ESUCCESS;
|
res = ESUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,7 +617,8 @@ int encfs_release(const char *path, struct fuse_file_info *finfo) {
|
|||||||
EncFS_Context *ctx = context();
|
EncFS_Context *ctx = context();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ctx->eraseNode(path, reinterpret_cast<FileNode *>(finfo->fh));
|
auto fnode = ctx->lookupFuseFh(finfo->fh);
|
||||||
|
ctx->eraseNode(path, fnode);
|
||||||
return ESUCCESS;
|
return ESUCCESS;
|
||||||
} catch (encfs::Error &err) {
|
} catch (encfs::Error &err) {
|
||||||
RLOG(ERROR) << "error caught in release: " << err.what();
|
RLOG(ERROR) << "error caught in release: " << err.what();
|
||||||
|
Loading…
Reference in New Issue
Block a user