1 /* radare2 - LGPL - Copyright 2011-2019 - pancake */
2
3 #include <r_fs.h>
4 #include "config.h"
5 #include "types.h"
6 #include <errno.h>
7 #include "../../shlr/grub/include/grub/msdos_partition.h"
8
9 #if WITH_GPL
10 # ifndef USE_GRUB
11 # define USE_GRUB 1
12 # endif
13 #endif
14
15 R_LIB_VERSION (r_fs);
16
17 static RFSPlugin* fs_static_plugins[] = {
18 R_FS_STATIC_PLUGINS
19 };
20
r_fs_new(void)21 R_API RFS* r_fs_new(void) {
22 int i;
23 RFSPlugin* static_plugin;
24 RFS* fs = R_NEW0 (RFS);
25 if (fs) {
26 fs->view = R_FS_VIEW_NORMAL;
27 fs->roots = r_list_new ();
28 if (!fs->roots) {
29 r_fs_free (fs);
30 return NULL;
31 }
32 fs->roots->free = (RListFree) r_fs_root_free;
33 fs->plugins = r_list_new ();
34 if (!fs->plugins) {
35 r_fs_free (fs);
36 return NULL;
37 }
38 fs->plugins->free = free;
39 // XXX fs->roots->free = r_fs_plugin_free;
40 for (i = 0; fs_static_plugins[i]; i++) {
41 static_plugin = R_NEW (RFSPlugin);
42 if (!static_plugin) {
43 continue;
44 }
45 memcpy (static_plugin, fs_static_plugins[i], sizeof (RFSPlugin));
46 r_fs_add (fs, static_plugin);
47 free (static_plugin);
48 }
49 }
50 return fs;
51 }
52
r_fs_plugin_get(RFS * fs,const char * name)53 R_API RFSPlugin* r_fs_plugin_get(RFS* fs, const char* name) {
54 RListIter* iter;
55 RFSPlugin* p;
56 if (!fs || !name) {
57 return NULL;
58 }
59 r_list_foreach (fs->plugins, iter, p) {
60 if (!strcmp (p->name, name)) {
61 return p;
62 }
63 }
64 return NULL;
65 }
66
r_fs_free(RFS * fs)67 R_API void r_fs_free(RFS* fs) {
68 if (!fs) {
69 return;
70 }
71 //r_io_free (fs->iob.io);
72 //root makes use of plugin so revert to avoid UaF
73 r_list_free (fs->roots);
74 r_list_free (fs->plugins);
75 free (fs);
76 }
77
78 /* plugins */
r_fs_add(RFS * fs,RFSPlugin * p)79 R_API void r_fs_add(RFS* fs, RFSPlugin* p) {
80 // TODO: find coliding plugin name
81 if (p && p->init) {
82 p->init ();
83 }
84 RFSPlugin* sp = R_NEW0 (RFSPlugin);
85 if (sp) {
86 if (p) {
87 memcpy (sp, p, sizeof (RFSPlugin));
88 }
89 r_list_append (fs->plugins, sp);
90 }
91 }
92
r_fs_del(RFS * fs,RFSPlugin * p)93 R_API void r_fs_del(RFS* fs, RFSPlugin* p) {
94 // TODO: implement r_fs_del
95 }
96
97 /* mountpoint */
r_fs_mount(RFS * fs,const char * fstype,const char * path,ut64 delta)98 R_API RFSRoot* r_fs_mount(RFS* fs, const char* fstype, const char* path, ut64 delta) {
99 RFSPlugin* p;
100 RFSRoot* root;
101 RListIter* iter;
102 char* str;
103 int len, lenstr;
104 char *heapFsType = NULL;
105
106 if (path[0] != '/') {
107 eprintf ("r_fs_mount: invalid mountpoint %s\n", path);
108 return NULL;
109 }
110 if (!fstype || !*fstype) {
111 heapFsType = r_fs_name (fs, delta);
112 fstype = (const char *)heapFsType;
113 }
114 if (!(p = r_fs_plugin_get (fs, fstype))) {
115 // eprintf ("r_fs_mount: Invalid filesystem type\n");
116 free (heapFsType);
117 return NULL;
118 }
119 str = strdup (path);
120 if (!str) {
121 free (heapFsType);
122 return NULL;
123 }
124 r_str_trim_path (str);
125 if (*str && strchr (str + 1, '/')) {
126 eprintf ("r_fs_mount: mountpoint must have no subdirectories\n");
127 free (heapFsType);
128 return NULL;
129 }
130 /* Check if path exists */
131 r_list_foreach (fs->roots, iter, root) {
132 len = strlen (root->path);
133 lenstr = strlen (str);
134 if (!strncmp (str, root->path, len)) {
135 if (len < lenstr && str[len] != '/') {
136 continue;
137 }
138 if (len > lenstr && root->path[lenstr] == '/') {
139 continue;
140 }
141 eprintf ("r_fs_mount: Invalid mount point\n");
142 free (str);
143 free (heapFsType);
144 return NULL;
145 }
146 }
147 RFSFile* file = r_fs_open (fs, str, false);
148 if (file) {
149 r_fs_close (fs, file);
150 eprintf ("r_fs_mount: Invalid mount point\n");
151 free (heapFsType);
152 free (str);
153 return NULL;
154 }
155 RList *list = r_fs_dir (fs, str);
156 if (!r_list_empty (list)) {
157 //XXX: list need free ??
158 eprintf ("r_fs_mount: Invalid mount point\n");
159 free (str);
160 free (heapFsType);
161 return NULL;
162 }
163 // TODO: we should just construct the root with the rfs instance
164 root = r_fs_root_new (str, delta);
165 root->p = p;
166 root->iob = fs->iob;
167 root->cob = fs->cob;
168 if (!p->mount (root)) {
169 free (str);
170 free (heapFsType);
171 r_fs_root_free (root);
172 return NULL;
173 }
174 r_list_append (fs->roots, root);
175 eprintf ("Mounted %s on %s at 0x%" PFMT64x "\n", fstype, str, delta);
176 free (str);
177 free (heapFsType);
178 return root;
179 }
180
r_fs_match(const char * root,const char * path,int len)181 static inline bool r_fs_match(const char* root, const char* path, int len) {
182 return (!strncmp (path, root, len));
183 }
184
r_fs_umount(RFS * fs,const char * path)185 R_API bool r_fs_umount(RFS* fs, const char* path) {
186 int len;
187 RFSRoot* root;
188 RListIter* iter, * riter = NULL;
189
190 if (!path) {
191 return false;
192 }
193
194 r_list_foreach (fs->roots, iter, root) {
195 len = strlen (root->path);
196 if (r_fs_match (path, root->path, len)) {
197 riter = iter;
198 }
199 }
200 if (riter) {
201 r_list_delete (fs->roots, riter);
202 return true;
203 }
204 return false;
205 }
206
r_fs_root(RFS * fs,const char * p)207 R_API RList* r_fs_root(RFS* fs, const char* p) {
208 RList* roots;
209 RFSRoot* root;
210 RListIter* iter;
211 int len, olen;
212 char* path = strdup (p);
213 if (!path) {
214 return NULL;
215 }
216 roots = r_list_new ();
217 r_str_trim_path (path);
218 r_list_foreach (fs->roots, iter, root) {
219 len = strlen (root->path);
220 if (r_fs_match (path, root->path, len)) {
221 olen = strlen (path);
222 if (len == 1 || olen == len) {
223 r_list_append (roots, root);
224 } else if (olen > len && path[len] == '/') {
225 r_list_append (roots, root);
226 }
227 }
228 }
229 free (path);
230 return roots;
231 }
232
233 /* filez */
r_fs_open(RFS * fs,const char * p,bool create)234 R_API RFSFile* r_fs_open(RFS* fs, const char* p, bool create) {
235 RFSRoot* root;
236 RListIter* iter;
237 RFSFile* f = NULL;
238 const char* dir;
239 char* path = r_str_trim_dup (p);
240 RList *roots = r_fs_root (fs, path);
241 if (!r_list_empty (roots)) {
242 r_list_foreach (roots, iter, root) {
243 if (create) {
244 if (root && root->p && root->p->write) {
245 f = r_fs_file_new (root, path + strlen (root->path));
246 break;
247 }
248 continue;
249 }
250 if (root && root->p && root->p->open) {
251 if (strlen (root->path) == 1) {
252 dir = path;
253 } else {
254 dir = path + strlen (root->path);
255 }
256 f = root->p->open (root, dir, false);
257 if (f) {
258 break;
259 }
260 }
261 }
262 }
263 free (roots);
264 free (path);
265 return f;
266 }
267
268 // NOTE: close doesnt free
r_fs_close(RFS * fs,RFSFile * file)269 R_API void r_fs_close(RFS* fs, RFSFile* file) {
270 if (fs && file) {
271 R_FREE (file->data);
272 if (file->p && file->p->close) {
273 file->p->close (file);
274 }
275 }
276 }
277
r_fs_write(RFS * fs,RFSFile * file,ut64 addr,const ut8 * data,int len)278 R_API int r_fs_write(RFS* fs, RFSFile* file, ut64 addr, const ut8 *data, int len) {
279 if (len < 1) {
280 return -1;
281 }
282 if (fs && file) {
283 // TODO: fill file->data ? looks like dupe of rbuffer
284 if (file->p && file->p->write) {
285 return file->p->write (file, addr, data, len);;
286 }
287 eprintf ("r_fs_write: file->p->write is null\n");
288 }
289 return -1;
290 }
291
r_fs_read(RFS * fs,RFSFile * file,ut64 addr,int len)292 R_API int r_fs_read(RFS* fs, RFSFile* file, ut64 addr, int len) {
293 if (len < 1) {
294 eprintf ("r_fs_read: too short read\n");
295 return -1;
296 }
297 if (fs && file) {
298 if (file->p && file->p->read) {
299 if (!file->data) {
300 free (file->data);
301 file->data = calloc (1, len + 1);
302 }
303 return file->p->read (file, addr, len);
304 } else {
305 eprintf ("r_fs_read: file->p->read is null\n");
306 }
307 }
308 return -1;
309 }
310
r_fs_dir(RFS * fs,const char * p)311 R_API RList* r_fs_dir(RFS* fs, const char* p) {
312 RList *ret = NULL;
313 RFSRoot* root;
314 RListIter* iter;
315 const char* dir;
316 char* path = strdup (p);
317 r_str_trim_path (path);
318 RList *roots = r_fs_root (fs, path);
319 r_list_foreach (roots, iter, root) {
320 if (root) {
321 if (strlen (root->path) == 1) {
322 dir = path;
323 } else {
324 dir = path + strlen (root->path);
325 }
326 if (!*dir) {
327 dir = "/";
328 }
329 ret = root->p->dir (root, dir, fs->view);
330 if (ret) {
331 break;
332 }
333 }
334 }
335 free (roots);
336 free (path);
337 return ret;
338 }
339
r_fs_dir_dump(RFS * fs,const char * path,const char * name)340 R_API int r_fs_dir_dump(RFS* fs, const char* path, const char* name) {
341 RList* list;
342 RListIter* iter;
343 RFSFile* file, * item;
344 char* str, * npath;
345
346 list = r_fs_dir (fs, path);
347 if (!list) {
348 return false;
349 }
350 if (!r_sys_mkdir (name)) {
351 if (r_sys_mkdir_failed ()) {
352 eprintf ("Cannot create \"%s\"\n", name);
353 return false;
354 }
355 }
356 r_list_foreach (list, iter, file) {
357 if (!strcmp (file->name, ".") || !strcmp (file->name, "..")) {
358 continue;
359 }
360 str = (char*) malloc (strlen (name) + strlen (file->name) + 2);
361 if (!str) {
362 return false;
363 }
364 strcpy (str, name);
365 strcat (str, "/");
366 strcat (str, file->name);
367 npath = malloc (strlen (path) + strlen (file->name) + 2);
368 if (!npath) {
369 free (str);
370 return false;
371 }
372 strcpy (npath, path);
373 strcat (npath, "/");
374 strcat (npath, file->name);
375 switch (file->type) {
376 // DON'T FOLLOW MOUNTPOINTS
377 case R_FS_FILE_TYPE_DIRECTORY:
378 if (!r_fs_dir_dump (fs, npath, str)) {
379 free (npath);
380 free (str);
381 return false;
382 }
383 break;
384 case R_FS_FILE_TYPE_REGULAR:
385 item = r_fs_open (fs, npath, false);
386 if (item) {
387 r_fs_read (fs, item, 0, item->size);
388 if (!r_file_dump (str, item->data, item->size, 0)) {
389 free (npath);
390 free (str);
391 return false;
392 }
393 r_fs_close (fs, item);
394 }
395 break;
396 }
397 free (npath);
398 free (str);
399 }
400 return true;
401 }
402
r_fs_find_off_aux(RFS * fs,const char * name,ut64 offset,RList * list)403 static void r_fs_find_off_aux(RFS* fs, const char* name, ut64 offset, RList* list) {
404 RList* dirs;
405 RListIter* iter;
406 RFSFile* item, * file;
407 char* found = NULL;
408
409 dirs = r_fs_dir (fs, name);
410 r_list_foreach (dirs, iter, item) {
411 if (!strcmp (item->name, ".") || !strcmp (item->name, "..")) {
412 continue;
413 }
414
415 found = (char*) malloc (strlen (name) + strlen (item->name) + 2);
416 if (!found) {
417 break;
418 }
419 strcpy (found, name);
420 strcat (found, "/");
421 strcat (found, item->name);
422
423 if (item->type == R_FS_FILE_TYPE_DIRECTORY) {
424 r_fs_find_off_aux (fs, found, offset, list);
425 } else {
426 file = r_fs_open (fs, found, false);
427 if (file) {
428 r_fs_read (fs, file, 0, file->size);
429 if (file->off == offset) {
430 r_list_append (list, found);
431 }
432 r_fs_close (fs, file);
433 }
434 }
435 free (found);
436 }
437 }
438
r_fs_find_off(RFS * fs,const char * name,ut64 off)439 R_API RList* r_fs_find_off(RFS* fs, const char* name, ut64 off) {
440 RList* list = r_list_new ();
441 if (!list) {
442 return NULL;
443 }
444 list->free = free;
445 r_fs_find_off_aux (fs, name, off, list);
446 return list;
447 }
448
r_fs_find_name_aux(RFS * fs,const char * name,const char * glob,RList * list)449 static void r_fs_find_name_aux(RFS* fs, const char* name, const char* glob, RList* list) {
450 RList* dirs;
451 RListIter* iter;
452 RFSFile* item;
453 char* found;
454
455 dirs = r_fs_dir (fs, name);
456 r_list_foreach (dirs, iter, item) {
457 if (r_str_glob (item->name, glob)) {
458 found = (char*) malloc (strlen (name) + strlen (item->name) + 2);
459 if (!found) {
460 break;
461 }
462 strcpy (found, name);
463 strcat (found, "/");
464 strcat (found, item->name);
465 r_list_append (list, found);
466 }
467 if (!strcmp (item->name, ".") || !strcmp (item->name, "..")) {
468 continue;
469 }
470 if (item->type == R_FS_FILE_TYPE_DIRECTORY) {
471 found = (char*) malloc (strlen (name) + strlen (item->name) + 2);
472 if (!found) {
473 break;
474 }
475 strcpy (found, name);
476 strcat (found, "/");
477 strcat (found, item->name);
478 r_fs_find_name_aux (fs, found, glob, list);
479 free (found);
480 }
481 }
482 }
483
r_fs_find_name(RFS * fs,const char * name,const char * glob)484 R_API RList* r_fs_find_name(RFS* fs, const char* name, const char* glob) {
485 RList* list = r_list_newf (free);
486 if (list) {
487 r_fs_find_name_aux (fs, name, glob, list);
488 }
489 return list;
490 }
491
r_fs_slurp(RFS * fs,const char * path)492 R_API RFSFile* r_fs_slurp(RFS* fs, const char* path) {
493 RFSFile* file = NULL;
494 RFSRoot* root;
495 RList* roots = r_fs_root (fs, path);
496 RListIter* iter;
497 r_list_foreach (roots, iter, root) {
498 if (!root || !root->p) {
499 continue;
500 }
501 if (root->p->open && root->p->read && root->p->close) {
502 file = root->p->open (root, path, false);
503 if (file) {
504 root->p->read (file, 0, file->size); //file->data
505 }else {
506 eprintf ("r_fs_slurp: cannot open file\n");
507 }
508 } else {
509 if (root->p->slurp) {
510 free (roots);
511 return root->p->slurp (root, path);
512 }
513 eprintf ("r_fs_slurp: null root->p->slurp\n");
514 }
515 }
516 free (roots);
517 return file;
518 }
519
520 // TODO: move into grubfs
521 #include "../../shlr/grub/include/grubfs.h"
522
523 #if USE_GRUB
grub_parhook(void * disk,void * ptr,void * closure)524 static int grub_parhook(void* disk, void* ptr, void* closure) {
525 struct grub_partition* par = ptr;
526 RList* list = (RList*) closure;
527 RFSPartition* p = r_fs_partition_new (
528 r_list_length (list),
529 par->start * 512, 512 * par->len);
530 p->type = par->msdostype;
531 r_list_append (list, p);
532 return 0;
533 }
534 #endif
535
fs_parhook(void * disk,void * ptr,void * closure)536 static int fs_parhook(void* disk, void* ptr, void* closure) {
537 RFSPartition* par = ptr;
538 RList* list = (RList*) closure;
539 r_list_append (list, par);
540 return 0;
541 }
542
543 #include "p/part_dos.c"
544
545 static RFSPartitionType partitions[] = {
546 /* LGPL code */
547 {"dos", &fs_part_dos, fs_parhook},
548 #if USE_GRUB
549 /* WARNING GPL code */
550 #if !__EMSCRIPTEN__
551 // wtf for some reason is not available on emscripten
552 {"msdos", &grub_msdos_partition_map, grub_parhook},
553 #endif
554 {"apple", &grub_apple_partition_map, grub_parhook},
555 {"sun", &grub_sun_partition_map, grub_parhook},
556 {"sunpc", &grub_sun_pc_partition_map, grub_parhook},
557 {"amiga", &grub_amiga_partition_map, grub_parhook},
558 {"bsdlabel", &grub_bsdlabel_partition_map, grub_parhook},
559 {"gpt", &grub_gpt_partition_map, grub_parhook},
560 #endif
561 // XXX: In BURG all bsd partition map are in bsdlabel
562 //{ "openbsdlabel", &grub_openbsd_partition_map },
563 //{ "netbsdlabel", &grub_netbsd_partition_map },
564 //{ "acorn", &grub_acorn_partition_map },
565 { NULL }
566 };
567
r_fs_partition_type_get(int n)568 R_API const char* r_fs_partition_type_get(int n) {
569 if (n < 0 || n >= R_FS_PARTITIONS_LENGTH) {
570 return NULL;
571 }
572 return partitions[n].name;
573 }
574
r_fs_partition_get_size(void)575 R_API int r_fs_partition_get_size(void) {
576 return R_FS_PARTITIONS_LENGTH;
577 }
578
r_fs_partitions(RFS * fs,const char * ptype,ut64 delta)579 R_API RList* r_fs_partitions(RFS* fs, const char* ptype, ut64 delta) {
580 int i, cur = -1;
581 for (i = 0; partitions[i].name; i++) {
582 if (!strcmp (ptype, partitions[i].name)) {
583 cur = i;
584 break;
585 }
586 }
587 if (cur != -1) {
588 RList* list = r_list_newf ((RListFree) r_fs_partition_free);
589 #if USE_GRUB
590 void* disk = NULL;
591 if (partitions[i].iterate == grub_parhook) {
592 struct grub_partition_map* gpt = partitions[i].ptr;
593 grubfs_bind_io (NULL, 0);
594 disk = (void*) grubfs_disk (&fs->iob);
595 if (gpt) {
596 gpt->iterate (disk,
597 (void*) partitions[i].iterate, list);
598 }
599 grubfs_free (disk);
600 } else {
601 #else
602 {
603 #endif
604 RFSPartitionIterator iterate = partitions[i].ptr;
605 iterate (fs, partitions[i].iterate, list); //grub_parhook, list);
606 }
607 return list;
608 }
609 if (ptype && *ptype) {
610 eprintf ("Unknown partition type '%s'.\n", ptype);
611 }
612 eprintf ("Supported types:\n");
613 for (i = 0; partitions[i].name; i++) {
614 eprintf (" %s", partitions[i].name);
615 }
616 eprintf ("\n");
617 return NULL;
618 }
619
620 R_API int r_fs_partition_type_str(const char* type) {
621 // TODO: implement
622 return 0;
623 }
624
625 R_API const char* r_fs_partition_type(const char* part, int type) {
626 // XXX: part is ignored O_o
627 switch (type) {
628 case GRUB_PC_PARTITION_TYPE_FAT12:
629 case GRUB_PC_PARTITION_TYPE_FAT16_GT32M:
630 case GRUB_PC_PARTITION_TYPE_FAT16_LT32M:
631 case GRUB_PC_PARTITION_TYPE_FAT32:
632 case GRUB_PC_PARTITION_TYPE_FAT32_LBA:
633 case GRUB_PC_PARTITION_TYPE_FAT16_LBA:
634 return strdup ("fat");
635
636 case GRUB_PC_PARTITION_TYPE_EXT2FS:
637 return strdup ("ext2");
638
639 case GRUB_PC_PARTITION_TYPE_MINIX:
640 case GRUB_PC_PARTITION_TYPE_LINUX_MINIX:
641 return strdup ("minix");
642
643 case GRUB_PC_PARTITION_TYPE_NTFS:
644 return strdup ("ntfs");
645
646 case GRUB_PC_PARTITION_TYPE_EXTENDED:
647 case GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED:
648 return strdup ("ext3");
649
650 case GRUB_PC_PARTITION_TYPE_HFS:
651 return strdup ("hfs");
652
653 case GRUB_PC_PARTITION_TYPE_WIN95_EXTENDED: // fat?
654 case GRUB_PC_PARTITION_TYPE_EZD:
655 case GRUB_PC_PARTITION_TYPE_VSTAFS:
656 case GRUB_PC_PARTITION_TYPE_FREEBSD: // ufs
657 case GRUB_PC_PARTITION_TYPE_OPENBSD: // ufs
658 case GRUB_PC_PARTITION_TYPE_NETBSD: // ufs
659 case GRUB_PC_PARTITION_TYPE_GPT_DISK:
660 case GRUB_PC_PARTITION_TYPE_LINUX_RAID:
661 case GRUB_PC_PARTITION_TYPE_NONE:
662 default:
663 return NULL;
664 }
665 }
666
667 R_API char* r_fs_name(RFS* fs, ut64 offset) {
668 ut8 buf[1024];
669 int i, j, len, ret = false;
670
671 for (i = 0; fstypes[i].name; i++) {
672 RFSType* f = &fstypes[i];
673 len = R_MIN (f->buflen, sizeof (buf) - 1);
674 fs->iob.read_at (fs->iob.io, offset + f->bufoff, buf, len);
675 if (f->buflen > 0 && !memcmp (buf, f->buf, f->buflen)) {
676 ret = true;
677 len = R_MIN (f->bytelen, sizeof (buf));
678 fs->iob.read_at (fs->iob.io, offset + f->byteoff, buf, len);
679 // for (j = 0; j < f->bytelen; j++) {
680 for (j = 0; j < len; j++) {
681 if (buf[j] != f->byte) {
682 ret = false;
683 break;
684 }
685 }
686 if (ret) {
687 return strdup (f->name);
688 }
689 }
690 }
691 return NULL;
692 }
693
694 R_API void r_fs_view(RFS* fs, int view) {
695 fs->view = view;
696 }
697
698 R_API bool r_fs_check(RFS *fs, const char *p) {
699 RFSRoot *root;
700 RListIter *iter;
701 char* path = strdup (p);
702 if (!path) {
703 return false;
704 }
705 r_str_trim_path (path);
706 r_list_foreach (fs->roots, iter, root) {
707 if (r_fs_match (path, root->path, strlen (root->path))) {
708 free (path);
709 return true;
710 }
711 }
712 free (path);
713 return false;
714 }
715