6efc8339381903a9643c887a7329c272109a5f26
[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_create_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);
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
64     fsm_register(twifs);
65
66     fs_root = twifs_dir_node(NULL, NULL, 0, 0);
67 }
68
69 struct twifs_node*
70 __twifs_new_node(struct twifs_node* parent,
71                  const char* name,
72                  int name_len,
73                  uint32_t itype)
74 {
75     struct twifs_node* node = cake_grab(twi_pile);
76     memset(node, 0, sizeof(*node));
77
78     node->name = HSTR(name, name_len);
79     node->itype = itype;
80     hstr_rehash(&node->name, HSTR_FULL_HASH);
81     llist_init_head(&node->children);
82
83     if (parent) {
84         llist_append(&parent->children, &node->siblings);
85     }
86
87     return node;
88 }
89
90 int
91 twifs_rm_node(struct twifs_node* node)
92 {
93     if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
94         return ENOTEMPTY;
95     }
96     llist_delete(&node->siblings);
97     vfs_i_free(node->inode);
98     cake_release(twi_pile, node);
99     return 0;
100 }
101
102 struct twifs_node*
103 twifs_file_node(struct twifs_node* parent,
104                 const char* name,
105                 int name_len,
106                 uint32_t itype)
107 {
108     struct twifs_node* twi_node =
109       __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
110
111     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
112     twi_node->inode = twi_inode;
113
114     return twi_node;
115 }
116
117 struct twifs_node*
118 twifs_dir_node(struct twifs_node* parent,
119                const char* name,
120                int name_len,
121                uint32_t itype)
122 {
123     struct hstr hname = HSTR(name, name_len);
124     hstr_rehash(&hname, HSTR_FULL_HASH);
125     struct twifs_node* node = __twifs_get_node(parent, &hname);
126     if (node) {
127         return node;
128     }
129
130     struct twifs_node* twi_node =
131       __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
132
133     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
134     twi_node->inode = twi_inode;
135
136     return twi_node;
137 }
138
139 struct twifs_node*
140 twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
141 {
142     return twifs_dir_node(fs_root, name, name_len, itype);
143 }
144
145 int
146 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
147 {
148     struct twifs_node* parent_node = (struct twifs_node*)inode->data;
149     if (!(parent_node->itype & VFS_IFDIR)) {
150         return ENOTDIR;
151     }
152     struct twifs_node* new_node =
153       twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
154     dnode->inode = new_node->inode;
155
156     return 0;
157 }
158
159 int
160 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
161 {
162     mount_point->inode = fs_root->inode;
163     return 0;
164 }
165
166 struct v_inode*
167 __twifs_create_inode(struct twifs_node* twi_node)
168 {
169     struct v_inode* inode = vfs_i_alloc();
170     inode->itype = twi_node->itype;
171     inode->data = twi_node;
172
173     inode->id = inode_id++;
174     inode->ctime = clock_unixtime();
175     inode->atime = inode->ctime;
176     inode->mtime = inode->ctime;
177
178     inode->ops.dir_lookup = __twifs_dirlookup;
179     inode->ops.mkdir = __twifs_mkdir;
180     inode->ops.unlink = __twifs_rmstuff;
181     inode->ops.rmdir = __twifs_rmstuff;
182     inode->ops.open = __twifs_openfile;
183
184     inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
185                                                .write = __twifs_fwrite,
186                                                .readdir = __twifs_iterate_dir };
187
188     return inode;
189 }
190
191 int
192 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
193 {
194     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
195     if (!twi_node || !twi_node->ops.write) {
196         return ENOTSUP;
197     }
198     return twi_node->ops.write(inode, buffer, len, fpos);
199 }
200
201 int
202 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
203 {
204     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
205     if (!twi_node || !twi_node->ops.read) {
206         return ENOTSUP;
207     }
208     return twi_node->ops.read(inode, buffer, len, fpos);
209 }
210
211 struct twifs_node*
212 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
213 {
214     if (!parent)
215         return NULL;
216
217     struct twifs_node *pos, *n;
218     llist_for_each(pos, n, &parent->children, siblings)
219     {
220         if (HSTR_EQ(&pos->name, name)) {
221             return pos;
222         }
223     }
224     return NULL;
225 }
226
227 int
228 __twifs_rmstuff(struct v_inode* inode)
229 {
230     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
231     return twifs_rm_node(twi_node);
232 }
233
234 int
235 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
236 {
237     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
238
239     if (!(twi_node->itype & VFS_IFDIR)) {
240         return ENOTDIR;
241     }
242
243     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
244     if (child_node) {
245         dnode->inode = child_node->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 }