-
-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ZIM Fuse Filesystem #400
Open
juuz0
wants to merge
8
commits into
main
Choose a base branch
from
zimfuse
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
ZIM Fuse Filesystem #400
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d2567e2
Meson configuration for ZIMFuse
juuz0 739fde5
Tree implementation for ZIM file
juuz0 3bfb8ad
FUSE commands implemented: readdir, getattr, read, open
juuz0 cf4483e
Update README.md
juuz0 7e017f8
Switch to smart pointers
juuz0 717afc0
Don't allow filenames to exceed 500 chars
juuz0 93ab559
Add collision number to same file names
juuz0 7af6fa8
Cache stat values after first use.
juuz0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
#define FUSE_USE_VERSION 31 | ||
#include <fuse3/fuse.h> | ||
#include <sys/stat.h> | ||
#include <zim/archive.h> | ||
#include <zim/item.h> | ||
|
||
#include <string> | ||
|
||
#include "node.h" | ||
#include "tree.h" | ||
|
||
static const Node* getNode(const std::string& nName) | ||
{ | ||
Tree* const tree = static_cast<Tree*>(fuse_get_context()->private_data); | ||
auto node = tree->findNode(nName); | ||
return node; | ||
} | ||
|
||
void setStat(struct stat* st, const Node* node) | ||
{ | ||
Tree* const tree = static_cast<Tree*>(fuse_get_context()->private_data); | ||
if (tree->statCache.count(node->originalPath)) { | ||
*st = tree->statCache[node->originalPath]; | ||
return; | ||
} | ||
if (node->isDir) { | ||
st->st_mode = S_IFDIR | 0555; | ||
st->st_nlink = 1; | ||
} else { | ||
st->st_mode = S_IFREG | 0444; | ||
st->st_nlink = 1; | ||
Tree* const tree = static_cast<Tree*>(fuse_get_context()->private_data); | ||
st->st_size = tree->getArchive() | ||
->getEntryByPath(node->originalPath.substr(1)) | ||
.getItem(true) | ||
.getSize(); | ||
} | ||
tree->statCache[node->originalPath] = *st; | ||
} | ||
|
||
static int zimGetAttr(const char* path, struct stat* st, fuse_file_info* fi) | ||
{ | ||
const Node* const node = getNode(path); | ||
if (!node) | ||
return -ENOENT; | ||
setStat(st, node); | ||
return 0; | ||
} | ||
|
||
static int zimReadDir(const char* path, | ||
void* buf, | ||
fuse_fill_dir_t fill_dir, | ||
off_t offset, | ||
struct fuse_file_info* fi, | ||
enum fuse_readdir_flags flags) | ||
{ | ||
const Node* const node = getNode(path); | ||
if (!node) | ||
return -ENOENT; | ||
{ | ||
struct stat st; | ||
setStat(&st, node); | ||
fill_dir(buf, ".", &st, 0, (fuse_fill_dir_flags)0); | ||
} | ||
|
||
if (const Node* const parent = node->parent) { | ||
struct stat st; | ||
setStat(&st, parent); | ||
fill_dir(buf, "..", &st, 0, (fuse_fill_dir_flags)0); | ||
} else { | ||
fill_dir(buf, "..", nullptr, 0, (fuse_fill_dir_flags)0); | ||
} | ||
|
||
for (auto child : node->children) { | ||
struct stat st; | ||
setStat(&st, child); | ||
fill_dir(buf, child->name.c_str(), &st, 0, (fuse_fill_dir_flags)0); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int zimRead(const char* path, | ||
char* buf, | ||
size_t size, | ||
off_t offset, | ||
struct fuse_file_info* fi) | ||
{ | ||
const Node* const node = getNode(path); | ||
Tree* const tree = static_cast<Tree*>(fuse_get_context()->private_data); | ||
if (!node) | ||
return -ENOENT; | ||
const std::string strPath(path); | ||
zim::Entry entry = tree->getArchive()->getEntryByPath(node->originalPath.substr(1)); | ||
zim::Item item = entry.getItem(true); | ||
|
||
if (offset >= (off_t)item.getSize()) { | ||
return 0; | ||
} | ||
|
||
if (offset + size > item.getSize()) { | ||
size = item.getSize() - offset; | ||
} | ||
|
||
memcpy(buf, item.getData().data() + offset, size); | ||
|
||
return size; | ||
} | ||
|
||
static int zimOpen(const char* path, struct fuse_file_info* fi) | ||
{ | ||
if ((fi->flags & 3) != O_RDONLY) { | ||
return -EACCES; | ||
} | ||
|
||
const Node* const node = getNode(path); | ||
if (!node) | ||
return -ENOENT; | ||
if (node->isDir) | ||
return -EISDIR; | ||
return 0; | ||
} | ||
|
||
static struct fuse_operations ops = { | ||
.getattr = zimGetAttr, | ||
.open = zimOpen, | ||
.read = zimRead, | ||
.readdir = zimReadDir, | ||
}; | ||
|
||
enum { | ||
KEY_HELP, | ||
KEY_VERSION, | ||
}; | ||
|
||
struct Param { | ||
int str_arg_count = 0; | ||
std::string filename; | ||
std::string mount_point; | ||
~Param() {} | ||
}; | ||
|
||
void printUsage() | ||
{ | ||
fprintf(stderr, | ||
R"(Mounts a ZIM file as a FUSE filesystem | ||
|
||
Usage: zimfuse [options] <ZIM-file> [mount-point] | ||
|
||
General options: | ||
--help -h print help | ||
--version print version | ||
)"); | ||
} | ||
|
||
void printVersion() | ||
{ | ||
fprintf(stderr, "1.0"); | ||
} | ||
|
||
static int processArgs(void* data, const char* arg, int key, fuse_args* outargs) | ||
{ | ||
Param& param = *static_cast<Param*>(data); | ||
|
||
const int KEEP = 1; | ||
const int DISCARD = 0; | ||
const int ERROR = -1; | ||
|
||
switch (key) { | ||
case KEY_HELP: | ||
printUsage(); | ||
fuse_opt_add_arg(outargs, "-ho"); | ||
fuse_main(outargs->argc, outargs->argv, &ops, nullptr); | ||
std::exit(EXIT_SUCCESS); | ||
|
||
case KEY_VERSION: | ||
printVersion(); | ||
fuse_opt_add_arg(outargs, "--version"); | ||
fuse_main(outargs->argc, outargs->argv, &ops, nullptr); | ||
std::exit(EXIT_SUCCESS); | ||
|
||
case FUSE_OPT_KEY_NONOPT: | ||
switch (++param.str_arg_count) { | ||
case 1: | ||
param.filename = arg; | ||
return DISCARD; | ||
|
||
case 2: | ||
param.mount_point = arg; | ||
return KEEP; | ||
|
||
default: | ||
fprintf( | ||
stderr, | ||
"zimfuse: only two arguments allowed: filename and mountpoint\n"); | ||
return ERROR; | ||
} | ||
|
||
default: | ||
return KEEP; | ||
} | ||
} | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
fuse_args args = FUSE_ARGS_INIT(argc, argv); | ||
Param param; | ||
|
||
const fuse_opt opts[] = {FUSE_OPT_KEY("--help", KEY_HELP), | ||
FUSE_OPT_KEY("-h", KEY_HELP), | ||
FUSE_OPT_KEY("--version", KEY_VERSION), | ||
{nullptr, 0, 0}}; | ||
|
||
if (fuse_opt_parse(&args, ¶m, opts, processArgs)) | ||
return EXIT_FAILURE; | ||
|
||
if (param.filename.empty()) { | ||
printUsage(); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
auto tree = new Tree(param.filename); | ||
fuse_opt_add_arg(&args, "-s"); | ||
// fuse_opt_add_arg(&args, "-d"); | ||
|
||
auto ret = fuse_main(args.argc, args.argv, &ops, tree); | ||
fuse_opt_free_args(&args); | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
sources = [ | ||
'main.cpp', | ||
'tree.cpp' | ||
] | ||
|
||
deps = [libzim_dep, libfuse_dep] | ||
|
||
executable('zimfuse', | ||
sources, | ||
dependencies : deps, | ||
install : true) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#ifndef _ZIM_NODE_H | ||
#define _ZIM_NODE_H | ||
|
||
#include <memory> | ||
#include <string> | ||
#include <vector> | ||
|
||
struct Node { | ||
using Ptr = std::unique_ptr<Node>; | ||
std::string name; | ||
bool isDir = false; | ||
Node* parent; | ||
std::string fullPath; | ||
std::string originalPath; | ||
int collisionCount = 0; | ||
std::vector<Node*> children; | ||
|
||
void addChild(Node* child) | ||
{ | ||
if (child) | ||
children.push_back(child); | ||
} | ||
}; | ||
|
||
#endif |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to have a
on_windows
, or split this in two variableswith_writer
andwith_mount
.We should not link writer and mount compilation together (at least not explicitly in one variable)