/****************************************************************************** * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License * which accompanies this distribution, and is available at * http://www.opensource.org/licenses/bsd-license.php * * Contributors: * IBM Corporation - initial implementation *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define FFS_TARGET_HEADER_SIZE (4 * 8) extern int verbose; #define pad8_num(x) (((x) + 7) & ~7) static int file_exist(const char *name, int errdisp) { struct stat fileinfo; memset((void *) &fileinfo, 0, sizeof(struct stat)); if (stat(name, &fileinfo) != 0) { if (0 != errdisp) { perror(name); } return 0; } if (S_ISREG(fileinfo.st_mode)) { return 1; } return 0; } static int file_getsize(const char *name) { int rc; struct stat fi; rc = stat(name, &fi); if (rc != 0) return -1; return fi.st_size; } static int ffshdr_compare(const void *_a, const void *_b) { const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a; const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b; if (a->romaddr == b->romaddr) return 0; if (a->romaddr > b->romaddr) return 1; return -1; } static void hdr_print(struct ffs_header_t *hdr) { printf("hdr: %p\n", hdr); printf("\taddr: %08llx token: %s\n" "\tflags: %08llx romaddr: %08llx image_len: %08x\n" "\tsave_len: %08llx ffsize: %08x hdrsize: %08x\n" "\ttokensize: %08x\n", hdr->addr, hdr->token, hdr->flags, hdr->romaddr, hdr->imagefile_length, hdr->save_data_len, hdr->ffsize, hdr->hdrsize, hdr->tokensize); } int reorder_ffs_chain(struct ffs_chain_t *fs) { int i, j; int free_space; unsigned long long addr; struct ffs_header_t *hdr; int fix, flx, res, tab_size = fs->count; struct ffs_header_t *fix_tab[tab_size]; /* fixed offset */ struct ffs_header_t *flx_tab[tab_size]; /* flexible offset */ struct ffs_header_t *res_tab[tab_size]; /* result */ /* determine size data to be able to do the reordering */ for (hdr = fs->first; hdr; hdr = hdr->next) { if (hdr->linked_to) hdr->imagefile_length = 0; else hdr->imagefile_length = file_getsize(hdr->imagefile); if (hdr->imagefile_length == -1) return -1; hdr->tokensize = pad8_num(strlen(hdr->token) + 1); hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize; hdr->ffsize = hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8; } memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *)); memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *)); memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *)); /* now start with entries having fixed offs, reorder if needed */ for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next) if (needs_fix_offset(hdr)) fix_tab[fix++] = hdr; else flx_tab[flx++] = hdr; qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare); /* * for fixed files we need to also remove the hdrsize from the * free space because it placed in front of the romaddr */ for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) { fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize; free_space = fix_tab[i]->addr - addr; /* insert as many flexible files as possible */ for (; free_space > 0 && j < flx; j++) { if (flx_tab[j]->ffsize <= free_space) { /* fits */ flx_tab[j]->addr = addr; free_space -= flx_tab[j]->ffsize; addr += flx_tab[j]->ffsize; res_tab[res++] = flx_tab[j]; } else break; } res_tab[res++] = fix_tab[i]; addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize - fix_tab[i]->hdrsize; } /* at the end fill up the table with remaining flx entries */ for (; j < flx; j++) { flx_tab[j]->addr = addr; addr += flx_tab[j]->ffsize; res_tab[res++] = flx_tab[j]; } if (verbose) { printf("--- resulting order ---\n"); for (i = 0; i < tab_size; i++) hdr_print(res_tab[i]); } /* to check if the requested romfs images is greater than * the specified romfs_size it is necessary to add 8 for * the CRC to the totalsize */ addr += 8; /* sanity checking if user specified maximum romfs size */ if ((fs->romfs_size != 0) && addr > fs->romfs_size) { fprintf(stderr, "[build_romfs] romfs_size specified as %d " "bytes, but %lld bytes need to be written.\n", fs->romfs_size, addr); return 1; } /* resort result list */ for (i = 0; i < tab_size - 1; i++) res_tab[i]->next = res_tab[i + 1]; res_tab[i]->next = NULL; fs->first = res_tab[0]; return 0; } /** * allocate memory for a romfs file including header */ static unsigned char * malloc_file(int hdrsz, int datasz, int *ffsz) { void *tmp; /* complete file size is: * header + 8byte aligned(data) + end of file marker (-1) */ *ffsz = hdrsz + pad8_num(datasz) + 8; /* get the mem */ tmp = malloc(*ffsz); if (!tmp) return NULL; memset(tmp, 0, *ffsz); return (unsigned char *) tmp; } static int copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize, int ffile_offset, int ffsize) { int cnt = 0; int imgfd; int i; if (!file_exist(hdr->imagefile, 1)) { printf("access error to file: %s\n", hdr->imagefile); free(ffile); return -1; } imgfd = open(hdr->imagefile, O_RDONLY); if (0 >= imgfd) { perror(hdr->imagefile); free(ffile); return -1; } /* now copy file to file buffer */ /* FIXME using fread might be a good idea so that we do not need to deal with shortened reads/writes. Also error handling looks broken to me. Are we sure that all data is read when exiting this loop? */ while (1) { i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset); if (i <= 0) break; ffile_offset += i; cnt += i; } /* sanity check */ if (cnt != datasize) { printf("BUG!!! copy error on image file [%s](e%d, g%d)\n", hdr->imagefile, datasize, cnt); close(imgfd); free(ffile); return -1; } close(imgfd); return cnt; } static uint64_t next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize) { uint64_t tmp; /* no next file; end of filesystem */ if (hdr->next == NULL) return 0; if (hdr->next->romaddr > 0) { /* the next file does not follow directly after the * current file because it requested to be * placed at a special address; * we need to calculate the offset of the * next file; * the next file starts at hdr->next->romaddr which * is the address requested by the user */ tmp = hdr->next->romaddr; /* the next file starts, however, a bit earlier; * we need to point at the header of the next file; * therefore it is necessary to subtract the header size * of the _next_ file */ tmp -= FFS_TARGET_HEADER_SIZE; /* also remove the length of the filename of the _next_ * file */ tmp -= pad8_num(strlen(hdr->next->token) + 1); /* and it needs to be relative to the current file */ tmp -= rom_pos; return tmp; } /* if no special treatment is required the next file just * follows after the current file; * therefore just return the complete filesize as offset */ return ffsize; } static int next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize, unsigned int num_files) { /* check if file wants a specific address */ void *tmp; if ((hdr->flags & FLAG_LLFW) == 0) /* flag to get a specific address has been set */ return rom_pos; if (hdr->romaddr == 0) /* if the requested address is 0 then * something is not right; ignore the flag */ return rom_pos; /* check if romaddress is below current position */ if (hdr->romaddr < (rom_pos + hdrsize)) { printf("[%s] ERROR: requested impossible " "romaddr of %llx\n", hdr->token, hdr->romaddr); return -1; } /* spin offset to new position */ if (pad8_num(hdr->romaddr) != hdr->romaddr) { printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n"); return -1; } tmp = malloc(hdr->romaddr - rom_pos - hdrsize); if (!tmp) return -1; memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize); if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) { free(tmp); printf("write failed\n"); return -1; } free(tmp); if (!num_files) printf("\nWARNING: The filesystem will have no entry header!\n" " It is still usable but you need to find\n" " the FS by yourself in the image.\n\n"); return hdr->romaddr - hdrsize; } int build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime) { int ofdCRC; int ffsize, datasize, i; int tokensize, hdrsize, ffile_offset, hdrbegin; struct ffs_header_t *hdr; unsigned char *ffile; unsigned int rom_pos = 0; unsigned int num_files = 0; uint64_t tmp; if (NULL == fs->first) { return 1; } hdr = fs->first; /* check output file and open it for creation */ if (file_exist(outfile, 0)) { printf("Output file (%s) will be overwritten\n", outfile); } while (hdr) { if (hdr->linked_to) { printf("\nBUG!!! links not supported anymore\n"); return 1; } /* add +1 to strlen for zero termination */ tokensize = pad8_num(strlen(hdr->token) + 1); hdrsize = FFS_TARGET_HEADER_SIZE + tokensize; datasize = file_getsize(hdr->imagefile); if (datasize == -1) { perror(hdr->imagefile); return 1; } ffile_offset = 0; ffile = malloc_file(hdrsize, datasize, &ffsize); if (NULL == ffile) { perror("alloc mem for ffile"); return 1; } /* check if file wants a specific address */ rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files); hdrbegin = rom_pos; if (hdrbegin == -1) { /* something went wrong */ free(ffile); return 1; } /* write header ******************************************* */ /* next addr ********************************************** */ tmp = next_file_offset(hdr, rom_pos, ffsize); *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp); rom_pos += 8; ffile_offset += 8; /* length ************************************************* */ hdr->save_data_len = datasize; *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize); rom_pos += 8; ffile_offset += 8; /* flags ************************************************** */ *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags); rom_pos += 8; ffile_offset += 8; /* datapointer ******************************************** */ //save-data pointer is relative to rombase hdr->save_data = hdrbegin + hdrsize; hdr->save_data_valid = 1; //changed pointers to be relative to file: tmp = hdr->save_data - hdrbegin; *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp); rom_pos += 8; ffile_offset += 8; /* name (token) ******************************************* */ memset(ffile + ffile_offset, 0, tokensize); strcpy((char *) ffile + ffile_offset, hdr->token); rom_pos += tokensize; ffile_offset += tokensize; /* image file ********************************************* */ i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize); if (i == -1) return 1; /* pad file */ rom_pos += i + pad8_num(datasize) - datasize; ffile_offset += i + pad8_num(datasize) - datasize; /* limiter ************************************************ */ *(uint64_t *) (ffile + ffile_offset) = -1; rom_pos += 8; ffile_offset += 8; if (buildDataStream(ffile, ffsize) != 0) { printf ("Failed while processing file '%s' (size = %d bytes)\n", hdr->imagefile, datasize); return 1; } free(ffile); hdr = hdr->next; num_files++; } /* * FIXME Current limination seems to be about 4MiB. */ ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (0 > ofdCRC) { perror(outfile); return 1; } i = writeDataStream(ofdCRC, notime); close(ofdCRC); if (i) return 1; return 0; }