agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit bdd8da33645557dbd7b88d1ba6cecf6e93bba807
parent 56916c4a5f16c74268f6c084c05eb940dec61f61
Author: Marc Coquand <marc@coquand.email>
Date:   Fri, 30 May 2025 22:10:17 +0100

Clean up parsing logic

Diffstat:
Mmain.c | 605++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 304 insertions(+), 301 deletions(-)
diff --git a/main.c b/main.c
@@ -12,347 +12,350 @@
 
 #define ICS_DIR "./sample_ics"
 
+const char *display_date_fmt = "%b %d, %Y at %H:%M";
+
 typedef struct {
-    char *filename;
-    char *summary;
-    char *description;
-    time_t timestamp;
-    time_t created_at;
+	char *filename;
+	char *summary;
+	char *description;
+	time_t timestamp;
+	time_t created_at;
 } journal_entry;
 static journal_entry *entries = NULL;
 static size_t entry_count = 0;
 
 static void free_entry(journal_entry *entry) {
-    if (entry) {
-        free(entry->filename);
-        free(entry->summary);
-        free(entry->description);
-    }
+	if (entry) {
+		free(entry->filename);
+		free(entry->summary);
+		free(entry->description);
+	}
 }
 
 static void free_all_entries() {
-    for (size_t i = 0; i < entry_count; i++) {
-        free_entry(&entries[i]);
-    }
-    free(entries);
+	for (size_t i = 0; i < entry_count; i++) {
+		free_entry(&entries[i]);
+	}
+	free(entries);
 }
 
 static time_t parse_datetime(const char *datetime) {
-    struct tm tm = {0};
-    int ret = sscanf(datetime, "%4d%2d%2dT%2d%2d%2dZ",
-                      &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
-                      &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
-    if (ret == 6) {
-        tm.tm_year -= 1900;  // tm_year is years since 1900
-        tm.tm_mon -= 1;      // tm_mon is months since January (0-11)
-        tm.tm_isdst = -1;    // Let mktime determine if daylight savings is needed
-        return mktime(&tm);
-    }
-    return -1;
+	struct tm tm = {0};
+	int ret = sscanf(datetime, "%4d%2d%2dT%2d%2d%2dZ",
+					  &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+					  &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+	if (ret == 6) {
+		tm.tm_year -= 1900;  // tm_year is years since 1900
+		tm.tm_mon -= 1;	  // tm_mon is months since January (0-11)
+		tm.tm_isdst = -1;	// Let mktime determine if daylight savings is needed
+		return mktime(&tm);
+	}
+	return -1;
 }
 
-static int parse_ics_file(const char *file_path, journal_entry *entry) {
-    FILE *file = fopen(file_path, "r");
-    if (!file) {
-        perror("Failed to open .ics file");
-        return -1;
-    }
-
-    // Read the whole file into a string
-    fseek(file, 0, SEEK_END);
-    long file_size = ftell(file);
-    fseek(file, 0, SEEK_SET);
-
-    char *file_content = malloc(file_size + 1);
-    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);
-
-    // Regular expressions for SUMMARY and DESCRIPTION fields
-    regex_t regex_summary, regex_description, regex_dtstamp, regex_lastmod;
-    regmatch_t matches_summary[2], matches_description[2], matches_dtstamp[2], matches_lastmod[2];
-
-    // Compile regular expressions
-    if (regcomp(&regex_summary, "SUMMARY:([^\r\n]+)", REG_EXTENDED) != 0 ||
-        regcomp(&regex_description, "DESCRIPTION:([^\r\n]*)", REG_EXTENDED) != 0 || 
-        regcomp(&regex_dtstamp, "DTSTAMP:([0-9T]+Z)", REG_EXTENDED) != 0 ||
-        regcomp(&regex_lastmod, "LAST-MODIFIED:([0-9T]+Z)", REG_EXTENDED) != 0) {
-
-
-        fprintf(stderr, "Failed to compile regular expressions\n");
-        free(file_content);
-        return -1;
-    }
-
-    // Extract the SUMMARY
-    if (regexec(&regex_summary, file_content, 2, matches_summary, 0) == 0) {
-        size_t summary_len = matches_summary[1].rm_eo - matches_summary[1].rm_so;
-        entry->summary = malloc(summary_len + 1);
-        if (!entry->summary) {
-            perror("Memory allocation failed for SUMMARY");
-            free(file_content);
-            regfree(&regex_summary);
-            regfree(&regex_description);
-            return -1;
-        }
-        strncpy(entry->summary, file_content + matches_summary[1].rm_so, summary_len);
-        entry->summary[summary_len] = '\0';
-    } else {
-        fprintf(stderr, "SUMMARY field not found in: %s\n", file_path);
-        free(file_content);
-        regfree(&regex_summary);
-        regfree(&regex_description);
-        return -1;
-    }
+static int compile_regexes(regex_t *regex_summary, regex_t *regex_description,
+						   regex_t *regex_dtstamp, regex_t *regex_lastmod) {
+	if (regcomp(regex_summary, "SUMMARY:([^\r\n]+)", REG_EXTENDED) != 0) return -1;
+	if (regcomp(regex_description, "DESCRIPTION:([^\r\n]*)", REG_EXTENDED) != 0) return -1;
+	if (regcomp(regex_dtstamp, "DTSTAMP:([0-9T]+Z)", REG_EXTENDED) != 0) return -1;
+	if (regcomp(regex_lastmod, "LAST-MODIFIED:([0-9T]+Z)", REG_EXTENDED) != 0) return -1;
+	return 0;
+}
 
-    // Extract the DESCRIPTION (including multiline handling)
-    if (regexec(&regex_description, file_content, 2, matches_description, 0) == 0) {
-        size_t description_len = matches_description[1].rm_eo - matches_description[1].rm_so;
-        entry->description = malloc(description_len + 1);  // +1 for null-termination
-        if (!entry->description) {
-            perror("Memory allocation failed for DESCRIPTION");
-            free(file_content);
-            regfree(&regex_summary);
-            regfree(&regex_description);
-            regfree(&regex_dtstamp);
-            regfree(&regex_lastmod);
-            return -1;
-        }
-
-        // Copy the string using memcpy and ensure null termination
-        memcpy(entry->description, file_content + matches_description[1].rm_so, description_len);
-        entry->description[description_len] = '\0';  // Ensure null-termination
-
-        // Replace literal "\n" with actual newlines
-        char *newline_pos = NULL;
-        while ((newline_pos = strstr(entry->description, "\\n")) != NULL) {
-            *newline_pos = '\n';  // Replace literal '\n' with actual newline
-            memmove(newline_pos + 1, newline_pos + 2, strlen(newline_pos + 2) + 1);  // Shift the rest
-        }
-    } else {
-        fprintf(stderr, "DESCRIPTION field not found in: %s\n", file_path);
-        free(file_content);
-        regfree(&regex_summary);
-        regfree(&regex_description);
-        regfree(&regex_dtstamp);
-        regfree(&regex_lastmod);
-        return -1;
-    }
-    char *escaped_comma_pos = NULL;
-    while ((escaped_comma_pos = strstr(entry->description, "\\,")) != NULL) {
-        *escaped_comma_pos = ',';  // Replace escaped comma with actual comma
-        memmove(escaped_comma_pos + 1, escaped_comma_pos + 2, strlen(escaped_comma_pos + 2) + 1);  // Shift the rest of the string
-    }
+static char *extract_match(const char *content, regmatch_t match) {
+	size_t len = match.rm_eo - match.rm_so;
+	char *str = malloc(len + 1);
+	if (!str) return NULL;
+	memcpy(str, content + match.rm_so, len);
+	str[len] = '\0';
+	return str;
+}
 
-    // Set timestamp to the current time
-
-    // Extract the DTSTAMP
-    if (regexec(&regex_dtstamp, file_content, 2, matches_dtstamp, 0) == 0) {
-        size_t dtstamp_len = matches_dtstamp[1].rm_eo - matches_dtstamp[1].rm_so;
-        char dtstamp_str[dtstamp_len + 1];
-        strncpy(dtstamp_str, file_content + matches_dtstamp[1].rm_so, dtstamp_len);
-        dtstamp_str[dtstamp_len] = '\0';
-
-        entry->created_at = parse_datetime(dtstamp_str);
-        if (entry->created_at == -1) {
-            fprintf(stderr, "Failed to parse DTSTAMP in: %s\n", file_path);
-            free(file_content);
-            regfree(&regex_summary);
-            regfree(&regex_description);
-            regfree(&regex_dtstamp);
-            regfree(&regex_lastmod);
-            return -1;
-        }
+static void unescape_description(char *desc) {
+    char *pos;
+    while ((pos = strstr(desc, "\\n")) != NULL) {
+        *pos = '\n';
+        memmove(pos + 1, pos + 2, strlen(pos + 2) + 1);
     }
-
-    // Extract the LAST-MODIFIED (if present)
-    else if (regexec(&regex_lastmod, file_content, 2, matches_lastmod, 0) == 0) {
-        size_t lastmod_len = matches_lastmod[1].rm_eo - matches_lastmod[1].rm_so;
-        char lastmod_str[lastmod_len + 1];
-        strncpy(lastmod_str, file_content + matches_lastmod[1].rm_so, lastmod_len);
-        lastmod_str[lastmod_len] = '\0';
-
-        entry->timestamp = parse_datetime(lastmod_str);
-        if (entry->timestamp == -1) {
-            fprintf(stderr, "Failed to parse LAST-MODIFIED in: %s\n", file_path);
-            free(file_content);
-            regfree(&regex_summary);
-            regfree(&regex_description);
-            regfree(&regex_dtstamp);
-            regfree(&regex_lastmod);
-            return -1;
-        }
+    // Commas are saved as \,
+    while ((pos = strstr(desc, "\\,")) != NULL) {
+        *pos = ',';
+        memmove(pos + 1, pos + 2, strlen(pos + 2) + 1);
     }
+}
 
-    // If neither DTSTAMP nor LAST-MODIFIED found, set timestamp to current time
-    if (entry->timestamp == 0) {
-        entry->timestamp = time(NULL);
-    }
-    // Clean up
-    free(file_content);
-    regfree(&regex_summary);
-    regfree(&regex_description);
-    return 0;
+static int parse_ics_file(const char *file_path, journal_entry *entry) {
+	FILE *file = fopen(file_path, "r");
+	if (!file) {
+		perror("Failed to open .ics file");
+		return -1;
+	}
+
+	// Read the whole file into a string
+	fseek(file, 0, SEEK_END);
+	long file_size = ftell(file);
+	fseek(file, 0, SEEK_SET);
+
+	char *file_content = malloc(file_size + 1);
+	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);
+
+	regex_t regex_summary, regex_description, regex_dtstamp, regex_lastmod;
+	regmatch_t matches_summary[2], matches_description[2], matches_dtstamp[2], matches_lastmod[2];
+
+	size_t return_code = -1;
+
+	if (compile_regexes(&regex_summary, &regex_description, &regex_dtstamp, &regex_lastmod) != 0) {
+		fprintf(stderr, "Failed to compile regular expressions\n");
+		goto cleanup;
+	}
+
+	// Extract SUMMARY
+	if (regexec(&regex_summary, file_content, 2, matches_summary, 0) != 0) {
+		fprintf(stderr, "SUMMARY field not found in: %s\n", file_path);
+		goto cleanup;
+	 } 
+
+	entry->summary = extract_match(file_content, matches_summary[1]);
+	if (!entry->summary) {
+		perror("Memory allocation failed for SUMMARY");
+		goto cleanup;
+	}
+
+
+	// Extract DESCRIPTION
+	if (regexec(&regex_description, file_content, 2, matches_description, 0) != 0) {
+		fprintf(stderr, "DESCRIPTION field not found in: %s\n", file_path);
+		goto cleanup;
+	}
+	entry->description = extract_match(file_content, matches_description[1]);
+	if (!entry->description) {
+		perror("Memory allocation failed for DESCRIPTION");
+		goto cleanup;
+	}
+	unescape_description(entry->description);
+
+
+	// Extract the DTSTAMP, our created_at
+	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) {
+			fprintf(stderr, "Failed to parse DTSTAMP in: %s\n", file_path);
+			goto cleanup;
+		}
+	} else {
+		entry->created_at = time(NULL);
+	}
+
+	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) {
+			fprintf(stderr, "Failed to parse DTSTAMP in: %s\n", file_path);
+			goto cleanup;
+		}
+	} else {
+		entry->created_at = time(NULL);
+	}
+
+	// LAST-MODIFIED (timestamp)
+	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);
+		free(lastmod_str);
+		if (entry->timestamp == -1) {
+			fprintf(stderr, "Failed to parse LAST-MODIFIED in: %s\n", file_path);
+			goto cleanup;
+		}
+	} else {
+		entry->timestamp = entry->created_at;  // fallback
+	}
+
+	// Success and goto cleanup
+	return_code = 0;
+
+cleanup:
+	free(file_content);
+	regfree(&regex_summary);
+	regfree(&regex_description);
+	regfree(&regex_dtstamp);
+	regfree(&regex_lastmod);
+	return return_code;
 }
 
 static void load_journal_entries() {
-    printf("Loading journal entries from: %s\n", ICS_DIR);
-    DIR *dir = opendir(ICS_DIR);
-    if (!dir) {
-        perror("opendir");
-        return;
-    }
-
-    struct dirent *entry;
-    char filepath[512];
-    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;
-            new_entry.filename = strdup(entry->d_name);
-            if (parse_ics_file(filepath, &new_entry) == 0) {
-                entries = realloc(entries, sizeof(journal_entry) * (entry_count + 1));
-                entries[entry_count] = new_entry;
-                entry_count++;
-            } else {
-                free(new_entry.filename);
-            }
-        }
-    }
-    printf("Loaded %zu journal entries.\n", entry_count);
-    closedir(dir);
+	printf("Loading journal entries from: %s\n", ICS_DIR);
+	DIR *dir = opendir(ICS_DIR);
+	if (!dir) {
+		perror("opendir");
+		return;
+	}
+
+	struct dirent *entry;
+	char filepath[512];
+	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;
+			new_entry.filename = strdup(entry->d_name);
+			if (parse_ics_file(filepath, &new_entry) == 0) {
+				entries = realloc(entries, sizeof(journal_entry) * (entry_count + 1));
+				entries[entry_count] = new_entry;
+				entry_count++;
+			} else {
+				free(new_entry.filename);
+			}
+		}
+	}
+	printf("Loaded %zu journal entries.\n", entry_count);
+	closedir(dir);
 }
 
 static int journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) {
-    memset(stbuf, 0, sizeof(struct stat));
-
-    if (strcmp(path, "/") == 0) {
-        stbuf->st_mode = S_IFDIR | 0755;
-        stbuf->st_nlink = 2;
-        return 0;
-    }
-
-    for (size_t i = 0; i < entry_count; i++) {
-        char entry_path[256];
-        snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
-        if (strcmp(path, entry_path) == 0) {
-            stbuf->st_mode = S_IFREG | 0444;
-            stbuf->st_nlink = 1;
-            struct tm *tm_info = localtime(&entries[i].timestamp);
-            char timestamp_str[64];
-            strftime(timestamp_str, sizeof(timestamp_str), "%b %d, %Y at %H:%M", tm_info);
-
-            // Calculate the file size as in journal_read
-            int size = snprintf(NULL, 0, "%s\n%s\n---\n%s\n",
-                                entries[i].summary, timestamp_str, entries[i].description);
-
-            stbuf->st_size = (off_t)size;
-
-            // Set the times
-            stbuf->st_mtime = entries[i].timestamp;  // Use the timestamp as the modification time
-            stbuf->st_ctime = entries[i].timestamp;  // Set the change time to the same as the modification time
-            // Access time is current time
-            stbuf->st_atime = time(NULL);             
-
-            return 0;
-        }
-    }
-
-    return -ENOENT;
+	memset(stbuf, 0, sizeof(struct stat));
+
+	if (strcmp(path, "/") == 0) {
+		stbuf->st_mode = S_IFDIR | 0755;
+		stbuf->st_nlink = 2;
+		return 0;
+	}
+
+	for (size_t i = 0; i < entry_count; i++) {
+		char entry_path[256];
+		snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
+		if (strcmp(path, entry_path) == 0) {
+			stbuf->st_mode = S_IFREG | 0444;
+			stbuf->st_nlink = 1;
+			struct tm *tm_info = localtime(&entries[i].timestamp);
+			char timestamp_str[64];
+			strftime(timestamp_str, sizeof(timestamp_str), display_date_fmt, tm_info);
+
+			// Calculate the file size as in journal_read
+			int size = snprintf(NULL, 0, "%s\n%s\n---\n%s\n",
+								entries[i].summary, timestamp_str, entries[i].description);
+
+			stbuf->st_size = (off_t)size;
+
+			// Set the times
+			stbuf->st_mtime = entries[i].timestamp;  // Use the timestamp as the modification time
+			stbuf->st_ctime = entries[i].timestamp;  // Set the change time to the same as the modification time
+			// Access time is current time
+			stbuf->st_atime = time(NULL);			 
+
+			return 0;
+		}
+	}
+
+	return -ENOENT;
 }
 static int journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-                           off_t offset, struct fuse_file_info *fi,
-                           enum fuse_readdir_flags flags) {
-    if (strcmp(path, "/") != 0)
-        return -ENOENT;
-
-    filler(buf, ".", NULL, 0, 0);
-    filler(buf, "..", NULL, 0, 0);
-
-    for (size_t i = 0; i < entry_count; i++) {
-        char entry_name[256];
-        snprintf(entry_name, sizeof(entry_name), "%s.txt", entries[i].filename);
-        filler(buf, entry_name, NULL, 0, 0);
-    }
+						   off_t offset, struct fuse_file_info *fi,
+						   enum fuse_readdir_flags flags) {
+	if (strcmp(path, "/") != 0)
+		return -ENOENT;
 
-    return 0;
+	filler(buf, ".", NULL, 0, 0);
+	filler(buf, "..", NULL, 0, 0);
+
+	for (size_t i = 0; i < entry_count; i++) {
+		char entry_name[256];
+		snprintf(entry_name, sizeof(entry_name), "%s.txt", entries[i].filename);
+		filler(buf, entry_name, NULL, 0, 0);
+	}
+
+	return 0;
 }
 
 static int journal_open(const char *path, struct fuse_file_info *fi) {
-    for (size_t i = 0; i < entry_count; i++) {
-        char entry_path[256];
-        snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
-        if (strcmp(path, entry_path) == 0) {
-            return 0;
-        }
-    }
-    return -ENOENT;
+	for (size_t i = 0; i < entry_count; i++) {
+		char entry_path[256];
+		snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
+		if (strcmp(path, entry_path) == 0) {
+			return 0;
+		}
+	}
+	return -ENOENT;
 }
 
 static int journal_read(const char *path, char *buf, size_t size, off_t offset,
-                        struct fuse_file_info *fi) {
-    for (size_t i = 0; i < entry_count; i++) {
-        char entry_path[256];
-        snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
-
-        if (strcmp(path, entry_path) == 0) {
-            // Format timestamp
-            struct tm *tm_info = localtime(&entries[i].timestamp);
-            char timestamp_str[64];
-            strftime(timestamp_str, sizeof(timestamp_str), "%b %d, %Y at %H:%M", tm_info);
-
-            // Build full content string using snprintf(NULL, 0) to get length
-            int needed_len = snprintf(NULL, 0, "%s\n%s\n---\n%s\n",
-                                      entries[i].summary, timestamp_str, entries[i].description);
-            if (needed_len < 0)
-                return -EIO; // snprintf error
-
-            char *full_content = malloc(needed_len + 1);
-            if (!full_content) {
-                perror("Memory allocation failed");
-                return -ENOMEM;
-            }
-
-            snprintf(full_content, needed_len + 1, "%s\n%s\n---\n%s\n",
-                     entries[i].summary, timestamp_str, entries[i].description);
-
-            size_t len = (size_t)needed_len;
-
-            if (offset >= len) {
-                free(full_content);
-                return 0;  // EOF
-            }
-
-            if (offset + size > len)
-                size = len - offset;
-
-            memcpy(buf, full_content + offset, size);
-
-            free(full_content);
-            return size;
-        }
-    }
-    return -ENOENT;
+						struct fuse_file_info *fi) {
+	for (size_t i = 0; i < entry_count; i++) {
+		char entry_path[256];
+		snprintf(entry_path, sizeof(entry_path), "/%s.txt", entries[i].filename);
+
+		if (strcmp(path, entry_path) == 0) {
+			// Format timestamp
+			struct tm *tm_info = localtime(&entries[i].created_at);
+			char timestamp_str[64];
+			strftime(timestamp_str, sizeof(timestamp_str), display_date_fmt, tm_info);
+
+			// Build full content string using snprintf(NULL, 0) to get length
+			int needed_len = (size_t)snprintf(NULL, 0, "%s\n%s\n---\n%s\n",
+									  entries[i].summary, timestamp_str, entries[i].description);
+			if (needed_len < 0)
+				return -EIO; // snprintf error
+
+			char *full_content = malloc(needed_len + 1);
+			if (!full_content) {
+				perror("Memory allocation failed");
+				return -ENOMEM;
+			}
+
+			snprintf(full_content, needed_len + 1, "%s\n%s\n---\n%s\n",
+					 entries[i].summary, timestamp_str, entries[i].description);
+
+
+			if (offset >= needed_len) {
+				free(full_content);
+				return 0;  // EOF
+			}
+
+			if (offset + size > needed_len)
+				size = needed_len - offset;
+
+			memcpy(buf, full_content + offset, size);
+
+			free(full_content);
+			return size;
+		}
+	}
+	return -ENOENT;
 }
 
 static const struct fuse_operations journal_oper = {
-    .getattr = journal_getattr,
-    .readdir = journal_readdir,
-    .open    = journal_open,
-    .read    = journal_read,
+	.getattr = journal_getattr,
+	.readdir = journal_readdir,
+	.open	= journal_open,
+	.read	= journal_read,
 };
 
 int main(int argc, char *argv[]) {
-    load_journal_entries();
-    int ret = fuse_main(argc, argv, &journal_oper, NULL);
+	load_journal_entries();
+	int ret = fuse_main(argc, argv, &journal_oper, NULL);
 
-    // Cleanup before exit
-    free_all_entries();
+	// Cleanup before exit
+	free_all_entries();
 
-    return ret;
+	return ret;
 }