static int scan_header(struct partition *part) { int sectors_per_block; int i, rc = -ENOMEM; int blocks_found; size_t retlen; sectors_per_block = part->block_size / SECTOR_SIZE; part->total_blocks = part->mbd.mtd->size / part->block_size; if (part->total_blocks < 2) return -ENOENT; /* each erase block has three bytes header, followed by the map */ part->header_sectors_per_block = ((HEADER_MAP_OFFSET + sectors_per_block) * sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; part->data_sectors_per_block = sectors_per_block - part->header_sectors_per_block; part->header_size = (HEADER_MAP_OFFSET + part->data_sectors_per_block) * sizeof(u16); part->cylinders = (part->data_sectors_per_block * (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK; part->sector_count = part->cylinders * SECTORS_PER_TRACK; part->current_block = -1; part->reserved_block = -1; part->is_reclaiming = 0; part->header_cache = kmalloc(part->header_size, GFP_KERNEL); if (!part->header_cache) goto err; part->blocks = kcalloc(part->total_blocks, sizeof(struct block), GFP_KERNEL); if (!part->blocks) goto err; part->sector_map = vmalloc(part->sector_count * sizeof(u_long)); if (!part->sector_map) { printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " "sector map", part->mbd.mtd->name); goto err; } for (i=0; i<part->sector_count; i++) part->sector_map[i] = -1; for (i=0, blocks_found=0; i<part->total_blocks; i++) { rc = part->mbd.mtd->read(part->mbd.mtd, i * part->block_size, part->header_size, &retlen, (u_char*)part->header_cache); if (!rc && retlen != part->header_size) rc = -EIO; if (rc) goto err; if (!build_block_map(part, i)) blocks_found++; } if (blocks_found == 0) { printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n", part->mbd.mtd->name); rc = -ENOENT; goto err; } if (part->reserved_block == -1) { printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n", part->mbd.mtd->name); part->errors = 1; } return 0; err: vfree(part->sector_map); kfree(part->header_cache); kfree(part->blocks); return rc; }
int main(int argc, char *argv[]) { int fd, sectors_per_block; mtd_info_t mtd_info; struct rfd rfd; int i, blocks_found; int out_fd = 0; uint8_t sector[512]; int blank, rc, cylinders; process_options(argc, argv, &rfd); fd = open(rfd.mtd_filename, O_RDONLY); if (fd == -1) { perror(rfd.mtd_filename); return 1; } if (rfd.block_size == 0) { if (ioctl(fd, MEMGETINFO, &mtd_info)) { perror(rfd.mtd_filename); close(fd); return 1; } if (mtd_info.type != MTD_NORFLASH) { fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename); close(fd); return 2; } sectors_per_block = mtd_info.erasesize / SECTOR_SIZE; rfd.block_size = mtd_info.erasesize; rfd.block_count = mtd_info.size / mtd_info.erasesize; } else { struct stat st; if (fstat(fd, &st) == -1) { perror(rfd.mtd_filename); close(fd); return 1; } if (st.st_size % SECTOR_SIZE) fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename); sectors_per_block = rfd.block_size / SECTOR_SIZE; if (st.st_size % rfd.block_size) fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename); rfd.block_count = st.st_size / rfd.block_size; if (!rfd.block_count) { fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename); close(fd); return 2; } } rfd.header_sectors = ((HEADER_MAP_OFFSET + sectors_per_block) * sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; rfd.data_sectors = sectors_per_block - rfd.header_sectors; cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1) / SECTORS_PER_TRACK; rfd.sector_count = cylinders * SECTORS_PER_TRACK; rfd.header_size = (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t); rfd.header = malloc(rfd.header_size); if (!rfd.header) { perror(PROGRAM_NAME); close(fd); return 2; } rfd.sector_map = malloc(rfd.sector_count * sizeof(int)); if (!rfd.sector_map) { perror(PROGRAM_NAME); close(fd); free(rfd.sector_map); return 2; } rfd.mtd_filename = rfd.mtd_filename; for (i=0; i<rfd.sector_count; i++) rfd.sector_map[i] = -1; for (blocks_found=i=0; i<rfd.block_count; i++) { rc = build_block_map(&rfd, fd, i); if (rc > 0) blocks_found++; if (rc < 0) goto err; } if (!blocks_found) { fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename); goto err; } for (i=0; i<rfd.sector_count; i++) { if (rfd.sector_map[i] != -1) break; } if (i == rfd.sector_count) { fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename); goto err; } out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666); if (out_fd == -1) { perror(rfd.out_filename); goto err; } blank = 0; for (i=0; i<rfd.sector_count; i++) { if (rfd.sector_map[i] == -1) { memset(sector, 0, SECTOR_SIZE); blank++; } else { if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i]) != SECTOR_SIZE) { perror(rfd.mtd_filename); goto err; } } if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) { perror(rfd.out_filename); goto err; } } if (rfd.verbose) printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank); close(out_fd); close(fd); free(rfd.header); free(rfd.sector_map); return 0; err: if (out_fd) close(out_fd); close(fd); free(rfd.header); free(rfd.sector_map); return 2; }