1 /* radare2 - LGPL - Copyright 2017-2020 - condret, pancake, alvaro */
2
3 #include <r_io.h>
4 #include <sdb.h>
5 #include <string.h>
6
7 // shall be used by plugins for creating descs
r_io_desc_new(RIO * io,RIOPlugin * plugin,const char * uri,int perm,int mode,void * data)8 R_API RIODesc* r_io_desc_new(RIO* io, RIOPlugin* plugin, const char* uri, int perm, int mode, void* data) {
9 ut32 fd32 = 0;
10 // this is required for emscripten builds to work, but should assert
11 if (!io || !plugin || !uri) {
12 return NULL;
13 }
14 if (io->files) {
15 if (!r_id_pool_grab_id (io->files->pool, &fd32)) {
16 return NULL;
17 }
18 }
19 RIODesc* desc = R_NEW0 (RIODesc);
20 if (desc) {
21 desc->fd = fd32;
22 desc->io = io;
23 desc->plugin = plugin;
24 desc->data = data;
25 desc->perm = perm;
26 //because the uri-arg may live on the stack
27 desc->uri = strdup (uri);
28 }
29 return desc;
30 }
31
r_io_desc_free(RIODesc * desc)32 R_API void r_io_desc_free(RIODesc* desc) {
33 if (desc) {
34 free (desc->uri);
35 free (desc->referer);
36 free (desc->name);
37 r_io_desc_cache_fini (desc);
38 if (desc->io && desc->io->files) {
39 r_id_storage_delete (desc->io->files, desc->fd);
40 }
41 // free (desc->plugin);
42 }
43 free (desc);
44 }
45
r_io_desc_add(RIO * io,RIODesc * desc)46 R_API bool r_io_desc_add(RIO* io, RIODesc* desc) {
47 r_return_val_if_fail (io && desc && desc->io, false);
48 if (!r_id_storage_set (io->files, desc, desc->fd)) {
49 // TODO: use assert here
50 eprintf ("You are using this API incorrectly\n");
51 eprintf ("fd %d was probably not generated by this RIO-instance\n", desc->fd);
52 r_sys_backtrace ();
53 return false;
54 }
55 return true;
56 }
57
r_io_desc_del(RIO * io,int fd)58 R_API bool r_io_desc_del(RIO* io, int fd) { //can we pass this a riodesc and check if it belongs to the desc->io ?
59 r_return_val_if_fail (io && io->files, false);
60 RIODesc* desc = r_id_storage_get (io->files, fd);
61 r_io_desc_free (desc);
62 if (desc == io->desc) {
63 io->desc = NULL;
64 }
65 // remove all dead maps
66 r_io_map_cleanup (io);
67 return true;
68 }
69
r_io_desc_get(RIO * io,int fd)70 R_API RIODesc* r_io_desc_get(RIO* io, int fd) {
71 r_return_val_if_fail (io && io->files, NULL);
72 return (RIODesc*) r_id_storage_get (io->files, fd);
73 }
74
r_io_desc_get_next(RIO * io,RIODesc * desc)75 R_API RIODesc *r_io_desc_get_next(RIO *io, RIODesc *desc) {
76 r_return_val_if_fail (desc && io && io->files, NULL);
77 const int next_fd = r_io_fd_get_next (io, desc->fd);
78 if (next_fd == -1) {
79 return NULL;
80 }
81 return (RIODesc*) r_id_storage_get (io->files, next_fd);
82 }
83
r_io_desc_get_prev(RIO * io,RIODesc * desc)84 R_API RIODesc *r_io_desc_get_prev(RIO *io, RIODesc *desc) {
85 r_return_val_if_fail (desc && io && io->files, NULL);
86 const int prev_fd = r_io_fd_get_prev (io, desc->fd);
87 if (prev_fd == -1) {
88 return NULL;
89 }
90 return (RIODesc*) r_id_storage_get (io->files, prev_fd);
91 }
92
r_io_desc_get_highest(RIO * io)93 R_API RIODesc *r_io_desc_get_highest(RIO *io) {
94 int fd = r_io_fd_get_highest (io);
95 if (fd == -1) {
96 return NULL;
97 }
98 return r_io_desc_get (io, fd);
99 }
100
r_io_desc_get_lowest(RIO * io)101 R_API RIODesc *r_io_desc_get_lowest(RIO *io) {
102 int fd = r_io_fd_get_lowest (io);
103 if (fd == -1) {
104 return NULL;
105 }
106 return r_io_desc_get (io, fd);
107 }
108
r_io_desc_open(RIO * io,const char * uri,int perm,int mode)109 R_API RIODesc *r_io_desc_open(RIO *io, const char *uri, int perm, int mode) {
110 r_return_val_if_fail (io && uri, NULL);
111 RIOPlugin *plugin = r_io_plugin_resolve (io, uri, 0);
112 if (!plugin || !plugin->open) {
113 return NULL;
114 }
115 RIODesc *desc = plugin->open (io, uri, perm, mode);
116 if (!desc) {
117 return NULL;
118 }
119 // for none static callbacks, those that cannot use r_io_desc_new
120 if (!desc->name) {
121 desc->name = strdup (uri);
122 }
123 if (!desc->uri) {
124 desc->uri = strdup (uri);
125 }
126 if (!desc->plugin) {
127 desc->plugin = plugin;
128 }
129 if (!r_io_desc_add (io, desc)) {
130 r_io_desc_free (desc);
131 return NULL;
132 }
133 return desc;
134 }
135
r_io_desc_open_plugin(RIO * io,RIOPlugin * plugin,const char * uri,int perm,int mode)136 R_API RIODesc *r_io_desc_open_plugin(RIO *io, RIOPlugin *plugin, const char *uri, int perm, int mode) {
137 r_return_val_if_fail (io && io->files && uri, NULL);
138 if (!plugin || !plugin->open || !plugin->check || !plugin->check (io, uri, false)) {
139 return NULL;
140 }
141 RIODesc *desc = plugin->open (io, uri, perm, mode);
142 if (!desc) {
143 return NULL;
144 }
145 // for none static callbacks, those that cannot use r_io_desc_new
146 if (!desc->plugin) {
147 desc->plugin = plugin;
148 }
149 if (!desc->uri) {
150 desc->uri = strdup (uri);
151 }
152 if (!desc->name) {
153 desc->name = strdup (uri);
154 }
155 if (!r_io_desc_add (io, desc)) {
156 r_io_desc_free (desc);
157 return NULL;
158 }
159 return desc;
160 }
161
162
r_io_desc_close(RIODesc * desc)163 R_API bool r_io_desc_close(RIODesc *desc) {
164 RIO *io;
165 if (!desc || !desc->io || !desc->plugin) {
166 return false;
167 }
168 if (desc->plugin->close && desc->plugin->close (desc)) {
169 return false;
170 }
171 io = desc->io;
172 // remove entry from idstorage and free the desc-struct
173 r_io_desc_del (io, desc->fd);
174 // remove all dead maps
175 r_io_map_cleanup (io);
176 return true;
177 }
178
179 //returns length of written bytes
r_io_desc_write(RIODesc * desc,const ut8 * buf,int len)180 R_API int r_io_desc_write(RIODesc *desc, const ut8* buf, int len) {
181 r_return_val_if_fail (desc && buf, -1);
182 if (len < 0) {
183 return -1;
184 }
185 //check pointers and pcache
186 if (desc->io && (desc->io->p_cache & 2)) {
187 return r_io_desc_cache_write (desc,
188 r_io_desc_seek (desc, 0LL, R_IO_SEEK_CUR), buf, len);
189 }
190 return r_io_plugin_write (desc, buf, len);
191 }
192
193 // returns length of read bytes
r_io_desc_read(RIODesc * desc,ut8 * buf,int len)194 R_API int r_io_desc_read(RIODesc *desc, ut8 *buf, int len) {
195 // check pointers and permissions
196 if (!buf || !desc || !desc->plugin || !(desc->perm & R_PERM_R)) {
197 return -1;
198 }
199 ut64 seek = r_io_desc_seek (desc, 0LL, R_IO_SEEK_CUR);
200 if (desc->io->cachemode) {
201 if (seek != UT64_MAX && r_io_cache_at (desc->io, seek)) {
202 return r_io_cache_read (desc->io, seek, buf, len);
203 }
204 }
205 int ret = r_io_plugin_read (desc, buf, len);
206 if (ret > 0 && desc->io->cachemode) {
207 r_io_cache_write (desc->io, seek, buf, len);
208 } else if ((ret > 0) && desc->io && (desc->io->p_cache & 1)) {
209 ret = r_io_desc_cache_read (desc, seek, buf, ret);
210 }
211 return ret;
212 }
213
r_io_desc_seek(RIODesc * desc,ut64 offset,int whence)214 R_API ut64 r_io_desc_seek(RIODesc* desc, ut64 offset, int whence) {
215 if (!desc || !desc->plugin || !desc->plugin->lseek) {
216 return (ut64) -1;
217 }
218 return desc->plugin->lseek (desc->io, desc, offset, whence);
219 }
220
r_io_desc_size(RIODesc * desc)221 R_API ut64 r_io_desc_size(RIODesc* desc) {
222 if (!desc || !desc->plugin || !desc->plugin->lseek) {
223 return 0LL;
224 }
225 ut64 off = r_io_desc_seek (desc, 0LL, R_IO_SEEK_CUR);
226 ut64 ret = r_io_desc_seek (desc, 0LL, R_IO_SEEK_END);
227 // what to do if that seek fails?
228 r_io_desc_seek (desc, off, R_IO_SEEK_SET);
229 return ret;
230 }
231
r_io_desc_resize(RIODesc * desc,ut64 newsize)232 R_API bool r_io_desc_resize(RIODesc *desc, ut64 newsize) {
233 if (desc && desc->plugin && desc->plugin->resize) {
234 bool ret = desc->plugin->resize (desc->io, desc, newsize);
235 if (desc->io && desc->io->p_cache) {
236 r_io_desc_cache_cleanup (desc);
237 }
238 return ret;
239 }
240 return false;
241 }
242
r_io_desc_is_blockdevice(RIODesc * desc)243 R_API bool r_io_desc_is_blockdevice(RIODesc *desc) {
244 if (!desc || !desc->plugin || !desc->plugin->is_blockdevice) {
245 return false;
246 }
247 return desc->plugin->is_blockdevice (desc);
248 }
249
r_io_desc_is_chardevice(RIODesc * desc)250 R_API bool r_io_desc_is_chardevice(RIODesc *desc) {
251 if (!desc || !desc->plugin || !desc->plugin->is_chardevice) {
252 return false;
253 }
254 return desc->plugin->is_chardevice (desc);
255 }
256
r_io_desc_exchange(RIO * io,int fd,int fdx)257 R_API bool r_io_desc_exchange(RIO* io, int fd, int fdx) {
258 RIODesc* desc, * descx;
259 if (!(desc = r_io_desc_get (io, fd)) || !(descx = r_io_desc_get (io, fdx))) {
260 return false;
261 }
262 desc->fd = fdx;
263 descx->fd = fd;
264 r_id_storage_set (io->files, desc, fdx);
265 r_id_storage_set (io->files, descx, fd);
266 if (io->p_cache) {
267 HtUP* cache = desc->cache;
268 desc->cache = descx->cache;
269 descx->cache = cache;
270 r_io_desc_cache_cleanup (desc);
271 r_io_desc_cache_cleanup (descx);
272 }
273 void **it;
274 r_pvector_foreach (&io->maps, it) {
275 RIOMap *map = *it;
276 if (map->fd == fdx) {
277 map->perm &= (desc->perm | R_PERM_X);
278 } else if (map->fd == fd) {
279 map->perm &= (descx->perm | R_PERM_X);
280 }
281 }
282 return true;
283 }
284
r_io_desc_is_dbg(RIODesc * desc)285 R_API bool r_io_desc_is_dbg(RIODesc *desc) {
286 if (desc && desc->plugin) {
287 return desc->plugin->isdbg;
288 }
289 return false;
290 }
291
r_io_desc_get_pid(RIODesc * desc)292 R_API int r_io_desc_get_pid(RIODesc *desc) {
293 //-1 and -2 are reserved
294 if (!desc) {
295 return -3;
296 }
297 if (!desc->plugin) {
298 return -4;
299 }
300 if (!desc->plugin->isdbg) {
301 return -5;
302 }
303 if (!desc->plugin->getpid) {
304 return -6;
305 }
306 return desc->plugin->getpid (desc);
307 }
308
r_io_desc_get_tid(RIODesc * desc)309 R_API int r_io_desc_get_tid(RIODesc *desc) {
310 //-1 and -2 are reserved
311 if (!desc) {
312 return -3;
313 }
314 if (!desc->plugin) {
315 return -4;
316 }
317 if (!desc->plugin->isdbg) {
318 return -5;
319 }
320 if (!desc->plugin->gettid) {
321 return -6;
322 }
323 return desc->plugin->gettid (desc);
324 }
325
r_io_desc_get_base(RIODesc * desc,ut64 * base)326 R_API bool r_io_desc_get_base (RIODesc *desc, ut64 *base) {
327 if (!base || !desc || !desc->plugin || !desc->plugin->isdbg || !desc->plugin->getbase) {
328 return false;
329 }
330 return desc->plugin->getbase (desc, base);
331 }
332
r_io_desc_read_at(RIODesc * desc,ut64 addr,ut8 * buf,int len)333 R_API int r_io_desc_read_at(RIODesc *desc, ut64 addr, ut8 *buf, int len) {
334 if (desc && buf && (r_io_desc_seek (desc, addr, R_IO_SEEK_SET) == addr)) {
335 return r_io_desc_read (desc, buf, len);
336 }
337 return 0;
338 }
339
r_io_desc_write_at(RIODesc * desc,ut64 addr,const ut8 * buf,int len)340 R_API int r_io_desc_write_at(RIODesc *desc, ut64 addr, const ut8 *buf, int len) {
341 if (desc && buf && (r_io_desc_seek (desc, addr, R_IO_SEEK_SET) == addr)) {
342 return r_io_desc_write (desc, buf, len);
343 }
344 return 0;
345 }
346
r_io_desc_extend(RIODesc * desc,ut64 size)347 R_API int r_io_desc_extend(RIODesc *desc, ut64 size) {
348 if (desc && desc->plugin && desc->plugin->extend) {
349 return desc->plugin->extend (desc->io, desc, size);
350 }
351 return 0;
352 }
353
354 /* lifecycle */
355
356 // TODO: move into io.c : r_io_init
r_io_desc_init(RIO * io)357 R_IPI bool r_io_desc_init(RIO* io) {
358 r_return_val_if_fail (io, false);
359 r_io_desc_fini (io);
360 // TODO: it leaks if called twice
361 //fd is signed
362 io->files = r_id_storage_new (3, 0x80000000);
363 if (!io->files) {
364 return false;
365 }
366 return true;
367 }
368
desc_fini_cb(void * user,void * data,ut32 id)369 static bool desc_fini_cb(void* user, void* data, ut32 id) {
370 RIODesc* desc = (RIODesc*) data;
371 if (desc->plugin && desc->plugin->close) {
372 desc->plugin->close (desc);
373 }
374 r_io_desc_free (desc);
375 return true;
376 }
377
378 //closes all descs and frees all descs and io->files
r_io_desc_fini(RIO * io)379 R_IPI bool r_io_desc_fini(RIO* io) {
380 r_return_val_if_fail (io, NULL);
381 if (io->files) {
382 r_id_storage_foreach (io->files, desc_fini_cb, io);
383 r_id_storage_free (io->files);
384 io->files = NULL;
385 }
386 //no map-cleanup here, to keep it modular useable
387 io->desc = NULL;
388 return true;
389 }
390