2009-02-05 21:08:46 +00:00
|
|
|
/* radare - LGPL - Copyright 2008-2009 pancake<nopcode.org> */
|
|
|
|
|
|
|
|
#include "r_io.h"
|
|
|
|
#include "r_util.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2009-09-08 18:16:52 +00:00
|
|
|
// TODO: R_API int r_io_fetch(struct r_io_t *io, ut8 *buf, int len)
|
|
|
|
// --- check for EXEC perms in section (use cached read to accelerate)
|
|
|
|
|
2010-01-19 10:25:17 +00:00
|
|
|
R_API struct r_io_t *r_io_init(struct r_io_t *io) {
|
|
|
|
if (!io) return NULL;
|
2009-02-05 21:08:46 +00:00
|
|
|
io->write_mask_fd = -1;
|
|
|
|
io->last_align = 0;
|
|
|
|
io->redirect = NULL;
|
2009-09-20 00:16:14 +00:00
|
|
|
io->printf = (void*) printf;
|
2009-09-08 02:14:19 +00:00
|
|
|
r_io_cache_init(io);
|
2009-02-05 21:08:46 +00:00
|
|
|
r_io_map_init(io);
|
|
|
|
r_io_section_init(io);
|
|
|
|
r_io_handle_init(io);
|
2009-09-05 23:58:02 +00:00
|
|
|
r_io_desc_init(io);
|
2009-09-09 00:35:00 +00:00
|
|
|
r_io_undo_init(io);
|
2009-09-05 23:58:02 +00:00
|
|
|
return io;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2010-01-19 10:25:17 +00:00
|
|
|
R_API struct r_io_t *r_io_new() {
|
|
|
|
return r_io_init (MALLOC_STRUCT (struct r_io_t));
|
2009-08-22 01:54:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 00:28:33 +00:00
|
|
|
R_API RBuffer *r_io_read_buf(struct r_io_t *io, ut64 addr, int len)
|
2009-09-08 01:08:46 +00:00
|
|
|
{
|
2010-01-26 00:28:33 +00:00
|
|
|
RBuffer *b = MALLOC_STRUCT(RBuffer);
|
2009-09-08 01:08:46 +00:00
|
|
|
b->buf = malloc(len);
|
|
|
|
len = r_io_read_at(io, addr, b->buf, len);
|
|
|
|
if (len<0) len = 0;
|
|
|
|
b->length = len;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2010-01-19 10:25:17 +00:00
|
|
|
R_API int r_io_write_buf(struct r_io_t *io, struct r_buf_t *b) {
|
2009-09-08 01:08:46 +00:00
|
|
|
return r_io_write_at(io, b->base, b->buf, b->length);
|
|
|
|
}
|
|
|
|
|
2009-08-22 03:11:33 +00:00
|
|
|
R_API struct r_io_t *r_io_free(struct r_io_t *io)
|
|
|
|
{
|
2009-09-05 23:58:02 +00:00
|
|
|
/* TODO: properly free inner nfo */
|
2009-08-22 03:11:33 +00:00
|
|
|
free(io);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-09-05 23:58:02 +00:00
|
|
|
/* used by uri handler plugins */
|
2009-08-22 03:11:33 +00:00
|
|
|
R_API int r_io_redirect(struct r_io_t *io, const char *file)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
|
|
|
free(io->redirect);
|
|
|
|
io->redirect = file?strdup(file):NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-07 20:01:34 +00:00
|
|
|
R_API int r_io_open_as(struct r_io_t *io, const char *urihandler, const char *file, int flags, int mode)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *uri = malloc(strlen(urihandler)+strlen(file)+5);
|
|
|
|
strcpy(uri, urihandler);
|
|
|
|
strcpy(uri, "://");
|
|
|
|
strcpy(uri, file);
|
|
|
|
ret = r_io_open(io, uri, flags, mode);
|
|
|
|
free(uri);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-08-22 03:11:33 +00:00
|
|
|
R_API int r_io_open(struct r_io_t *io, const char *file, int flags, int mode)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-09-02 00:10:51 +00:00
|
|
|
int fd = -2;
|
|
|
|
char *uri = strdup(file);
|
2009-02-05 21:08:46 +00:00
|
|
|
struct r_io_handle_t *plugin;
|
2009-08-22 01:54:24 +00:00
|
|
|
if (io != NULL) {
|
2009-09-02 00:10:51 +00:00
|
|
|
for(;;) {
|
2009-02-05 21:08:46 +00:00
|
|
|
plugin = r_io_handle_resolve(io, uri);
|
|
|
|
if (plugin) {
|
2009-09-02 00:10:51 +00:00
|
|
|
fd = plugin->open(io, uri, flags, mode);
|
2009-02-05 21:08:46 +00:00
|
|
|
if (io->redirect) {
|
|
|
|
free((void *)uri);
|
|
|
|
uri = strdup(io->redirect);
|
|
|
|
r_io_redirect(io, NULL);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (fd != -1)
|
|
|
|
r_io_handle_open(io, fd, plugin);
|
2009-08-22 04:54:41 +00:00
|
|
|
if (fd != io->fd)
|
|
|
|
io->plugin = plugin;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-02 00:10:51 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-15 12:02:54 +00:00
|
|
|
if (fd == -2) {
|
|
|
|
#if __WINDOWS__
|
|
|
|
fd = open (file, 0);
|
|
|
|
#else
|
2009-09-08 18:16:52 +00:00
|
|
|
// XXX RDONLY; READ; WRITE AND MORE SOO...
|
2010-01-15 12:02:54 +00:00
|
|
|
fd = open (file, O_RDONLY, mode); // XXX drop posix depz here
|
|
|
|
#endif
|
|
|
|
}
|
2009-09-05 23:58:02 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
r_io_set_fd(io, fd);
|
|
|
|
r_io_desc_add(io, fd, file, flags, io->plugin);
|
|
|
|
} else fd = -1;
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
free((void *)uri);
|
|
|
|
return fd;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2010-01-19 10:25:17 +00:00
|
|
|
// TODO: Rename to use_fd ?
|
2009-08-22 04:54:41 +00:00
|
|
|
R_API int r_io_set_fd(struct r_io_t *io, int fd)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-09-02 00:10:51 +00:00
|
|
|
if (fd != -1 && fd != io->fd) {
|
2009-08-22 04:54:41 +00:00
|
|
|
io->plugin = r_io_handle_resolve_fd(io, fd);
|
|
|
|
io->fd = fd;
|
|
|
|
}
|
2009-09-02 00:10:51 +00:00
|
|
|
return io->fd;
|
2009-08-22 04:54:41 +00:00
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_read(struct r_io_t *io, ut8 *buf, int len)
|
2009-08-22 04:54:41 +00:00
|
|
|
{
|
2009-09-08 02:14:19 +00:00
|
|
|
int ret;
|
|
|
|
/* check section permissions */
|
|
|
|
if (io->enforce_rwx && !(r_io_section_get_rwx(io, io->seek) & R_IO_READ))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (io->cached) {
|
|
|
|
ret = r_io_cache_read(io, io->seek, buf, len);
|
|
|
|
if (ret == len)
|
|
|
|
return len;
|
|
|
|
if (ret > 0) {
|
|
|
|
len -= ret;
|
|
|
|
buf += ret;
|
|
|
|
}
|
2009-09-17 09:48:36 +00:00
|
|
|
// partial reads
|
|
|
|
if (ret == len)
|
|
|
|
return len;
|
2009-09-08 02:14:19 +00:00
|
|
|
}
|
|
|
|
ret = r_io_map_read_at(io, io->seek, buf, len);
|
2009-09-17 09:48:36 +00:00
|
|
|
|
2009-09-08 02:14:19 +00:00
|
|
|
// partial reads
|
2009-09-17 09:48:36 +00:00
|
|
|
if (ret != len) {
|
|
|
|
if (ret != -1) {
|
|
|
|
len -= ret;
|
|
|
|
buf += len;
|
|
|
|
}
|
|
|
|
if (io->plugin && io->plugin->read) {
|
|
|
|
if (io->plugin->read != NULL)
|
|
|
|
ret = io->plugin->read(io, io->fd, buf, len);
|
|
|
|
else fprintf(stderr, "IO handler for fd=%d has no read()\n", io->fd);
|
|
|
|
} else ret = read(io->fd, buf, len);
|
2009-09-07 20:01:34 +00:00
|
|
|
}
|
2009-09-17 09:48:36 +00:00
|
|
|
|
|
|
|
if (ret == len && io->cached_read) {
|
|
|
|
/* if read is cached. cache it :) */
|
|
|
|
r_io_cache_write(io, io->seek, buf, len);
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
2009-09-17 09:48:36 +00:00
|
|
|
return ret;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_read_at(struct r_io_t *io, ut64 addr, ut8 *buf, int len)
|
|
|
|
{
|
2009-09-07 20:01:34 +00:00
|
|
|
if (r_io_seek(io, addr, R_IO_SEEK_SET)==-1)
|
2009-09-02 00:10:51 +00:00
|
|
|
return -1;
|
|
|
|
return r_io_read(io, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API ut64 r_io_read_i(struct r_io_t *io, ut64 addr, int sz, int endian)
|
2009-08-22 04:54:41 +00:00
|
|
|
{
|
|
|
|
ut64 ret = 0LL;
|
|
|
|
int err;
|
2009-09-02 00:10:51 +00:00
|
|
|
ut8 buf[8];
|
2009-08-22 04:54:41 +00:00
|
|
|
if (sz > 8) sz = 8;
|
|
|
|
if (sz < 0) sz = 1;
|
2009-09-02 00:10:51 +00:00
|
|
|
err = r_io_read_at(io, addr, buf, sz);
|
|
|
|
if (err == sz) r_mem_copyendian((ut8*)&ret, buf, sz, endian);
|
|
|
|
else perror("Cannot read");
|
2009-08-22 04:54:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_resize(struct r_io_t *io, const char *file, int flags, int mode)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2010-01-24 22:47:18 +00:00
|
|
|
// XXX not implemented
|
2009-02-05 21:08:46 +00:00
|
|
|
#if 0
|
|
|
|
/* TODO */
|
|
|
|
struct r_io_handle_t *plugin = r_io_handle_resolve(file);
|
2009-08-22 04:54:41 +00:00
|
|
|
if (plugin && io->plugin->resize) {
|
|
|
|
int fd = plugin->resize(file, flags, mode);
|
2009-02-05 21:08:46 +00:00
|
|
|
if (fd != -1)
|
|
|
|
r_io_handle_open(fd, plugin);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_set_write_mask(struct r_io_t *io, const ut8 *buf, int len)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-09-02 00:10:51 +00:00
|
|
|
int ret = R_FALSE;
|
2009-02-05 21:08:46 +00:00
|
|
|
if (len) {
|
2009-09-02 00:10:51 +00:00
|
|
|
io->write_mask_fd = io->fd;
|
2009-07-08 11:49:55 +00:00
|
|
|
io->write_mask_buf = (ut8 *)malloc(len);
|
2009-02-05 21:08:46 +00:00
|
|
|
memcpy(io->write_mask_buf, buf, len);
|
|
|
|
io->write_mask_len = len;
|
|
|
|
ret = R_TRUE;
|
2009-09-02 00:10:51 +00:00
|
|
|
} else io->write_mask_fd = -1;
|
2009-02-05 21:08:46 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_write(struct r_io_t *io, const ut8 *buf, int len)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
|
2009-09-08 02:14:19 +00:00
|
|
|
/* check section permissions */
|
|
|
|
if (io->enforce_rwx && !(r_io_section_get_rwx(io, io->seek) & R_IO_WRITE))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (io->cached) {
|
|
|
|
ret = r_io_cache_write(io, io->seek, buf, len);
|
|
|
|
if (ret == len)
|
|
|
|
return len;
|
|
|
|
if (ret > 0) {
|
|
|
|
len -= ret;
|
|
|
|
buf += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: implement IO cache here. to avoid dupping work on vm for example */
|
|
|
|
|
2009-02-05 21:08:46 +00:00
|
|
|
/* apply write binary mask */
|
|
|
|
if (io->write_mask_fd != -1) {
|
2009-07-08 11:49:55 +00:00
|
|
|
ut8 *data = alloca(len);
|
2009-09-07 20:01:34 +00:00
|
|
|
r_io_seek(io, io->seek, R_IO_SEEK_SET);
|
2009-09-02 00:10:51 +00:00
|
|
|
r_io_read(io, data, len);
|
2009-09-07 20:01:34 +00:00
|
|
|
r_io_seek(io, io->seek, R_IO_SEEK_SET);
|
2009-02-05 21:08:46 +00:00
|
|
|
for(i=0;i<len;i++) {
|
|
|
|
data[i] = buf[i] & \
|
|
|
|
io->write_mask_buf[i%io->write_mask_len];
|
|
|
|
}
|
|
|
|
buf = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_io_map_write_at(io, io->seek, buf, len) != 0)
|
|
|
|
return len;
|
|
|
|
if (io->plugin) {
|
|
|
|
if (io->plugin->write)
|
2009-09-02 00:10:51 +00:00
|
|
|
ret = io->plugin->write(io, io->fd, buf, len);
|
|
|
|
else fprintf(stderr, "r_io_write: io handler with no write callback\n");
|
|
|
|
} else ret = write(io->fd, buf, len);
|
2009-02-05 21:08:46 +00:00
|
|
|
if (ret == -1)
|
|
|
|
fprintf(stderr, "r_io_write: cannot write\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_write_at(struct r_io_t *io, ut64 addr, const ut8 *buf, int len)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-09-07 20:01:34 +00:00
|
|
|
if (r_io_seek(io, addr, R_IO_SEEK_SET)<0)
|
2009-09-02 00:10:51 +00:00
|
|
|
return -1;
|
|
|
|
return r_io_write(io, buf, len);
|
|
|
|
}
|
2009-08-22 04:54:41 +00:00
|
|
|
|
2009-09-07 20:01:34 +00:00
|
|
|
R_API ut64 r_io_seek(struct r_io_t *io, ut64 offset, int whence)
|
2009-09-02 00:10:51 +00:00
|
|
|
{
|
|
|
|
int posix_whence = SEEK_SET;
|
2009-02-05 21:08:46 +00:00
|
|
|
|
|
|
|
/* pwn seek value */
|
|
|
|
switch(whence) {
|
|
|
|
case R_IO_SEEK_SET:
|
2009-09-08 02:14:19 +00:00
|
|
|
/* TODO: Deprecate remove section align ?? */
|
2009-09-02 00:10:51 +00:00
|
|
|
offset = r_io_section_align(io, offset, 0, 0);
|
2009-02-05 21:08:46 +00:00
|
|
|
io->seek = offset;
|
|
|
|
posix_whence = SEEK_SET;
|
|
|
|
break;
|
|
|
|
case R_IO_SEEK_CUR:
|
|
|
|
io->seek += offset;
|
|
|
|
posix_whence = SEEK_CUR;
|
|
|
|
break;
|
|
|
|
case R_IO_SEEK_END:
|
2009-09-07 20:01:34 +00:00
|
|
|
io->seek = 0xffffffff; // XXX: depending on io bitz?
|
2009-02-05 21:08:46 +00:00
|
|
|
posix_whence = SEEK_END;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-09-08 02:14:19 +00:00
|
|
|
// TODO: implement io->enforce_seek here!
|
2009-09-02 00:10:51 +00:00
|
|
|
if (io->plugin && io->plugin->lseek)
|
|
|
|
io->seek = io->plugin->lseek(io, io->fd, offset, whence);
|
2009-02-05 21:08:46 +00:00
|
|
|
// XXX can be problematic on w32..so no 64 bit offset?
|
2009-09-02 00:10:51 +00:00
|
|
|
else io->seek = lseek(io->fd, offset, posix_whence);
|
|
|
|
|
2009-09-09 00:35:00 +00:00
|
|
|
r_io_sundo_push(io);
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
return io->seek;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2009-08-22 04:54:41 +00:00
|
|
|
R_API ut64 r_io_size(struct r_io_t *io, int fd)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-08-22 04:54:41 +00:00
|
|
|
ut64 size, here;
|
|
|
|
fd = r_io_set_fd(io, fd);
|
2009-09-07 20:01:34 +00:00
|
|
|
here = r_io_seek(io, 0, R_IO_SEEK_CUR);
|
|
|
|
size = r_io_seek(io, 0, R_IO_SEEK_END);
|
|
|
|
r_io_seek(io, here, R_IO_SEEK_SET);
|
2009-02-05 21:08:46 +00:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
R_API int r_io_system(struct r_io_t *io, const char *cmd)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-09-05 23:58:02 +00:00
|
|
|
int ret = -1;
|
2009-09-02 00:10:51 +00:00
|
|
|
if (io->plugin && io->plugin->system)
|
2009-09-05 23:58:02 +00:00
|
|
|
ret = io->plugin->system(io, io->fd, cmd);
|
|
|
|
return ret;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2009-09-02 00:10:51 +00:00
|
|
|
// TODO: remove int fd here???
|
2009-08-22 04:54:41 +00:00
|
|
|
R_API int r_io_close(struct r_io_t *io, int fd)
|
2009-02-05 21:08:46 +00:00
|
|
|
{
|
2009-08-22 04:54:41 +00:00
|
|
|
fd = r_io_set_fd(io, fd);
|
2009-09-05 23:58:02 +00:00
|
|
|
if (fd != -1 && io->plugin) {
|
|
|
|
r_io_desc_del(io, fd);
|
|
|
|
r_io_map_del(io, fd);
|
2009-02-05 21:08:46 +00:00
|
|
|
r_io_handle_close(io, fd, io->plugin);
|
|
|
|
if (io->plugin->close)
|
|
|
|
return io->plugin->close(io, fd);
|
|
|
|
}
|
2009-09-05 23:58:02 +00:00
|
|
|
io->fd = -1; // unset current fd
|
2009-02-05 21:08:46 +00:00
|
|
|
return close(fd);
|
|
|
|
}
|
2009-09-10 20:51:34 +00:00
|
|
|
|
|
|
|
R_API int r_io_bind(struct r_io_t *io, struct r_io_bind_t *bnd)
|
|
|
|
{
|
|
|
|
bnd->io = io;
|
|
|
|
bnd->init = R_TRUE;
|
|
|
|
bnd->read_at = r_io_read_at;
|
|
|
|
bnd->write_at = r_io_write_at;
|
|
|
|
//bnd->fd = io->fd;// do we need to store ptr to fd??
|
|
|
|
return R_TRUE;
|
|
|
|
}
|