agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 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:
Magenda_entry.c | 111++++++++++++++++++++++++++++++++++++-------------------------------------------
Magenda_entry.h | 18+++++++++---------
Mmain.c | 17+++++++----------
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");