Tagsistant is a program that interacts with Linux kernel using FUSE. You can imagine what happens between the kernel and Tagsistant as in the following dialogue:
Kernel: Hey tag-guy, Mr. user asked me to provide the content of /home/user/tags/t1. Do you know how to give him what he asks?
Tagsistant: Sure, let me do some SQL mumblings and I'll be back with the results [ ... something happens on DB ... ] So, here are the results.
Kernel: OK, I'm gonna pass all that to the user.
[ ... the user does something with the data ... ]
Kernel: Ehm, tag-ddicted, are you still there? The user seems to like what you gave him. Now he's asking for /home/user/tags/t1/photo.jpg.
And so on.
Saying it technically, FUSE makes writing kernel extensions a lot easier, changing the context from the kernel space into the user space. (Wow, seems sci-fi!) Usually a programmer must be a geek superhero to write a real filesystem, since his code will work inside the internals of the kernel, and doing something wrong can even lead to a full system freeze. But a FUSE filesystem is a user space program (something that runs outside the kernel). The second huge difference is that a user space filesystem can access user space libraries and services, like an SQL server, a web server and so on.
Coming back to Tagsistant, this means that, with small effort, it can store its data inside an SQL server. The 0.4 version is the first to be even able to talk to different SQL servers (SQLite and MySQL being actually supported).
In fact, each Tagsistant mounted installation has a backend called a repository. Objects are stored inside the repository directory called archive, using the underlying (and this time real) filesystem. Metadata, like tags, tagging and relations between tags, are stored inside SQL, in the tags.sql file if SQLite is used, or inside the database named tagsistant, if MySQL is used.
That's the big picture. If you are interested in internals logic, keep reading. As you will see browsing the source, Tagsistant does the major workload while managing readdir() calls, in 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:
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.