agendafs
A filesystem for your calendar.
git clone git://mccd.space/agendafscommit 9e88f3cbc71e562b1f2f20c96f3f60593d843630
parent 1aff4c96ef6d5f6deb6c34246f72b9aa544a34c2
Author: Marc Coquand <marc@coquand.email>
Date: Fri, 27 Jun 2025 12:01:39 +0100
Updates
Diffstat:
5 files changed, 142 insertions(+), 17 deletions(-)
diff --git a/journal_entry.c b/journal_entry.c
@@ -382,15 +382,15 @@ is_directory_component(icalcomponent *component)
// We assume it to be a directory if it has a property directory property
// so or is a parent node
bool
-entry_is_directory(tree_node *node)
+node_is_directory(tree_node *node)
{
- if (!node->data) {
- return true;
- }
- else if (node->child_count > 0) {
+ if (is_root_node(node) || node_has_children(node)) {
return true;
}
else {
+ // When user creates a directory, a directory component is
+ // stored in the ics file. So even if a node has no children
+ // it can still be that it should be shown as a directory.
struct journal_entry *entry = node->data;
return is_directory_component(entry->component);
}
@@ -484,10 +484,18 @@ int
load_journal_entry_from_ics_file(char *filename, struct journal_entry *entry)
{
char *filepath = NULL;
+
if (asprintf(&filepath, "%s/%s", ICS_DIR, filename) == -1) {
perror("aspintf failed");
return -1;
}
+ struct stat fileStat;
+ if (stat(filepath, &fileStat) == -1) {
+ LOG("Can not stat %s. skipping", filepath);
+ free(filepath);
+ return -1;
+ }
+
entry->filename_original = strdup(filename);
if (!entry->filename_original) {
perror("strdup failed");
@@ -501,6 +509,9 @@ load_journal_entry_from_ics_file(char *filename, struct journal_entry *entry)
return -1;
}
+ entry->uid = fileStat.st_uid;
+ entry->gid = fileStat.st_gid;
+
// Make sure filename, which happens when
// Two entries are created on the same minute
// TODO: Check for duplicates
@@ -572,6 +583,7 @@ load_journal_entries()
// First pass: Store everything in root tree, fill up hashmap
while ((entry = readdir(dir))) {
if (entry->d_type == DT_REG && strstr(entry->d_name, ".ics")) {
+
struct journal_entry *new_entry =
xcalloc(1, sizeof(struct journal_entry));
@@ -661,6 +673,24 @@ get_last_modified(struct journal_entry *entry)
}
}
+uid_t
+get_node_uid(tree_node *node)
+{
+ if (is_root_node(node)) {
+ return getuid();
+ }
+ return get_entry(node)->uid;
+}
+
+gid_t
+get_node_gid(tree_node *node)
+{
+ if (is_root_node(node)) {
+ return getgid();
+ }
+ return get_entry(node)->gid;
+}
+
struct journal_entry *
copy_journal_entry(const struct journal_entry *src)
{
@@ -669,6 +699,8 @@ copy_journal_entry(const struct journal_entry *src)
copy->filename = strdup(src->filename);
copy->filename_original = strdup(src->filename_original);
copy->component = icalcomponent_new_clone(src->component);
+ copy->gid = src->gid;
+ copy->uid = src->uid;
return copy;
}
@@ -957,7 +989,7 @@ create_entry_from_fuse(const char *fuse_path)
LOG("Parent is not node");
return -ENOENT;
}
- if (!entry_is_directory(parent)) {
+ if (!node_is_directory(parent)) {
LOG("Parent is not directory ");
return -ENOTDIR;
@@ -1013,7 +1045,7 @@ create_directory_from_fuse_path(const char *fuse_path)
LOG("Parent is not node");
return -ENOENT;
}
- if (!entry_is_directory(parent)) {
+ if (!node_is_directory(parent)) {
LOG("Parent is not directory ");
return -ENOTDIR;
@@ -1070,6 +1102,43 @@ update_or_create_fuse_entry_from_original(const char *filename)
LOG("File updated");
}
+int
+delete_dir_from_fuse_path(const char *filepath)
+{
+ int res = 0;
+ tree_node *node = get_node_by_path(fuse_tree_root, filepath);
+ if (!node) {
+ LOG("Node not found");
+ return -EIO;
+ }
+ if (!node_is_directory(node)) {
+ return -ENOTDIR;
+ }
+ if (node->child_count > 0) {
+ return -ENOTEMPTY;
+ }
+
+ struct journal_entry *entry = get_entry(node);
+ char *filepath_original = get_original_filepath(entry);
+ if (!filepath_original) {
+ LOG("Entry not found");
+ return -EIO;
+ }
+ LOG("Deleting file %s, located at %s", filepath, filepath_original);
+
+ res = remove(filepath_original);
+ if (res != 0) {
+ LOG("Failed to delete file");
+ return -res;
+ }
+
+ hashmap_remove(entries_original_ics, filepath_original);
+
+ detach_tree_node(node);
+ free_tree(node);
+ return res;
+}
+
// Deletes original file too!
int
delete_from_fuse_path(const char *filepath)
@@ -1079,22 +1148,21 @@ delete_from_fuse_path(const char *filepath)
if (!node) {
return -EIO;
}
+ if (node_is_directory(node)) {
+ return -EISDIR;
+ }
struct journal_entry *entry = get_entry(node);
char *filepath_original = get_original_filepath(entry);
if (!filepath_original) {
LOG("Entry not found");
return -EIO;
}
- LOG("Deleting file %s", filepath);
+ LOG("Deleting file %s, located at %s", filepath, filepath_original);
- res = remove(filepath);
+ res = remove(filepath_original);
hashmap_remove(entries_original_ics, filepath_original);
- // TODO: Subdirectories SHOULD NOT BE REMOVED HERE
- // Instead, update the children so they have a new parent
- // which is the parent node.
- // Requires a change_parent function.
detach_tree_node(node);
free_tree(node);
return res;
diff --git a/journal_entry.h b/journal_entry.h
@@ -31,6 +31,9 @@ struct journal_entry {
// filename_original is the relative path to ICS_DIR
// I.E. 910319208nrao19p.ics
char *filename_original;
+ uid_t uid;
+ gid_t gid;
+
icalcomponent *component;
};
@@ -85,8 +88,11 @@ find_node_by_path(struct tree_node *root, const char *path);
struct journal_entry *
get_entry(struct tree_node *node);
+int
+delete_dir_from_fuse_path(const char *filepath);
+
bool
-entry_is_directory(struct tree_node *node);
+node_is_directory(struct tree_node *node);
int
delete_from_fuse_path(const char *filepath);
@@ -144,6 +150,12 @@ create_vjournal_entry(char *summary);
int
create_directory_from_fuse_path(const char *fuse_path);
+uid_t
+get_node_uid(struct tree_node *node);
+
+gid_t
+get_node_gid(struct tree_node *node);
+
void
remove_file_extension(char *path);
diff --git a/main.c b/main.c
@@ -39,6 +39,10 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0444;
stbuf->st_nlink = 2;
+
+ // TODO: Probably should be set with an option?
+ stbuf->st_uid = getuid();
+ stbuf->st_gid = getgid();
goto unlock_and_return;
}
@@ -50,12 +54,18 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
}
struct journal_entry *entry = get_entry(node);
- if (entry_is_directory(node)) {
+ if (node_is_directory(node)) {
stbuf->st_mode = S_IFDIR | 0444;
+ stbuf->st_uid = get_node_uid(node);
+ stbuf->st_gid = get_node_gid(node);
+
stbuf->st_nlink = 2;
}
else {
stbuf->st_mode = S_IFREG | 0774;
+ stbuf->st_uid = get_node_uid(node);
+ stbuf->st_gid = get_node_gid(node);
+
stbuf->st_nlink = 1;
}
@@ -108,7 +118,10 @@ journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
st.st_ino = i + 1;
st.st_mode = S_IFREG | 0744;
- if (entry_is_directory(node)) {
+ st.st_uid = get_node_uid(node);
+ st.st_gid = get_node_gid(node);
+
+ if (node_is_directory(node)) {
st.st_mode = S_IFDIR | 0755;
}
@@ -127,7 +140,10 @@ journal_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
st.st_ino = i + 1;
st.st_mode = S_IFREG | 0744;
- if (entry_is_directory(child)) {
+ st.st_uid = get_node_uid(child);
+ st.st_gid = get_node_gid(child);
+
+ if (node_is_directory(child)) {
st.st_mode = S_IFDIR | 0755;
}
@@ -263,6 +279,25 @@ journal_unlink(const char *file)
}
int
+journal_rmdir(const char *file)
+{
+ pthread_mutex_lock(&entries_mutex);
+ LOG("DELETE %s", file);
+ int res = 0;
+
+ res = delete_dir_from_fuse_path(file);
+ if (res != 0) {
+ LOG("Failed to delete file");
+ pthread_mutex_unlock(&entries_mutex);
+ return res;
+ }
+
+ LOG("Delete successful");
+ pthread_mutex_unlock(&entries_mutex);
+ return 0;
+}
+
+int
journal_rename(const char *old, const char *new, unsigned int flags)
{
pthread_mutex_lock(&entries_mutex);
@@ -375,6 +410,7 @@ static const struct fuse_operations journal_oper = {.getattr = journal_getattr,
.create = journal_create,
.mkdir = journal_mkdir,
.unlink = journal_unlink,
+ .rmdir = journal_rmdir,
.readlink =
journal_readlink,
.rename = journal_rename};
diff --git a/tree.c b/tree.c
@@ -45,6 +45,12 @@ update_node_data(tree_node *node, void *data)
node->data = data;
}
+bool
+node_has_children(tree_node *node)
+{
+ return node->child_count > 0;
+}
+
// Free a node and all its children
void
free_tree(tree_node *node)
diff --git a/tree.h b/tree.h
@@ -18,6 +18,9 @@ typedef struct tree_node {
tree_node *
create_tree_node(void *data, void (*free_fn)(void *));
+bool
+node_has_children(tree_node *node);
+
void
update_node_data(tree_node *node, void *data);