1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#include <libpayload.h>
31#include <arch/endian.h>
32
33#define ROM_RESET_VECTOR 0xFFFFFFF0
34
35static void * next_header(void * cur)
36{
37 struct lar_header *header = (struct lar_header *) cur;
38 int offset = ((ntohl(header->offset) + ntohl(header->len)) + 15) &
39 0xFFFFFFF0;
40
41 return (void *) (cur + offset);
42}
43
44static struct lar_header *lar_get_header(struct LAR *lar, int index)
45{
46 int i;
47
48 if (index < lar->count)
49 return (struct lar_header *) lar->headers[index];
50
51 if (lar->eof && index >= lar->eof)
52 return NULL;
53
54 for(i = lar->count; i <= index; i++) {
55 void *next = (i == 0) ?
56 lar->start : next_header(lar->headers[i - 1]);
57
58 if (strncmp((const char *) next, LAR_MAGIC, 8)) {
59 lar->eof = lar->count;
60 return NULL;
61 }
62
63 if (lar->count == lar->alloc) {
64 void *tmp = realloc(lar->headers,
65 (lar->alloc + 16) * sizeof(void *));
66
67 if (tmp == NULL)
68 return NULL;
69
70 lar->headers = tmp;
71 lar->alloc += 16;
72 }
73
74 lar->headers[lar->count++] = next;
75 }
76
77 return (struct lar_header *) lar->headers[index];
78}
79
80
81
82
83
84
85
86
87
88
89struct LAR *openlar(void *addr)
90{
91 struct LAR *lar;
92
93
94
95
96 if (addr == NULL) {
97 u32 size = *((u32 *) (ROM_RESET_VECTOR + 4));
98 addr = (void *) ((ROM_RESET_VECTOR + 16) - size);
99 }
100
101
102 if (strncmp((const char *) addr, LAR_MAGIC, strlen(LAR_MAGIC)))
103 return NULL;
104
105 lar = calloc(sizeof(struct LAR), 1);
106
107 if (!lar)
108 return NULL;
109
110 lar->start = addr;
111
112
113
114
115 lar->headers = malloc(16 * sizeof(void *));
116
117 if (!lar->headers)
118 return NULL;
119
120 lar->alloc = 16;
121 lar->count = lar->eof = 0;
122 lar->cindex = 0;
123
124 return lar;
125}
126
127
128
129
130
131
132
133
134int closelar(struct LAR *lar)
135{
136 if (!lar)
137 return 0;
138
139 if (lar->headers)
140 free(lar->headers);
141
142 free(lar);
143
144 return 0;
145}
146
147
148
149
150
151
152
153
154
155struct larent *readlar(struct LAR *lar)
156{
157 static struct larent _larent;
158 struct lar_header *header;
159 int nlen;
160
161 if (!lar)
162 return NULL;
163
164 header = lar_get_header(lar, lar->cindex);
165
166 if (header == NULL)
167 return NULL;
168
169 nlen = ntohl(header->offset) - sizeof(*header);
170
171 if (nlen > LAR_MAX_PATHLEN - 1)
172 nlen = LAR_MAX_PATHLEN - 1;
173
174 memcpy((void *) _larent.name, ((char *) header + sizeof(*header)),
175 nlen);
176
177 _larent.name[nlen] = 0;
178
179 lar->cindex++;
180
181 return (struct larent *) &_larent;
182}
183
184void rewindlar(struct LAR *lar)
185{
186 if (lar != NULL)
187 lar->cindex = 0;
188}
189
190static struct lar_header *get_header_by_name(struct LAR *lar, const char *name)
191{
192 struct lar_header *header;
193 int i;
194
195 for(i = 0; ; i++) {
196 header = lar_get_header(lar, i);
197
198 if (header == NULL)
199 return NULL;
200
201 if (!strcmp(name, ((char *) header + sizeof(*header))))
202 return header;
203 }
204}
205
206int larstat(struct LAR *lar, const char *path, struct larstat *buf)
207{
208 struct lar_header *header = get_header_by_name(lar, path);
209
210 if (header == NULL || buf == NULL)
211 return -1;
212
213 buf->len = ntohl(header->len);
214 buf->reallen = ntohl(header->reallen);
215 buf->checksum = ntohl(header->checksum);
216 buf->compchecksum = ntohl(header->compchecksum);
217 buf->compression = ntohl(header->compression);
218 buf->entry = ntohll(header->entry);
219 buf->loadaddress = ntohll(header->loadaddress);
220 buf->offset = ((u32) header - (u32) lar->start) + ntohl(header->offset);
221
222 return 0;
223}
224
225void * larfptr(struct LAR *lar, const char *filename)
226{
227 struct lar_header *header = get_header_by_name(lar, filename);
228
229 if (header == NULL)
230 return NULL;
231
232 return (void *) ((u8 *) header + ntohl(header->offset));
233}
234
235
236
237
238
239
240
241
242
243
244int lfverify(struct LAR *lar, const char *filename)
245{
246 struct lar_header *header = get_header_by_name(lar, filename);
247
248 u8 *ptr = (u8 *) header;
249 int len = ntohl(header->len) + ntohl(header->offset);
250 int offset;
251 u32 csum = 0;
252
253 if (header == NULL)
254 return -1;
255
256
257
258
259
260
261 len = (len + 15) & 0xFFFFFFF0;
262
263 for(offset = 0; offset < len; offset += 4) {
264 csum += *((u32 *) (ptr + offset));
265 }
266
267 return (csum == 0xFFFFFFFF) ? 1 : 0;
268}
269
270struct LFILE * lfopen(struct LAR *lar, const char *filename)
271{
272 struct LFILE *file;
273 struct lar_header *header = get_header_by_name(lar, filename);
274
275 if (header == NULL)
276 return NULL;
277
278
279
280 file = malloc(sizeof(struct LFILE));
281
282 if (file == NULL)
283 return NULL;
284
285 file->lar = lar;
286 file->header = header;
287 file->size = ntohl(header->len);
288 file->start = ((u8 *) header + ntohl(header->offset));
289 file->offset = 0;
290
291 return file;
292}
293
294void *lfmap(struct LFILE *file, int offset)
295{
296 if (file == NULL)
297 return (void *) -1;
298
299 if (offset > file->size)
300 return (void *) -1;
301
302 return (void *) (file->start + offset);
303};
304
305int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream)
306{
307 size_t tsize, actual;
308 size_t remain = stream->size - stream->offset;
309
310 if (!stream || !remain)
311 return 0;
312
313 tsize = (size * nmemb);
314 actual = (tsize > remain) ? remain : tsize;
315
316 memcpy(ptr, (void *) (stream->start + stream->offset), actual);
317 stream->offset += actual;
318
319 return actual;
320}
321
322int lfseek(struct LFILE *file, long offset, int whence)
323{
324 int o = file->offset;
325
326 switch(whence) {
327 case SEEK_SET:
328 o = offset;
329 break;
330 case SEEK_CUR:
331 o += offset;
332 break;
333
334 case SEEK_END:
335 return -1;
336 }
337
338 if (o < 0 || o > file->size)
339 return -1;
340
341 file->offset = o;
342 return file->offset;
343}
344
345int lfclose(struct LFILE *file)
346{
347 if (file)
348 free(file);
349 return 0;
350}
351