fix dependency check logic cause config always disabled
[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/api.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     inode->itype = VFS_IFFILE;
68
69     if ((flags & RAMF_DIR)) {
70         inode->itype |= VFS_IFDIR;
71     }
72
73     if ((flags & RAMF_SYMLINK)) {
74         inode->itype |= VFS_IFSYMLINK;
75     }
76
77     if (nod_out) {
78         *nod_out = inode;
79     }
80
81     vfs_i_addhash(inode);
82     vfs_assign_inode(dnode, inode);
83
84     return 0;
85 }
86
87 int
88 ramfs_readdir(struct v_file* file, struct dir_context* dctx)
89 {
90     unsigned int i = 2;
91     struct v_dnode *pos, *n;
92
93     if (fsapi_handle_pseudo_dirent(file, dctx)) {
94         return 1;
95     }
96
97     llist_for_each(pos, n, &file->dnode->children, siblings)
98     {
99         if (i++ >= file->f_pos) {
100             dctx->read_complete_callback(dctx,
101                                          pos->name.value,
102                                          pos->name.len,
103                                          vfs_get_dtype(pos->inode->itype));
104             return 1;
105         }
106     }
107     return 0;
108 }
109
110 int
111 ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode)
112 {
113     return __ramfs_mknod(dnode, NULL, RAMF_DIR);
114 }
115
116 int
117 ramfs_create(struct v_inode* this, struct v_dnode* dnode, unsigned int itype)
118 {
119     return __ramfs_mknod(dnode, NULL, RAMF_FILE);
120 }
121
122 void
123 ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode)
124 {
125     inode->id = ino++;
126     inode->ops = (struct v_inode_ops*)&ramfs_inode_ops;
127     inode->default_fops = (struct v_file_ops*)&ramfs_file_ops;
128 }
129
130 int
131 ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
132 {
133     vsb->ops.init_inode = ramfs_inode_init;
134
135     int errno = __ramfs_mknod(mount_point, NULL, RAMF_DIR);
136
137     if (!errno) {
138         fsapi_inode_setaccess(mount_point->inode, FSACL_DEFAULT);
139     }
140
141     return errno;
142 }
143
144 int
145 ramfs_unmount(struct v_superblock* vsb)
146 {
147     return 0;
148 }
149
150 int
151 ramfs_mksymlink(struct v_inode* this, const char* target)
152 {
153     struct ram_inode* rinode = RAM_INODE(this->data);
154
155     assert(!(rinode->flags & RAMF_SYMLINK));
156
157     size_t len = strlen(target) + 1;
158     char* symlink = valloc(len);
159
160     if (!symlink) {
161         return ENOMEM;
162     }
163
164     memcpy(symlink, target, len);
165
166     this->itype = VFS_IFSYMLINK;
167     rinode->flags |= RAMF_SYMLINK;
168     rinode->symlink = symlink;
169     rinode->size = len;
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 rinode->size;
186 }
187
188 int
189 ramfs_unlink(struct v_inode* this, struct v_dnode* name)
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 &= ~F_SYMLINK;
196
197         vfree(rinode->symlink);
198
199         return 0;
200     }
201
202     // TODO
203
204     return 0;
205 }
206
207 static void
208 ramfs_init()
209 {
210     struct filesystem* fs;
211     fs = fsapi_fs_declare("ramfs", FSTYPE_PSEUDO);
212     
213     fsapi_fs_set_mntops(fs, ramfs_mount, ramfs_unmount);
214     fsapi_fs_finalise(fs);
215 }
216 EXPORT_FILE_SYSTEM(ramfs, ramfs_init);
217
218 const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir,
219                                              .rmdir = default_inode_rmdir,
220                                              .dir_lookup =
221                                                default_inode_dirlookup,
222                                              .create = ramfs_create,
223                                              .open = default_inode_open,
224                                              .unlink = ramfs_unlink,
225                                              .set_symlink = ramfs_mksymlink,
226                                              .read_symlink = ramfs_read_symlink,
227                                              .rename = default_inode_rename };
228
229 const struct v_file_ops ramfs_file_ops = { .readdir = ramfs_readdir,
230                                            .close = default_file_close,
231                                            .read = default_file_read,
232                                            .read_page = default_file_read_page,
233                                            .write = default_file_write,
234                                            .write_page =
235                                              default_file_write_page,
236                                            .seek = default_file_seek };