1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
16 #include <sys/types.h>
23 #include <createcrc.h>
25 #define FFS_TARGET_HEADER_SIZE (4 * 8)
29 #define pad8_num(x) (((x) + 7) & ~7)
32 file_exist(const char *name, int errdisp)
36 memset((void *) &fileinfo, 0, sizeof(struct stat));
37 if (stat(name, &fileinfo) != 0) {
43 if (S_ISREG(fileinfo.st_mode)) {
50 file_getsize(const char *name)
62 ffshdr_compare(const void *_a, const void *_b)
64 const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a;
65 const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b;
67 if (a->romaddr == b->romaddr)
69 if (a->romaddr > b->romaddr)
75 hdr_print(struct ffs_header_t *hdr)
77 printf("hdr: %p\n", hdr);
78 printf("\taddr: %08llx token: %s\n"
79 "\tflags: %08llx romaddr: %08llx image_len: %08x\n"
80 "\tsave_len: %08llx ffsize: %08x hdrsize: %08x\n"
81 "\ttokensize: %08x\n",
82 hdr->addr, hdr->token, hdr->flags, hdr->romaddr,
83 hdr->imagefile_length, hdr->save_data_len,
84 hdr->ffsize, hdr->hdrsize, hdr->tokensize);
88 reorder_ffs_chain(struct ffs_chain_t *fs)
92 unsigned long long addr;
93 struct ffs_header_t *hdr;
94 int fix, flx, res, tab_size = fs->count;
95 struct ffs_header_t *fix_tab[tab_size]; /* fixed offset */
96 struct ffs_header_t *flx_tab[tab_size]; /* flexible offset */
97 struct ffs_header_t *res_tab[tab_size]; /* result */
99 /* determine size data to be able to do the reordering */
100 for (hdr = fs->first; hdr; hdr = hdr->next) {
102 hdr->imagefile_length = 0;
104 hdr->imagefile_length = file_getsize(hdr->imagefile);
105 if (hdr->imagefile_length == -1)
108 hdr->tokensize = pad8_num(strlen(hdr->token) + 1);
109 hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize;
111 hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8;
114 memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *));
115 memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *));
116 memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *));
118 /* now start with entries having fixed offs, reorder if needed */
119 for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next)
120 if (needs_fix_offset(hdr))
121 fix_tab[fix++] = hdr;
123 flx_tab[flx++] = hdr;
124 qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare);
127 * for fixed files we need to also remove the hdrsize from the
128 * free space because it placed in front of the romaddr
130 for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) {
131 fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize;
132 free_space = fix_tab[i]->addr - addr;
134 /* insert as many flexible files as possible */
135 for (; free_space > 0 && j < flx; j++) {
136 if (flx_tab[j]->ffsize <= free_space) { /* fits */
137 flx_tab[j]->addr = addr;
138 free_space -= flx_tab[j]->ffsize;
139 addr += flx_tab[j]->ffsize;
140 res_tab[res++] = flx_tab[j];
144 res_tab[res++] = fix_tab[i];
145 addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize -
148 /* at the end fill up the table with remaining flx entries */
149 for (; j < flx; j++) {
150 flx_tab[j]->addr = addr;
151 addr += flx_tab[j]->ffsize;
152 res_tab[res++] = flx_tab[j];
156 printf("--- resulting order ---\n");
157 for (i = 0; i < tab_size; i++)
158 hdr_print(res_tab[i]);
161 /* to check if the requested romfs images is greater than
162 * the specified romfs_size it is necessary to add 8 for
163 * the CRC to the totalsize */
166 /* sanity checking if user specified maximum romfs size */
167 if ((fs->romfs_size != 0) && addr > fs->romfs_size) {
168 fprintf(stderr, "[build_romfs] romfs_size specified as %d "
169 "bytes, but %lld bytes need to be written.\n",
170 fs->romfs_size, addr);
174 /* resort result list */
175 for (i = 0; i < tab_size - 1; i++)
176 res_tab[i]->next = res_tab[i + 1];
177 res_tab[i]->next = NULL;
178 fs->first = res_tab[0];
183 * allocate memory for a romfs file including header
185 static unsigned char *
186 malloc_file(int hdrsz, int datasz, int *ffsz)
190 /* complete file size is:
191 * header + 8byte aligned(data) + end of file marker (-1) */
192 *ffsz = hdrsz + pad8_num(datasz) + 8;
199 memset(tmp, 0, *ffsz);
201 return (unsigned char *) tmp;
205 copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize,
206 int ffile_offset, int ffsize)
212 if (!file_exist(hdr->imagefile, 1)) {
213 printf("access error to file: %s\n", hdr->imagefile);
218 imgfd = open(hdr->imagefile, O_RDONLY);
220 perror(hdr->imagefile);
225 /* now copy file to file buffer */
226 /* FIXME using fread might be a good idea so
227 that we do not need to deal with shortened
228 reads/writes. Also error handling looks
229 broken to me. Are we sure that all data is
230 read when exiting this loop? */
232 i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset);
240 if (cnt != datasize) {
241 printf("BUG!!! copy error on image file [%s](e%d, g%d)\n",
242 hdr->imagefile, datasize, cnt);
254 next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize)
258 /* no next file; end of filesystem */
259 if (hdr->next == NULL)
262 if (hdr->next->romaddr > 0) {
263 /* the next file does not follow directly after the
264 * current file because it requested to be
265 * placed at a special address;
266 * we need to calculate the offset of the
268 * the next file starts at hdr->next->romaddr which
269 * is the address requested by the user */
270 tmp = hdr->next->romaddr;
271 /* the next file starts, however, a bit earlier;
272 * we need to point at the header of the next file;
273 * therefore it is necessary to subtract the header size
274 * of the _next_ file */
275 tmp -= FFS_TARGET_HEADER_SIZE;
276 /* also remove the length of the filename of the _next_
278 tmp -= pad8_num(strlen(hdr->next->token) + 1);
279 /* and it needs to be relative to the current file */
284 /* if no special treatment is required the next file just
285 * follows after the current file;
286 * therefore just return the complete filesize as offset */
291 next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize,
292 unsigned int num_files)
294 /* check if file wants a specific address */
297 if ((hdr->flags & FLAG_LLFW) == 0)
298 /* flag to get a specific address has been set */
301 if (hdr->romaddr == 0)
302 /* if the requested address is 0 then
303 * something is not right; ignore the flag */
306 /* check if romaddress is below current position */
307 if (hdr->romaddr < (rom_pos + hdrsize)) {
308 printf("[%s] ERROR: requested impossible " "romaddr of %llx\n",
309 hdr->token, hdr->romaddr);
313 /* spin offset to new position */
314 if (pad8_num(hdr->romaddr) != hdr->romaddr) {
315 printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n");
319 tmp = malloc(hdr->romaddr - rom_pos - hdrsize);
324 memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize);
325 if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) {
327 printf("write failed\n");
334 printf("\nWARNING: The filesystem will have no entry header!\n"
335 " It is still usable but you need to find\n"
336 " the FS by yourself in the image.\n\n");
338 return hdr->romaddr - hdrsize;
342 build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime)
345 int ffsize, datasize, i;
346 int tokensize, hdrsize, ffile_offset, hdrbegin;
347 struct ffs_header_t *hdr;
348 unsigned char *ffile;
349 unsigned int rom_pos = 0;
350 unsigned int num_files = 0;
353 if (NULL == fs->first) {
358 /* check output file and open it for creation */
359 if (file_exist(outfile, 0)) {
360 printf("Output file (%s) will be overwritten\n", outfile);
365 if (hdr->linked_to) {
366 printf("\nBUG!!! links not supported anymore\n");
370 /* add +1 to strlen for zero termination */
371 tokensize = pad8_num(strlen(hdr->token) + 1);
372 hdrsize = FFS_TARGET_HEADER_SIZE + tokensize;
373 datasize = file_getsize(hdr->imagefile);
375 if (datasize == -1) {
376 perror(hdr->imagefile);
381 ffile = malloc_file(hdrsize, datasize, &ffsize);
384 perror("alloc mem for ffile");
388 /* check if file wants a specific address */
389 rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files);
392 if (hdrbegin == -1) {
393 /* something went wrong */
398 /* write header ******************************************* */
399 /* next addr ********************************************** */
400 tmp = next_file_offset(hdr, rom_pos, ffsize);
402 *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
406 /* length ************************************************* */
407 hdr->save_data_len = datasize;
409 *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize);
413 /* flags ************************************************** */
414 *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags);
418 /* datapointer ******************************************** */
420 //save-data pointer is relative to rombase
421 hdr->save_data = hdrbegin + hdrsize;
422 hdr->save_data_valid = 1;
423 //changed pointers to be relative to file:
424 tmp = hdr->save_data - hdrbegin;
426 *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
430 /* name (token) ******************************************* */
431 memset(ffile + ffile_offset, 0, tokensize);
432 strcpy((char *) ffile + ffile_offset, hdr->token);
433 rom_pos += tokensize;
434 ffile_offset += tokensize;
436 /* image file ********************************************* */
437 i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize);
443 rom_pos += i + pad8_num(datasize) - datasize;
444 ffile_offset += i + pad8_num(datasize) - datasize;
446 /* limiter ************************************************ */
447 *(uint64_t *) (ffile + ffile_offset) = -1;
451 if (buildDataStream(ffile, ffsize) != 0) {
453 ("Failed while processing file '%s' (size = %d bytes)\n",
454 hdr->imagefile, datasize);
463 * FIXME Current limination seems to be about 4MiB.
465 ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
470 i = writeDataStream(ofdCRC, notime);