1 /* radare - LGPL - Copyright 2013-2016 - pancake */
2
3 #include <r_userconf.h>
4 #include <r_io.h>
5 #include <r_lib.h>
6
7 typedef struct r_io_mmo_t {
8 char * filename;
9 int mode;
10 int flags;
11 int fd;
12 int opened;
13 ut8 modified;
14 RBuffer *buf;
15 RIO * io_backref;
16 } RIOMMapFileObj;
17
r_io_mmap_seek(RIO * io,RIOMMapFileObj * mmo,ut64 offset,int whence)18 static ut64 r_io_mmap_seek(RIO *io, RIOMMapFileObj *mmo, ut64 offset, int whence) {
19 ut64 seek_val = r_buf_tell (mmo->buf);
20 switch (whence) {
21 case SEEK_SET:
22 seek_val = (r_buf_size (mmo->buf) < offset)? r_buf_size (mmo->buf): offset;
23 r_buf_seek (mmo->buf, io->off = seek_val, R_BUF_SET);
24 return seek_val;
25 case SEEK_CUR:
26 seek_val = (r_buf_size (mmo->buf) < (offset + r_buf_tell (mmo->buf)))? r_buf_size (mmo->buf): offset + r_buf_tell (mmo->buf);
27 r_buf_seek (mmo->buf, io->off = seek_val, R_BUF_SET);
28 return seek_val;
29 case SEEK_END:
30 seek_val = r_buf_size (mmo->buf);
31 r_buf_seek (mmo->buf, io->off = seek_val, R_BUF_SET);
32 return seek_val;
33 }
34 return seek_val;
35 }
36
r_io_mmap_refresh_buf(RIOMMapFileObj * mmo)37 static bool r_io_mmap_refresh_buf(RIOMMapFileObj *mmo) {
38 RIO* io = mmo->io_backref;
39 ut64 cur = mmo->buf? r_buf_tell (mmo->buf): 0;
40 if (mmo->buf) {
41 r_buf_free (mmo->buf);
42 mmo->buf = NULL;
43 }
44 mmo->buf = r_buf_new_mmap (mmo->filename, mmo->flags);
45 if (mmo->buf) {
46 r_io_mmap_seek (io, mmo, cur, SEEK_SET);
47 }
48 return mmo->buf != NULL;
49 }
50
r_io_mmap_free(RIOMMapFileObj * mmo)51 static void r_io_mmap_free(RIOMMapFileObj *mmo) {
52 free (mmo->filename);
53 r_buf_free (mmo->buf);
54 memset (mmo, 0, sizeof (RIOMMapFileObj));
55 free (mmo);
56 }
57
r_io_mmap_create_new_file(RIO * io,const char * filename,int mode,int flags)58 RIOMMapFileObj *r_io_mmap_create_new_file(RIO *io, const char *filename, int mode, int flags) {
59 RIOMMapFileObj *mmo;
60 if (!io) {
61 return NULL;
62 }
63 mmo = R_NEW0 (RIOMMapFileObj);
64 if (!mmo) {
65 return NULL;
66 }
67 mmo->filename = strdup (filename);
68 mmo->fd = r_num_rand (0xFFFF); // XXX: Use r_io_fd api
69 mmo->mode = mode;
70 mmo->flags = flags;
71 mmo->io_backref = io;
72 if (!r_io_mmap_refresh_buf (mmo)) {
73 r_io_mmap_free (mmo);
74 mmo = NULL;
75 }
76 return mmo;
77 }
78
r_io_mmap_close(RIODesc * fd)79 static int r_io_mmap_close(RIODesc *fd) {
80 if (!fd || !fd->data) {
81 return -1;
82 }
83 r_io_mmap_free ((RIOMMapFileObj *) fd->data);
84 fd->data = NULL;
85 return 0;
86 }
87
r_io_mmap_check(const char * filename)88 static int r_io_mmap_check (const char *filename) {
89 return (filename && !strncmp (filename, "mmap://", 7) && *(filename + 7));
90 }
91
r_io_mmap_read(RIO * io,RIODesc * fd,ut8 * buf,int count)92 static int r_io_mmap_read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
93 RIOMMapFileObj *mmo = NULL;
94 if (!fd || !fd->data || !buf) {
95 return -1;
96 }
97 mmo = fd->data;
98 if (r_buf_size (mmo->buf) < io->off) {
99 io->off = r_buf_size (mmo->buf);
100 }
101 int r = r_buf_read_at (mmo->buf, io->off, buf, count);
102 if (r >= 0) {
103 r_buf_seek (mmo->buf, r, R_BUF_CUR);
104 }
105 return r;
106 }
107
r_io_mmap_write(RIO * io,RIODesc * fd,const ut8 * buf,int count)108 static int r_io_mmap_write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
109 RIOMMapFileObj *mmo;
110 int len = count;
111 ut64 addr;
112
113 if (!io || !fd || !fd->data || !buf) {
114 return -1;
115 }
116 mmo = fd->data;
117 addr = io->off;
118 if ( !(mmo->flags & R_PERM_W)) {
119 return -1;
120 }
121 if ( (count + addr > r_buf_size (mmo->buf)) || r_buf_size (mmo->buf) == 0) {
122 ut64 sz = count + addr;
123 r_file_truncate (mmo->filename, sz);
124 }
125 len = r_file_mmap_write (mmo->filename, io->off, buf, len);
126 if (!r_io_mmap_refresh_buf (mmo) ) {
127 eprintf ("io_mmap: failed to refresh the mmap backed buffer.\n");
128 // XXX - not sure what needs to be done here (error handling).
129 }
130 return len;
131 }
132
r_io_mmap_open(RIO * io,const char * file,int flags,int mode)133 static RIODesc *r_io_mmap_open(RIO *io, const char *file, int flags, int mode) {
134 if (!strncmp (file, "mmap://", 7)) {
135 file += 7;
136 }
137 RIOMMapFileObj *mmo = r_io_mmap_create_new_file (io, file, mode, flags);
138 return mmo? r_io_desc_new (io, &r_io_plugin_mmap, mmo->filename, flags, mode, mmo): NULL;
139 }
140
r_io_mmap_lseek(RIO * io,RIODesc * fd,ut64 offset,int whence)141 static ut64 r_io_mmap_lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
142 RIOMMapFileObj *mmo;
143 if (!fd || !fd->data) {
144 return -1;
145 }
146 mmo = fd->data;
147 return r_io_mmap_seek (io, mmo, offset, whence);
148 }
149
r_io_mmap_truncate(RIOMMapFileObj * mmo,ut64 size)150 static bool r_io_mmap_truncate(RIOMMapFileObj *mmo, ut64 size) {
151 int res = r_file_truncate (mmo->filename, size);
152 if (res && !r_io_mmap_refresh_buf (mmo)) {
153 eprintf ("r_io_mmap_truncate: Error trying to refresh the mmap'ed file.");
154 res = false;
155 } else if (res) {
156 eprintf ("r_io_mmap_truncate: Error trying to resize the file.");
157 }
158 return res;
159 }
160
161
__plugin_open(RIO * io,const char * file,bool many)162 static bool __plugin_open(RIO *io, const char *file, bool many) {
163 return r_io_mmap_check (file);
164 }
165
__open(RIO * io,const char * file,int flags,int mode)166 static RIODesc *__open(RIO *io, const char *file, int flags, int mode) {
167 if (!r_io_mmap_check (file)) {
168 return NULL;
169 }
170 return r_io_mmap_open (io, file, flags, mode);
171 }
172
__read(RIO * io,RIODesc * fd,ut8 * buf,int len)173 static int __read(RIO *io, RIODesc *fd, ut8 *buf, int len) {
174 return r_io_mmap_read (io, fd, buf, len);
175 }
176
__write(RIO * io,RIODesc * fd,const ut8 * buf,int len)177 static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int len) {
178 return r_io_mmap_write(io, fd, buf, len);
179 }
180
__lseek(RIO * io,RIODesc * fd,ut64 offset,int whence)181 static ut64 __lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
182 return r_io_mmap_lseek (io, fd, offset, whence);
183 }
184
__close(RIODesc * fd)185 static int __close(RIODesc *fd) {
186 return r_io_mmap_close (fd);
187 }
188
__resize(RIO * io,RIODesc * fd,ut64 size)189 static bool __resize(RIO *io, RIODesc *fd, ut64 size) {
190 if (!fd || !fd->data) {
191 return false;
192 }
193 return r_io_mmap_truncate ((RIOMMapFileObj*)fd->data, size);
194 }
195
196 struct r_io_plugin_t r_io_plugin_mmap = {
197 .name = "mmap",
198 .desc = "Open files using mmap",
199 .uris = "mmap://",
200 .license = "LGPL3",
201 .open = __open,
202 .close = __close,
203 .read = __read,
204 .check = __plugin_open,
205 .lseek = __lseek,
206 .write = __write,
207 .resize = __resize,
208 };
209
210 #ifndef R2_PLUGIN_INCORE
211 R_API RLibStruct radare_plugin = {
212 .type = R_LIB_TYPE_IO,
213 .data = &r_io_plugin_mmap,
214 .version = R2_VERSION
215 };
216 #endif
217