agendafs
A filesystem for your calendar.
git clone git://mccd.space/agendafscommit ab5df2237f20b676f1e110c40078beb3d1a860ee
parent 14f9a718a0e5503115702044bcea54fc34788fe3
Author: Marc Coquand <marc@coquand.email>
Date: Sun, 1 Jun 2025 20:50:31 +0100
Add ability to create file
Diffstat:
| M | Makefile | | | 6 | +++--- |
| M | main.c | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
| M | shell.nix | | | 1 | + |
3 files changed, 86 insertions(+), 27 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,14 +1,14 @@
CC = gcc
CFLAGS = -Wall -O3
CFLAGS_DEBUG = -Wall -g
-LIBS = `pkg-config fuse3 --cflags --libs`
+LIBS = `pkg-config uuid fuse3 --cflags --libs`
all: caldavfs
-caldavfs: main.c hashmap.c
+caldavfs: main.c util.c hashmap.c
$(CC) $(CFLAGS) main.c util.c hashmap.c -o caldavfs $(LIBS)
-debug: main.c hashmap.c
+debug: main.c util.c hashmap.c
$(CC) $(CFLAGS_DEBUG) $(DEBUG_FLAGS) main.c util.c hashmap.c -o caldavfs-debug $(LIBS)
clean:
diff --git a/main.c b/main.c
@@ -15,6 +15,8 @@
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
+#include <uuid/uuid.h>
+
#define ICS_DIR "/home/mccd/dev/fuse-journal/sample_ics"
#define LOG(fmt, ...) \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
@@ -52,8 +54,13 @@ free_journal_entry(void *val)
free(entry->uid);
free(entry->filename);
free(entry->filename_original);
- free(entry->summary);
- free(entry->description);
+ if (entry->summary != NULL && strcmp(entry->summary, "") != 0) {
+ free(entry->summary);
+ }
+
+ if (entry->description != NULL && strcmp(entry->description, "") != 0) {
+ free(entry->description);
+ }
free(entry);
}
@@ -716,8 +723,13 @@ parse_entry_content(journal_entry *entry, const char *buf, size_t size)
summary = strdup(summary_line);
// Clean up old values
- free(entry->summary);
- free(entry->description);
+ if (entry->summary != NULL && strcmp(entry->summary, "") != 0) {
+ free(entry->summary);
+ }
+
+ if (entry->description != NULL && strcmp(entry->description, "") != 0) {
+ free(entry->description);
+ }
entry->summary = summary;
entry->description = strdup(description);
entry->modified_at = time(NULL);
@@ -766,6 +778,7 @@ journal_write(const char *path, const char *buf, size_t size, off_t offset,
}
// Update hashmap with input
+ LOG("Parsing entry content");
int ret = parse_entry_content(entry, buf, size);
if (ret != 0) {
pthread_mutex_unlock(&entries_mutex);
@@ -803,18 +816,9 @@ copy_journal_entry(const journal_entry *src)
time_t
timestamp_from_filename(const char *filename)
{
-
- const char *basename = strrchr(filename, '/');
- if (basename != NULL) {
- basename++;
- }
- else {
- basename = filename;
- }
-
regmatch_t matches[3];
- if (regexec(®ex_fuse_file, basename, 3, matches, 0) != 0)
+ if (regexec(®ex_fuse_file, filename, 3, matches, 0) != 0)
return INVALID_TIME;
// Extract YYYYMMDD and HH:MM
@@ -823,10 +827,10 @@ timestamp_from_filename(const char *filename)
snprintf(date_str, sizeof(date_str), "%.*s",
matches[1].rm_eo - matches[1].rm_so,
- basename + matches[1].rm_so);
+ filename + matches[1].rm_so);
snprintf(time_str, sizeof(time_str), "%.*s",
matches[2].rm_eo - matches[2].rm_so,
- basename + matches[2].rm_so);
+ filename + matches[2].rm_so);
int year, month, day, hour, minute;
if (sscanf(date_str, "%4d%2d%2d", &year, &month, &day) != 3)
@@ -892,11 +896,12 @@ static int
journal_rename(const char *old, const char *new, unsigned int flags)
{
pthread_mutex_lock(&entries_mutex);
- LOG("Renaming %s -> %s", old, new);
+ LOG("RENAME %s -> %s", old, new);
// Strip path, validate just the new basename
const char *new_basename = strrchr(new, '/');
- time_t new_created_at = timestamp_from_filename(new);
+ new_basename++;
+ time_t new_created_at = timestamp_from_filename(new_basename);
if (new_created_at == INVALID_TIME) {
LOG("Invalid filename format: %s", new_basename);
@@ -910,6 +915,65 @@ journal_rename(const char *old, const char *new, unsigned int flags)
return res;
}
+// uuid-app.ics
+char *
+create_new_unique_ics_uid()
+{
+ uuid_t uuid;
+ char uuid_str[37]; // UUIDs are 36 characters + null terminator
+ uuid_generate(uuid);
+ uuid_unparse(uuid, uuid_str);
+ char *res = NULL;
+ if (asprintf(&res, "%s-caldavfs", uuid_str) == -1) {
+ return NULL;
+ }
+ return res;
+}
+
+int
+journal_create(const char *filename, mode_t mode, struct fuse_file_info *info)
+{
+ pthread_mutex_lock(&entries_mutex);
+ LOG("CREATE %s", filename);
+
+ // Strip path, validate just the new basename
+ const char *new_basename = strrchr(filename, '/');
+ new_basename++;
+ time_t created_at = timestamp_from_filename(new_basename);
+
+ if (created_at == INVALID_TIME) {
+ LOG("Invalid filename format: %s", new_basename);
+ pthread_mutex_unlock(&entries_mutex);
+ return -EINVAL;
+ }
+
+ journal_entry *new_entry = xcalloc(1, sizeof(journal_entry));
+ new_entry->filename = strdup(new_basename);
+ new_entry->created_at = created_at;
+ new_entry->modified_at = created_at;
+ new_entry->summary = "";
+ new_entry->description = "";
+ new_entry->uid = create_new_unique_ics_uid();
+ asprintf(&new_entry->filename_original, "%s.ics", new_entry->uid);
+
+ hashmap_insert(entries_original_key, new_entry->filename_original,
+ new_entry);
+ hashmap_insert(entries_fuse_key, new_entry->filename, new_entry);
+
+ // Write back to the original
+ char *filepath = get_original_filepath(new_entry);
+
+ if (write_entry_to_ical_file(new_entry, filepath) != 0) {
+ free(filepath);
+ return -EIO;
+ }
+
+ free(filepath);
+
+ pthread_mutex_unlock(&entries_mutex);
+ return 0;
+}
+
void
update_fuse_entry_from_original(const char *filename)
{
@@ -1013,12 +1077,6 @@ watch_ics_dir(void *arg)
return NULL;
}
-int
-journal_create(const char *file_name, mode_t mode, struct fuse_file_info *info)
-{
- return -EIO;
-}
-
static const struct fuse_operations journal_oper = {.getattr = journal_getattr,
.readdir = journal_readdir,
.open = journal_open,
diff --git a/shell.nix b/shell.nix
@@ -13,5 +13,6 @@ pkgs.mkShell {
gdb
pkg-config
valgrind
+ libuuid
];
}