a semantic filesystem for Linux kernels
based on libfuse
How works Tagsistant?
Tagsistant is basically an application of libfuse which is a Linux (and now BSD) kernel driver and user space library which allows "non kernel programmers" to create "filesystems". Well, not exactly filesystem (meaning with filesystem the code that allows an operating system to organize data on mass storage devices). Filesystem means more properly a piece of code that play with the kernel as a kernel expects a filesystem play.
Ok, confusing. Let's simplify. With fuse you can write code that uses "normal" user space library (from libc to whatever) and performs any operation an usual application can do. But results can be sent back to kernel which will receive them as "files" and "directories".
That means that you can write a "filesystem" which uses an SQL database as its backend; or a "filesystem" which performs some processing on data before returning data to users. (To have an idea of how many usages have already been found, please refer to this page located on fuse website).
Tagsistant simply uses fuse to interface itself with the kernel, using a native filesystem tree as its storage. Inside this storage there is an archive directory which holds files and a tags.sql file which is a SQLite database describing tags (implemented as directories). Tagging a file means basically adding an entry into SQL tables to mark that file as tagged. That operation is masked by Tagsistant, when a new file is created by copying or moving it across directories. (That means that creating a symlink or doing a copy is basically the same thing for Tagsistant internals).
Fuse requires a filesystem to implement a set of functions (some are optional and some, like open() or readdir(), are mandatory). That's enough to build a new filesystem.
As you will see browsing the source, Tagsistant does little more than fuse example filesystem. The major workload is managed by readdir() function which uses code from path_resolution.c file.
When a query is issued, readdir() calls build_querytree() to create a data structure which rappresent logical query. A query can have that syntax:
Tagsistant/tag1/AND/tag2/OR/tag3
That creates a 2 nodes structure of ptree_or_node_t objects which rappresent the two branches of the query separated by the "OR" operator. Each of them is then provided with a linked list of ptree_and_node_t objects wich rappresent the tokens inside the "AND" list. So this query translate basically into:
ptree_or_node_t or1 -> ptree_and_node_t "tag1" + ptree_and_node_t "tag2"
+
ptree_or_node_t or2 -> ptree_and_node_t "tag3"
That kind of list can be processed by build_filetree() which searches for files matching the query structure returned by build_querytree().
After list of all files has been created, readdir() can return files to kernel, and kernel to user's ls command or file manager.
Creating a tag inside Tagsistant is as simple as creating a new directory. Tagging a file is as simple as copying or moving a file inside a directory.
(tagfs)




