refactor: mount system reworked
[lunaix-os.git] / lunaix-os / kernel / fs / twifs / 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 static volatile int32_t inode_id = 0;
23
24 int
25 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
26
27 int
28 __twifs_openfile(struct v_inode* inode, struct v_file* file);
29
30 struct twifs_node*
31 __twifs_get_node(struct twifs_node* parent, struct hstr* name);
32
33 struct v_inode*
34 __twifs_get_inode(struct twifs_node* twi_node);
35
36 int
37 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx);
38
39 int
40 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
41
42 int
43 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
44
45 int
46 __twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir);
47
48 int
49 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
50
51 int
52 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
53
54 void
55 twifs_init()
56 {
57     twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
58
59     struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
60     twifs->fs_name = HSTR("twifs", 5);
61     twifs->mount = __twifs_mount;
62     twifs->types = FSTYPE_ROFS;
63     twifs->fs_id = 0;
64
65     fsm_register(twifs);
66
67     fs_root = twifs_dir_node(NULL, NULL, 0, 0);
68 }
69
70 struct twifs_node*
71 __twifs_new_node(struct twifs_node* parent,
72                  const char* name,
73                  int name_len,
74                  uint32_t itype)
75 {
76     struct twifs_node* node = cake_grab(twi_pile);
77     memset(node, 0, sizeof(*node));
78
79     node->name = HSTR(name, name_len);
80     node->itype = itype;
81     node->ino_id = inode_id++;
82     hstr_rehash(&node->name, HSTR_FULL_HASH);
83     llist_init_head(&node->children);
84
85     if (parent) {
86         llist_append(&parent->children, &node->siblings);
87     }
88
89     return node;
90 }
91
92 int
93 twifs_rm_node(struct twifs_node* node)
94 {
95     if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
96         return ENOTEMPTY;
97     }
98     llist_delete(&node->siblings);
99     cake_release(twi_pile, node);
100     return 0;
101 }
102
103 struct twifs_node*
104 twifs_file_node(struct twifs_node* parent,
105                 const char* name,
106                 int name_len,
107                 uint32_t itype)
108 {
109     struct twifs_node* twi_node =
110       __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
111
112     return twi_node;
113 }
114
115 struct twifs_node*
116 twifs_dir_node(struct twifs_node* parent,
117                const char* name,
118                int name_len,
119                uint32_t itype)
120 {
121     struct hstr hname = HSTR(name, name_len);
122     hstr_rehash(&hname, HSTR_FULL_HASH);
123     struct twifs_node* node = __twifs_get_node(parent, &hname);
124     if (node) {
125         return node;
126     }
127
128     struct twifs_node* twi_node =
129       __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
130
131     return twi_node;
132 }
133
134 struct twifs_node*
135 twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
136 {
137     return twifs_dir_node(fs_root, name, name_len, itype);
138 }
139
140 int
141 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
142 {
143     return ENOTSUP;
144 }
145
146 void
147 __twifs_init_inode(struct v_inode* inode, void* data)
148 {
149     struct twifs_node* twi_node = (struct twifs_node*)data;
150
151     inode->itype = twi_node->itype;
152     inode->data = twi_node;
153
154     inode->ctime = clock_unixtime();
155     inode->atime = inode->ctime;
156     inode->mtime = inode->ctime;
157
158     inode->ops.dir_lookup = __twifs_dirlookup;
159     inode->ops.mkdir = __twifs_mkdir;
160     inode->ops.rmdir = __twifs_rmstuff;
161     inode->ops.open = __twifs_openfile;
162
163     inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
164                                                .write = __twifs_fwrite,
165                                                .readdir = __twifs_iterate_dir };
166
167     return inode;
168 }
169
170 int
171 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
172 {
173     vsb->dev = 1;
174     struct v_inode* inode =
175       vfs_i_alloc(vsb, fs_root->ino_id, __twifs_init_inode, fs_root);
176     if (!inode) {
177         return ENOMEM;
178     }
179     vfs_assign_inode(mount_point, inode);
180     return 0;
181 }
182
183 int
184 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
185 {
186     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
187     if (!twi_node || !twi_node->ops.write) {
188         return ENOTSUP;
189     }
190     return twi_node->ops.write(inode, buffer, len, fpos);
191 }
192
193 int
194 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
195 {
196     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
197     if (!twi_node || !twi_node->ops.read) {
198         return ENOTSUP;
199     }
200     return twi_node->ops.read(inode, buffer, len, fpos);
201 }
202
203 struct twifs_node*
204 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
205 {
206     if (!parent)
207         return NULL;
208
209     struct twifs_node *pos, *n;
210     llist_for_each(pos, n, &parent->children, siblings)
211     {
212         if (HSTR_EQ(&pos->name, name)) {
213             return pos;
214         }
215     }
216     return NULL;
217 }
218
219 int
220 __twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir)
221 {
222     return ENOTSUP;
223 }
224
225 int
226 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
227 {
228     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
229
230     if (!(twi_node->itype & VFS_IFDIR)) {
231         return ENOTDIR;
232     }
233
234     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
235     if (child_node) {
236         struct v_inode* inode = vfs_i_alloc(dnode->super_block,
237                                             child_node->ino_id,
238                                             __twifs_init_inode,
239                                             child_node);
240         if (!inode) {
241             return ENOENT;
242         }
243
244         dnode->data = twi_node->data;
245         vfs_assign_inode(dnode, inode);
246         return 0;
247     }
248     return ENOENT;
249 }
250
251 int
252 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx)
253 {
254     struct twifs_node* twi_node = (struct twifs_node*)(inode->data);
255     int counter = 0;
256     struct twifs_node *pos, *n;
257
258     llist_for_each(pos, n, &twi_node->children, siblings)
259     {
260         if (counter++ >= dctx->index) {
261             dctx->index = counter;
262             dctx->read_complete_callback(
263               dctx, pos->name.value, pos->name.len, pos->itype);
264             return 0;
265         }
266     }
267
268     return 1;
269 }
270
271 int
272 __twifs_openfile(struct v_inode* inode, struct v_file* file)
273 {
274     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
275     if (twi_node) {
276         return 0;
277     }
278     return ENOTSUP;
279 }