agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 3a3d9770d3cdf542c3956b3468a3b3db4eda7491
parent c54832fbe8785da3c9b2bb743d16171cdbd55816
Author: Marc Coquand <marc@coquand.email>
Date:   Mon, 30 Jun 2025 12:30:02 +0100

Fix inotify bugs

Implements: https://todo.sr.ht/~marcc/agendafs/20
Closes: https://todo.sr.ht/~marcc/agendafs/19

Diffstat:
Mjournal_entry.c | 62++++++++++++++++++++++++++++++++++++++++++--------------------
Mmain.c | 35++++++++++++++++++++---------------
Mtree.c | 2+-
3 files changed, 63 insertions(+), 36 deletions(-)
diff --git a/journal_entry.c b/journal_entry.c
@@ -26,7 +26,8 @@ static const char *IS_DIRECTORY_PROPERTY = "X-CALDAVFS-ISDIRECTORY";
 // tree of journal entries
 struct tree_node *fuse_tree_root = NULL;
 
-// journal_entry
+// journal_entry, 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 tree_node *
@@ -36,6 +37,7 @@ create_file_node(struct journal_entry *entry)
 	    create_tree_node(entry, free_journal_entry);
 	return file_node;
 }
+
 struct journal_entry *
 get_entry(tree_node *node)
 {
@@ -602,6 +604,8 @@ load_journal_entries()
 				free_journal_entry(new_entry);
 				continue;
 			}
+			LOG("Inserted filename_original: %s",
+			    new_entry->filename_original);
 		}
 	}
 	closedir(dir);
@@ -1082,38 +1086,56 @@ create_directory_from_fuse_path(const char *fuse_path)
 
 // TODO: Add return status
 void
-update_or_create_fuse_entry_from_original(const char *filename)
+update_or_create_fuse_entry_from_original(const char *filepath_original)
 {
-	char *base_name = strrchr(filename, '/');
-	struct journal_entry *new_entry =
+	char *filename_original = get_filename(filepath_original);
+	LOG("Filename original is %s", filename_original);
+
+	struct journal_entry *updated_entry =
 	    xcalloc(1, sizeof(struct journal_entry));
 
-	if (load_journal_entry_from_ics_file(base_name, new_entry) != 0) {
+	if (load_journal_entry_from_ics_file(filename_original,
+					     updated_entry) != 0) {
 		// Parsing failed, clean up and maybe remove old entry
 		// if any
 		LOG("PARSING FAILED");
-		free_journal_entry(new_entry);
-		return;
-	}
-	const char *target_uuid = icalcomponent_get_uid(new_entry->component);
-	if (!target_uuid) {
 		return;
 	}
 
-	// TODO: Handle directories
-	tree_node *existing_node = get_node_by_uuid(target_uuid);
+	tree_node *new_or_updated_node =
+	    hashmap_get(entries_original_ics, filename_original);
 
-	// TODO: Enable subdirectories
-	if (existing_node) {
-		update_node_data(existing_node, new_entry);
+	if (new_or_updated_node) {
+		LOG("Updating existing entry");
+		update_node_data(new_or_updated_node, updated_entry);
 	}
 	else {
-		tree_node *new_node = create_file_node(new_entry);
-		// TODO: Look for child-parent relationship and update
-		// accordingly
-		add_child(fuse_tree_root, new_node);
+		LOG("Creating new entry");
+		new_or_updated_node = create_file_node(updated_entry);
 		hashmap_insert(entries_original_ics,
-			       new_entry->filename_original, new_node);
+			       updated_entry->filename_original,
+			       new_or_updated_node);
+	}
+
+	const char *parent_uid = get_parent_uid(updated_entry->component);
+	LOG("Looking up updated_entry %s, %s", updated_entry->filename_original,
+	    updated_entry->filename);
+	if (parent_uid) {
+		LOG("Has parent");
+		tree_node *parent = get_node_by_uuid(parent_uid);
+		if (parent) {
+			move_node(new_or_updated_node->parent, parent,
+				  new_or_updated_node);
+		}
+		else {
+			LOG("Parent not found, adding to root");
+			add_child(fuse_tree_root, new_or_updated_node);
+		}
+	}
+	else {
+		LOG("Does not have parent");
+		detach_tree_node(new_or_updated_node);
+		add_child(fuse_tree_root, new_or_updated_node);
 	}
 
 	LOG("File updated");
diff --git a/main.c b/main.c
@@ -383,7 +383,13 @@ watch_ics_dir(void *arg)
 					pthread_mutex_unlock(&entries_mutex);
 				}
 				else if (event->mask & IN_CREATE) {
-					// TODO
+					pthread_mutex_lock(&entries_mutex);
+
+					// Reload entries on any change
+					update_or_create_fuse_entry_from_original(
+					    full_path);
+
+					pthread_mutex_unlock(&entries_mutex);
 				}
 			}
 			free(full_path);
@@ -398,26 +404,25 @@ watch_ics_dir(void *arg)
 }
 
 // Ignore for now
-static int
+int
 journal_utimens(const char *path, const struct timespec tv[2],
 		struct fuse_file_info *info)
 {
 	return 0;
 }
 
-static const struct fuse_operations journal_oper = {.getattr = journal_getattr,
-						    .readdir = journal_readdir,
-						    .open = journal_open,
-						    .read = journal_read,
-						    .utimens = journal_utimens,
-						    .write = journal_write,
-						    .create = journal_create,
-						    .mkdir = journal_mkdir,
-						    .unlink = journal_unlink,
-						    .rmdir = journal_rmdir,
-						    .readlink =
-							journal_readlink,
-						    .rename = journal_rename};
+struct fuse_operations journal_oper = {.getattr = journal_getattr,
+				       .readdir = journal_readdir,
+				       .open = journal_open,
+				       .read = journal_read,
+				       .utimens = journal_utimens,
+				       .write = journal_write,
+				       .create = journal_create,
+				       .mkdir = journal_mkdir,
+				       .unlink = journal_unlink,
+				       .rmdir = journal_rmdir,
+				       .readlink = journal_readlink,
+				       .rename = journal_rename};
 
 int
 main(int argc, char *argv[])
diff --git a/tree.c b/tree.c
@@ -85,7 +85,7 @@ print_tree(tree_node *node, int depth, void (*print_data)(void *))
 bool
 detach_tree_node(tree_node *node)
 {
-	if (!node || !node->parent)
+	if (!node->parent)
 		return false;
 
 	tree_node *parent = node->parent;