agendafs
A filesystem for your calendar.
git clone git://mccd.space/agendafscommit a1671013c01a9540c78910e978f23c9f4df5da82
parent 0687368b70be16eb0593c1de843686501db9ee69
Author: Marc Coquand <marc@coquand.email>
Date: Thu, 5 Jun 2025 21:08:42 +0100
Add a today directory with summary as title
Diffstat:
| M | main.c | | | 140 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
1 file changed, 82 insertions(+), 58 deletions(-)
diff --git a/main.c b/main.c
@@ -42,8 +42,14 @@ typedef struct {
} journal_entry;
// We create two maps that link to the same entries
-struct hashmap *entries_fuse_key = NULL;
-struct hashmap *entries_original_key = NULL;
+// journal_entry
+struct hashmap *entries_fuse = NULL;
+
+// journal_entry
+struct hashmap *entries_original_ics = NULL;
+
+// string -> string
+struct hashmap *entries_today = NULL;
static pthread_mutex_t entries_mutex = PTHREAD_MUTEX_INITIALIZER;
icaltimetype
@@ -113,7 +119,7 @@ get_entry_from_fuse_path(const char *path)
}
LOG("Looking up key: '%s'\n", key);
- journal_entry *entry = hashmap_get(entries_fuse_key, key);
+ journal_entry *entry = hashmap_get(entries_fuse, key);
if (!entry) {
LOG("No entry found for key: '%s'\n", key);
@@ -233,8 +239,8 @@ load_journal_entries()
{
pthread_mutex_lock(&entries_mutex);
- entries_original_key = hashmap_new(NULL);
- entries_fuse_key = hashmap_new(free_journal_entry);
+ entries_original_ics = hashmap_new(NULL);
+ entries_fuse = hashmap_new(free_journal_entry);
LOG("Loading journal entries from: %s\n", ICS_DIR);
@@ -257,10 +263,9 @@ load_journal_entries()
continue;
}
- if (hashmap_insert(entries_fuse_key,
- new_entry->filename,
+ if (hashmap_insert(entries_fuse, new_entry->filename,
new_entry) != 0 ||
- hashmap_insert(entries_original_key,
+ hashmap_insert(entries_original_ics,
new_entry->filename_original,
new_entry) != 0) {
LOG("Failed to insert entry");
@@ -348,16 +353,8 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
const char *today_prefix = "/today/";
if (strncmp(path, today_prefix, strlen(today_prefix)) == 0) {
const char *key = path + strlen(today_prefix);
- journal_entry *entry = hashmap_get(entries_fuse_key, key);
-
- if (!entry) {
- ret_code = -ENOENT;
- goto unlock_and_return;
- }
-
- icalcomponent *component = entry->component;
- struct icaltimetype dt = icalcomponent_get_dtstamp(component);
- if (icaltime_compare_date_only(dt, icaltime_today()) != 0) {
+ char *entry_filename = hashmap_get(entries_today, key);
+ if (!entry_filename) {
ret_code = -ENOENT;
goto unlock_and_return;
}
@@ -405,19 +402,62 @@ journal_readlink(const char *path, char *buf, size_t size)
pthread_mutex_lock(&entries_mutex);
const char *key = path + strlen(today_prefix);
LOG("Lookup %s", key);
- journal_entry *entry = hashmap_get(entries_fuse_key, key);
+ char *link = hashmap_get(entries_today, key);
- if (!entry)
+ if (!link) {
+ LOG("Link not found for %s", key);
return -ENOENT;
+ }
+ LOG("Link found %s", link);
// Return symlink target
- snprintf(buf, size, "../entries/%s", key);
+ snprintf(buf, size, "%s", link);
pthread_mutex_unlock(&entries_mutex);
return 0;
}
return -ENOENT;
}
+
+int
+buildTodayHashmap()
+{
+ hashmap_free(entries_today);
+ entries_today = hashmap_new(free);
+
+ size_t n_keys = 0;
+ char **keys = hashmap_get_keys(entries_fuse, &n_keys);
+ if (!keys) {
+ return -ENOMEM;
+ }
+
+ for (size_t i = 0; i < n_keys; i++) {
+ journal_entry *entry = hashmap_get(entries_fuse, keys[i]);
+ if (!entry)
+ continue;
+
+ // Get the dtstamp of the first icalcomponent
+ icalcomponent *component = entry->component;
+ if (!component)
+ continue;
+
+ struct icaltimetype dt = icalcomponent_get_dtstamp(component);
+
+ if (icaltime_compare_date_only(dt, icaltime_today()) == 0) {
+ char *filename =
+ strdup(icalcomponent_get_summary(component));
+ char *dest;
+ if (asprintf(&dest, "../entries/%s", entry->filename) ==
+ -1)
+ return -ENOMEM;
+ hashmap_insert(entries_today, filename, dest);
+ }
+ }
+
+ hashmap_free_keys(keys, n_keys);
+ return 0;
+}
+
int
journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
@@ -436,7 +476,7 @@ journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
}
else if (strcmp(path, "/entries") == 0) {
size_t n_keys = 0;
- char **keys = hashmap_get_keys(entries_fuse_key, &n_keys);
+ char **keys = hashmap_get_keys(entries_fuse, &n_keys);
if (!keys) {
pthread_mutex_unlock(&entries_mutex);
return -ENOMEM;
@@ -450,30 +490,13 @@ journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
}
else if (strcmp(path, "/today") == 0) {
size_t n_keys = 0;
- char **keys = hashmap_get_keys(entries_fuse_key, &n_keys);
+ buildTodayHashmap();
+ char **keys = hashmap_get_keys(entries_today, &n_keys);
if (!keys) {
- pthread_mutex_unlock(&entries_mutex);
return -ENOMEM;
}
-
for (size_t i = 0; i < n_keys; i++) {
- journal_entry *entry =
- hashmap_get(entries_fuse_key, keys[i]);
- if (!entry)
- continue;
-
- // Get the dtstamp of the first icalcomponent
- icalcomponent *component = entry->component;
- if (!component)
- continue;
-
- struct icaltimetype dt =
- icalcomponent_get_dtstamp(component);
-
- if (icaltime_compare_date_only(dt, icaltime_today()) ==
- 0) {
- filler(buf, keys[i], NULL, 0, 0);
- }
+ filler(buf, keys[i], NULL, 0, 0);
}
hashmap_free_keys(keys, n_keys);
@@ -691,7 +714,7 @@ do_journal_entry_rename(time_t new_created_at, const char *old, const char *new)
const char *new_basename = strrchr(new, '/');
new_basename = new_basename + 1;
- journal_entry *old_entry = hashmap_get(entries_fuse_key, old_basename);
+ journal_entry *old_entry = hashmap_get(entries_fuse, old_basename);
if (!old_entry) {
LOG("Entry does not exist");
return -EINVAL;
@@ -705,13 +728,13 @@ do_journal_entry_rename(time_t new_created_at, const char *old, const char *new)
icalcomponent_set_dtstamp(new_entry->component, created_at_ical);
- hashmap_remove(entries_original_key, old_entry->filename_original);
+ hashmap_remove(entries_original_ics, old_entry->filename_original);
// remove handles freeing here
- hashmap_remove(entries_fuse_key, old_entry->filename);
+ hashmap_remove(entries_fuse, old_entry->filename);
- hashmap_insert(entries_original_key, new_entry->filename_original,
+ hashmap_insert(entries_original_ics, new_entry->filename_original,
new_entry);
- hashmap_insert(entries_fuse_key, new_entry->filename, new_entry);
+ hashmap_insert(entries_fuse, new_entry->filename, new_entry);
if (write_entry_to_ical_file(new_entry) != 0) {
return -EIO;
@@ -732,7 +755,7 @@ journal_unlink(const char *file)
const char *keyname = strrchr(file, '/');
keyname++;
- journal_entry *entry = hashmap_get(entries_fuse_key, keyname);
+ journal_entry *entry = hashmap_get(entries_fuse, keyname);
if (!entry) {
LOG("Entry does not exist");
pthread_mutex_unlock(&entries_mutex);
@@ -757,9 +780,9 @@ journal_unlink(const char *file)
return -EIO;
}
- hashmap_remove(entries_original_key, keyname);
+ hashmap_remove(entries_original_ics, keyname);
// Frees
- hashmap_remove(entries_fuse_key, keyname);
+ hashmap_remove(entries_fuse, keyname);
free(filepath);
LOG("Delete successful");
@@ -864,9 +887,9 @@ journal_create(const char *filename, mode_t mode, struct fuse_file_info *info)
}
LOG("Inserting vjournal entry");
- hashmap_insert(entries_original_key, new_entry->filename_original,
+ hashmap_insert(entries_original_ics, new_entry->filename_original,
new_entry);
- hashmap_insert(entries_fuse_key, new_entry->filename, new_entry);
+ hashmap_insert(entries_fuse, new_entry->filename, new_entry);
// Write back to the original
char *filepath = get_original_filepath(new_entry);
@@ -903,9 +926,9 @@ update_or_create_fuse_entry_from_original(const char *filename)
pthread_mutex_unlock(&entries_mutex);
return;
- hashmap_insert(entries_original_key, new_entry->filename_original,
+ hashmap_insert(entries_original_ics, new_entry->filename_original,
new_entry);
- hashmap_insert(entries_fuse_key, new_entry->filename, new_entry);
+ hashmap_insert(entries_fuse, new_entry->filename, new_entry);
LOG("File updated");
@@ -920,9 +943,9 @@ update_fuse_entry_delete(const char *file)
const char *keyname = strrchr(file, '/');
keyname++;
LOG("Found entry to delete");
- hashmap_remove(entries_original_key, keyname);
+ hashmap_remove(entries_original_ics, keyname);
// Frees
- hashmap_remove(entries_fuse_key, keyname);
+ hashmap_remove(entries_fuse, keyname);
pthread_mutex_unlock(&entries_mutex);
return 0;
}
@@ -1079,8 +1102,9 @@ main(int argc, char *argv[])
pthread_join(watcher_thread, NULL); // Clean up
LOG("Pthread freed");
- hashmap_free(entries_fuse_key);
- hashmap_free(entries_original_key);
+ hashmap_free(entries_fuse);
+ hashmap_free(entries_original_ics);
+ hashmap_free(entries_today);
LOG("Hashmap freed");
regfree(®ex_fuse_file);