feat: simple device abstraction layer
[lunaix-os.git] / lunaix-os / kernel / fs / twifs.c
1 /**
2  * @file twifs.c
3  * @author Lunaixsky (zelong56@gmail.com)
4  * @brief TwiFS - A pseudo file system for kernel state exposure.
5  * @version 0.1
6  * @date 2022-07-21
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <klibc/string.h>
12 #include <lunaix/clock.h>
13 #include <lunaix/fs.h>
14 #include <lunaix/fs/twifs.h>
15 #include <lunaix/mm/cake.h>
16 #include <lunaix/mm/valloc.h>
17
18 static struct twifs_node* fs_root;
19
20 static struct cake_pile* twi_pile;
21
22 int
23 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
24
25 int
26 __twifs_openfile(struct v_inode* inode, struct v_file* file);
27
28 struct twifs_node*
29 __twifs_get_node(struct twifs_node* parent, struct hstr* name);
30
31 struct v_inode*
32 __twifs_create_inode(struct twifs_node* twi_node);
33
34 int
35 __twifs_iterate_dir(struct v_file* file, struct dir_context* dctx);
36
37 int
38 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
39
40 int
41 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
42
43 void
44 twifs_init()
45 {
46     twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
47
48     struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
49     twifs->fs_name = HSTR("twifs", 5);
50     twifs->mount = __twifs_mount;
51
52     fsm_register(twifs);
53
54     fs_root = twifs_dir_node(NULL, NULL, 0);
55 }
56
57 struct twifs_node*
58 __twifs_new_node(struct twifs_node* parent, const char* name, int name_len)
59 {
60     struct twifs_node* node = cake_grab(twi_pile);
61     memset(node, 0, sizeof(*node));
62
63     node->name = HSTR(name, name_len);
64     hstr_rehash(&node->name, HSTR_FULL_HASH);
65     llist_init_head(&node->children);
66
67     if (parent) {
68         llist_append(&parent->children, &node->siblings);
69     }
70
71     return node;
72 }
73
74 void
75 twifs_rm_node(struct twifs_node* node)
76 {
77     // TODO recursivly delete any sub-directories.
78     if ((node->itype & VFS_INODE_TYPE_DIR)) {
79         struct twifs_node* dir = __twifs_get_node(node, &vfs_dot);
80         struct twifs_node* dir2 = __twifs_get_node(node, &vfs_ddot);
81         vfs_i_free(dir->inode);
82         vfs_i_free(dir2->inode);
83         cake_release(twi_pile, dir);
84         cake_release(twi_pile, dir2);
85     }
86     llist_delete(&node->siblings);
87     vfs_i_free(node->inode);
88     cake_release(twi_pile, node);
89 }
90
91 struct twifs_node*
92 twifs_file_node(struct twifs_node* parent, const char* name, int name_len)
93 {
94     struct twifs_node* twi_node = __twifs_new_node(parent, name, name_len);
95     twi_node->itype = VFS_INODE_TYPE_FILE;
96
97     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
98     twi_node->inode = twi_inode;
99
100     return twi_node;
101 }
102
103 struct twifs_node*
104 twifs_dir_node(struct twifs_node* parent, const char* name, int name_len)
105 {
106     struct hstr hname = HSTR(name, name_len);
107     hstr_rehash(&hname, HSTR_FULL_HASH);
108     struct twifs_node* node = __twifs_get_node(parent, &hname);
109     if (node) {
110         return node;
111     }
112
113     struct twifs_node* twi_node = __twifs_new_node(parent, name, name_len);
114     twi_node->itype = VFS_INODE_TYPE_DIR;
115     twi_node->fops.readdir = __twifs_iterate_dir;
116
117     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
118     struct twifs_node* dot = __twifs_new_node(twi_node, ".", 1);
119     struct twifs_node* ddot = __twifs_new_node(twi_node, "..", 2);
120
121     dot->itype = VFS_INODE_TYPE_DIR;
122     ddot->itype = VFS_INODE_TYPE_DIR;
123
124     twi_node->inode = twi_inode;
125     dot->inode = twi_inode;
126     ddot->inode = parent ? parent->inode : twi_inode;
127
128     return twi_node;
129 }
130
131 struct twifs_node*
132 twifs_toplevel_node(const char* name, int name_len)
133 {
134     return twifs_dir_node(fs_root, name, name_len);
135 }
136
137 int
138 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
139 {
140     struct twifs_node* parent_node = (struct twifs_node*)inode->data;
141     if (!(parent_node->itype & VFS_INODE_TYPE_DIR)) {
142         return ENOTDIR;
143     }
144     struct twifs_node* new_node =
145       twifs_dir_node(parent_node, dnode->name.value, dnode->name.len);
146     dnode->inode = new_node->inode;
147
148     return 0;
149 }
150
151 int
152 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
153 {
154     mount_point->inode = fs_root->inode;
155     // FIXME try to mitigate this special case or pull it up to higher level of
156     // abstraction
157     if (mount_point->parent && mount_point->parent->inode) {
158         struct hstr ddot_name = HSTR("..", 2);
159         struct twifs_node* root_ddot = __twifs_get_node(fs_root, &ddot_name);
160         root_ddot->inode = mount_point->parent->inode;
161     }
162     return 0;
163 }
164
165 struct v_inode*
166 __twifs_create_inode(struct twifs_node* twi_node)
167 {
168     struct v_inode* inode = vfs_i_alloc();
169     *inode = (struct v_inode){ .ctime = 0,
170                                .itype = twi_node->itype,
171                                .lb_addr = 0,
172                                .lb_usage = 0,
173                                .data = twi_node,
174                                .mtime = 0,
175                                .ref_count = 0 };
176     inode->ops.dir_lookup = __twifs_dirlookup;
177     inode->ops.mkdir = __twifs_mkdir;
178     inode->ops.open = __twifs_openfile;
179
180     return inode;
181 }
182
183 struct twifs_node*
184 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
185 {
186     if (!parent)
187         return NULL;
188
189     struct twifs_node *pos, *n;
190     llist_for_each(pos, n, &parent->children, siblings)
191     {
192         if (HSTR_EQ(&pos->name, name)) {
193             return pos;
194         }
195     }
196     return NULL;
197 }
198
199 int
200 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
201 {
202     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
203
204     if (!(twi_node->itype & VFS_INODE_TYPE_DIR)) {
205         return ENOTDIR;
206     }
207
208     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
209     if (child_node) {
210         dnode->inode = child_node->inode;
211         return 0;
212     }
213     return ENOENT;
214 }
215
216 int
217 __twifs_iterate_dir(struct v_file* file, struct dir_context* dctx)
218 {
219     struct twifs_node* twi_node = (struct twifs_node*)(file->inode->data);
220     int counter = 0;
221     struct twifs_node *pos, *n;
222
223     llist_for_each(pos, n, &twi_node->children, siblings)
224     {
225         if (counter++ >= dctx->index) {
226             dctx->index = counter;
227             dctx->read_complete_callback(
228               dctx, pos->name.value, pos->name.len, pos->itype);
229             return 0;
230         }
231     }
232
233     return 1;
234 }
235
236 int
237 __twifs_openfile(struct v_inode* inode, struct v_file* file)
238 {
239     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
240     if (twi_node) {
241         file->inode = twi_node->inode;
242         file->ops = twi_node->fops;
243         return 0;
244     }
245     return ENOTSUP;
246 }