1 /* radare - LGPL - Copyright 2009-2020 - ret2libc */
2 
3 #include <r_util.h>
4 
5 struct buf_sparse_priv {
6 	RList *sparse;
7 	ut64 offset;
8 };
9 
buffer_sparse_free(void * a)10 static void buffer_sparse_free(void *a) {
11 	RBufferSparse *s = (RBufferSparse *)a;
12 	free (s->data);
13 	free (s);
14 }
15 
sparse_limits(RList * l,ut64 * max)16 static bool sparse_limits(RList *l, ut64 *max) {
17 	bool set = false;
18 	RBufferSparse *s;
19 	RListIter *iter;
20 
21 	r_list_foreach (l, iter, s) {
22 		if (set) {
23 			if (max && s->to > *max) {
24 				*max = s->to;
25 			}
26 		} else {
27 			set = true;
28 			if (max) {
29 				*max = s->to;
30 			}
31 		}
32 	}
33 	return set;
34 }
35 
sparse_append(RList * l,ut64 addr,const ut8 * data,ut64 len)36 static RBufferSparse *sparse_append(RList *l, ut64 addr, const ut8 *data, ut64 len) {
37 	if (l && data) {
38 		RBufferSparse *s = R_NEW0 (RBufferSparse);
39 		if (s) {
40 			s->data = calloc (1, len);
41 			if (s->data) {
42 				s->from = addr;
43 				s->to = addr + len;
44 				s->size = len;
45 				memcpy (s->data, data, len);
46 				return r_list_append (l, s)? s: NULL;
47 			}
48 			free (s);
49 		}
50 	}
51 	return NULL;
52 }
53 
54 //ret -1 if failed; # of bytes copied if success
sparse_write(RList * l,ut64 addr,const ut8 * data,ut64 len)55 static st64 sparse_write(RList *l, ut64 addr, const ut8 *data, ut64 len) {
56 	RBufferSparse *s;
57 	RListIter *iter;
58 	ut64 olen = len;
59 
60 	r_list_foreach (l, iter, s) {
61 		if (addr >= s->from && addr < s->to) {
62 			ut64 delta = addr - s->from;
63 			ut64 reallen = s->size - delta >= len? len: s->size - delta;
64 			memcpy (s->data + delta, data, reallen);
65 			data += reallen;
66 			len -= reallen;
67 			addr += reallen;
68 		}
69 		if (len == 0) {
70 			return olen;
71 		}
72 	}
73 	if (len > 0 && !sparse_append (l, addr, data, len)) {
74 		return -1;
75 	}
76 	return olen;
77 }
78 
get_priv_sparse(RBuffer * b)79 static inline struct buf_sparse_priv *get_priv_sparse(RBuffer *b) {
80 	struct buf_sparse_priv *priv = (struct buf_sparse_priv *)b->priv;
81 	r_warn_if_fail (priv);
82 	return priv;
83 }
84 
buf_sparse_init(RBuffer * b,const void * user)85 static bool buf_sparse_init(RBuffer *b, const void *user) {
86 	struct buf_sparse_priv *priv = R_NEW0 (struct buf_sparse_priv);
87 	if (!priv) {
88 		return false;
89 	}
90 	priv->sparse = r_list_newf (buffer_sparse_free);
91 	priv->offset = 0;
92 	b->priv = priv;
93 	return true;
94 }
95 
buf_sparse_fini(RBuffer * b)96 static bool buf_sparse_fini(RBuffer *b) {
97 	struct buf_sparse_priv *priv = get_priv_sparse (b);
98 	r_list_free (priv->sparse);
99 	R_FREE (b->priv);
100 	return true;
101 }
102 
buf_sparse_resize(RBuffer * b,ut64 newsize)103 static bool buf_sparse_resize(RBuffer *b, ut64 newsize) {
104 	struct buf_sparse_priv *priv = get_priv_sparse (b);
105 	RListIter *iter, *tmp;
106 	RBufferSparse *s;
107 
108 	r_list_foreach_safe (priv->sparse, iter, tmp, s) {
109 		if (s->from >= newsize) {
110 			r_list_delete (priv->sparse, iter);
111 		} else if (s->to >= newsize) {
112 			RBufferSparse *ns = R_NEW (RBufferSparse);
113 			ns->from = s->from;
114 			ns->to = newsize;
115 			ns->size = ns->to - ns->from;
116 			ut8 *tmp = realloc (s->data, s->size);
117 			if (!tmp) {
118 				free (ns);
119 				return false;
120 			}
121 			// otherwise it will be double-freed by r_list_delete
122 			s->data = NULL;
123 			ns->data = tmp;
124 			ns->written = s->written;
125 			r_list_append (priv->sparse, ns);
126 			r_list_delete (priv->sparse, iter);
127 		}
128 	}
129 	ut64 max;
130 	max = sparse_limits (priv->sparse, &max)? max: 0;
131 	if (max < newsize) {
132 		return !!sparse_write (priv->sparse, newsize - 1, &b->Oxff_priv, 1);
133 	}
134 	return true;
135 }
136 
buf_sparse_size(RBuffer * b)137 static ut64 buf_sparse_size(RBuffer *b) {
138 	struct buf_sparse_priv *priv = get_priv_sparse (b);
139 	ut64 max;
140 
141 	return sparse_limits (priv->sparse, &max)? max: 0;
142 }
143 
buf_sparse_read(RBuffer * b,ut8 * buf,ut64 len)144 static st64 buf_sparse_read(RBuffer *b, ut8 *buf, ut64 len) {
145 	struct buf_sparse_priv *priv = get_priv_sparse (b);
146 	RBufferSparse *c;
147 	RListIter *iter;
148 	ut64 max = 0;
149 
150 	memset (buf, b->Oxff_priv, len);
151 	r_list_foreach (priv->sparse, iter, c) {
152 		if (max < c->to) {
153 			max = c->to;
154 		}
155 		if (priv->offset < c->to && c->from < priv->offset + len) {
156 			if (priv->offset < c->from) {
157 				ut64 l = R_MIN (priv->offset + len - c->from, c->size);
158 				memcpy (buf + c->from - priv->offset, c->data, l);
159 			} else {
160 				ut64 l = R_MIN (c->to - priv->offset, len);
161 				memcpy (buf, c->data + priv->offset - c->from, l);
162 			}
163 		}
164 	}
165 	if (priv->offset > max) {
166 		return -1;
167 	}
168 	ut64 r = R_MIN (max - priv->offset, len);
169 	priv->offset += r;
170 	return r;
171 }
172 
buf_sparse_write(RBuffer * b,const ut8 * buf,ut64 len)173 static st64 buf_sparse_write(RBuffer *b, const ut8 *buf, ut64 len) {
174 	struct buf_sparse_priv *priv = get_priv_sparse (b);
175 	st64 r = sparse_write (priv->sparse, priv->offset, buf, len);
176 	priv->offset += r;
177 	return r;
178 }
179 
buf_sparse_seek(RBuffer * b,st64 addr,int whence)180 static st64 buf_sparse_seek(RBuffer *b, st64 addr, int whence) {
181 	struct buf_sparse_priv *priv = get_priv_sparse (b);
182 	ut64 max;
183 	if (addr < 0 && (-addr) > (st64)priv->offset) {
184 		return -1;
185 	}
186 
187 	switch (whence) {
188 	case R_BUF_CUR:
189 		priv->offset += addr;
190 		break;
191 	case R_BUF_SET:
192 		priv->offset = addr;
193 		break;
194 	case R_BUF_END:
195 		if (!sparse_limits (priv->sparse, &max)) {
196 			max = 0;
197 		}
198 		priv->offset = max + addr;
199 		break;
200 	default:
201 		r_warn_if_reached ();
202 		return -1;
203 	}
204 	return priv->offset;
205 }
206 
buf_sparse_nonempty_list(RBuffer * b)207 static RList *buf_sparse_nonempty_list(RBuffer *b) {
208 	struct buf_sparse_priv *priv = get_priv_sparse (b);
209 	return r_list_clone (priv->sparse);
210 }
211 
212 static const RBufferMethods buffer_sparse_methods = {
213 	.init = buf_sparse_init,
214 	.fini = buf_sparse_fini,
215 	.read = buf_sparse_read,
216 	.write = buf_sparse_write,
217 	.get_size = buf_sparse_size,
218 	.resize = buf_sparse_resize,
219 	.seek = buf_sparse_seek,
220 	.nonempty_list = buf_sparse_nonempty_list,
221 };
222