agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs

fuse_node_store.c (3389B)

      1 #include "agenda_entry.h"
      2 #include "hashmap.h"
      3 #include "path.h"
      4 #include "tree.h"
      5 #include "util.h"
      6 #include <stddef.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 char VDIR[256];
     10 
     11 char FILE_EXTENSION[256] = "";
     12 
     13 // A structure of the current root
     14 struct tree_node *fuse_root = NULL;
     15 // ics entries, keys are the filename as stored in ICS_DIR
     16 // I.E. bcb4c14b-8f3f-4a53-ad33-1f4499071a9m-caldavfs.ics
     17 struct hashmap *entries_vdir = NULL;
     18 
     19 // Copies vdir
     20 void
     21 set_vdir(const char *expanded_path)
     22 {
     23 	strlcpy(VDIR, expanded_path, sizeof(VDIR));
     24 }
     25 
     26 const char *
     27 get_default_file_extension()
     28 {
     29 	return FILE_EXTENSION;
     30 }
     31 
     32 int
     33 set_file_extension(const char *extension)
     34 {
     35 	if (extension[0] == '.') {
     36 		return -1;
     37 	}
     38 
     39 	if (strlen(extension) > 256) {
     40 		return -2;
     41 	}
     42 
     43 	strlcpy(FILE_EXTENSION, extension, sizeof(FILE_EXTENSION));
     44 	return 0;
     45 }
     46 
     47 int
     48 set_node_filename(struct tree_node *node, const char *filename)
     49 {
     50 	struct agenda_entry *entry = node->data;
     51 	free(entry->filename);
     52 	entry->filename = xstrdup(filename);
     53 	return 0;
     54 }
     55 
     56 struct tree_node *
     57 get_fuse_node_from_vdir_name(const char *vdir_name)
     58 {
     59 	return hashmap_get(entries_vdir, vdir_name);
     60 }
     61 
     62 const struct agenda_entry *
     63 get_entry(const struct tree_node *node)
     64 {
     65 	return node->data;
     66 }
     67 
     68 bool
     69 is_root_node(const struct tree_node *node)
     70 {
     71 	// Root node is the only item without an agenda_entry
     72 	return !node->data;
     73 }
     74 
     75 const char *
     76 get_node_filename(const struct tree_node *node)
     77 {
     78 	struct agenda_entry *entry = node->data;
     79 	if (entry == NULL)
     80 		return "";
     81 	return entry->filename;
     82 }
     83 
     84 const char *
     85 get_vdir_filepath(arena *ar, const struct tree_node *node)
     86 {
     87 	const struct agenda_entry *entry = get_entry(node);
     88 	return append_path(ar, VDIR, entry->filename_vdir);
     89 }
     90 
     91 void
     92 delete_fuse_node(struct tree_node *node)
     93 {
     94 	const struct agenda_entry *e = get_entry(node);
     95 	hashmap_remove(entries_vdir, e->filename_vdir);
     96 	detach_tree_node(node);
     97 	free_tree(node);
     98 }
     99 
    100 // Copies agenda_entry
    101 struct tree_node *
    102 create_fuse_node(const struct agenda_entry *entry)
    103 {
    104 	struct agenda_entry *cpy = copy_agenda_entry(entry);
    105 
    106 	struct tree_node *new_node =
    107 	    create_tree_node(cpy, (void *)free_agenda_entry);
    108 
    109 	hashmap_insert(entries_vdir, cpy->filename_vdir, new_node);
    110 
    111 	return new_node;
    112 }
    113 
    114 struct tree_node *
    115 upsert_fuse_node(const struct agenda_entry *entry)
    116 {
    117 	struct tree_node *node =
    118 	    hashmap_get(entries_vdir, entry->filename_vdir);
    119 	if (node) {
    120 		set_node_filename(node, entry->filename);
    121 	}
    122 	else {
    123 		node = create_fuse_node(entry);
    124 	}
    125 
    126 	return node;
    127 }
    128 
    129 // Add fuse child to node.
    130 // OBS: Modifies filename if not unique!
    131 size_t
    132 add_fuse_child(struct tree_node *parent, struct tree_node *child)
    133 {
    134 	const char *filename = get_node_filename(child);
    135 
    136 	char *new_filename = xstrdup(filename);
    137 
    138 	size_t conflict_count = 1;
    139 
    140 	while (true) {
    141 		bool is_unique = true;
    142 		for (size_t i = 0; i < parent->child_count; i++) {
    143 			const char *sibling_filename =
    144 			    get_node_filename(parent->children[i]);
    145 
    146 			if (strcmp(new_filename, sibling_filename) == 0) {
    147 				is_unique = false;
    148 				break;
    149 			}
    150 		}
    151 
    152 		if (is_unique) {
    153 			break;
    154 		}
    155 
    156 		free(new_filename);
    157 		new_filename = filename_numbered(filename, conflict_count++);
    158 	}
    159 
    160 	set_node_filename(child, new_filename);
    161 
    162 	return add_child(parent, child);
    163 }
    164 
    165 size_t
    166 move_fuse_node(struct tree_node *new_parent, struct tree_node *child)
    167 {
    168 	detach_tree_node(child);
    169 	return add_fuse_child(new_parent, child);
    170 }