agendafs
A filesystem for your calendar.
git clone git://mccd.space/agendafscommit 0febeb19faf0280117d45362f41df0ec81070ec8
parent 207e596113d7f00d584a63adb10ad39a4fa9ae89
Author: Marc Coquand <marc@coquand.email>
Date: Wed, 23 Jul 2025 20:24:24 +0200
original -> vdir
Closes: https://todo.sr.ht/~marcc/agendafs/24
Diffstat:
3 files changed, 67 insertions(+), 79 deletions(-)
diff --git a/agenda_entry.c b/agenda_entry.c
@@ -20,7 +20,7 @@
#include <wordexp.h>
const char *IS_DIRECTORY_PROPERTY = "X-CALDAVFS-ISDIRECTORY";
-char ICS_DIR[256];
+char VDIR[256];
// Most memory is managed by memory_region, two exceptions are the
// global states fuse_root and entries_original_ics, which manages its own
@@ -30,7 +30,7 @@ char ICS_DIR[256];
struct tree_node *fuse_root = NULL;
// ics entries, keys are the filename as stored in ICS_DIR
// I.E. bcb4c14b-8f3f-4a53-ad33-1f4499071a9m-caldavfs.ics
-struct hashmap *entries_original_ics = NULL;
+struct hashmap *entries_vdir = NULL;
struct agenda_entry *
copy_agenda_entry(const struct agenda_entry *src)
@@ -41,7 +41,7 @@ copy_agenda_entry(const struct agenda_entry *src)
}
struct agenda_entry *copy = xmalloc(sizeof(struct agenda_entry));
copy->filename = xstrdup(src->filename);
- copy->filename_original = xstrdup(src->filename_original);
+ copy->filename_vdir = xstrdup(src->filename_vdir);
copy->gid = src->gid;
copy->uid = src->uid;
copy->ino = src->ino;
@@ -55,8 +55,8 @@ free_agenda_entry(struct agenda_entry *entry)
return;
if (entry->filename)
free(entry->filename);
- if (entry->filename_original)
- free(entry->filename_original);
+ if (entry->filename_vdir)
+ free(entry->filename_vdir);
free(entry);
return;
}
@@ -64,18 +64,16 @@ free_agenda_entry(struct agenda_entry *entry)
struct tree_node *
get_node_by_uuid(memory_region *mreg, const char *target_uuid)
{
- char *filename_original = NULL;
+ char *filename_vdir = NULL;
// Filenames are uid.ics, so we levarage that
- size_t wRes =
- rasprintf(mreg, &filename_original, "%s.ics", target_uuid);
+ size_t wRes = rasprintf(mreg, &filename_vdir, "%s.ics", target_uuid);
assert(wRes != -1);
LOG("Looking for UID: '%s'", target_uuid);
- LOG("Full filename: '%s'", filename_original);
+ LOG("Full filename: '%s'", filename_vdir);
- struct tree_node *node =
- hashmap_get(entries_original_ics, filename_original);
+ struct tree_node *node = hashmap_get(entries_vdir, filename_vdir);
LOG("Found it: %b", node != NULL);
return node;
@@ -190,10 +188,10 @@ get_entry(const struct tree_node *node)
}
char *
-get_original_filepath(memory_region *mreg, const struct tree_node *node)
+get_vdir_filepath(memory_region *mreg, const struct tree_node *node)
{
struct agenda_entry *entry = get_entry(node);
- return append_path(mreg, ICS_DIR, entry->filename_original);
+ return append_path(mreg, VDIR, entry->filename_vdir);
}
// Owner: ctx
@@ -255,7 +253,7 @@ write_ical_file(memory_region *mreg, const struct tree_node *node,
char *ical_str = ricalcomponent_as_ical_string_r(mreg, ic);
- int res = write_to_file(get_original_filepath(mreg, node), ical_str);
+ int res = write_to_file(get_vdir_filepath(mreg, node), ical_str);
return res;
}
@@ -268,7 +266,7 @@ get_icalcomponent_from_node(memory_region *mreg, const struct tree_node *n)
return NULL;
}
- char *orig_path = get_original_filepath(mreg, n);
+ char *orig_path = get_vdir_filepath(mreg, n);
// TODO: Cache intermediate results within context
icalcomponent *ic = parse_ics_file(mreg, orig_path);
return ic;
@@ -406,7 +404,7 @@ parse_ics_to_agenda_entry(memory_region *mreg, const char *filepath)
e->filename = xstrdup(icalcomponent_get_summary(component));
- e->filename_original = xstrdup(get_filename(filepath));
+ e->filename_vdir = xstrdup(get_filename(filepath));
return e;
}
@@ -416,7 +414,7 @@ parse_ics_to_agenda_entry(memory_region *mreg, const char *filepath)
struct agenda_entry *
load_agenda_entry_from_ics_file(memory_region *mreg, const char *filename)
{
- path *filepath = append_path(mreg, ICS_DIR, filename);
+ path *filepath = append_path(mreg, VDIR, filename);
LOG("Filepath is %s", filepath);
struct stat fileStat;
@@ -437,7 +435,7 @@ load_agenda_entry_from_ics_file(memory_region *mreg, const char *filename)
new_entry->gid = fileStat.st_gid;
new_entry->ino = fileStat.st_ino;
- LOG("Parsed %s to file %s", new_entry->filename_original,
+ LOG("Parsed %s to file %s", new_entry->filename_vdir,
new_entry->filename);
return new_entry;
}
@@ -445,12 +443,12 @@ load_agenda_entry_from_ics_file(memory_region *mreg, const char *filename)
void
load_root_node_tree()
{
- entries_original_ics = hashmap_new(NULL);
+ entries_vdir = hashmap_new(NULL);
fuse_root = create_tree_node(NULL, NULL);
memory_region *mreg = create_region();
- LOG("Loading journal entries from: %s\n", ICS_DIR);
+ LOG("Loading journal entries from: %s\n", VDIR);
- DIR *dir = opendir(ICS_DIR);
+ DIR *dir = opendir(VDIR);
if (!dir) {
perror("opendir");
return;
@@ -475,23 +473,21 @@ load_root_node_tree()
struct tree_node *new_node = create_tree_node(
owned_entry, (void *)free_agenda_entry);
- hashmap_insert(entries_original_ics,
- new_entry->filename_original, new_node);
+ hashmap_insert(entries_vdir, new_entry->filename_vdir,
+ new_node);
- LOG("Inserted filename_original: %s, %s",
- owned_entry->filename,
- owned_entry->filename_original);
+ LOG("Inserted filename_vdir: %s, %s",
+ owned_entry->filename, owned_entry->filename_vdir);
}
}
closedir(dir);
LOG("Set up directories according to parent-child");
size_t n_keys = 0;
- char **keys = hashmap_get_keys(entries_original_ics, &n_keys);
+ char **keys = hashmap_get_keys(entries_vdir, &n_keys);
for (size_t i = 0; i < n_keys; i++) {
const char *filename = keys[i];
- struct tree_node *child =
- hashmap_get(entries_original_ics, filename);
+ struct tree_node *child = hashmap_get(entries_vdir, filename);
LOG("Parsing %s", filename);
icalcomponent *ic = get_icalcomponent_from_node(mreg, child);
@@ -500,7 +496,7 @@ load_root_node_tree()
struct agenda_entry *entry = get_entry(child);
const char *parent_uid = get_parent_uid(ic);
- LOG("Looking up entry %s, %s", entry->filename_original,
+ LOG("Looking up entry %s, %s", entry->filename_vdir,
entry->filename);
if (parent_uid) {
LOG("Has parent");
@@ -534,10 +530,10 @@ load_root_node_tree()
}
size_t
-load_agendafs_environment(char *ics_dir_env)
+load_agendafs_environment(char *vdir_env)
{
wordexp_t expanded;
- if (wordexp(ics_dir_env, &expanded, 0) != 0 || expanded.we_wordc == 0) {
+ if (wordexp(vdir_env, &expanded, 0) != 0 || expanded.we_wordc == 0) {
fprintf(stderr, "Failed to expand CALDAVFS_ICS_DIR\n");
wordfree(&expanded);
return -1;
@@ -547,7 +543,7 @@ load_agendafs_environment(char *ics_dir_env)
struct stat s;
if (stat(expanded_path, &s) == 0 && S_ISDIR(s.st_mode)) {
- strlcpy(ICS_DIR, expanded_path, sizeof(ICS_DIR));
+ strlcpy(VDIR, expanded_path, sizeof(VDIR));
wordfree(&expanded);
return 0;
}
@@ -903,7 +899,7 @@ create_entry_from_fuse(memory_region *mreg, const char *fuse_path)
create_vjournal_entry(mreg, new_basename);
new_entry->filename = xstrdup(new_basename);
- if (asprintf(&new_entry->filename_original, "%s.ics",
+ if (asprintf(&new_entry->filename_vdir, "%s.ics",
icalcomponent_get_uid(new_component)) == -1) {
LOG("Failed to create journal entry");
free_agenda_entry(new_entry);
@@ -936,13 +932,11 @@ create_entry_from_fuse(memory_region *mreg, const char *fuse_path)
add_child(parent, new_node);
}
- hashmap_insert(entries_original_ics, new_entry->filename_original,
- new_node);
+ hashmap_insert(entries_vdir, new_entry->filename_vdir, new_node);
if (write_ical_file(mreg, new_node, new_component) != 0) {
LOG("Write to entry failed");
- hashmap_remove(entries_original_ics,
- new_entry->filename_original);
+ hashmap_remove(entries_vdir, new_entry->filename_vdir);
free_tree(new_node);
return -EIO;
@@ -968,7 +962,7 @@ create_directory_from_fuse_path(memory_region *mreg, const char *fuse_path)
create_vjournal_directory(mreg, new_basename);
new_entry->filename = xstrdup(new_basename);
- if (asprintf(&new_entry->filename_original, "%s.ics",
+ if (asprintf(&new_entry->filename_vdir, "%s.ics",
icalcomponent_get_uid(new_component)) == -1) {
LOG("Failed to create journal entry");
free_agenda_entry(new_entry);
@@ -1001,13 +995,11 @@ create_directory_from_fuse_path(memory_region *mreg, const char *fuse_path)
add_child(parent, new_node);
}
- hashmap_insert(entries_original_ics, new_entry->filename_original,
- new_node);
+ hashmap_insert(entries_vdir, new_entry->filename_vdir, new_node);
if (write_ical_file(mreg, new_node, new_component) != 0) {
LOG("Write to entry failed");
- hashmap_remove(entries_original_ics,
- new_entry->filename_original);
+ hashmap_remove(entries_vdir, new_entry->filename_vdir);
free_tree(new_node);
return -EIO;
@@ -1018,20 +1010,20 @@ create_directory_from_fuse_path(memory_region *mreg, const char *fuse_path)
}
void
-update_or_create_fuse_entry_from_original(memory_region *mreg,
- const char *filepath_original)
+update_or_create_fuse_entry_from_vdir(memory_region *mreg,
+ const char *filepath_vdir)
{
- const char *filename_original = get_filename(filepath_original);
- LOG("Filename original is %s", filename_original);
+ const char *filename_vdir = get_filename(filepath_vdir);
+ LOG("Filename original is %s", filename_vdir);
struct agenda_entry *updated_entry =
- load_agenda_entry_from_ics_file(mreg, filename_original);
+ load_agenda_entry_from_ics_file(mreg, filename_vdir);
struct agenda_entry *updated_entry_owned =
copy_agenda_entry(updated_entry);
struct tree_node *new_or_updated_node =
- hashmap_get(entries_original_ics, filename_original);
+ hashmap_get(entries_vdir, filename_vdir);
if (new_or_updated_node) {
LOG("Updating existing entry");
@@ -1041,8 +1033,7 @@ update_or_create_fuse_entry_from_original(memory_region *mreg,
LOG("Creating new entry");
new_or_updated_node = create_tree_node(
updated_entry_owned, (void *)free_agenda_entry);
- hashmap_insert(entries_original_ics,
- updated_entry_owned->filename_original,
+ hashmap_insert(entries_vdir, updated_entry_owned->filename_vdir,
new_or_updated_node);
}
@@ -1083,7 +1074,7 @@ delete_dir_from_fuse_path(memory_region *mreg, const char *filepath)
return -ENOTEMPTY;
}
- char *filepath_original = get_original_filepath(mreg, node);
+ char *filepath_original = get_vdir_filepath(mreg, node);
if (!filepath_original) {
LOG("Entry not found");
return -EIO;
@@ -1096,7 +1087,7 @@ delete_dir_from_fuse_path(memory_region *mreg, const char *filepath)
return -res;
}
- hashmap_remove(entries_original_ics, filepath_original);
+ hashmap_remove(entries_vdir, filepath_original);
detach_tree_node(node);
free_tree(node);
@@ -1178,7 +1169,7 @@ delete_from_fuse_path(memory_region *mreg, const char *filepath)
if (node_is_directory(mreg, node, node_ics)) {
return -EISDIR;
}
- char *filepath_original = get_original_filepath(mreg, node);
+ char *filepath_original = get_vdir_filepath(mreg, node);
LOG("Deleting file %s, located at %s", filepath, filepath_original);
@@ -1187,7 +1178,7 @@ delete_from_fuse_path(memory_region *mreg, const char *filepath)
return -EIO;
}
- hashmap_remove(entries_original_ics, filepath_original);
+ hashmap_remove(entries_vdir, filepath_original);
detach_tree_node(node);
free_tree(node);
return res;
@@ -1226,10 +1217,10 @@ get_node_path(memory_region *mreg, struct tree_node *node)
}
char *
-get_fuse_path_from_original(memory_region *mreg, const char *filepath)
+get_fuse_path_from_vdir(memory_region *mreg, const char *filepath)
{
struct tree_node *node =
- hashmap_get(entries_original_ics, get_filename(filepath));
+ hashmap_get(entries_vdir, get_filename(filepath));
if (node) {
return get_node_path(mreg, node);
@@ -1238,11 +1229,11 @@ get_fuse_path_from_original(memory_region *mreg, const char *filepath)
}
int
-delete_from_original_path(memory_region *mreg, const char *filepath)
+delete_from_vdir_path(memory_region *mreg, const char *filepath)
{
// Strip path, validate just the new basename
const char *keyname = get_filename(filepath);
- struct agenda_entry *entry = hashmap_get(entries_original_ics, keyname);
+ struct agenda_entry *entry = hashmap_get(entries_vdir, keyname);
if (!entry) {
return -EIO;
}
@@ -1256,6 +1247,6 @@ delete_from_original_path(memory_region *mreg, const char *filepath)
// Requires a change_parent function.
detach_tree_node(node);
free_tree(node);
- hashmap_remove(entries_original_ics, keyname);
+ hashmap_remove(entries_vdir, keyname);
return 0;
}
diff --git a/agenda_entry.h b/agenda_entry.h
@@ -27,13 +27,13 @@ struct agenda_entry {
char *filename;
// filename_original is the relative path to ICS_DIR
// I.E. 910319208nrao19p.ics
- char *filename_original;
+ char *filename_vdir;
uid_t uid;
gid_t gid;
ino_t ino;
};
-extern char ICS_DIR[256];
+extern char VDIR[256];
extern const char *IS_DIRECTORY_PROPERTY;
@@ -41,7 +41,7 @@ extern const char *IS_DIRECTORY_PROPERTY;
extern struct tree_node *fuse_root;
// ics entries, keys are the filename as stored in ICS_DIR
// I.E. bcb4c14b-8f3f-4a53-ad33-1f4499071a9m-caldavfs.ics
-extern struct hashmap *entries_original_ics;
+extern struct hashmap *entries_vdir;
struct agenda_entry *
copy_agenda_entry(const struct agenda_entry *src);
@@ -72,7 +72,7 @@ struct agenda_entry *
get_entry(const struct tree_node *node);
char *
-get_original_filepath(memory_region *mreg, const struct tree_node *node);
+get_vdir_filepath(memory_region *mreg, const struct tree_node *node);
// Owner: ctx
icalcomponent *
@@ -130,7 +130,7 @@ void
load_root_node_tree();
size_t
-load_agendafs_environment(char *ics_dir_env);
+load_agendafs_environment(char *);
// Returns comma separated list of categories for a file
char *
@@ -164,7 +164,7 @@ create_new_unique_ics_uid(memory_region *mreg);
ino_t
get_node_ino(const struct tree_node *node);
char *
-get_fuse_path_from_original(memory_region *mreg, const char *filepath);
+get_fuse_path_from_vdir(memory_region *mreg, const char *filepath);
icalcomponent *
create_vjournal_entry(memory_region *mreg, const char *summary);
@@ -190,8 +190,7 @@ int
create_directory_from_fuse_path(memory_region *mreg, const char *fuse_path);
void
-update_or_create_fuse_entry_from_original(memory_region *mreg,
- const char *filepath_original);
+update_or_create_fuse_entry_from_vdir(memory_region *, const char *);
int
delete_dir_from_fuse_path(memory_region *mreg, const char *filepath);
@@ -203,5 +202,6 @@ int
delete_from_fuse_path(memory_region *mreg, const char *filepath);
int
-delete_from_original_path(memory_region *mreg, const char *filepath);
+delete_from_vdir_path(memory_region *mreg, const char *filepath);
#endif // agenda_entry_h_INCLUDED
+
diff --git a/main.c b/main.c
@@ -27,8 +27,6 @@
// Listening to file changes of the original content
#define EVENT_BUF_LEN (1024 * (sizeof(struct inotify_event) + 16))
-static struct fuse *fuse_instance = NULL;
-static struct fuse_session *session = NULL;
static pthread_mutex_t entries_mutex = PTHREAD_MUTEX_INITIALIZER;
static int
@@ -81,7 +79,7 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
stbuf->st_nlink = 1;
}
- char *full_disk_path = get_original_filepath(mreg, node);
+ char *full_disk_path = get_vdir_filepath(mreg, node);
struct stat disk_stat;
if (stat(full_disk_path, &disk_stat) == 0) {
stbuf->st_mtime = disk_stat.st_mtime;
@@ -540,18 +538,18 @@ handle_ics_event(struct inotify_event *event)
LOG("Detected change in ICS file: %s\n", event->name);
char *full_path = NULL;
- rasprintf(mreg, &full_path, "%s/%s", ICS_DIR, event->name);
+ rasprintf(mreg, &full_path, "%s/%s", VDIR, event->name);
if (event->mask & IN_DELETE) {
- delete_from_original_path(mreg, full_path);
+ delete_from_vdir_path(mreg, full_path);
}
else if (event->mask & IN_MODIFY) {
LOG("RUNNING IN_MODIFY HOOK");
- update_or_create_fuse_entry_from_original(mreg, full_path);
+ update_or_create_fuse_entry_from_vdir(mreg, full_path);
}
else if (event->mask & IN_CREATE) {
LOG("RUNNING IN_CREATE HOOK");
- update_or_create_fuse_entry_from_original(mreg, full_path);
+ update_or_create_fuse_entry_from_vdir(mreg, full_path);
}
pthread_mutex_unlock(&entries_mutex);
@@ -564,8 +562,7 @@ watch_ics_dir(void *arg)
int fd = inotify_init1(IN_NONBLOCK);
assert(fd >= 0);
- int wd =
- inotify_add_watch(fd, ICS_DIR, IN_CREATE | IN_MODIFY | IN_DELETE);
+ int wd = inotify_add_watch(fd, VDIR, IN_CREATE | IN_MODIFY | IN_DELETE);
assert(wd >= 0);
char buffer[EVENT_BUF_LEN];
@@ -706,7 +703,7 @@ main(int argc, char *argv[])
pthread_join(watcher_thread, NULL);
LOG("Pthread freed");
- hashmap_free(entries_original_ics);
+ hashmap_free(entries_vdir);
free_tree(fuse_root);
LOG("Hashmap and tree freed");