FreeCalypso > hg > freecalypso-reveng
view mpffs/common.c @ 29:e96d6862cec0
mpffs-rdutils code started
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 30 Jun 2013 05:16:23 +0000 |
parents | |
children | 9c3c5a572b57 |
line wrap: on
line source
/* * This module contains the code that will be common between mpffs-cat, * mpffs-ls and mpffs-xtr. */ #include <sys/types.h> #include <sys/file.h> #include <sys/stat.h> #include <endian.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <unistd.h> #include "types.h" #include "struct.h" u8 mpffs_header[6] = {'F', 'f', 's', '#', 0x10, 0x02}; char *imgfile; u32 eraseblk_size; int total_blocks; u32 total_ffs_size; u8 *image, *indexblk; int index_blk_num, root_node_no; int verbose; /* * The following function is used to verify that the specified or computed * flash erase block size is a power of 2. */ count_ones(word) u32 word; { int count; for (count = 0; word; word >>= 1) count += word & 1; return count; } eraseblk_size_reasonable() { if (count_ones(eraseblk_size) != 1 || eraseblk_size < 16384) { fprintf(stderr, "0x%lx is an unreasonable erase block size\n", (u_long) eraseblk_size); exit(1); } } read_img_file() { int fd; struct stat st; fd = open(imgfile, O_RDONLY); if (fd < 0) { perror(imgfile); exit(1); } fstat(fd, &st); if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s is not a regular file\n", imgfile); exit(1); } if (!eraseblk_size && !total_blocks) { switch (st.st_size) { case 0x70000: /* assume Closedmoko */ eraseblk_size = 0x10000; total_blocks = 7; break; case 0x480000: /* assume Pirelli */ eraseblk_size = 0x40000; total_blocks = 18; break; default: noauto: fprintf(stderr, "cannot intuit the flash parameters of %s: use -e and -n options\n", imgfile); exit(1); } } else if (!total_blocks) { total_blocks = st.st_size / eraseblk_size; if (!total_blocks || total_blocks * eraseblk_size != st.st_size) goto noauto; } else if (!eraseblk_size) { if (total_blocks * 0x10000 == st.st_size) eraseblk_size = 0x10000; else if (total_blocks * 0x40000 == st.st_size) eraseblk_size = 0x40000; else goto noauto; } total_ffs_size = eraseblk_size * total_blocks; if (st.st_size < total_ffs_size) { fprintf(stderr, "%s has fewer than 0x%x bytes\n", imgfile, total_ffs_size); exit(1); } image = malloc(total_ffs_size); if (!image) { perror("malloc"); exit(1); } read(fd, image, total_ffs_size); close(fd); } find_index_block() { int i, abcnt; u8 *ptr; if (index_blk_num) { if (index_blk_num < 0 || index_blk_num >= total_blocks) { fprintf(stderr, "invalid block # given with the -a option\n"); exit(1); } ptr = image + index_blk_num * eraseblk_size; if (bcmp(ptr, mpffs_header, 6) || ptr[8] != 0xAB) { fprintf(stderr, "no MPFFS index found at the specified block #%d\n", index_blk_num); exit(1); } indexblk = ptr; return(0); } abcnt = 0; for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) { if (bcmp(ptr, mpffs_header, 6)) { fprintf(stderr, "warning: no MPFFS signature in erase block #%d (offset %x)\n", i, ptr - image); continue; } switch (ptr[8]) { case 0xAB: if (verbose) printf( "Found AB index in erase block #%d (offset %x)\n", i, ptr - image); index_blk_num = i; indexblk = ptr; abcnt++; continue; case 0xBD: case 0xBF: continue; } fprintf(stderr, "warning: non-understood block type %02X at offset %x\n", ptr[8], ptr - image); } if (!indexblk) { fprintf(stderr, "could not find an MPFFS index block in %s\n", imgfile); exit(1); } if (abcnt > 1) { fprintf(stderr, "found more than one AB block; use -a\n"); exit(1); } return(0); } get_index_entry(oi) struct objinfo *oi; { struct mpffs_index *le; if (oi->entryno >= (eraseblk_size >> 4)) { fprintf(stderr, "error: index block pointer %x past the erase block size!\n", oi->entryno); exit(1); } le = (struct mpffs_index *) indexblk + oi->entryno; oi->idxrec = le; oi->len = le16toh(le->len); oi->type = le->type; oi->descend = le16toh(le->descend); oi->sibling = le16toh(le->sibling); return(0); } validate_chunk(oi) struct objinfo *oi; { u32 dptr; if (oi->len & 0xF || !oi->len) { fprintf(stderr, "index entry #%x: invalid chunk length\n", oi->entryno); exit(1); } dptr = le32toh(oi->idxrec->dataptr); if (dptr > 0x0FFFFFFF) { invdptr: fprintf(stderr, "index entry #%x: invalid data pointer\n", oi->entryno); exit(1); } dptr <<= 4; if (dptr >= total_img_size - oi->len) goto invdptr; oi->offset = dptr; oi->dataptr = image + dptr; return(0); } validate_obj_name(oi) struct objinfo *oi; { u8 *cp; int cnt; for (cp = oi->dataptr, cnt = 0; ; cp++, cnt++) { if (cnt >= oi->len) { fprintf(stderr, "object at index %x: name expected at %x: length overrun\n", oi->entryno, oi->offset); exit(1); } if (!*cp) break; if (*cp < '!' || *cp > '~') { fprintf(stderr, "object at index %x: name expected at %x: bad character\n", oi->entryno, oi->offset); exit(1); } } if (!cnt) { fprintf(stderr, "object at index %x: name expected at %x: null string\n", oi->entryno, oi->offset); exit(1); } return(0); } u8 * find_end_of_chunk(ch) struct objinfo *ch; { u8 *p; int i; p = ch->dataptr + ch->len; for (i = 1; i <= 16; i++) { if (!p[-i]) return(p - i); if (p[-1] != 0xFF) break; } fprintf(stderr, "chunk starting at %x (index entry %x): no valid termination found\n", ch->offset, ch->entryno); exit(1); }