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