agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 15fee8c7819f82aaf530f105a20bb85912c88c17
parent ddbd94ee1fb30c687f9dd0f034ff095ead25b6e0
Author: Marc Coquand <marc@coquand.email>
Date:   Sun,  1 Jun 2025 19:21:07 +0100

simplify and safeify

Diffstat:
Mmain.c | 83+++++++++++++++++++++++++++++++++++++++++++------------------------------------
1 file changed, 45 insertions(+), 38 deletions(-)
diff --git a/main.c b/main.c
@@ -1,6 +1,7 @@
 #define FUSE_USE_VERSION 31
 
 #include "hashmap.h"
+#include "util.h"
 #include <dirent.h>
 #include <errno.h>
 #include <fuse3/fuse.h>
@@ -104,7 +105,7 @@ extract_ical_field(const char *ical, const char *field_name)
 	start++;
 
 	const char *p = start;
-	char *result = calloc(strlen(p) + 1, sizeof(char));
+	char *result = xcalloc(strlen(p) + 1, sizeof(char));
 
 	size_t len = 0;
 
@@ -147,7 +148,7 @@ static char *
 extract_match(const char *content, regmatch_t match)
 {
 	size_t len = match.rm_eo - match.rm_so;
-	char *m_str = calloc(len + 1, sizeof(char));
+	char *m_str = xcalloc(len + 1, sizeof(char));
 	memcpy(m_str, content + match.rm_so, len);
 	m_str[len] = '\0';
 	return m_str;
@@ -365,6 +366,7 @@ parse_ics_file(const char *file_path, journal_entry *entry)
 }
 
 // Dynamically create a time string using format
+// Needs to be freed after use
 char *
 time_string(time_t time_val, const char *format)
 {
@@ -374,9 +376,9 @@ time_string(time_t time_val, const char *format)
 	}
 
 	size_t buf_size = 64;
-	char *buffer = malloc(buf_size);
+	char *buffer = xmalloc(buf_size);
 
-	size_t len = strftime(buffer, buf_size, format, &tm_info);
+	strftime(buffer, buf_size, format, &tm_info);
 	return buffer;
 }
 
@@ -387,33 +389,31 @@ get_unique_filename(time_t created_at, struct hashmap *entries_map)
 {
 	char *filename_time_str = time_string(created_at, date_title_fmt);
 	if (!filename_time_str) {
-		fprintf(stderr, "Failed to format date string\n");
+		LOG("Failed to format date string");
 		return NULL;
 	}
 
-	// Prepare base filename leaving room for suffix and extension
-	char base_filename[128];
-	size_t base_len = strnlen(filename_time_str, strlen(filename_time_str));
-	if (base_len > sizeof(base_filename) - 12) {
-		base_len = sizeof(base_filename) - 12;
-	}
-	strncpy(base_filename, filename_time_str, base_len);
-	base_filename[base_len] = '\0';
-
-	free(filename_time_str);
-
 	// Attempt filename and increment suffix if needed
-	char unique_filename[140];
-	snprintf(unique_filename, sizeof(unique_filename), "%s.txt",
-		 base_filename);
+	char *unique_filename = NULL;
+	if (asprintf(&unique_filename, "%s.txt", filename_time_str) == -1) {
+		free(filename_time_str);
+		return NULL;
+	}
 
+	// In the rare cases that some entry is created on the same minute.
 	int suffix = 1;
 	while (hashmap_get(entries_map, unique_filename) != NULL) {
-		snprintf(unique_filename, sizeof(unique_filename), "%s_%d.txt",
-			 base_filename, suffix++);
+		suffix++;
+		free(unique_filename);
+		if (asprintf(&unique_filename, "%s_%d.txt", filename_time_str,
+			     suffix) == -1) {
+			return NULL;
+		}
 	}
 
-	return strdup(unique_filename);
+	free(filename_time_str);
+
+	return unique_filename;
 }
 
 // Initializes
@@ -438,23 +438,24 @@ load_journal_entries()
 	}
 
 	struct dirent *entry;
-	char filepath[512];
+	char *filepath;
 
 	while ((entry = readdir(dir))) {
 		if (entry->d_type == DT_REG && strstr(entry->d_name, ".ics")) {
-			snprintf(filepath, sizeof(filepath), "%s/%s", ICS_DIR,
-				 entry->d_name);
-
-			journal_entry *new_entry =
-			    calloc(1, sizeof(journal_entry));
-			if (!new_entry) {
-				perror("calloc failed");
+			if (asprintf(&filepath, "%s/%s", ICS_DIR,
+				     entry->d_name) == -1) {
+				perror("aspintf fialed");
 				continue;
 			}
 
+			journal_entry *new_entry =
+			    xcalloc(1, sizeof(journal_entry));
+
 			new_entry->filename_original = strdup(entry->d_name);
 			if (!new_entry->filename_original) {
 				perror("strdup failed");
+
+				free(filepath);
 				free(new_entry);
 				continue;
 			}
@@ -462,6 +463,8 @@ load_journal_entries()
 			// Parse the ICS file and check for errors
 			if (parse_ics_file(filepath, new_entry) != 0) {
 				LOG("Failed to parse entry: %s", entry->d_name);
+
+				free(filepath);
 				free(new_entry->filename_original);
 				free(new_entry);
 				continue;
@@ -475,6 +478,8 @@ load_journal_entries()
 			if (!unique_filename) {
 				LOG("Failed to generate filename for %s",
 				    entry->d_name);
+
+				free(filepath);
 				free(new_entry->filename_original);
 				free(new_entry);
 				continue;
@@ -489,14 +494,17 @@ load_journal_entries()
 					   new_entry->filename_original,
 					   new_entry) != 0) {
 				LOG("Failed to insert entry");
+
+				free(filepath);
 				free(new_entry->filename);
 				free(new_entry->filename_original);
 				free(new_entry);
 				continue;
 			}
+
+			free(filepath);
 		}
 	}
-
 	closedir(dir);
 	pthread_mutex_unlock(&entries_mutex);
 }
@@ -543,7 +551,7 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 
 	stbuf->st_size = (off_t)size;
 
-	LOG("Entry found %s, %s", entry->filename, entry->description);
+	LOG("Entry found: %s", entry->filename);
 	stbuf->st_mtime = entry->modified_at;
 	stbuf->st_ctime = entry->modified_at;
 	stbuf->st_atime = time(NULL);
@@ -609,7 +617,7 @@ journal_read(const char *path, char *buf, size_t size, off_t offset,
 	// Calculate required length for full content
 	int needed_len = get_entry_content_size(entry);
 
-	char *full_content = calloc(needed_len + 1, sizeof(char));
+	char *full_content = xcalloc(needed_len + 1, sizeof(char));
 	write_entry_content(full_content, needed_len + 1, entry);
 
 	if (offset >= needed_len) {
@@ -653,7 +661,7 @@ journal_entry_to_ical(const journal_entry *entry)
 			    strlen(escaped_description) + strlen(entry->uid) +
 			    strlen(dtstamp) + strlen(lastmod) + 512;
 
-	char *ical = calloc(total_size, sizeof(char));
+	char *ical = xcalloc(total_size, sizeof(char));
 
 	snprintf(ical, total_size,
 		 "BEGIN:VCALENDAR\n"
@@ -735,7 +743,7 @@ get_original_filepath(const journal_entry *entry)
 {
 	size_t needed =
 	    snprintf(NULL, 0, "%s/%s", ICS_DIR, entry->filename_original);
-	char *filepath = calloc(needed + 1, sizeof(char));
+	char *filepath = xcalloc(needed + 1, sizeof(char));
 	snprintf(filepath, needed + 1, "%s/%s", ICS_DIR,
 		 entry->filename_original);
 	return filepath;
@@ -771,7 +779,7 @@ journal_write(const char *path, const char *buf, size_t size, off_t offset,
 journal_entry *
 copy_journal_entry(const journal_entry *src)
 {
-	journal_entry *copy = calloc(1, sizeof(journal_entry));
+	journal_entry *copy = xcalloc(1, sizeof(journal_entry));
 
 	copy->filename = strdup(src->filename);
 	copy->filename_original = strdup(src->filename_original);
@@ -899,11 +907,10 @@ update_fuse_entry_from_original(const char *filename)
 	// TODO: Create entry when file is not found
 	if (!entry) {
 		LOG("Entry not found. Registering new file");
-		perror("calloc");
 		pthread_mutex_unlock(&entries_mutex);
 		return;
 	}
-	journal_entry *new_entry = calloc(1, sizeof(journal_entry));
+	journal_entry *new_entry = xcalloc(1, sizeof(journal_entry));
 	if (!new_entry) {
 		perror("calloc");
 		pthread_mutex_unlock(&entries_mutex);