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