/* radare2 - LGPL - Copyright 2011-2016 - pancake */ #include #include "../config.h" #include "types.h" #include #include "../../shlr/grub/include/grub/msdos_partition.h" #if WITH_GPL #ifndef USE_GRUB #define USE_GRUB 1 #endif #endif R_LIB_VERSION (r_fs); static RFSPlugin *fs_static_plugins[] = { R_FS_STATIC_PLUGINS }; R_API RFS *r_fs_new() { int i; RFSPlugin *static_plugin; RFS *fs = R_NEW0 (RFS); if (fs) { fs->view = R_FS_VIEW_NORMAL; fs->roots = r_list_new (); if (!fs->roots) { r_fs_free (fs); return NULL; } fs->roots->free = (RListFree)r_fs_root_free; fs->plugins = r_list_new (); if (!fs->plugins) { r_fs_free (fs); return NULL; } fs->plugins->free = free; // XXX fs->roots->free = r_fs_plugin_free; for (i = 0; fs_static_plugins[i]; i++) { static_plugin = R_NEW (RFSPlugin); if (!static_plugin) continue; memcpy (static_plugin, fs_static_plugins[i], sizeof (RFSPlugin)); r_fs_add (fs, static_plugin); free (static_plugin); } } return fs; } R_API RFSPlugin *r_fs_plugin_get(RFS *fs, const char *name) { RListIter *iter; RFSPlugin *p; r_list_foreach (fs->plugins, iter, p) { if (!strcmp (p->name, name)) return p; } return NULL; } R_API void r_fs_free(RFS *fs) { if (!fs) return; //r_io_free (fs->iob.io); r_list_free (fs->plugins); r_list_free (fs->roots); free (fs); } /* plugins */ R_API void r_fs_add(RFS *fs, RFSPlugin *p) { // TODO: find coliding plugin name if (p && p->init) { p->init (); } RFSPlugin *sp = R_NEW0 (RFSPlugin); if (!sp) { return; } if (p) { memcpy (sp, p, sizeof (RFSPlugin)); } r_list_append (fs->plugins, sp); } R_API void r_fs_del(RFS *fs, RFSPlugin *p) { // TODO: implement r_fs_del } /* mountpoint */ R_API RFSRoot *r_fs_mount(RFS *fs, const char *fstype, const char *path, ut64 delta) { RFSPlugin *p; RFSRoot *root; RFSFile *file; RList *list; RListIter *iter; char *str; int len, lenstr; if (path[0] != '/') { eprintf ("r_fs_mount: invalid mountpoint\n"); return NULL; } if (!(p = r_fs_plugin_get (fs, fstype))) { eprintf ("r_fs_mount: Invalid filesystem type\n"); return NULL; } str = strdup (path); if (!str) return NULL; r_str_chop_path (str); /* Check if path exists */ r_list_foreach (fs->roots, iter, root) { len = strlen (root->path); lenstr = strlen (str); if (!strncmp (str, root->path, len)) { if (len < lenstr && str[len] != '/') continue; else if (len > lenstr && root->path[lenstr] == '/') continue; eprintf ("r_fs_mount: Invalid mount point\n"); free (str); return NULL; } } file = r_fs_open (fs, str); if (file) { r_fs_close (fs, file); eprintf ("r_fs_mount: Invalid mount point\n"); free (str); return NULL; } else { list = r_fs_dir (fs, str); if (!r_list_empty (list)) { //XXX: list need free ?? eprintf ("r_fs_mount: Invalid mount point\n"); free (str); return NULL; } } root = r_fs_root_new (str, delta); root->p = p; //memcpy (&root->iob, &fs->iob, sizeof (root->iob)); root->iob = fs->iob; if (!p->mount (root)) { eprintf ("r_fs_mount: Cannot mount partition\n"); free (str); r_fs_root_free (root); return NULL; } r_list_append (fs->roots, root); eprintf ("Mounted %s on %s at 0x%" PFMT64x "\n", fstype, str, delta); free (str); return root; } static inline int r_fs_match(const char *root, const char *path, int len) { return (!strncmp (path, root, len)); } R_API bool r_fs_umount(RFS *fs, const char *path) { int len; RFSRoot *root; RListIter *iter, *riter = NULL; if (!path) return false; r_list_foreach (fs->roots, iter, root) { len = strlen (root->path); if (r_fs_match (path, root->path, len)) riter = iter; } if (riter) { r_list_delete (fs->roots, riter); return true; } return false; } R_API RList *r_fs_root(RFS *fs, const char *p) { RList *roots; RFSRoot *root; RListIter *iter; int len, olen; char *path = strdup (p); if (!path) { return NULL; } roots = r_list_new (); r_str_chop_path (path); r_list_foreach (fs->roots, iter, root) { len = strlen (root->path); if (r_fs_match (path, root->path, len)) { olen = strlen (path); if (len == 1 || olen == len) r_list_append (roots, root); else if (olen > len && path[len] == '/') r_list_append (roots, root); } } free (path); return roots; } /* filez */ R_API RFSFile *r_fs_open(RFS *fs, const char *p) { RFSRoot *root; RList *roots; RListIter *iter; RFSFile *f = NULL; const char *dir; char *path = strdup (p); //r_str_chop_path (path); roots = r_fs_root (fs, path); if (!r_list_empty (roots)) { r_list_foreach (roots, iter, root) { if (root && root->p && root->p->open) { if (strlen (root->path) == 1) dir = path; else dir = path + strlen (root->path); f = root->p->open (root, dir); if (f) break; } } } free (roots); free (path); return f; } // TODO: close or free? R_API void r_fs_close(RFS *fs, RFSFile *file) { if (fs && file && file->p && file->p->close) file->p->close (file); } R_API int r_fs_read(RFS *fs, RFSFile *file, ut64 addr, int len) { if (len < 1) { eprintf ("r_fs_read: too short read\n"); return false; } if (fs && file) { free (file->data); file->data = malloc (len + 1); if (file->p && file->p->read) { file->p->read (file, addr, len); return true; } else eprintf ("r_fs_read: file->p->read is null\n"); } return false; } R_API RList *r_fs_dir(RFS *fs, const char *p) { RList *roots, *ret = NULL; RFSRoot *root; RListIter *iter; const char *dir; char *path = strdup (p); r_str_chop_path (path); roots = r_fs_root (fs, path); r_list_foreach (roots, iter, root) { if (root) { if (strlen (root->path) == 1) dir = path; else dir = path + strlen (root->path); if (!*dir) dir = "/"; ret = root->p->dir (root, dir, fs->view); if (ret) break; } } free (roots); free (path); return ret; } R_API int r_fs_dir_dump(RFS *fs, const char *path, const char *name) { RList *list; RListIter *iter; RFSFile *file, *item; char *str, *npath; list = r_fs_dir (fs, path); if (!list) return false; if (!r_sys_mkdir (name)) { if (r_sys_mkdir_failed ()) { eprintf ("Cannot create \"%s\"\n", name); return false; } } r_list_foreach (list, iter, file) { if (!strcmp (file->name, ".") || !strcmp (file->name, "..")) continue; str = (char *)malloc (strlen (name) + strlen (file->name) + 2); if (!str) return false; strcpy (str, name); strcat (str, "/"); strcat (str, file->name); npath = malloc (strlen (path) + strlen (file->name) + 2); if (!npath) { free (str); return false; } strcpy (npath, path); strcat (npath, "/"); strcat (npath, file->name); if (file->type != R_FS_FILE_TYPE_DIRECTORY) { item = r_fs_open (fs, npath); if (item) { r_fs_read (fs, item, 0, item->size); r_file_dump (str, item->data, item->size, 0); free (item->data); r_fs_close (fs, item); } } else { r_fs_dir_dump (fs, npath, str); } free (npath); free (str); } return true; } static void r_fs_find_off_aux(RFS *fs, const char *name, ut64 offset, RList *list) { RList *dirs; RListIter *iter; RFSFile *item, *file; char *found = NULL; dirs = r_fs_dir (fs, name); r_list_foreach (dirs, iter, item) { if (!strcmp (item->name, ".") || !strcmp (item->name, "..")) continue; found = (char *)malloc (strlen (name) + strlen (item->name) + 2); if (!found) break; strcpy (found, name); strcat (found, "/"); strcat (found, item->name); if (item->type == R_FS_FILE_TYPE_DIRECTORY) { r_fs_find_off_aux (fs, found, offset, list); } else { file = r_fs_open (fs, found); if (file) { r_fs_read (fs, file, 0, file->size); if (file->off == offset) r_list_append (list, found); free (file->data); r_fs_close (fs, file); } } free (found); } } R_API RList *r_fs_find_off(RFS *fs, const char *name, ut64 off) { RList *list = r_list_new (); if (!list) return NULL; list->free = free; r_fs_find_off_aux (fs, name, off, list); return list; } static void r_fs_find_name_aux(RFS *fs, const char *name, const char *glob, RList *list) { RList *dirs; RListIter *iter; RFSFile *item; char *found; dirs = r_fs_dir (fs, name); r_list_foreach (dirs, iter, item) { if (r_str_glob (item->name, glob)) { found = (char *)malloc (strlen (name) + strlen (item->name) + 2); if (!found) break; strcpy (found, name); strcat (found, "/"); strcat (found, item->name); r_list_append (list, found); } if (!strcmp (item->name, ".") || !strcmp (item->name, "..")) continue; if (item->type == R_FS_FILE_TYPE_DIRECTORY) { found = (char *)malloc (strlen (name) + strlen (item->name) + 2); if (!found) break; strcpy (found, name); strcat (found, "/"); strcat (found, item->name); r_fs_find_name_aux (fs, found, glob, list); free (found); } } } R_API RList *r_fs_find_name(RFS *fs, const char *name, const char *glob) { RList *list = r_list_newf (free); if (!list) return NULL; r_fs_find_name_aux (fs, name, glob, list); return list; } R_API RFSFile *r_fs_slurp(RFS *fs, const char *path) { RFSFile *file = NULL; RFSRoot *root; RList *roots = r_fs_root (fs, path); RListIter *iter; r_list_foreach (roots, iter, root) { if (!root || !root->p) continue; if (root->p->open && root->p->read && root->p->close) { file = root->p->open (root, path); if (file) root->p->read (file, 0, file->size); //file->data else eprintf ("r_fs_slurp: cannot open file\n"); } else { if (root->p->slurp) { free (roots); return root->p->slurp (root, path); } eprintf ("r_fs_slurp: null root->p->slurp\n"); } } free (roots); return file; } // TODO: move into grubfs #include "../../shlr/grub/include/grubfs.h" #if USE_GRUB static int grub_parhook(void *disk, void *ptr, void *closure) { struct grub_partition *par = ptr; RList *list = (RList *)closure; RFSPartition *p = r_fs_partition_new ( r_list_length (list), par->start * 512, 512 * par->len); p->type = par->msdostype; r_list_append (list, p); return 0; } #endif static int fs_parhook(void *disk, void *ptr, void *closure) { RFSPartition *par = ptr; RList *list = (RList *)closure; r_list_append (list, par); return 0; } #include "p/part_dos.c" static RFSPartitionType partitions[] = { /* LGPL code */ {"dos", &fs_part_dos, fs_parhook}, #if USE_GRUB /* WARNING GPL code */ {"msdos", &grub_msdos_partition_map, grub_parhook}, {"apple", &grub_apple_partition_map, grub_parhook}, {"sun", &grub_sun_partition_map, grub_parhook}, {"sunpc", &grub_sun_pc_partition_map, grub_parhook}, {"amiga", &grub_amiga_partition_map, grub_parhook}, {"bsdlabel", &grub_bsdlabel_partition_map, grub_parhook}, {"gpt", &grub_gpt_partition_map, grub_parhook}, #endif // XXX: In BURG all bsd partition map are in bsdlabel //{ "openbsdlabel", &grub_openbsd_partition_map }, //{ "netbsdlabel", &grub_netbsd_partition_map }, //{ "acorn", &grub_acorn_partition_map }, { NULL }}; R_API const char *r_fs_partition_type_get(int n) { if (n < 0 || n >= R_FS_PARTITIONS_LENGTH) return NULL; return partitions[n].name; } R_API int r_fs_partition_get_size() { return R_FS_PARTITIONS_LENGTH; } R_API RList *r_fs_partitions(RFS *fs, const char *ptype, ut64 delta) { int i, cur = -1; for (i = 0; partitions[i].name; i++) { if (!strcmp (ptype, partitions[i].name)) { cur = i; break; } } if (cur != -1) { RList *list = r_list_newf ((RListFree)r_fs_partition_free); #if USE_GRUB void *disk = NULL; if (partitions[i].iterate == grub_parhook) { struct grub_partition_map *gpt = partitions[i].ptr; grubfs_bind_io (NULL, 0); disk = (void *)grubfs_disk (&fs->iob); if (gpt) { gpt->iterate (disk, (void *)partitions[i].iterate, list); } grubfs_free (disk); } else { #else { #endif RFSPartitionIterator iterate = partitions[i].ptr; iterate (fs, partitions[i].iterate, list); //grub_parhook, list); } return list; } if (ptype && *ptype) eprintf ("Unknown partition type '%s'.\n", ptype); eprintf ("Supported types:\n"); for (i = 0; partitions[i].name; i++) eprintf (" %s", partitions[i].name); eprintf ("\n"); return NULL; } R_API int r_fs_partition_type_str(const char *type) { // TODO: implement return 0; } R_API const char *r_fs_partition_type(const char *part, int type) { // XXX: part is ignored O_o switch (type) { case GRUB_PC_PARTITION_TYPE_FAT12: case GRUB_PC_PARTITION_TYPE_FAT16_GT32M: case GRUB_PC_PARTITION_TYPE_FAT16_LT32M: case GRUB_PC_PARTITION_TYPE_FAT32: case GRUB_PC_PARTITION_TYPE_FAT32_LBA: case GRUB_PC_PARTITION_TYPE_FAT16_LBA: return strdup ("fat"); case GRUB_PC_PARTITION_TYPE_EXT2FS: return strdup ("ext2"); case GRUB_PC_PARTITION_TYPE_MINIX: case GRUB_PC_PARTITION_TYPE_LINUX_MINIX: return strdup ("minix"); case GRUB_PC_PARTITION_TYPE_NTFS: return strdup ("ntfs"); case GRUB_PC_PARTITION_TYPE_EXTENDED: case GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED: return strdup ("ext3"); case GRUB_PC_PARTITION_TYPE_HFS: return strdup ("hfs"); case GRUB_PC_PARTITION_TYPE_WIN95_EXTENDED: // fat? case GRUB_PC_PARTITION_TYPE_EZD: case GRUB_PC_PARTITION_TYPE_VSTAFS: case GRUB_PC_PARTITION_TYPE_FREEBSD: // ufs case GRUB_PC_PARTITION_TYPE_OPENBSD: // ufs case GRUB_PC_PARTITION_TYPE_NETBSD: // ufs case GRUB_PC_PARTITION_TYPE_GPT_DISK: case GRUB_PC_PARTITION_TYPE_LINUX_RAID: case GRUB_PC_PARTITION_TYPE_NONE: default: return NULL; } } R_API char *r_fs_name(RFS *fs, ut64 offset) { ut8 buf[1024]; int i, j, len, ret = false; for (i = 0; fstypes[i].name; i++) { RFSType *f = &fstypes[i]; len = R_MIN (f->buflen, sizeof (buf) - 1); fs->iob.read_at (fs->iob.io, offset + f->bufoff, buf, len); if (f->buflen > 0 && !memcmp (buf, f->buf, f->buflen)) { ret = true; len = R_MIN (f->bytelen, sizeof (buf)); fs->iob.read_at (fs->iob.io, offset + f->byteoff, buf, len); for (j = 0; j < f->bytelen; j++) { if (buf[j] != f->byte) { ret = false; break; } } if (ret) return strdup (f->name); } } return NULL; } #define PROMT_PATH_BUFSIZE 1024 R_API int r_fs_prompt(RFS *fs, const char *root) { char buf[PROMT_PATH_BUFSIZE]; char path[PROMT_PATH_BUFSIZE]; char str[2048]; char *input; RList *list = NULL; RListIter *iter; RFSFile *file = NULL; if (root && *root) { strncpy (buf, root, sizeof (buf) - 1); r_str_chop_path (buf); list = r_fs_root (fs, buf); if (r_list_empty (list)) { printf ("Unknown root\n"); r_list_free (list); return false; } strncpy (path, buf, sizeof (path) - 1); } else strcpy (path, "/"); for (;;) { printf ("[%s]> ", path); fflush (stdout); fgets (buf, sizeof (buf) - 1, stdin); if (feof (stdin)) break; buf[strlen (buf) - 1] = '\0'; if (!strcmp (buf, "q") || !strcmp (buf, "exit")) { r_list_free (list); return true; } if (buf[0] == '!') { r_sandbox_system (buf + 1, 1); } else if (!memcmp (buf, "ls", 2)) { if (buf[2] == ' ') { if (buf[3] != '/') { strncpy (str, path, sizeof (str) - 1); strcat (str, "/"); strncat (str, buf + 3, sizeof (buf) - 1); list = r_fs_dir (fs, str); } else list = r_fs_dir (fs, buf + 3); } else list = r_fs_dir (fs, path); if (list) { r_list_foreach (list, iter, file) printf ("%c %s\n", file->type, file->name); } else eprintf ("Unknown path: %s\n", path); } else if (!strncmp (buf, "pwd", 3)) { eprintf ("%s\n", path); } else if (!memcmp (buf, "cd ", 3)) { char opath[PROMT_PATH_BUFSIZE]; strncpy (opath, path, sizeof (opath) - 1); input = buf + 3; while (*input == ' ') input++; if (!strcmp (input, "..")) { char *p = (char *)r_str_lchr (path, '/'); if (p) p[(p == path)? 1: 0] = 0; } else { strcat (path, "/"); if (*input == '/') { strncpy (path, input, sizeof (opath) - 1); } else { if ((strlen (path) + strlen (input)) >= sizeof (path)) { // overflow path[0] = 0; } else { strcat (path, input); } } path[sizeof (path) - 1] = 0; } r_str_chop_path (path); list = r_fs_dir (fs, path); if (r_list_empty (list)) { strcpy (path, opath); eprintf ("cd: unknown path: %s\n", path); } } else if (!memcmp (buf, "cat ", 4)) { input = buf + 3; while (input[0] == ' ') input++; if (input[0] == '/') { if (root) strncpy (str, root, sizeof (str) - 1); else str[0] = 0; } else strncpy (str, path, sizeof (str) - 1); strncat (str, "/", sizeof (str) - strlen (str) - 1); strncat (str, input, sizeof (str) - strlen (str) - 1); file = r_fs_open (fs, str); if (file) { r_fs_read (fs, file, 0, file->size); write (1, file->data, file->size); free (file->data); r_fs_close (fs, file); } else eprintf ("Cannot open file\n"); } else if (!memcmp (buf, "mount", 5)) { RFSRoot *r; r_list_foreach (fs->roots, iter, r) { eprintf ("%s %s\n", r->path, r->p->name); } } else if (!memcmp (buf, "get ", 4)) { char *s = 0; input = buf + 3; while (input[0] == ' ') input++; if (input[0] == '/') { if (root) { s = malloc (strlen (root) + strlen (input) + 2); if (!s) goto beach; strcpy (s, root); } } else { s = malloc (strlen (path) + strlen (input) + 2); if (!s) goto beach; strcpy (s, path); } if (!s) { s = malloc (strlen (input) + 32); if (!s) goto beach; } strcat (s, "/"); strcat (s, input); file = r_fs_open (fs, s); if (file) { r_fs_read (fs, file, 0, file->size); r_file_dump (input, file->data, file->size, 0); free (file->data); r_fs_close (fs, file); } else { input -= 2; //OMFG!!!! O_O memcpy (input, "./", 2); if (!r_fs_dir_dump (fs, s, input)) printf ("Cannot open file\n"); } free (s); } else if (!memcmp (buf, "help", 4) || !strcmp (buf, "?")) { eprintf ( "Commands:\n" " !cmd ; escape to system\n" " ls [path] ; list current directory\n" " cd path ; change current directory\n" " cat file ; print contents of file\n" " get file ; dump file to disk\n" " mount ; list mount points\n" " q/exit ; leave prompt mode\n" " ?/help ; show this help\n"); } else eprintf ("Unknown command %s\n", buf); } beach: clearerr (stdin); printf ("\n"); r_list_free (list); return true; } R_API void r_fs_view(RFS *fs, int view) { fs->view = view; }