Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
iso9660.c
Go to the documentation of this file.
1#include "iso9660.h"
2#include "libk/serial.h"
3#include "memory/kalloc.h"
4#include "type.h"
5#include "vfs/enum.h"
6#include "vfs/filesystem.h"
7#include "vfs/vfs.h"
8#include <str.h>
9#include <vfs/dentry.h>
10#include <vfs/dev.h>
11#include <vfs/vnode.h>
12
15static vops_lnk_t _lnk_ops = {0};
16
22
23static int iso9660_get_rr_symlink(struct iso9660_dir* entry, char* out_target) {
24 /* SUA started after fixed header (33 byte) + name_len, align into 2
25 * byte */
26 uint8_t name_len = entry->name_len;
27 uint8_t sua_offset = 33 + name_len;
28 if (sua_offset % 2 != 0)
29 sua_offset += 1; /* padding byte */
30
31 uint8_t total_len = entry->length;
32 if (sua_offset >= total_len)
33 return 0; /* no SUA */
34
35 uint8_t* sua = (uint8_t*)entry + sua_offset;
36 uint8_t sua_len = total_len - sua_offset;
37 uint8_t i = 0;
38 int target_len = 0;
39
40 out_target[0] = '\0';
41
42 while (i + 4 <= sua_len) {
43 uint8_t sig0 = sua[i];
44 uint8_t sig1 = sua[i + 1];
45 uint8_t len = sua[i + 2];
46 /* uint8_t ver = sua[i + 3]; */
47
48 if (len < 4)
49 break;
50
51 /* Rock Ridge SL (Symbolic Link) */
52 if (sig0 == 'S' && sig1 == 'L') {
53 uint8_t comp_offset = 5;
54
55 while (comp_offset < len) {
56 uint8_t c_flags = sua[i + comp_offset];
57 uint8_t c_len = sua[i + comp_offset + 1];
58 uint8_t* c_content = &sua[i + comp_offset + 2];
59
60 if (c_flags & 0x08) { /* ROOT */
61 out_target[target_len++] = '/';
62 } else if (c_flags & 0x02) { /* CURRENT */
63 out_target[target_len++] = '.';
64 out_target[target_len++] = '/';
65 } else if (c_flags & 0x04) { /* PARENT */
66 out_target[target_len++] = '.';
67 out_target[target_len++] = '.';
68 out_target[target_len++] = '/';
69 } else {
70 /* Komponen nama reguler */
71 memcopy(&out_target[target_len],
72 c_content, c_len);
73 target_len += c_len;
74
75 if (!(c_flags & 0x01) &&
76 (comp_offset + 2 + c_len < len)) {
77 out_target[target_len++] = '/';
78 }
79 }
80
81 comp_offset += 2 + c_len;
82 }
83
84 out_target[target_len] = '\0';
85 return target_len;
86 }
87
88 i += len;
89 }
90
91 return 0;
92}
93
94static int iso9660_get_rr_name(struct iso9660_dir* entry, char* out_name) {
95 /* SUA started after fixed header (33 byte) + name_len, align into 2
96 * byte */
97 uint8_t name_len = entry->name_len;
98 uint8_t sua_offset = 33 + name_len;
99 if (sua_offset % 2 != 0)
100 sua_offset += 1; /* padding byte */
101
102 uint8_t total_len = entry->length;
103 if (sua_offset >= total_len)
104 return 0; /* no SUA */
105
106 uint8_t* sua = (uint8_t*)entry + sua_offset;
107 uint8_t sua_len = total_len - sua_offset;
108 uint8_t i = 0;
109
110 while (i + 4 <= sua_len) {
111 uint8_t sig0 = sua[i];
112 uint8_t sig1 = sua[i + 1];
113 uint8_t len = sua[i + 2];
114 /* uint8_t ver = sua[i + 3]; */
115
116 if (len < 4)
117 break;
118
119 /* Rock Ridge NM (Alternate Name) */
120 if (sig0 == 'N' && sig1 == 'M') {
121 uint8_t flags = sua[i + 4];
122 if (flags & 0x06)
123 return 0;
124
125 uint8_t nm_len =
126 len - 5; /* 2 sig + 1 len + 1 ver + 1 flags */
127 if (nm_len == 0 || nm_len > 255)
128 return 0;
129
130 memcopy(out_name, &sua[i + 5], nm_len);
131 out_name[nm_len] = '\0';
132 return nm_len;
133 }
134
135 i += len;
136 }
137 return 0;
138}
139
141 dentry_ptr* out) {
142
143 if (!out) {
144 return -1;
145 }
146
147 auto block_dentry = instance->block_dentry;
148 if (!block_dentry) {
149 LOG2_WARN("ISO9660", "missing block dentry");
150 return -1;
151 }
152
153 auto block_vnode = block_dentry->vnode;
154 if (!block_vnode) {
155 LOG2_WARN("ISO9660", "missing block vnode");
156 return -1;
157 }
158
159 auto ops = (vops_blk_t*)block_vnode->ops;
160 if (!ops) {
161 LOG2_WARN("ISO9660", "missing cdev ops");
162 return -1;
163 }
164
165 if (!parent) {
166 auto pvd =
167 (struct iso9660_pvd*)kalloc(sizeof(struct iso9660_pvd));
168 if (!pvd) {
169 LOG2_WARN("ISO9660", "empty buffer");
170 return -2;
171 }
172
173 if (ops->read(block_vnode, 16, pvd,
174 sizeof(struct iso9660_pvd)) < 0) {
175 LOG2_WARN("ISO9660", "read failed");
176 kfree2(pvd);
177 return -2;
178 }
179
180 if (memcmp(instance->fs->data.magic.magic, pvd->id,
181 instance->fs->data.magic.count) != 0) {
182 LOG2_WARN("ISO9660", "invalid magic");
183 kfree2(pvd);
184 return -2;
185 }
186
187 if (pvd->type != 1) {
188 LOG2_WARN("ISO9660", "invalid pvd type");
189 kfree2(pvd);
190 return -2;
191 }
192
193 auto root_dir = (struct iso9660_dir*)pvd->root_dir_record;
194
195 struct iso9660_internal_data* iso_node =
197 sizeof(struct iso9660_internal_data));
198 if (!iso_node) {
199 kfree2(pvd);
200 return -2;
201 }
202 iso_node->extent = root_dir->extent_le;
203 iso_node->size = root_dir->size_le;
204 iso_node->flags = root_dir->flags;
205
206 if (!*out) {
207 LOG2_WARN("ISO9660", "no dentry provided for root");
208 kfree2(iso_node);
209 kfree2(pvd);
210 return -2;
211 }
212
213 if (!(*out)->vnode) {
214 (*out)->vnode = create_and_attach_vnode();
215 if (!(*out)->vnode) {
216 kfree2(iso_node);
217 kfree2(pvd);
218 return -2;
219 }
220 }
221
222 (*out)->vnode->vnode_private = iso_node;
223 (*out)->vnode->type = VNODE_TYPE_DIR;
224 (*out)->vnode->fs_instance = instance;
225
226 LOG_DEBUG("ISO9660", "root dir extent=0x%x size=%d",
227 iso_node->extent, iso_node->size);
228
229 kfree2(pvd);
230 return VFS_OK;
231 }
232
233 if (!parent->vnode) {
234 LOG_WARN("ISO9660", "missing vnode");
235 return -2;
236 }
237
238 if (!parent->vnode->vnode_private) {
239 LOG_WARN("ISO9660", "missing vnode private data");
240 return -2;
241 }
242
243 auto iso_node =
244 (struct iso9660_internal_data*)parent->vnode->vnode_private;
245 LOG2_INFO("ISO9660", "parent %s size %d", parent->name->c_str,
246 iso_node->size);
247
248 uint8_t* dir_buf = (uint8_t*)kalloc(iso_node->size);
249 if (!dir_buf) {
250 LOG2_ERROR("ISO9660", "failed to alloc dir buffer");
251 return -2;
252 }
253
254 if (ops->read(block_vnode, iso_node->extent, dir_buf, iso_node->size) <
255 0) {
256 LOG2_ERROR("ISO9660", "failed to read dir extent");
257 kfree2(dir_buf);
258 return -3;
259 }
260
261 if (!*out) {
262 *out = create_dentry(str(path), 0, parent);
263 }
264
265 if (!(*out)->vnode) {
266 (*out)->vnode = create_and_attach_vnode();
267 }
268
269 if (!(*out)->vnode) {
270 LOG2_ERROR("ISO9660", "failed to create vnode");
271 kfree2(dir_buf);
272 return -2;
273 }
274
275 {
276 uintptr_t base = (uintptr_t)dir_buf;
278 uintptr_t end = base + iso_node->size;
279
280 while (ptr < end) {
281 auto entry = (struct iso9660_dir*)ptr;
282
283 if (entry->length == 0) {
285 uintptr_t next_sector =
286 ((offset / 2048) + 1) * 2048;
287 if (next_sector >= iso_node->size)
288 break;
289 ptr = base + next_sector;
290 continue;
291 }
292
293 if (entry->name_len == 1 && (entry->name[0] == 0x00 ||
294 entry->name[0] == 0x01)) {
295 ptr += entry->length;
296 continue;
297 }
298
299 char name[256];
300 auto name_len = iso9660_get_rr_name(entry, name);
301
302 if (name_len <= 0) {
303 uint8_t iso_len = entry->name_len;
304 if (iso_len > 255)
305 iso_len = 255;
306 memcopy(name, entry->name, iso_len);
307 name[iso_len] = '\0';
308 name_len = iso_len;
309
310 for (int i = 0; i < name_len; i++) {
311 if (name[i] == ';') {
312 name[i] = '\0';
313 name_len = i;
314 break;
315 }
316 }
317
319 }
320
321 if (strlen(name) == strlen(path) &&
322 strncmp(name, path, strlen(path)) == 0) {
323
324 serial2_printf("file %s flags %b (%d)\n", name,
325 (uint8_t)entry->flags,
326 entry->size_be);
327
328 char symlink_target[256];
329 int sym_len = iso9660_get_rr_symlink(
330 entry, symlink_target);
331
332 if (sym_len > 0) {
334 "found symlink at %s (%d)\n",
335 symlink_target, sym_len);
336 (*out)->vnode->type = VNODE_TYPE_LNK;
337 (*out)->vnode->vnode_private =
338 kalloc(256);
339 memcopy((*out)->vnode->vnode_private,
340 symlink_target,
341 (size_t)sym_len);
342
343 (*out)->vnode->ops =
345 (*out)->vnode->fs_instance = instance;
346 } else {
347 auto priv_data =
348 (struct iso9660_internal_data*)
349 kalloc(sizeof(
350 struct
352 if (!priv_data) {
353 kfree2(dir_buf);
354 return -2;
355 }
356
357 priv_data->extent = entry->extent_le;
358 priv_data->size = entry->size_le;
359 priv_data->flags = entry->flags;
360
361 if (entry->flags & iOS9660_DIR_FLAG) {
362 (*out)->vnode->type =
364 } else {
365 (*out)->vnode->type =
367 (*out)->vnode->ops =
369 (*out)->vnode->size =
370 entry->size_le;
371 }
372
373 (*out)->vnode->vnode_private =
374 priv_data;
375 (*out)->vnode->fs_instance = instance;
376 }
377 kfree2(dir_buf);
378 return VFS_OK;
379 }
380
381 ptr += entry->length;
382 }
383 }
384
385 kfree2(dir_buf);
386 return -1;
387}
388
389int iso9660_read(vnode_t* vnode, void* buf, size_t len, size_t offset) {
390 UNUSED(offset);
391
392 if (!vnode || !buf || !len)
393 return -1;
394
395 auto iso_node = (struct iso9660_internal_data*)vnode->vnode_private;
396 if (!iso_node)
397 return -2;
398
399 auto block_dentry = vnode->fs_instance->block_dentry;
400 if (!block_dentry)
401 return -2;
402
403 auto block_vnode = block_dentry->vnode;
404 if (!block_vnode)
405 return -2;
406
407 auto ops = (vops_blk_t*)block_vnode->ops;
408 if (!ops)
409 return -3;
410
411 if (ops->read(block_vnode, iso_node->extent, buf, iso_node->size) < 0) {
412 LOG2_ERROR("ISO9660", "failed to read dir extent");
413 return -3;
414 }
415
416 return 0;
417}
418
419int iso9660_readlink(vnode_t* vnode, char* buf, size_t len) {
420 auto priv_data = (char*)vnode->vnode_private;
421 serial2_printf("%s \n", (char*)priv_data);
422 if (!priv_data)
423 return -1;
424
425 auto len_ = strlen(priv_data) > len ? len : strlen(priv_data);
426 memcopy(buf, priv_data, len_);
427 buf[strlen(priv_data)] = '\0';
428
429 return (int)len_;
430}
431
436
438 _fs_ops.lookup = iso9660_lookup;
439 return &_fs_ops;
440}
441
443 _lnk_ops.readlink = iso9660_readlink;
444 return &_lnk_ops;
445}
static AHCIModule instance
Definition init.cpp:5
kstring name
Definition dentry.h:5
struct dentry * dentry_ptr
Definition dentry.h:20
dentry_ptr parent
Definition dentry.h:7
void * ops
Definition dev.h:2
elf_section_map uintptr_t base
Definition elf.h:296
@ VFS_OK
Definition enum.h:5
struct vnode vnode_t
Definition filesystem.h:10
struct fs_operations fs_operations_t
uint16_t flags
Definition thread.h:5
void serial2_printf(const char *fmt,...)
fs_operations_t * iso9660_fs_operations(void)
Definition iso9660.c:437
vops_file_t * iso9660_file_operations(void)
Definition iso9660.c:432
static fs_operations_t _fs_ops
Definition iso9660.c:13
int iso9660_lookup(struct fs_instance *instance, char *path, dentry_ptr parent, dentry_ptr *out)
Definition iso9660.c:140
static vops_file_t _file_ops
Definition iso9660.c:14
static vops_lnk_t _lnk_ops
Definition iso9660.c:15
static int iso9660_get_rr_name(struct iso9660_dir *entry, char *out_name)
Definition iso9660.c:94
vops_lnk_t * iso9660_lnk_operations(void)
Definition iso9660.c:442
int iso9660_readlink(vnode_t *vnode, char *buf, size_t len)
Definition iso9660.c:419
int iso9660_read(vnode_t *vnode, void *buf, size_t len, size_t offset)
Definition iso9660.c:389
static int iso9660_get_rr_symlink(struct iso9660_dir *entry, char *out_target)
Definition iso9660.c:23
uint8_t name_len
Definition iso9660.h:19
#define iOS9660_DIR_FLAG
Definition iso9660.h:118
void * kalloc(size_t size)
void kfree2(void *ptr)
size_t len
Definition oct2bin.h:7
#define LOG2_WARN(mod, fmt,...)
Definition serial.h:40
#define LOG_WARN(mod, fmt,...)
Definition serial.h:27
#define LOG2_ERROR(mod, fmt,...)
Definition serial.h:38
#define LOG2_INFO(mod, fmt,...)
Definition serial.h:33
#define LOG_DEBUG(mod, fmt,...)
Definition serial.h:22
int strncmp(const char *s1, const char *s2, size_t n)
void to_lowercase(char *str)
Definition str.c:64
int memcmp(const void *s1, const void *s2, size_t n)
size_t strlen(const char *s)
Definition str.c:105
void memcopy(void *dest, void *src, size_t size)
kstring str(const char *str)
struct vnode * vnode
Definition dentry.h:33
dentry_ptr block_dentry
Definition filesystem.h:39
uint8_t name_len
Definition iso9660.h:113
uint8_t length
Definition iso9660.h:94
Definition vnode.h:59
void * vnode_private
Definition vnode.h:72
struct fs_instance * fs_instance
Definition vnode.h:67
unsigned int uint32_t
Definition type.h:19
unsigned long uintptr_t
Definition type.h:73
#define UNUSED(x)
Definition type.h:100
unsigned char uint8_t
Definition type.h:7
vnode_t * create_and_attach_vnode()
uint32_t offset
Definition virtio.h:6
@ VNODE_TYPE_FILE
Definition vnode.h:12
@ VNODE_TYPE_LNK
Definition vnode.h:19
@ VNODE_TYPE_DIR
Definition vnode.h:13
struct vops_blk vops_blk_t
kstring path
Definition voxmo.h:7
uint64_t ptr
Definition xhci.hpp:0