blob: fd34d851c19d8595a775b9d0e48c7dc69a77235e [file] [log] [blame]
Uwe Hermann7eb845e2008-11-02 17:01:06 +00001/*
2 * This file is part of the bayou project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Uwe Hermann7eb845e2008-11-02 17:01:06 +000018 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <sys/stat.h>
26#include <sys/mman.h>
27#include <arpa/inet.h>
28
29#include "liblar.h"
30#include "self.h"
31
32static int lar_compress(struct LAR *lar, int algo, char *src, char *dst,
33 int len)
34{
35 int ret;
36
37 if (!lar->cfuncs[algo])
38 return -1;
39
40 lar->cfuncs[algo] (src, len, dst, &ret);
41 return ret;
42}
43
44static int lar_decompress(struct LAR *lar, int algo, char *src, char *dst,
45 int slen, int dlen)
46{
47 if (!lar->dfuncs[algo])
48 return -1;
49
50 lar->dfuncs[algo] (src, slen, dst, dlen);
51 return dlen;
52}
53
54static struct LARHeader *lar_get_header(struct LAR *lar, const char *filename)
55{
56 char *buffer;
57 int offset = 0;
58 struct LARHeader *lheader = NULL;
59 struct lar_header *header;
60
61 printf("Getting %s\n", filename);
62
63 buffer = malloc(sizeof(struct lar_header) + MAX_PATHLEN);
64
65 if (buffer == NULL)
66 return NULL;
67
68 while (1) {
69 int ret;
70
71 if (lseek(lar->fd, offset, SEEK_SET) == -1)
72 goto err;
73
74 ret = read(lar->fd, buffer, sizeof(struct lar_header));
75
76 if (ret <= 0)
77 goto err;
78
79 header = (struct lar_header *)buffer;
80
81 if (strncmp(header->magic, MAGIC, sizeof(MAGIC)))
82 goto err;
83
84 ret = read(lar->fd, buffer + sizeof(struct lar_header),
85 ntohl(header->offset) - sizeof(struct lar_header));
86
87 if (ret <= 0)
88 goto err;
89
90 if (!strcmp(buffer + sizeof(struct lar_header), filename))
91 break;
92
93 offset += ntohl(header->offset) +
94 ((ntohl(header->len) + 15) & ~0xF);
95 }
96
97 lheader = calloc(sizeof(struct LARHeader), 1);
98
99 if (lheader == NULL)
100 goto err;
101
102 lheader->hoffset = offset;
103 lheader->offset = offset + ntohl(header->offset);
104
105 lheader->reallen = ntohl(header->reallen);
106 lheader->len = ntohl(header->len);
107
108 lheader->loadaddress = ntohl(header->loadaddress);
109 lheader->compression = ntohl(header->compression);
110 lheader->entry = ntohl(header->entry);
111 lheader->checksum = ntohl(header->checksum);
112
113err:
114 free(buffer);
115 return lheader;
116}
117
118static int LAR_AppendBlob(struct LAR *lar, unsigned char *buffer,
119 int len, int rlen, struct LARAttr *attr)
120{
121 int nlen, nsize, lsize, i;
122 struct lar_header *header;
123 u8 *lptr;
124 u32 csum = 0;
125
126 if (attr == NULL)
127 return -1;
128
129 nlen = strlen(attr->name) + 1;
130
131 if (nlen > MAX_PATHLEN - 1)
132 nlen = MAX_PATHLEN - 1;
133
134 nsize = (nlen + 15) & ~0xF;
135
136 lsize = sizeof(struct lar_header) + nsize + len;
137 lptr = calloc(lsize + 1, 1);
138
139 if (lptr == NULL)
140 return -1;
141
142 header = (struct lar_header *)lptr;
143
144 memcpy(header->magic, MAGIC, 8);
145 header->reallen = htonl(rlen);
146 header->len = htonl(len);
147 header->offset = htonl(lsize - len);
148 header->loadaddress = htonl(attr->loadaddr);
149 header->compression = htonl(attr->compression);
150 header->entry = htonl(attr->entry);
151
152 strncpy(((char *)header) + sizeof(struct lar_header), attr->name, nlen);
153
154 for (i = 0; i < sizeof(struct lar_header) + nsize; i += 4)
155 csum += *((u32 *) (lptr + i));
156
157 for (i = 0; i < len; i += 4) {
158 /*
159 * The checksum needs to include the 16 byte padding at
160 * the end of the data before the next lar header. The
161 * problem is that the padding isn't going to be in the
162 * buffer, and if we try to read off the end of the buffer,
163 * we are just asking for trouble. So account for the
164 * situation where the datalen is not a multiple of four
165 * and get a safe value to add into the checksum.
166 * The rest of the padding will be zero, and can be safely
167 * ignored here.
168 */
169 if ((len - i) < 4) {
170 u32 val = 0;
171 int t;
172
173 for (t = 0; t < (len - i); t++)
174 val |= *((u8 *) buffer + (i + t)) << (t * 8);
175 csum += val;
176 } else
177 csum += *((u32 *) (buffer + i));
178 }
179
180 header->checksum = (u32) (~0 - csum);
181
182 lseek(lar->fd, 0, SEEK_END);
183
184 /* FIXME: Error check here. */
185
186 write(lar->fd, header, sizeof(struct lar_header) + nsize);
187 write(lar->fd, buffer, len);
188
189 /* Add in padding to the next 16 byte boundary. */
190 if (lsize & 0xF) {
191 int i;
192 char null = '\0';
193
194 for (i = lsize & 0xF; i < 0x10; i++)
195 write(lar->fd, &null, 1);
196 }
197
198 return 0;
199}
200
201int LAR_AppendBuffer(struct LAR *lar, unsigned char *buffer, int len,
202 struct LARAttr *attr)
203{
204 unsigned char *tbuf;
205 int rlen, ret = -1;
206
207 if (attr->compression == ALGO_NONE)
208 return LAR_AppendBlob(lar, buffer, len, len, attr);
209
210 tbuf = malloc(len);
211
212 if (tbuf == NULL)
213 return -1;
214
215 rlen = lar_compress(lar, attr->compression, (char *)buffer,
216 (char *)tbuf, len);
217
218 if (rlen > 0)
219 ret = LAR_AppendBlob(lar, tbuf, rlen, len, attr);
220
221 free(tbuf);
222 return ret;
223}
224
225int LAR_AppendSelf(struct LAR *lar, const char *filename, struct LARAttr *attr)
226{
227 unsigned char *buffer;
228 int len = elf_to_self(filename, &buffer,
229 lar->cfuncs[attr->compression]);
230 int ret;
231
232 if (len == -1)
233 return -1;
234
235 ret = LAR_AppendBlob(lar, buffer, len, len, attr);
236 free(buffer);
237
238 return ret;
239}
240
241int LAR_AppendFile(struct LAR *lar, const char *filename, struct LARAttr *attr)
242{
243 int fd;
244 struct stat s;
245 char *filep;
246 int ret;
247
248 if (iself((char *)filename))
249 return LAR_AppendSelf(lar, filename, attr);
250
251 fd = open(filename, O_RDONLY);
252
253 if (fd == -1)
254 return -1;
255
256 if (fstat(fd, &s))
257 return -1;
258
259 filep = (char *)mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
260
261 if (filep == MAP_FAILED)
262 return -1;
263
264 ret = LAR_AppendBuffer(lar, (unsigned char *)filep, s.st_size, attr);
265
266 munmap(filep, s.st_size);
267 return ret;
268}
269
270int LAR_DeleteFile(struct LAR *lar, const char *filename)
271{
272 struct LARHeader *header = lar_get_header(lar, filename);
273 int len, ret = -1;
274 char *filep, *buffer;
275
276 if (header == NULL)
277 return -1;
278
279 buffer = malloc(4096);
280 if (buffer == NULL)
281 return -1;
282
283 len = header->offset + header->len;
284
285 /* First, map the space and zero it out. */
286
287 filep = (char *)mmap(0, len, PROT_READ, MAP_SHARED, lar->fd,
288 header->hoffset);
289
290 if (filep == MAP_FAILED)
291 return -1;
292
293 memset(filep, 0, len);
294 munmap(filep, len);
295
296 /* Now move the rest of the LAR into place. */
297 /* FIXME: This does not account for the bootblock! */
298
299 int dst = header->hoffset;
300 int src = header->hoffset + len;
301
302 while (1) {
303 int l, w;
304
305 if (lseek(lar->fd, src, SEEK_SET))
306 goto err;
307
308 l = read(lar->fd, buffer, 8192);
309
310 if (l == -1)
311 goto err;
312 if (l == 0)
313 goto err;
314 if (lseek(lar->fd, dst, SEEK_SET))
315 goto err;
316
317 w = write(lar->fd, buffer, l);
318
319 if (w <= 0)
320 goto err;
321
322 dst += w;
323 src += w;
324 }
325
326 ret = 0;
327
328err:
329 free(buffer);
330 return ret;
331}
332
333void LAR_CloseFile(struct LARFile *file)
334{
335 if (file != NULL) {
336 if (file->buffer != NULL)
337 free(file->buffer);
338 free(file);
339 }
340}
341
342struct LARFile *LAR_MapFile(struct LAR *lar, const char *filename)
343{
344 struct LARFile *file;
345 struct LARHeader *header = lar_get_header(lar, filename);
346 char *filep;
347 int ret;
348
349 if (header == NULL)
350 return NULL;
351
352 file = calloc(sizeof(struct LARFile), 1);
353
354 if (file == NULL)
355 return NULL;
356
357 file->len = header->reallen;
358 file->buffer = calloc(header->reallen, 1);
359
360 if (file->buffer == NULL)
361 goto err;
362
363 /*
364 * The offset needs to be a multiple of PAGE_SIZE, so just mmap
365 * from offset 0, its easier then doing the math.
366 */
367
368 filep = mmap(0, header->offset + header->len,
369 PROT_READ, MAP_SHARED, lar->fd, 0);
370
371 if (filep == MAP_FAILED) {
372 printf("Map failed: %m\n");
373 goto err;
374 }
375
376 if (header->compression != ALGO_NONE) {
377 ret = lar_decompress(lar, header->compression,
378 filep + header->offset, file->buffer,
379 header->len, header->reallen);
380 } else {
381 memcpy(file->buffer, filep + header->offset, header->len);
382 ret = header->len;
383 }
384
385 munmap(filep, header->offset + header->len);
386
387 if (ret == header->reallen)
388 return file;
389
390err:
391 if (file->buffer)
392 free(file->buffer);
393
394 free(file);
395 return NULL;
396}
397
398int LAR_SetCompressionFuncs(struct LAR *lar, int algo,
399 LAR_CompFunc cfunc, LAR_DecompFunc dfunc)
400{
401
402 if (algo >= ALGO_INVALID)
403 return -1;
404
405 lar->cfuncs[algo] = cfunc;
406 lar->dfuncs[algo] = dfunc;
407
408 return 0;
409}
410
411void LAR_Close(struct LAR *lar)
412{
413 if (lar != NULL) {
414 if (lar->fd)
415 close(lar->fd);
416
417 free(lar);
418 }
419}
420
421struct LAR *LAR_Open(const char *filename)
422{
423 struct LAR *lar = calloc(sizeof(struct LAR), 1);
424
425 if (lar == NULL)
426 return NULL;
427
428 lar->fd = open(filename, O_RDWR);
429
430 if (lar->fd > 0)
431 return lar;
432
433 free(lar);
434 return NULL;
435}
436
437struct LAR *LAR_Create(const char *filename)
438{
439 struct LAR *lar = calloc(sizeof(struct LAR), 1);
440
441 if (lar == NULL)
442 return NULL;
443
444 lar->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
445
446 if (lar->fd > 0)
447 return lar;
448
449 free(lar);
450 return NULL;
451}
452
453void LAR_SetAttrs(struct LARAttr *attrs, char *name, int algo)
454{
455 if (attrs == NULL)
456 return;
457
458 memset(attrs, 0, sizeof(*attrs));
459 snprintf(attrs->name, sizeof(attrs->name) - 1, name);
460 attrs->compression = algo;
461}