static void do_file(char *path, struct cramfs_inode *i) { unsigned long offset = i->offset << 2; int fd = 0; if (offset == 0 && i->size != 0) { die(FSCK_UNCORRECTED, 0, "file inode has zero offset and non-zero size"); } if (i->size == 0 && offset != 0) { die(FSCK_UNCORRECTED, 0, "file inode has zero size and non-zero offset"); } if (offset != 0 && offset < start_data) { start_data = offset; } if (opt_verbose) { print_node('f', i, path); } if (opt_extract) { fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode); if (fd < 0) { die(FSCK_ERROR, 1, "open failed: %s", path); } } if (i->size) { do_uncompress(path, fd, offset, i->size); } if (opt_extract) { close(fd); change_file_status(path, i); } }
static void do_file(char *path, struct cramfs_inode *i) { unsigned long offset = i->offset << 2; int fd = 0; if (offset == 0 && i->size != 0) errx(FSCK_EX_UNCORRECTED, _("file inode has zero offset and non-zero size")); if (i->size == 0 && offset != 0) errx(FSCK_EX_UNCORRECTED, _("file inode has zero size and non-zero offset")); if (offset != 0 && offset < start_data) start_data = offset; if (opt_verbose) print_node('f', i, path); if (*extract_dir != '\0') { fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode); if (fd < 0) err(FSCK_EX_ERROR, _("cannot open %s"), path); } if (i->size) do_uncompress(path, fd, offset, i->size); if ( *extract_dir != '\0') { if (close_fd(fd) != 0) err(FSCK_EX_ERROR, _("write failed: %s"), path); change_file_status(path, i); } }
static void expand_fs(int pathlen, char *path, struct cramfs_inode *inode) { if (S_ISDIR(inode->mode)) { int count = inode->size; unsigned long offset = inode->offset << 2; char *newpath = malloc(pathlen + 256); if (count > 0 && offset < start_inode) { start_inode = offset; } /* XXX - need to check end_inode for empty case? */ memcpy(newpath, path, pathlen); newpath[pathlen] = '/'; pathlen++; if (opt_verbose) { print_node('d', inode, path); } if (opt_extract) { mkdir(path, inode->mode); change_file_status(path, inode); } while (count > 0) { struct cramfs_inode *child = iget(offset); int size; int newlen = child->namelen << 2; size = sizeof(struct cramfs_inode) + newlen; count -= size; offset += sizeof(struct cramfs_inode); memcpy(newpath + pathlen, romfs_read(offset), newlen); newpath[pathlen + newlen] = 0; if ((pathlen + newlen) - strlen(newpath) > 3) { fprintf(stderr, "%s: invalid cramfs--bad path length\n", filename); exit(4); } expand_fs(strlen(newpath), newpath, child); offset += newlen; if (offset > end_inode) { end_inode = offset; } } return; } if (S_ISREG(inode->mode)) { int fd = 0; unsigned long offset = inode->offset << 2; if (offset > 0 && offset < start_data) { start_data = offset; } if (opt_verbose) { print_node('f', inode, path); } if (opt_extract) { fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, inode->mode); } if (inode->size) { do_uncompress(fd, offset, inode->size); } if (opt_extract) { close(fd); change_file_status(path, inode); } return; } if (S_ISLNK(inode->mode)) { unsigned long offset = inode->offset << 2; if (offset < start_data) { start_data = offset; } do_symlink(path, inode); return; } else { do_special_inode(path, inode); return; } }
int main(int argc, char **argv) { int errors = 0; int verbose = 0; char *prog_name = argv[0]; two_pass = 1; ++argv; --argc; if (argc != 2) { usage(prog_name); return 1; } FILE *fd = fopen(argv[0], "r"); if (!fd) { perror(argv[0]); return 1; } while (1) { union jffs2_node_union node; int off = ftell(fd); if (fread(&node, 1, sizeof(node), fd) != sizeof(node)) break; if (node.u.magic == KSAMTIB_CIGAM_2SFFJ) { fprintf(stderr, "ERROR: reverse endianess detected!\n"); break; } if (node.u.magic == 0xFFFF) { if (verbose) printf("%08x: empty marker - going to next eraseblock\n", off); if (fseek(fd, (off + ES + 1) & ~ES , SEEK_SET) < 0) break; continue; } if (verbose) printf("at %08x: %04x | %04x (%lu bytes): ", off, node.u.magic, node.u.nodetype, node.u.totlen); if (crc32_no_comp(0, (unsigned char*)&node, sizeof(node.u) - 4) != node.u.hdr_crc) { ++errors; printf(" ** wrong crc **\n"); } switch (node.u.nodetype) { case JFFS2_NODETYPE_DIRENT: { fseek(fd, off + sizeof(struct jffs2_raw_dirent), SEEK_SET); char name[node.d.nsize + 1]; fread(name, node.d.nsize, 1, fd); name[node.d.nsize] = 0; if (verbose) printf("DIRENT, ino %lu (%s), parent=%lu\n", node.d.ino, name, node.d.pino); inodes[node.d.ino] = name; node_type[node.d.ino] = node.d.type; childs[node.d.pino].push_back(node.d.ino); break; } case JFFS2_NODETYPE_INODE: { if (verbose) printf("\n"); if (crc32_no_comp(0, (unsigned char*)&node.i, sizeof(struct jffs2_raw_inode) - 8) != node.i.node_crc) { errors++; printf(" ** wrong node crc **\n"); } if (verbose) { printf(" INODE, ino %lu (version %lu) at %08lx\n", node.i.ino, node.i.version, node.i.offset); printf(" compression: %d, user compression requested: %d\n", node.i.compr, node.i.usercompr); } int compr_size = node.i.csize; int uncompr_size = node.i.dsize; if (verbose) printf(" compr_size: %d, uncompr_size: %d\n", compr_size, uncompr_size); unsigned char compr[compr_size], uncomp[uncompr_size]; off_t whence = ftello(fd); fread(compr, compr_size, 1, fd); if (crc32_no_comp(0, compr, compr_size) != node.i.data_crc) { errors++; printf(" ** wrong data crc **\n"); } else { if (verbose) printf(" data crc ok\n"); if (!two_pass) { if (do_uncompress(uncomp, uncompr_size, compr, compr_size, node.i.compr) != uncompr_size) { errors++; printf(" ** data uncompress failed!\n"); } else { nodedata[node.i.ino][node.i.version] = nodedata_s(uncomp, uncompr_size, node.i.offset, node.i.isize, node.i.gid, node.i.uid, node.i.mode); } } else { nodedata[node.i.ino][node.i.version] = nodedata_s(fd, whence, uncompr_size, node.i.compr, uncompr_size, node.i.offset, node.i.isize, node.i.gid, node.i.uid, node.i.mode); } } break; } case JFFS2_NODETYPE_CLEANMARKER: if (verbose) printf("CLEANMARKER\n"); break; case JFFS2_NODETYPE_PADDING: if (verbose) printf("PADDING\n"); break; default: errors++; printf(" ** INVALID ** - nodetype %04x\n", node.u.nodetype); } if (node.u.totlen) fseek(fd, (off + node.u.totlen + 3) &~3 , SEEK_SET); else { errors++; printf(" ** INVALID NODE SIZE. skipping to next eraseblock\n"); fseek(fd, (off + ES + 1) & ~ES , SEEK_SET); } } if (errors) { if (!inodes.empty()) printf("there were errors, but some valid stuff was detected. continuing.\n"); else { fprintf(stderr, "errors present and no valid data.\n"); return 2; } } node_type[1] = DT_DIR; prefix = argv[1]; do_list(1); return 0; }
void do_list(int inode, std::string root="") { std::string pathname = prefix + root + inodes[inode]; std::map<int, struct nodedata_s> &data = nodedata[inode]; int max_size = 0, gid = 0, uid = 0, mode = 0755; if (!data.empty()) { std::map<int, struct nodedata_s>::iterator last = data.end(); --last; max_size = last->second.isize; mode = last->second.mode; gid = last->second.gid; uid = last->second.uid; } if ((node_type[inode] == DT_BLK) || (node_type[inode] == DT_CHR)) max_size = 2; unsigned char *merged_data = (unsigned char*)calloc(1, max_size + 1); int major = 0, minor = 0; for (std::map<int, struct nodedata_s>::iterator i(data.begin()); i != data.end(); ++i) { int size = i->second.size; int offset = i->second.offset; if (offset + size > max_size) size = max_size - offset; if (size > 0) { if (!i->second.data) { unsigned char compr[i->second.size], uncomp[i->second.uncompr_size]; fseeko(i->second.f, i->second.foffset, SEEK_SET); fread(compr, i->second.size, 1, i->second.f); if (do_uncompress(uncomp, i->second.uncompr_size, compr, i->second.size, i->second.compr) != i->second.uncompr_size) fprintf(stderr, " ** data uncompress failed!\n"); else memcpy(merged_data + i->second.offset, uncomp, i->second.size); } else memcpy(merged_data + i->second.offset, i->second.data, i->second.size); } } switch (node_type[inode]) { case DT_DIR: if (mkdir(pathname.c_str(), mode & 0777)) perror(pathname.c_str()); break; case DT_REG: { FILE *f = fopen(pathname.c_str(), "wb"); if (!f) perror(pathname.c_str()); else { fwrite(merged_data, max_size, 1, f); fclose(f); } break; } case DT_LNK: { symlink((char*)merged_data, pathname.c_str()); break; } case DT_CHR: case DT_BLK: { major = merged_data[1]; minor = merged_data[0]; if (mknod(pathname.c_str(), ((node_type[inode] == DT_BLK) ? S_IFBLK : S_IFCHR) | (mode & 07777), makedev(major, minor))) { if (!whine++) perror("mknod"); } break; } case DT_UNKNOWN: case DT_FIFO: case DT_SOCK: case DT_WHT: printf("unhandled inode type!\n"); break; } free(merged_data); if (node_type[inode] != DT_LNK) { if (chmod(pathname.c_str(), mode)) if (!whine++) perror("chmod"); if (chown(pathname.c_str(), uid, gid)) if (!whine++) perror("chown"); } // printf("%s (%d)\n", pathname.c_str(), max_size); std::list<int> &child = childs[inode]; for (std::list<int>::iterator i(child.begin()); i != child.end(); ++i) do_list(*i, root + inodes[inode].c_str() + "/"); }
int compress_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; compress_filter_context_t *zfx = opaque; z_stream *zs = zfx->opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_uncompress( zfx, zs ); zfx->status = 1; } #ifndef __riscos__ zs->next_out = buf; #else /* __riscos__ */ zs->next_out = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_out = size; zfx->outbufsize = size; /* needed only for calculation */ rc = do_uncompress( zfx, zs, a, ret_len ); } else if( control == IOBUFCTRL_FLUSH ) { if( !zfx->status ) { PACKET pkt; PKT_compressed cd; if( !zfx->algo ) zfx->algo = DEFAULT_COMPRESS_ALGO; if( zfx->algo != 1 && zfx->algo != 2 ) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; if( build_packet( a, &pkt )) log_bug("build_packet(PKT_COMPRESSED) failed\n"); zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_compress( zfx, zs ); zfx->status = 2; } #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = size; rc = do_compress( zfx, zs, Z_NO_FLUSH, a ); } else if( control == IOBUFCTRL_FREE ) { if( zfx->status == 1 ) { inflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } else if( zfx->status == 2 ) { #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = 0; do_compress( zfx, zs, Z_FINISH, a ); deflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } if (zfx->release) zfx->release (zfx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "compress_filter"; return rc; }
int compress_filter_bz2( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; compress_filter_context_t *zfx = opaque; bz_stream *bzs = zfx->opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { bzs = zfx->opaque = xmalloc_clear( sizeof *bzs ); init_uncompress( zfx, bzs ); zfx->status = 1; } bzs->next_out = buf; bzs->avail_out = size; zfx->outbufsize = size; /* needed only for calculation */ rc = do_uncompress( zfx, bzs, a, ret_len ); } else if( control == IOBUFCTRL_FLUSH ) { if( !zfx->status ) { PACKET pkt; PKT_compressed cd; if( zfx->algo != COMPRESS_ALGO_BZIP2 ) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; /* if( build_packet( a, &pkt )) log_bug("build_packet(PKT_COMPRESSED) failed\n"); */ //FIXME bzs = zfx->opaque = xmalloc_clear( sizeof *bzs ); init_compress( zfx, bzs ); zfx->status = 2; } bzs->next_in = buf; bzs->avail_in = size; rc = do_compress( zfx, bzs, BZ_RUN, a ); } else if( control == IOBUFCTRL_FREE ) { if( zfx->status == 1 ) { BZ2_bzDecompressEnd(bzs); xfree(bzs); zfx->opaque = NULL; xfree(zfx->outbuf); zfx->outbuf = NULL; } else if( zfx->status == 2 ) { bzs->next_in = buf; bzs->avail_in = 0; do_compress( zfx, bzs, BZ_FINISH, a ); BZ2_bzCompressEnd(bzs); xfree(bzs); zfx->opaque = NULL; xfree(zfx->outbuf); zfx->outbuf = NULL; } if (zfx->release) zfx->release (zfx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "compress_filter"; return rc; }