agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 3d7e628aadcc9df41ec48687bd6aa4762faa64d2
parent 29e47888b538a412d4a23347cdad3b93a5023d96
Author: Marc Coquand <marc@coquand.email>
Date:   Tue, 29 Jul 2025 11:52:51 +0200

Add macro for resource initialization

I typically avoid macros and don't like them, but since C
lacks closures, the options are:

- Repeat the code everywhere (error prone, makes it hard to modify)
- Use gcc specific RAII features (non-standard)
- Use macros (bad tooling support, increases complexity of learning
the code)

Since I want to avoid RAII features, I think macros are the least
bad option here.

Diffstat:
Mmain.c | 225++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 102 insertions(+), 123 deletions(-)
diff --git a/main.c b/main.c
@@ -30,14 +30,35 @@
 #define EVENT_BUF_LEN (1024 * (sizeof(struct inotify_event) + 16))
 static pthread_rwlock_t entries_lock = PTHREAD_RWLOCK_INITIALIZER;
 
+#define FUSE_WRITE_BEGIN                                                       \
+	LOG("%s", __func__);                                                   \
+	pthread_rwlock_wrlock(&entries_lock);                                  \
+	memory_region *mreg = create_region();                                 \
+	int status = 0;                                                        \
+	if (!mreg) {                                                           \
+		pthread_rwlock_unlock(&entries_lock);                          \
+		return -ENOMEM;                                                \
+	}
+
+#define FUSE_READ_BEGIN                                                        \
+	LOG("%s", __func__);                                                   \
+	pthread_rwlock_rdlock(&entries_lock);                                  \
+	memory_region *mreg = create_region();                                 \
+	int status = 0;                                                        \
+	if (!mreg) {                                                           \
+		pthread_rwlock_unlock(&entries_lock);                          \
+		return -ENOMEM;                                                \
+	}
+
+#define FUSE_CLEANUP                                                           \
+	pthread_rwlock_unlock(&entries_lock);                                  \
+	rfree_all(mreg);
+
 static int
 fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 {
-	LOG("STAT %s", path);
-
-	pthread_rwlock_rdlock(&entries_lock);
-	memory_region *mreg = create_region();
-	int ret_code = 0;
+	FUSE_READ_BEGIN;
+	LOG("%s", path);
 
 	memset(stbuf, 0, sizeof(struct stat));
 
@@ -55,7 +76,7 @@ fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 	const struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
 		LOG("Entry not found");
-		ret_code = -ENOENT;
+		status = -ENOENT;
 		goto cleanup_return;
 	}
 
@@ -68,9 +89,8 @@ fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 	stbuf->st_atime = time(NULL);
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return ret_code;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
@@ -86,10 +106,8 @@ fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
 	     struct fuse_file_info *fi, enum fuse_readdir_flags flags)
 {
 
-	LOG("READDIR %s", path);
-	pthread_rwlock_rdlock(&entries_lock);
-	memory_region *mreg = create_region();
-	int status = 0;
+	FUSE_READ_BEGIN;
+	LOG("%s", path);
 
 	filler(buf, ".", NULL, 0, 0);
 	filler(buf, "..", NULL, 0, 0);
@@ -114,19 +132,15 @@ fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
 	}
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }
 
 static int
 fuse_open(const char *path, struct fuse_file_info *fi)
 {
-	LOG("OPEN %s", path);
-
-	memory_region *mreg = create_region();
-	pthread_rwlock_rdlock(&entries_lock);
-	int status = 0;
+	FUSE_READ_BEGIN;
+	LOG("%s", path);
 
 	const struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
@@ -134,25 +148,18 @@ fuse_open(const char *path, struct fuse_file_info *fi)
 		status = -ENOENT;
 	}
 
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-
+	FUSE_CLEANUP;
 	return status;
 }
 
 static int
 fuse_mkdir(const char *path, mode_t mode)
 {
-	LOG("MKDIR %s", path);
-
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	int status = 0;
+	FUSE_WRITE_BEGIN;
 
 	status = create_entry_from_fuse(mreg, path, ENTRY_DIRECTORY);
 
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }
 
@@ -160,19 +167,18 @@ static int
 fuse_read(const char *path, char *buf, size_t size, off_t offset,
 	  struct fuse_file_info *fi)
 {
-	LOG("READ called: offset=%ld, size=%zu", offset, size);
-	memory_region *mreg = create_region();
-	pthread_rwlock_rdlock(&entries_lock);
-	int ret_i = 0;
+	FUSE_READ_BEGIN;
+
+	LOG("READ: offset=%ld, size=%zu", offset, size);
 
 	const struct tree_node *n = get_node_by_path(mreg, path);
 	if (!n) {
-		ret_i = -ENOENT;
+		status = -ENOENT;
 		goto cleanup_return;
 	}
 	icalcomponent *ic = get_icalcomponent_from_node(mreg, n);
 	if (!ic) {
-		ret_i = -EIO;
+		status = -EIO;
 		goto cleanup_return;
 	}
 
@@ -195,12 +201,11 @@ fuse_read(const char *path, char *buf, size_t size, off_t offset,
 		memcpy(buf, description + offset, bytes_to_read);
 	}
 
-	ret_i = bytes_to_read;
+	status = bytes_to_read;
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return ret_i;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
@@ -208,20 +213,17 @@ fuse_write(const char *path, const char *buf, size_t size, off_t offset,
 	   struct fuse_file_info *fi)
 {
 
-	LOG("WRITE %s, %zu, %zu", buf, size, offset);
-
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	int ret_i = 0;
+	FUSE_WRITE_BEGIN;
+	LOG("%s, %zu, %zu", buf, size, offset);
 
 	if (pathIsHidden(path)) {
-		ret_i = -EPERM;
+		status = -EPERM;
 		goto cleanup_return;
 	}
 
 	const struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
-		ret_i = -ENONET;
+		status = -ENONET;
 		goto cleanup_return;
 	}
 
@@ -232,118 +234,103 @@ fuse_write(const char *path, const char *buf, size_t size, off_t offset,
 
 	icalcomponent_insert_description(mreg, ic, buf, size, offset);
 
-	ret_i = write_ical_file(mreg, node, ic);
+	status = write_ical_file(mreg, node, ic);
 
-	ret_i = ret_i >= 0 ? size : ret_i;
+	status = status >= 0 ? size : status;
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return ret_i;
+	FUSE_CLEANUP;
+	return status;
 }
 
 // Aka remove or delete
 static int
 fuse_unlink(const char *file)
 {
-	LOG("DELETE %s", file);
-
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	int res = 0;
+	FUSE_WRITE_BEGIN;
+	LOG("%s", file);
 
 	struct tree_node *node = get_node_by_path(mreg, file);
 	if (!node) {
-		res = -ENOENT;
+		status = -ENOENT;
 		goto cleanup_return;
 	}
 
 	icalcomponent *node_ics = get_icalcomponent_from_node(mreg, node);
 	if (node_is_directory(mreg, node, node_ics)) {
-		res = -EISDIR;
+		status = -EISDIR;
 		goto cleanup_return;
 	}
 
-	res = delete_vdir_entry(mreg, node);
+	status = delete_vdir_entry(mreg, node);
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return res;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
 fuse_rmdir(const char *filepath)
 {
-	LOG("DELETE %s", filepath);
-
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	int res = 0;
+	FUSE_WRITE_BEGIN;
+	LOG("%s", filepath);
 
 	struct tree_node *node = get_node_by_path(mreg, filepath);
 	if (!node) {
-		res = -ENOENT;
+		status = -ENOENT;
 		goto cleanup_return;
 	}
 
 	icalcomponent *node_ics = get_icalcomponent_from_node(mreg, node);
 	if (!node_is_directory(mreg, node, node_ics)) {
-		res = -ENOTDIR;
+		status = -ENOTDIR;
 		goto cleanup_return;
 	}
 
 	if (node->child_count > 0) {
-		res = -ENOTEMPTY;
+		status = -ENOTEMPTY;
 		goto cleanup_return;
 	}
 
-	res = delete_vdir_entry(mreg, node);
+	status = delete_vdir_entry(mreg, node);
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return res;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
 fuse_rename(const char *old, const char *new, unsigned int flags)
 {
 
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	LOG("RENAME %s -> %s", old, new);
-	int res = 0;
+	FUSE_WRITE_BEGIN;
+	LOG("%s -> %s", old, new);
 
 	struct tree_node *existing_node = get_node_by_path(mreg, new);
 	if (existing_node) {
 		if (node_has_children(existing_node)) {
-			res = -ENOTEMPTY;
+			status = -ENOTEMPTY;
 			goto cleanup_return;
 		}
 		if (delete_vdir_entry(mreg, existing_node) != 0) {
-			res = -EIO;
+			status = -EIO;
 			goto cleanup_return;
 		}
 	}
 
-	res = do_agenda_rename(mreg, old, new);
+	status = do_agenda_rename(mreg, old, new);
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
-	return res;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
 fuse_create(const char *filepath, mode_t mode, struct fuse_file_info *info)
 {
 
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	LOG("CREATE %s", filepath);
-
-	int status = 0;
+	FUSE_WRITE_BEGIN;
+	LOG("%s", filepath);
 
 	// Reserved
 	if (pathIsHidden(filepath)) {
@@ -361,18 +348,16 @@ fuse_create(const char *filepath, mode_t mode, struct fuse_file_info *info)
 	create_entry_from_fuse(mreg, filepath, ENTRY_FILE);
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }
 
 static int
 fuse_removexattr(const char *path, const char *attribute)
 {
-	LOG("REMOVEXATTR '%s' '%s'", path, attribute);
-	memory_region *mreg = create_region();
-	int status = -EINVAL;
-	pthread_rwlock_wrlock(&entries_lock);
+	FUSE_WRITE_BEGIN;
+	LOG("'%s' '%s'", path, attribute);
+
 	struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
 		status = -ENONET;
@@ -395,10 +380,13 @@ fuse_removexattr(const char *path, const char *attribute)
 		status = write_ical_file(mreg, node, ic);
 		goto cleanup_return;
 	}
+	else {
+		status = -EINVAL;
+		goto cleanup_return;
+	}
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }
 
@@ -406,11 +394,9 @@ static int
 fuse_setxattr(const char *path, const char *attribute, const char *value,
 	      size_t s, int flags)
 {
-	LOG("SETXATTR '%s' '%s' '%zu' '%s' '%d'", path, attribute, s, attribute,
-	    flags);
-	memory_region *mreg = create_region();
-	pthread_rwlock_wrlock(&entries_lock);
-	int status = 0;
+
+	FUSE_WRITE_BEGIN;
+	LOG("'%s' '%s' '%zu' '%s' '%d'", path, attribute, s, attribute, flags);
 
 	// Limit imposed in xattr(7)
 	if (strlen(attribute) >= 256) {
@@ -454,18 +440,15 @@ fuse_setxattr(const char *path, const char *attribute, const char *value,
 	}
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }
 
 static int
 fuse_listxattr(const char *path, char *list, size_t size)
 {
-	LOG("LISTXATTR %s %zu", list, size);
-	memory_region *mreg = create_region();
-	pthread_rwlock_rdlock(&entries_lock);
-	int return_i = 0;
+	FUSE_READ_BEGIN;
+	LOG("%s %zu", list, size);
 
 	FILE *stream;
 	char *membuffer = NULL;
@@ -473,12 +456,12 @@ fuse_listxattr(const char *path, char *list, size_t size)
 
 	struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
-		return_i = -ENONET;
+		status = -ENONET;
 		goto cleanup_return_2;
 	}
 
 	if (is_root_node(node)) {
-		return_i = -EPERM;
+		status = -EPERM;
 		goto cleanup_return_2;
 	}
 
@@ -487,7 +470,7 @@ fuse_listxattr(const char *path, char *list, size_t size)
 
 	stream = open_memstream(&membuffer, &membuffer_len);
 	if (stream == NULL) {
-		return_i = -EIO;
+		status = -EIO;
 		goto cleanup_return_2;
 	}
 
@@ -506,7 +489,7 @@ fuse_listxattr(const char *path, char *list, size_t size)
 	icalcomponent_write_x_props(stream, comp);
 
 	if (fclose(stream) != 0) {
-		return_i = -EIO;
+		status = -EIO;
 		goto cleanup_return;
 	}
 
@@ -519,23 +502,20 @@ fuse_listxattr(const char *path, char *list, size_t size)
 			list[size - 1] = '\0';
 		}
 	}
-	return_i = membuffer_len;
+	status = membuffer_len;
 
 cleanup_return:
 	free(membuffer);
 cleanup_return_2:
-	rfree_all(mreg);
-	pthread_rwlock_unlock(&entries_lock);
-	return return_i;
+	FUSE_CLEANUP;
+	return status;
 }
 
 static int
 fuse_getxattr(const char *path, const char *attribute, char *buf, size_t s)
 {
-	LOG("GETXATTR '%s' '%s' '%zu'\n", path, attribute, s);
-	pthread_rwlock_rdlock(&entries_lock);
-	memory_region *mreg = create_region();
-	int status = 0;
+	FUSE_READ_BEGIN;
+	LOG("'%s' '%s' '%zu'\n", path, attribute, s);
 
 	struct tree_node *node = get_node_by_path(mreg, path);
 	if (!node) {
@@ -600,8 +580,7 @@ fuse_getxattr(const char *path, const char *attribute, char *buf, size_t s)
 	}
 
 cleanup_return:
-	pthread_rwlock_unlock(&entries_lock);
-	rfree_all(mreg);
+	FUSE_CLEANUP;
 	return status;
 }