agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 1c1a7b02588e34e81036a31fc12e8f1bac9bd3d8
parent 84c07426a0268fe5b2b10d3c2cda34501c537887
Author: Marc Coquand <marc@coquand.email>
Date:   Sun,  1 Jun 2025 16:01:29 +0100

Cleanup

Diffstat:
Mmain.c | 128+++++++++++++++++++++++++++----------------------------------------------------
1 file changed, 43 insertions(+), 85 deletions(-)
diff --git a/main.c b/main.c
@@ -32,7 +32,7 @@ typedef struct {
 	char *summary;
 	char *description;
 	char *uid;
-	time_t timestamp;
+	time_t modified_at;
 	time_t created_at;
 } journal_entry;
 
@@ -68,7 +68,7 @@ static time_t parse_datetime(const char *datetime)
 		    -1; // Let mktime determine if daylight savings is needed
 		return mktime(&tm);
 	}
-	return -1;
+	return INVALID_TIME;
 }
 
 // Folds are [\r]\n followed by ' ' or '\t'
@@ -276,11 +276,7 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	fseek(file, 0, SEEK_SET);
 
 	char *file_content = calloc(file_size + 1, sizeof(char));
-	if (!file_content) {
-		perror("Memory allocation failed");
-		fclose(file);
-		return -1;
-	}
+
 	fread(file_content, 1, file_size, file);
 	file_content[file_size] = '\0'; // Null-terminate the string
 	fclose(file);
@@ -291,7 +287,8 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	entry->summary = extract_ical_field(file_content, "SUMMARY");
 	if (!entry->summary) {
 		fprintf(stderr, "SUMMARY field not found in: %s\n", file_path);
-		goto cleanup;
+		free_journal_entry(entry);
+		return -1;
 	}
 	unescape_text(entry->summary);
 
@@ -299,7 +296,8 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	entry->uid = extract_ical_field(file_content, "UID");
 	if (!entry->uid) {
 		fprintf(stderr, "UID field not found in: %s\n", file_path);
-		goto cleanup;
+		free_journal_entry(entry);
+		return -1;
 	}
 	unescape_text(entry->uid);
 
@@ -308,7 +306,9 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	if (!entry->description) {
 		fprintf(stderr, "DESCRIPTION field not found in: %s\n",
 			file_path);
-		goto cleanup;
+
+		free_journal_entry(entry);
+		return -1;
 	}
 
 	unescape_text(entry->description);
@@ -317,16 +317,14 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	if (regexec(&regex_dtstamp, file_content, 2, matches_dtstamp, 0) == 0) {
 		char *dtstamp_str =
 		    extract_match(file_content, matches_dtstamp[1]);
-		if (!dtstamp_str) {
-			perror("Memory allocation failed for DTSTAMP");
-			goto cleanup;
-		}
 		entry->created_at = parse_datetime(dtstamp_str);
 		free(dtstamp_str);
-		if (entry->created_at == -1) {
+		if (entry->created_at == INVALID_TIME) {
 			fprintf(stderr, "Failed to parse DTSTAMP in: %s\n",
 				file_path);
-			goto cleanup;
+
+			free_journal_entry(entry);
+			return -1;
 		}
 	}
 	else {
@@ -337,37 +335,23 @@ static int parse_ics_file(const char *file_path, journal_entry *entry)
 	if (regexec(&regex_lastmod, file_content, 2, matches_lastmod, 0) == 0) {
 		char *lastmod_str =
 		    extract_match(file_content, matches_lastmod[1]);
-		if (!lastmod_str) {
-			perror("Memory allocation failed for LAST-MODIFIED");
-			goto cleanup;
-		}
-		entry->timestamp = parse_datetime(lastmod_str);
+		entry->modified_at = parse_datetime(lastmod_str);
 		free(lastmod_str);
-		if (entry->timestamp == -1) {
+		if (entry->modified_at == INVALID_TIME) {
 			fprintf(stderr,
 				"Failed to parse LAST-MODIFIED in: %s\n",
 				file_path);
-			goto cleanup;
+
+			free_journal_entry(entry);
+			return -1;
 		}
 	}
 	else {
-		entry->timestamp = entry->created_at;
+		entry->modified_at = entry->created_at;
 	}
 
-	// Success
-
 	free(file_content);
 	return 0;
-
-cleanup:
-	if (entry->summary)
-		free(entry->summary);
-	if (entry->description)
-		free(entry->description);
-	if (entry->uid)
-		free(entry->uid);
-	free(file_content);
-	return -1;
 }
 
 // Dynamically create a time string using format
@@ -378,18 +362,11 @@ char *time_string(time_t time_val, const char *format)
 		return NULL;
 	}
 
-	// Allocate a reasonably large buffer
 	size_t buf_size = 64;
 	char *buffer = malloc(buf_size);
-	if (!buffer)
-		return NULL;
 
 	size_t len = strftime(buffer, buf_size, format, &tm_info);
-	if (len == 0) {
-		free(buffer);
-		return NULL; // Formatting failed (buffer too small)
-	}
-	return buffer; // caller must free this
+	return buffer;
 }
 
 // Uses created_at as filename.
@@ -427,6 +404,10 @@ char *get_unique_filename(time_t created_at, struct hashmap *entries_map)
 	return strdup(unique_filename);
 }
 
+// Initializes
+// entries_original_key
+// entries_fuse_key
+// Should only be run once
 static void load_journal_entries()
 {
 	pthread_mutex_lock(&entries_mutex);
@@ -543,14 +524,13 @@ int journal_getattr(const char *path, struct stat *stbuf,
 	stbuf->st_mode = S_IFREG | 0444;
 	stbuf->st_nlink = 1;
 
-	// Write to nothing and get the size
 	int size = get_entry_content_size(entry);
 
 	stbuf->st_size = (off_t)size;
 
 	LOG("Entry found %s, %s", entry->filename, entry->description);
-	stbuf->st_mtime = entry->timestamp;
-	stbuf->st_ctime = entry->timestamp;
+	stbuf->st_mtime = entry->modified_at;
+	stbuf->st_ctime = entry->modified_at;
 	stbuf->st_atime = time(NULL);
 
 	ret_code = 0;
@@ -612,7 +592,6 @@ static int journal_read(const char *path, char *buf, size_t size, off_t offset,
 	int needed_len = get_entry_content_size(entry);
 
 	char *full_content = calloc(needed_len + 1, sizeof(char));
-
 	write_entry_content(full_content, needed_len + 1, entry);
 
 	if (offset >= needed_len) {
@@ -625,9 +604,10 @@ static int journal_read(const char *path, char *buf, size_t size, off_t offset,
 	if (offset + size > (size_t)needed_len)
 		size = needed_len - offset;
 
+	// Write to read buffer only the requested amount
 	memcpy(buf, full_content + offset, size);
-
 	free(full_content);
+
 	ret_code = size;
 
 unlock_and_return:
@@ -640,17 +620,10 @@ char *journal_entry_to_ical(const journal_entry *entry)
 	char *escaped_summary = escape_text(entry->summary);
 	char *escaped_description = escape_text(entry->description);
 
-	if (!escaped_summary || !escaped_description) {
-		free(escaped_summary);
-		free(escaped_description);
-		LOG("FAILED TO ESCAPE");
-		return NULL;
-	}
-
 	// Format timestamps
 	struct tm created_tm, modified_tm;
 	gmtime_r(&entry->created_at, &created_tm);
-	gmtime_r(&entry->timestamp, &modified_tm);
+	gmtime_r(&entry->modified_at, &modified_tm);
 
 	char dtstamp[32], lastmod[32];
 	strftime(dtstamp, sizeof(dtstamp), "%Y%m%dT%H%M%SZ", &created_tm);
@@ -659,15 +632,9 @@ char *journal_entry_to_ical(const journal_entry *entry)
 	// Estimate total size (safe upper bound)
 	size_t total_size = strlen(escaped_summary) +
 			    strlen(escaped_description) + strlen(entry->uid) +
-			    strlen(dtstamp) + strlen(lastmod) +
-			    512; // Extra for formatting
+			    strlen(dtstamp) + strlen(lastmod) + 512;
 
-	char *ical = malloc(total_size);
-	if (!ical) {
-		free(escaped_summary);
-		free(escaped_description);
-		return NULL;
-	}
+	char *ical = calloc(total_size, sizeof(char));
 
 	snprintf(ical, total_size,
 		 "BEGIN:VCALENDAR\n"
@@ -691,15 +658,14 @@ char *journal_entry_to_ical(const journal_entry *entry)
 int parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 {
 	char *copy = strndup(buf, size);
-	if (!copy)
-		return -ENOMEM;
 
 	char *summary = NULL, *description = NULL;
 	char *sep = strstr(copy, "\n---\n");
 
+	// Malformed input
 	if (!sep) {
 		free(copy);
-		return -EINVAL; // Malformed input
+		return -EINVAL;
 	}
 
 	*sep = '\0';
@@ -712,18 +678,13 @@ int parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 	}
 
 	summary = strdup(summary_line);
-	if (!summary) {
-		free(copy);
-		return -ENOMEM;
-	}
 
 	// Clean up old values
 	free(entry->summary);
 	free(entry->description);
 	entry->summary = summary;
-	entry->description = strdup(description ? description : "");
-
-	entry->timestamp = time(NULL); // Update modified time
+	entry->description = strdup(description);
+	entry->modified_at = time(NULL);
 
 	free(copy);
 	return 0;
@@ -732,9 +693,6 @@ int parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 int write_entry_to_ical_file(const journal_entry *entry, const char *filepath)
 {
 	char *ical_str = journal_entry_to_ical(entry);
-	if (!ical_str) {
-		return -EIO;
-	}
 
 	FILE *f = fopen(filepath, "w");
 	if (!f) {
@@ -750,7 +708,7 @@ int write_entry_to_ical_file(const journal_entry *entry, const char *filepath)
 	return 0;
 }
 
-// Full filepath
+// Full filepath of original ics file
 char *get_original_filepath(const journal_entry *entry)
 {
 	size_t needed =
@@ -779,7 +737,6 @@ static int journal_write(const char *path, const char *buf, size_t size,
 	}
 
 	char *filepath = get_original_filepath(entry);
-
 	if (write_entry_to_ical_file(entry, filepath) != 0) {
 		pthread_mutex_unlock(&entries_mutex);
 		return -EIO;
@@ -798,7 +755,7 @@ journal_entry *copy_journal_entry(const journal_entry *src)
 	copy->description = strdup(src->description);
 	copy->uid = strdup(src->uid);
 
-	copy->timestamp = src->timestamp;
+	copy->modified_at = src->modified_at;
 	copy->created_at = src->created_at;
 
 	return copy;
@@ -863,14 +820,14 @@ static int do_journal_entry_rename(time_t new_created_at, const char *old,
 	}
 
 	journal_entry *new_entry = copy_journal_entry(old_entry);
-
-	hashmap_remove(entries_original_key, old_entry->filename_original);
-	hashmap_remove(entries_fuse_key, old_entry->filename);
-
 	free(new_entry->filename);
 	new_entry->filename = strdup(new_basename);
 	new_entry->created_at = new_created_at;
 
+	// hashmap frees old_entry
+	hashmap_remove(entries_original_key, old_entry->filename_original);
+	hashmap_remove(entries_fuse_key, old_entry->filename);
+
 	hashmap_insert(entries_original_key, new_entry->filename_original,
 		       new_entry);
 	hashmap_insert(entries_fuse_key, new_entry->filename, new_entry);
@@ -1009,6 +966,7 @@ void *watch_ics_dir(void *arg)
 	close(fd);
 	return NULL;
 }
+
 int journal_create(const char *file_name, mode_t mode,
 		   struct fuse_file_info *info)
 {