agendafs
A filesystem for your calendar.
git clone git://mccd.space/agendafscommit 94f608109c357719f8016b33c4177b32f32731a3
parent ebde89072fc4eede36efd1ed68c850890b4de89d
Author: Marc Coquand <marc@coquand.email>
Date: Thu, 10 Jul 2025 10:46:06 +0200
Add setxattr for user categories
References: https://todo.sr.ht/~marcc/agendafs/1
Diffstat:
| M | journal_entry.c | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | journal_entry.h | | | 6 | ++++++ |
| M | main.c | | | 68 | +++++++++++++++++++++++++++++++++++++++++++++----------------------- |
3 files changed, 112 insertions(+), 23 deletions(-)
diff --git a/journal_entry.c b/journal_entry.c
@@ -784,6 +784,67 @@ get_node_categories(const struct tree_node *node)
return result_buffer;
}
+int
+delete_node_categories(const struct tree_node *node)
+{
+ const struct journal_entry *entry = node->data;
+ if (!entry) {
+ return -ENOENT;
+ }
+
+ icalcomponent *inner = icalcomponent_get_inner(entry->component);
+
+ icalproperty *catp =
+ icalcomponent_get_first_property(inner, ICAL_CATEGORIES_PROPERTY);
+
+ // Delete old categories
+ while (catp) {
+ icalcomponent_remove_property(inner, catp);
+
+ catp = icalcomponent_get_next_property(
+ inner, ICAL_CATEGORIES_PROPERTY);
+ }
+
+ return write_entry_to_ical_file(entry);
+}
+
+int
+set_node_categories(const struct tree_node *node, const char *new_categories,
+ size_t s)
+{
+ const struct journal_entry *entry = node->data;
+ if (!entry) {
+ return -ENOENT;
+ }
+
+ icalcomponent *inner = icalcomponent_get_inner(entry->component);
+
+ icalproperty *catp =
+ icalcomponent_get_first_property(inner, ICAL_CATEGORIES_PROPERTY);
+
+ // Delete old categories
+ while (catp) {
+ icalcomponent_remove_property(inner, catp);
+
+ catp = icalcomponent_get_next_property(
+ inner, ICAL_CATEGORIES_PROPERTY);
+ }
+
+ if (s == 0) {
+ return write_entry_to_ical_file(entry);
+ }
+
+ char *null_terminated_categories = xmalloc(s + 1);
+ strncpy(null_terminated_categories, new_categories, s);
+ null_terminated_categories[s] = '\0';
+
+ icalproperty *new_cat_prop =
+ icalproperty_new_categories(null_terminated_categories);
+ icalcomponent_add_property(inner, new_cat_prop);
+
+ return write_entry_to_ical_file(entry);
+}
+
size_t
write_entry_to_ical_file(const struct journal_entry *entry)
{
diff --git a/journal_entry.h b/journal_entry.h
@@ -140,6 +140,12 @@ const char *
get_node_categories(const struct tree_node *);
int
+delete_node_categories(const struct tree_node *);
+
+int
+set_node_categories(const struct tree_node *, const char *, size_t s);
+
+int
build_notes_hashmap();
size_t
diff --git a/main.c b/main.c
@@ -326,6 +326,50 @@ journal_create(const char *filename, mode_t mode, struct fuse_file_info *info)
return 0;
}
+static int
+journal_setxattr(const char *path, const char *header,
+ const char *new_attributes, size_t s, int flags)
+{
+ LOG("SETXATTR '%s' '%s' '%zu' '%s' '%d'", path, header, s,
+ new_attributes, flags);
+
+ if (strcmp(header, "user.categories") != 0) {
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&entries_mutex);
+ struct tree_node *node = get_node_by_path(path);
+ int status = set_node_categories(node, new_attributes, s);
+ pthread_mutex_unlock(&entries_mutex);
+
+ return status;
+}
+
+static int
+journal_getxattr(const char *path, const char *header, char *buf, size_t s)
+{
+ LOG("GETXATTR '%s' '%s' '%zu'\n", path, header, s);
+
+ if (strcmp(header, "user.categories") != 0) {
+ return -ENODATA;
+ }
+
+ pthread_mutex_lock(&entries_mutex);
+ struct tree_node *node = get_node_by_path(path);
+
+ const char *cats = get_node_categories(node);
+ pthread_mutex_unlock(&entries_mutex);
+
+ int string_len = strlen(cats);
+
+ // If s == 0 we don't need to write, just return size to allocate
+ if (s > 0) {
+ snprintf(buf, s, "%s", cats);
+ }
+
+ return string_len;
+}
+
static void *
watch_ics_dir(void *arg)
{
@@ -414,29 +458,6 @@ journal_utimens(const char *path, const struct timespec tv[2],
return 0;
}
-static int
-journal_getxattr(const char *path, const char *header, char *buf, size_t s)
-{
- LOG("GETXATTR '%s' '%s' '%zu'\n", path, header, s);
-
- if (strcmp(header, "user.categories") != 0) {
- return -ENODATA;
- }
-
- struct tree_node *node = get_node_by_path(path);
-
- const char *cats = get_node_categories(node);
-
- int string_len = strlen(cats);
-
- // If s == 0 we don't need to write, just return size to allocate
- if (s > 0) {
- snprintf(buf, s, "%s", cats);
- }
-
- return string_len;
-}
-
struct fuse_operations journal_oper = {.getattr = journal_getattr,
.readdir = journal_readdir,
.open = journal_open,
@@ -447,6 +468,7 @@ struct fuse_operations journal_oper = {.getattr = journal_getattr,
.mkdir = journal_mkdir,
.unlink = journal_unlink,
.getxattr = journal_getxattr,
+ .setxattr = journal_setxattr,
.rmdir = journal_rmdir,
.readlink = journal_readlink,
.rename = journal_rename};