blob: ef99d02b36bdc394f6e8d50b984339bf47a7a1d2 [file] [log] [blame]
swissChili480f1762021-07-26 22:17:34 -07001#include <dri/fs/ext2/ext2.h>
2#include <dri/fs/ext2/ext2_vfs.h>
3#include <sync.h>
4#include <alloc.h>
5#include <log.h>
6#include <io.h>
7
8struct ext2_fs_dirent
9{
10 struct fs_node *node;
11 char name[256];
12 uint name_len;
13 uint inode;
14
15 struct ext2_fs_dirent *next;
16};
17
18struct ext2_fs_data
19{
20 struct ext2_superblock *sb;
21
22 /// Cached inode
23 struct ext2_inode *in;
24
25 /// Reference count for the inode cache. Once this hits 0 we free
26 /// in. Only used for **files**, directories **always** cache
27 /// their inode.
28 uint rc;
29
30 semaphore_t lock;
31
32 /// Entries (if this is a directory)
33 struct ext2_fs_dirent *dirent;
34};
35
36uint ext2_file_read(struct fs_node *node, size_t ofs, size_t size,
37 uchar *buffer)
38{
39 struct ext2_fs_data *d = node->dri_res_p;
40 const uint block_size = ext2_block_size(d->sb);
41
42 // temporary buffer
43 uchar *tmp = malloc(block_size);
44
45 uint num_read = 0;
46
47 if (!buffer)
48 {
49 kprintf(WARN "ext2_file_read out of memory!\n");
50 return 0;
51 }
52
53 uint block_start = ofs / block_size;
54 uint block_offset = ofs % block_size;
55 int to_read;
56
57 do
58 {
59 // How much from this block to read
60 to_read = MIN(block_size - block_offset, size);
61 ext2_read_inode_block(d->sb, d->in, tmp, block_start);
62
63 // Copy that to the user buffer
64 memcpy(buffer, tmp + block_offset, to_read);
65 buffer += to_read;
66 size -= to_read;
67 num_read += to_read;
68
69 // Move to the next block
70 block_start++;
71 block_offset = 0;
72 }
73 while (to_read > 0);
74
75 free(tmp);
76 return num_read;
77}
78
79void ext2_file_open(struct fs_node *node)
80{
81 struct ext2_fs_data *d = node->dri_res_p;
82
83 sm_wait(d->lock);
84
85 if (d->rc++ == 0)
86 {
87 d->in = malloc(sizeof(struct ext2_inode));
88
89 if (d->in == NULL)
90 {
91 // lol
92 kpanic("ext2_file_open: ENOMEM");
93 }
94
95 if (!ext2_find_inode(d->sb, node->inode, d->in))
96 {
97 kprintf(ERROR "ext2_file_open: can't find inode %d\n",
98 node->inode);
99
100 free(d->in);
101 goto done;
102 }
103 }
104
105done:
106 sm_signal(d->lock);
107}
108
109void ext2_file_close(struct fs_node *node)
110{
111 struct ext2_fs_data *d = node->dri_res_p;
112
113 sm_wait(d->lock);
114
115 if (--d->rc == 0)
116 {
117 free(d->in);
118 d->in = NULL;
119 }
120
121 sm_signal(d->lock);
122}
123
124struct fs_vtable ext2_file_vfs_vt =
125{
126 .read = ext2_file_read,
127 .write = NULL,
128 .open = ext2_file_open,
129 .close = ext2_file_close,
130 .readdir = NULL,
131 .finddir = NULL,
132};
133
134bool ext2_dir_readdir(struct fs_node *node, uint index, struct fs_dirent *dirent)
135{
136 struct ext2_fs_data *d = node->dri_res_p;
137 struct ext2_fs_dirent *dent = d->dirent;
138
139 uint i;
140
141 for (i = 0; i < index && dent; i++, dent = dent->next)
142 {
143 }
144
swissChili9d876782021-07-27 19:50:07 -0700145 if (dent && i == index)
swissChili480f1762021-07-26 22:17:34 -0700146 {
swissChili9d876782021-07-27 19:50:07 -0700147 memcpy(dirent->name, dent->name, MAX(dent->name_len, FS_MAX_NAME_LEN));
swissChili480f1762021-07-26 22:17:34 -0700148 dirent->name_len = dent->name_len;
149 dirent->inode = dent->inode;
150
151 return true;
152 }
153
154 return false;
155}
156
157struct fs_node *ext2_dir_finddir(struct fs_node *node, char *name, uint name_len)
158{
159 name_len = MIN(name_len, 256);
160 struct ext2_fs_data *d = node->dri_res_p;
161 struct ext2_fs_dirent *dent = d->dirent;
162
163 for (; dent; dent = dent->next)
164 {
165 if (strncmp(dent->name, name, name_len) == 0)
166 {
167 return dent->node;
168 }
169 }
170
171 return NULL;
172}
173
174struct fs_vtable ext2_dir_vfs_vt =
175{
176 .read = NULL,
177 .write = NULL,
178 .open = NULL,
179 .close = NULL,
180 .readdir = ext2_dir_readdir,
181 .finddir = ext2_dir_finddir,
182};
183
184struct ext2_fs_dirent_to_fs_data
185{
186 struct ext2_fs_data *d;
187 struct ext2_fs_dirent *last;
188 struct ext2_superblock *sb;
189};
190
191static bool ext2_dirent_to_fs_node_cb(uint inode, const char *name,
192 uint name_len, void *data)
193{
194 struct ext2_fs_dirent_to_fs_data *d = data;
195
196 struct ext2_fs_dirent *dent =
197 malloc(sizeof(struct ext2_fs_dirent));
198
swissChili9d876782021-07-27 19:50:07 -0700199 if (strncmp(".", (char *)name, name_len) == 0 ||
200 strncmp("..", (char *)name, name_len) == 0)
swissChilia664e722021-07-27 17:47:55 -0700201 {
202 return true;
203 }
204
swissChili480f1762021-07-26 22:17:34 -0700205 dent->node = ext2_inode2vfs(d->sb, inode, (char *)name, name_len);
206 dent->name_len = name_len;
207 memcpy(dent->name, name, MIN(name_len, 256));
208 dent->inode = inode;
209
210 if (d->last)
211 {
212 d->last->next = dent;
213 d->last = dent;
214 }
215 else
216 {
217 d->last = d->d->dirent = dent;
218 }
219
220 return true;
221}
222
223struct fs_node *ext2_inode2vfs(struct ext2_superblock *sb, uint inode,
224 char *name, uint name_len)
225{
226 struct ext2_inode in;
227
228 if (!ext2_find_inode(sb, inode, &in))
229 {
230 // Something has gone terribly wrong!
231 return NULL;
232 }
233
234 struct ext2_fs_data *d = malloc(sizeof(struct ext2_fs_data));
235
236 d->sb = sb;
237 d->rc = 0;
238 d->lock = sm_new();
239 d->in = NULL;
240 d->dirent = NULL;
241
242 struct fs_node *n = malloc(sizeof(struct fs_node));
243
244 n->name_len = MIN(name_len, FS_MAX_NAME_LEN);
245 memcpy(n->name, name, n->name_len);
246 n->inode = inode;
247 n->dri_res_p = d;
248
249 n->mask = in.mode & 0xfff;
250 n->gid = in.gid;
251 n->uid = in.uid;
252 n->size = in.size;
253
254 switch (in.mode & EXT2_F_TYPE)
255 {
256 case EXT2_S_IFREG:
257 {
258 n->flags = FS_FILE;
259 n->vtable = &ext2_file_vfs_vt;
260
261 break;
262 }
263
264 case EXT2_S_IFDIR:
265 {
266 n->flags = FS_DIRECTORY;
267 n->vtable = &ext2_dir_vfs_vt;
268
269 struct ext2_fs_dirent_to_fs_data data;
270 data.d = d;
271 data.last = NULL;
swissChilia664e722021-07-27 17:47:55 -0700272 data.sb = sb;
swissChili480f1762021-07-26 22:17:34 -0700273
274 ext2_dir_ls(sb, &in, ext2_dirent_to_fs_node_cb, &data);
275
276 break;
277 }
278
279 default:
280 {
281 kprintf(ERROR "ext2_inode2vfs: unimplemented for dir type%d\n",
282 EXT2_S_TO_FT(in.mode));
283 kpanic("Unimplemented");
284 }
285 }
286
287 return n;
288}