agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit c158ec9753686e842b29e6dc7a73ffdde4a2115e
parent e4dd4497aaf9dd976bb478ebd51f276b0d7d4854
Author: Marc Coquand <marc@coquand.email>
Date:   Fri,  1 Aug 2025 17:17:38 +0200

Display uid in xattributes

Diffstat:
Magendafs.8.scd | 11+++++++++--
Mmain.c | 24++++++++++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/agendafs.8.scd b/agendafs.8.scd
@@ -39,9 +39,16 @@ usage. Built-in extended attributes are:
 	The classification of an entry. Can be either *public*,
 	*private* or *confidential*. By default classification is set to
 	*private*.
+	
+*user.sibling*
+	Reserved for the future.
 
-Arbitrary user-provided attributes are also supported. Limits are set
-to 255 bytes and 64 kilobytes for attributes and value respectively.
+*user.uid*
+	Immutable. The underlying UUID for the file. In the future, this
+	can be used to reference notes with *user.sibling*.
+
+Arbitrary user-provided attributes are also supported. Limits are set to
+255 bytes for attributes and 64 kilobytes for their value.
 
 # FILE PERMISSIONS
 
diff --git a/main.c b/main.c
@@ -425,6 +425,16 @@ fuse_setxattr(const char *path, const char *attribute, const char *value,
 		goto cleanup_return;
 	}
 
+	if (strcmp(attribute, "user.uid") == 0) {
+		status = -EPERM;
+		goto cleanup_return;
+	}
+
+	if (strcmp(attribute, "user.sibling") == 0) {
+		status = -EPERM;
+		goto cleanup_return;
+	}
+
 	if (strcmp(attribute, "user.categories") == 0) {
 		status = set_node_categories(mreg, node, value, s);
 		goto cleanup_return;
@@ -493,6 +503,10 @@ fuse_listxattr(const char *path, char *list, size_t size)
 		fputc('\0', stream);
 	}
 
+	// All notes have a uid
+	fprintf(stream, "user.uid");
+	fputc('\0', stream);
+
 	const char *iclass = get_node_class(mreg, node);
 	if (iclass != NULL && strcmp("", iclass) != 0) {
 		fprintf(stream, "user.class");
@@ -555,6 +569,16 @@ fuse_getxattr(const char *path, const char *attribute, char *buf, size_t s)
 		status = string_len;
 		goto cleanup_return;
 	}
+	if (strcmp(attribute, "user.uid") == 0) {
+		icalcomponent *ic = get_icalcomponent_from_node(mreg, node);
+		const char *uid = icalcomponent_get_uid(ic);
+		assert(uid);
+
+		int string_len = strlen(uid);
+		snprintf(buf, s, "%s", uid);
+		status = string_len;
+		goto cleanup_return;
+	}
 	else if (strcmp(attribute, "user.class") == 0) {
 		const char *c = get_node_class(mreg, node);
 		if (!c || *c == '\0') {