radare2/libr/fs/p/fs_r2.c

322 lines
8.1 KiB
C

/* radare - LGPL - Copyright 2017-2019 - pancake */
#include <r_fs.h>
#include <r_lib.h>
#include <sys/stat.h>
typedef RList *(*DirHandler)(RFSRoot *root, const char *path);
typedef RFSFile *(*CatHandler)(RFSRoot *root, RFSFile *file, const char *path);
typedef bool (*WriteHandler)(RFSFile *file, ut64 addr, const ut8 *data, int len);
typedef struct {
const char *path;
DirHandler dir;
CatHandler cat;
WriteHandler write;
} Routes;
static RFSFile *__flags_cat(RFSRoot *root, RFSFile *file, const char *path);
static RFSFile *__cfg_cat(RFSRoot *root, RFSFile *file, const char *path);
static RFSFile *__seek_cat(RFSRoot *root, RFSFile *file, const char *path);
static RFSFile *__bsize_cat(RFSRoot *root, RFSFile *file, const char *path);
static bool __cfg_write(RFSFile *file, ut64 addr, const ut8 *data, int len);
static bool __seek_write(RFSFile *file, ut64 addr, const ut8 *data, int len);
static bool __bsize_write(RFSFile *file, ut64 addr, const ut8 *data, int len);
static RFSFile *__version(RFSRoot *root, RFSFile *file, const char *path);
static RList *__root(RFSRoot *root, const char *path);
static RList *__cfg(RFSRoot *root, const char *path);
static RList *__flags(RFSRoot *root, const char *path);
static Routes routes[] = {
{"/cfg", &__cfg, &__cfg_cat, &__cfg_write },
{"/flags", &__flags, &__flags_cat, NULL},
{"/version", NULL, &__version, NULL},
{"/seek", NULL, &__seek_cat, &__seek_write },
{"/bsize", NULL, &__bsize_cat, &__bsize_write },
{"/", &__root},
{NULL, NULL}
};
static void append_file(RList *list, const char *name, int type, int time, ut64 size) {
if (!list || !name || !*name) {
return;
}
RFSFile *fsf = r_fs_file_new (NULL, name);
if (!fsf) {
return;
}
fsf->type = type;
fsf->time = time;
fsf->size = size;
r_list_append (list, fsf);
}
static RList *fscmd(RFSRoot *root, const char *cmd, int type) {
char *res = root->cob.cmdstr (root->cob.core, cmd);
if (res) {
RList *list = r_list_newf (free);
if (!list) {
free (res);
return NULL;
}
size_t i, count = 0;
size_t *lines = r_str_split_lines (res, &count);
if (lines) {
for (i = 0; i < count; i++) {
append_file (list, res + lines[i], type, 0, 0);
}
free (lines);
}
free (res);
return list;
}
return NULL;
}
static RFSFile* fs_r2_open(RFSRoot *root, const char *path, bool create) {
int i;
for (i = 0; routes[i].path; i++) {
const char *cwd = routes[i].path;
if (routes[i].cat && !strncmp (path, cwd, strlen (cwd))) {
return routes[i].cat (root, NULL, path);
}
}
return NULL;
}
static bool fs_r2_write(RFSFile *file, ut64 addr, const ut8 *data, int len) {
int i;
const char *path = file->path;
const char *name = file->name;
for (i = 0; routes[i].path; i++) {
if (routes[i].write) {
if (!strncmp (name, routes[i].path + 1, strlen (routes[i].path) - 1)) {
return routes[i].write (file, addr, data, len);
}
if (!strncmp (path, routes[i].path, strlen (routes[i].path))) {
return routes[i].write (file, addr, data, len);
}
}
}
return false;
}
static bool fs_r2_read(RFSFile *file, ut64 addr, int len) {
int i;
const char *path = file->name;
for (i = 0; routes[i].path; i++) {
if (routes[i].cat && !strncmp (path, routes[i].path, strlen (routes[i].path))) {
return routes[i].cat (file->root, file, path);
}
}
return false;
}
static void fs_r2_close(RFSFile *file) {
// eprintf ("TODO: fs.r2.close\n");
//fclose (file->ptr);
}
static RFSFile *__version(RFSRoot *root, RFSFile *file, const char *path) {
char *res = root->cob.cmdstrf (root->cob.core, "?V");
/// root->iob.io->cb_printf ("%s\n", res);
if (!file) {
file = r_fs_file_new (root, path);
}
file->ptr = NULL;
free (file->data);
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
return file;
}
static RFSFile *__flags_cat(RFSRoot *root, RFSFile *file, const char *path) {
r_return_val_if_fail (root && path, NULL);
const char *last = r_str_rchr (path, NULL, '/');
if (last) {
last++;
} else {
last = path;
}
char *res = root->cob.cmdstrf (root->cob.core, "?v %s", last);
if (file) {
file->ptr = NULL;
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
} else {
file = r_fs_file_new (root, path);
file->ptr = NULL;
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
}
return file;
}
static bool __bsize_write(RFSFile *file, ut64 addr, const ut8 *data, int len) {
void *core = file->root->cob.core;
char *res = file->root->cob.cmdstrf (core, "b %s", data);
free (res);
return true;
}
static RFSFile *__bsize_cat(RFSRoot *root, RFSFile *file, const char *path) {
char *res = root->cob.cmdstrf (root->cob.core, "b");
if (!file) {
file = r_fs_file_new (root, path);
}
file->ptr = NULL;
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
return file;
}
static bool __seek_write(RFSFile *file, ut64 addr, const ut8 *data, int len) {
void *core = file->root->cob.core;
char *res = file->root->cob.cmdstrf (core, "s %s", data);
free (res);
return true;
}
static RFSFile *__seek_cat(RFSRoot *root, RFSFile *file, const char *path) {
char *res = root->cob.cmdstrf (root->cob.core, "s");
if (!file) {
file = r_fs_file_new (root, path);
}
file->ptr = NULL;
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
return file;
}
static bool __cfg_write(RFSFile *file, ut64 addr, const ut8 *data, int len) {
const char *a = file->name;
void *core = file->root->cob.core;
char *prefix = strdup (file->path + strlen ("/cfg/"));
char *res = file->root->cob.cmdstrf (core, "e %s.%s=%s", prefix, a, data);
free (prefix);
free (res);
return true;
}
static RFSFile *__cfg_cat(RFSRoot *root, RFSFile *file, const char *path) {
if (strlen (path) < 6) {
return NULL;
}
char *a = strdup (path + 5);
r_str_replace_char (a, '/', '.');
char *res = root->cob.cmdstrf (root->cob.core, "e %s", a);
// root->iob.io->cb_printf ("%s\n", res);
// eprintf ("%s", res);
if (!file) {
file = r_fs_file_new (root, path);
}
file->ptr = NULL;
file->data = (ut8*)res;
file->p = root->p;
file->size = strlen (res);
return file;
}
static RList *__flags(RFSRoot *root, const char *path) {
const char *prefix = NULL;
if (!strncmp (path, "/flags/", 7)) {
prefix = path + 7;
}
char *cmd = prefix
? r_str_newf ("fq@F:%s", prefix)
: strdup ("fsq");
RList *res = fscmd (root, cmd, prefix? 'f': 'd');
free (cmd);
return res;
}
static RList *__cfg(RFSRoot *root, const char *path) {
const char *prefix = NULL;
if (!strncmp (path, "/cfg/", 5)) {
prefix = path + 5;
}
char *cmd = prefix
? r_str_newf ("es %s", prefix)
: strdup ("es");
char *res = root->cob.cmdstr (root->cob.core, cmd);
free (cmd);
if (res) {
RList *list = r_list_new ();
if (!list) {
free (res);
return NULL;
}
size_t i, count = 0;
size_t *lines = r_str_split_lines (res, &count);
if (lines) {
for (i = 0; i < count; i++) {
char *line = res + lines[i];
append_file (list, line, prefix? 'f': 'd', 0, 0);
}
free (res);
free (lines);
}
return list;
}
return NULL;
}
static RList *__root(RFSRoot *root, const char *path) {
RList *list = r_list_newf (NULL);
if (!list) {
return NULL;
}
int i;
for (i = 0; routes[i].path; i++) {
char type = routes[i].dir? 'd': 'f';
append_file (list, routes[i].path + 1, type, 0, 0);
}
return list;
}
static RList *fs_r2_dir(RFSRoot *root, const char *path, int view /*ignored*/) {
int i;
for (i = 0; routes[i].path; i++) {
if (routes[i].dir && !strncmp (path, routes[i].path, strlen (routes[i].path))) {
return routes[i].dir (root, path);
}
}
return NULL;
}
static int fs_r2_mount(RFSRoot *root) {
root->ptr = NULL;
return true;
}
static void fs_r2_umount(RFSRoot *root) {
root->ptr = NULL;
}
RFSPlugin r_fs_plugin_r2 = {
.name = "r2",
.desc = "r2-based filesystem",
.license = "MIT",
.open = fs_r2_open, // open == read
.read = fs_r2_read, // read == open
.write = fs_r2_write,
.close = fs_r2_close,
.dir = &fs_r2_dir,
.mount = fs_r2_mount,
.umount = fs_r2_umount,
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_FS,
.data = &r_fs_plugin_r2,
.versr2n = R2_VERSION
};
#endif