feat: device subsystem rework
[lunaix-os.git] / lunaix-os / kernel / fs / ramfs / ramfs.c
1 /**
2  * @file ramfs.c
3  * @author Lunaixsky
4  * @brief RamFS - a file system sit in RAM
5  * @version 0.1
6  * @date 2022-08-18
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <klibc/string.h>
12 #include <lunaix/fs.h>
13 #include <lunaix/fs/ramfs.h>
14 #include <lunaix/mm/valloc.h>
15 #include <lunaix/spike.h>
16
17 /*
18     A RAM FS will play a role of being a root.
19
20     This is an temporary meaure as we don't have any concrete fs
21     yet. In the near future, we will have an ISO-9660 as our first
22     fs and mount our boot medium as root. And similar thing could
23     be done when we have installed our OS into hard disk, in that
24     case, our rootfs will be something like ext2.
25
26     RamFS vs. TwiFS: Indeed, they are both fs that lives in RAM so
27     there is no foundmental differences. However, TwiFS is designed
28     to be a 'virtual FIlesystem for KERnel space' (FIKER), so other
29     kernel sub-modules can just create node and attach their own
30     implementation of read/write, without brothering to create a
31     full featured concrete filesystem. This particularly useful for
32     kernel state exposure. In Lunaix, TwiFS is summation of procfs,
33     sysfs and kernfs in Linux world.
34
35     However, there is a smell of bad-design in the concept of TwiFS.
36     Since it tries to integrate too much responsibility. The TwiFS may
37     be replaced by more specific fs in the future.
38
39     On the other hand, RamFS is designed to be act like a dummy fs
40     that just ensure 'something there at least' and thus provide basic
41     'mountibility' for other fs.
42 */
43
44 static volatile inode_t ino = 0;
45
46 extern const struct v_inode_ops ramfs_inode_ops;
47 extern const struct v_file_ops ramfs_file_ops;
48
49 static int
50 __ramfs_mknod(struct v_dnode* dnode, struct v_inode** nod_out, u32_t flags)
51 {
52     struct v_inode* inode = vfs_i_alloc(dnode->super_block);
53
54     if (!inode) {
55         return ENOMEM;
56     }
57
58     struct ram_inode* rinode = valloc(sizeof(struct ram_inode));
59
60     if (!rinode) {
61         vfs_i_free(inode);
62         return ENOMEM;
63     }
64
65     rinode->flags = flags;
66     inode->data = rinode;
67
68     if ((flags & RAMF_DIR)) {
69         inode->itype = VFS_IFDIR;
70     } else {
71         inode->itype = VFS_IFFILE;
72     }
73
74     if ((flags & RAMF_SYMLINK)) {
75         inode->itype |= VFS_IFSYMLINK;
76     }
77
78     if (nod_out) {
79         *nod_out = inode;
80     }
81
82     vfs_i_addhash(inode);
83     vfs_assign_inode(dnode, inode);
84
85     return 0;
86 }
87
88 int
89 ramfs_readdir(struct v_file* file, struct dir_context* dctx)
90 {
91     int i = 0;
92     struct v_dnode *pos, *n;
93     llist_for_each(pos, n, &file->dnode->children, siblings)
94     {
95         if (i++ >= dctx->index) {
96             dctx->read_complete_callback(dctx,
97                                          pos->name.value,
98                                          pos->name.len,
99                                          vfs_get_dtype(pos->inode->itype));
100             return 1;
101         }
102     }
103     return 0;
104 }
105
106 int
107 ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode)
108 {
109     return __ramfs_mknod(dnode, NULL, RAMF_DIR);
110 }
111
112 int
113 ramfs_create(struct v_inode* this, struct v_dnode* dnode)
114 {
115     return __ramfs_mknod(dnode, NULL, RAMF_FILE);
116 }
117
118 void
119 ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode)
120 {
121     inode->id = ino++;
122     inode->ops = (struct v_inode_ops*)&ramfs_inode_ops;
123     inode->default_fops = (struct v_file_ops*)&ramfs_file_ops;
124 }
125
126 int
127 ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
128 {
129     vsb->ops.init_inode = ramfs_inode_init;
130
131     return __ramfs_mknod(mount_point, NULL, RAMF_DIR);
132 }
133
134 int
135 ramfs_unmount(struct v_superblock* vsb)
136 {
137     return 0;
138 }
139
140 void
141 ramfs_init()
142 {
143     struct filesystem* ramfs = fsm_new_fs("ramfs", -1);
144     ramfs->mount = ramfs_mount;
145     ramfs->unmount = ramfs_unmount;
146
147     fsm_register(ramfs);
148 }
149 EXPORT_FILE_SYSTEM(ramfs, ramfs_init);
150
151 int
152 ramfs_mksymlink(struct v_inode* this, const char* target)
153 {
154     struct ram_inode* rinode = RAM_INODE(this->data);
155
156     assert(!(rinode->flags & RAMF_SYMLINK));
157
158     size_t len = strlen(target);
159     char* symlink = valloc(len);
160
161     if (!symlink) {
162         return ENOMEM;
163     }
164
165     memcpy(symlink, target, len);
166
167     this->itype |= VFS_IFSYMLINK;
168     rinode->flags |= RAMF_SYMLINK;
169     rinode->symlink = symlink;
170
171     return 0;
172 }
173
174 int
175 ramfs_read_symlink(struct v_inode* this, const char** path_out)
176 {
177     struct ram_inode* rinode = RAM_INODE(this->data);
178
179     if (!(rinode->flags & RAMF_SYMLINK)) {
180         return EINVAL;
181     }
182
183     *path_out = rinode->symlink;
184
185     return 0;
186 }
187
188 int
189 ramfs_unlink(struct v_inode* this)
190 {
191     struct ram_inode* rinode = RAM_INODE(this->data);
192
193     if ((rinode->flags & RAMF_SYMLINK)) {
194         rinode->flags &= ~RAMF_SYMLINK;
195         this->itype &= ~VFS_IFSYMLINK;
196
197         vfree(rinode->symlink);
198
199         return 0;
200     }
201
202     // TODO
203
204     return 0;
205 }
206
207 const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir,
208                                              .rmdir = default_inode_rmdir,
209                                              .dir_lookup =
210                                                default_inode_dirlookup,
211                                              .create = ramfs_create,
212                                              .open = default_inode_open,
213                                              .unlink = ramfs_unlink,
214                                              .set_symlink = ramfs_mksymlink,
215                                              .read_symlink = ramfs_read_symlink,
216                                              .rename = default_inode_rename };
217
218 const struct v_file_ops ramfs_file_ops = { .readdir = ramfs_readdir,
219                                            .close = default_file_close,
220                                            .read = default_file_read,
221                                            .read_page = default_file_read,
222                                            .write = default_file_write,
223                                            .write_page = default_file_write,
224                                            .seek = default_file_seek };