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;
}
Beispiel #2
0
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;
}