/*
 * One 4-byte pointer per block and then the actual blocked
 * output. The first block does not need an offset pointer,
 * as it will start immediately after the pointer block;
 * so the i'th pointer points to the end of the i'th block
 * (i.e. the start of the (i+1)'th block or past EOF).
 *
 * Note that size > 0, as a zero-sized file wouldn't ever
 * have gotten here in the first place.
 */
static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
{
	unsigned long original_size = size;
	unsigned long original_offset = offset;
	unsigned long new_size;
	unsigned long blocks = (size - 1) / blksize + 1;
	unsigned long curr = offset + 4 * blocks;
	int change;

	total_blocks += blocks;

	do {
		unsigned long len = 2 * blksize;
		unsigned int input = size;
		int err;

		if (input > blksize)
			input = blksize;
		size -= input;
		if (!(opt_holes && is_zero (uncompressed, input))) {
			err = compress_data(base + curr, &len, uncompressed,
				input, Z_BEST_COMPRESSION);
			if (err != Z_OK) {
				die(MKFS_ERROR, 0, "compression error: %s", zError(err));
			}
			curr += len;
		}
		uncompressed += input;

		if (len > blksize*2) {
			/* (I don't think this can happen with zlib.) */
			die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len);
		}

		*(u32 *) (base + offset) = CRAMFS_32(curr);
		offset += 4;
	} while (size);

	curr = (curr + 3) & ~3;
	new_size = curr - original_offset;
	/* TODO: Arguably, original_size in these 2 lines should be
	   st_blocks * 512.  But if you say that then perhaps
	   administrative data should also be included in both. */
	change = new_size - original_size;
	if (opt_verbose > 1) {
		printf("%6.2f%% (%+d bytes)\t%s\n",
		       (change * 100) / (double) original_size, change, name);
	}

	return curr;
}
示例#2
0
/*
 * One 4-byte pointer per block and then the actual blocked
 * output. The first block does not need an offset pointer,
 * as it will start immediately after the pointer block;
 * so the i'th pointer points to the end of the i'th block
 * (i.e. the start of the (i+1)'th block or past EOF).
 *
 * Note that size > 0, as a zero-sized file wouldn't ever
 * have gotten here in the first place.
 */
static unsigned int do_compress(char *base, unsigned int offset, struct entry *entry)
{
	unsigned int size = entry->size;
	unsigned long original_size = size;
	unsigned long original_offset = offset;
	unsigned long new_size;
	unsigned long blocks = (size - 1) / blksize + 1;
	unsigned long curr = offset + 4 * blocks;
	int change;
	char *uncompressed = entry->uncompressed;

	total_blocks += blocks; 

	do {
		unsigned long len = 2 * blksize;
		unsigned int input = size;
		if (input > blksize)
			input = blksize;
		size -= input;
		if (!is_zero (uncompressed, input)) {
			compress(base + curr, &len, uncompressed, input);
			curr += len;
		}
		uncompressed += input;

		if (len > blksize*2) {
			/* (I don't think this can happen with zlib.) */
			error_msg_and_die("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
		}

		*(u32 *) (base + offset) = CRAMFS_32(curr);
		offset += 4;
	} while (size);

	curr = (curr + 3) & ~3;
	new_size = curr - original_offset;
	/* TODO: Arguably, original_size in these 2 lines should be
	   st_blocks * 512.  But if you say that then perhaps
	   administrative data should also be included in both. */
	change = new_size - original_size;
#if 0
	if (opt_verbose) {
	    printf("%6.2f%% (%+d bytes)\t%s\n",
		    (change * 100) / (double) original_size, change, entry->name);
	}
#endif

	return curr;
}
static void do_uncompress(char *path, int fd, unsigned long offset, unsigned long size)
{
	unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE);

	do {
		unsigned long out = PAGE_CACHE_SIZE;
		unsigned long next = CRAMFS_32(*(u32 *) romfs_read(offset));

		if (next > end_data) {
			end_data = next;
		}

		offset += 4;
		if (curr == next) {
			if (opt_verbose > 1) {
				printf("  hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE);
			}
			if (size < PAGE_CACHE_SIZE)
				out = size;
			memset(outbuffer, 0x00, out);
		}
		else {
			if (opt_verbose > 1) {
				printf("  uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
			}
			out = uncompress_block(romfs_read(curr), next - curr);
		}
		if (size >= PAGE_CACHE_SIZE) {
			if (out != PAGE_CACHE_SIZE) {
				die(FSCK_UNCORRECTED, 0, "non-block (%ld) bytes", out);
			}
		} else {
			if (out != size) {
				die(FSCK_UNCORRECTED, 0, "non-size (%ld vs %ld) bytes", out, size);
			}
		}
		size -= out;
		if (opt_extract) {
			if (write(fd, outbuffer, out) < 0) {
				die(FSCK_ERROR, 1, "write failed: %s", path);
			}
		}
		curr = next;
	} while (size);
}
static void do_symlink(char *path, struct cramfs_inode *i)
{
	unsigned long offset = i->offset << 2;
	unsigned long curr = offset + 4;
	unsigned long next = CRAMFS_32(*(u32 *) romfs_read(offset));
	unsigned long size;

	if (offset == 0) {
		die(FSCK_UNCORRECTED, 0, "symbolic link has zero offset");
	}
	if (i->size == 0) {
		die(FSCK_UNCORRECTED, 0, "symbolic link has zero size");
	}

	if (offset < start_data) {
		start_data = offset;
	}
	if (next > end_data) {
		end_data = next;
	}

	size = uncompress_block(romfs_read(curr), next - curr);
	if (size != i->size) {
		die(FSCK_UNCORRECTED, 0, "size error in symlink: %s", path);
	}
	outbuffer[size] = 0;
	if (opt_verbose) {
		char *str;

		asprintf(&str, "%s -> %s", path, outbuffer);
		print_node('l', i, str);
		if (opt_verbose > 1) {
			printf("  uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
		}
		free(str);
	}
	if (opt_extract) {
		if (symlink(outbuffer, path) < 0) {
			die(FSCK_ERROR, 1, "symlink failed: %s", path);
		}
		change_file_status(path, i);
	}
}
/* Returns sizeof(struct cramfs_super), which includes the root inode. */
static unsigned int write_superblock(struct entry *root, char *base, int size)
{
	struct cramfs_super *super = (struct cramfs_super *) base;
	unsigned int offset = sizeof(struct cramfs_super) + image_length;

	offset += opt_pad;	/* 0 if no padding */

	super->magic = CRAMFS_32(CRAMFS_MAGIC);
	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
	if (opt_holes)
		super->flags |= CRAMFS_FLAG_HOLES;
	if (image_length > 0)
		super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
	super->flags |= blksize_bit << CRAMFS_FLAG_BLKSZ_SHIFT;
	super->flags |= opt_compression << CRAMFS_FLAG_COMP_METHOD_SHIFT;
	super->flags = CRAMFS_32(super->flags);
	super->size = CRAMFS_32(size);
	memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));

	super->fsid.crc = CRAMFS_32(crc32(0L, Z_NULL, 0));
	super->fsid.edition = CRAMFS_32(opt_edition);
	super->fsid.blocks = CRAMFS_32(total_blocks);
	super->fsid.files = CRAMFS_32(total_nodes);

	memset(super->name, 0x00, sizeof(super->name));
	if (opt_name)
		strncpy(super->name, opt_name, sizeof(super->name));
	else
		strncpy(super->name, "Compressed", sizeof(super->name));

	super->root.mode = CRAMFS_16(root->mode);
	super->root.uid = CRAMFS_16(root->uid);
	super->root.gid = root->gid;
	super->root.size = CRAMFS_24(root->size);
	CRAMFS_SET_OFFSET(&(super->root), offset >> 2);

	return offset;
}
static void test_super(int *start, size_t *length) {
	struct stat st;

	/* find the physical size of the file or block device */
	if (stat(filename, &st) < 0) {
		die(FSCK_ERROR, 1, "stat failed: %s", filename);
	}
	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		die(FSCK_ERROR, 1, "open failed: %s", filename);
	}
	if (S_ISBLK(st.st_mode)) {
		if (ioctl(fd, BLKGETSIZE, length) < 0) {
			die(FSCK_ERROR, 1, "ioctl failed: unable to determine device size: %s", filename);
		}
		*length = *length * 512;
	}
	else if (S_ISREG(st.st_mode)) {
		*length = st.st_size;
	}
	else {
		die(FSCK_ERROR, 0, "not a block device or file: %s", filename);
	}

	if (*length < sizeof(struct cramfs_super)) {
		die(FSCK_UNCORRECTED, 0, "file length too short");
	}

	/* find superblock */
	if (read(fd, &super, sizeof(super)) != sizeof(super)) {
		die(FSCK_ERROR, 1, "read failed: %s", filename);
	}
	if (super.magic == CRAMFS_MAGIC) {
		*start = 0;
	}
       else if (super.magic == bswap_32(CRAMFS_MAGIC)) {
               *start = 0;
               need_swapping = 1;
       }
	else if (*length >= (PAD_SIZE + sizeof(super))) {
		lseek(fd, PAD_SIZE, SEEK_SET);
		if (read(fd, &super, sizeof(super)) != sizeof(super)) {
			die(FSCK_ERROR, 1, "read failed: %s", filename);
		}
        if (super.magic == CRAMFS_32(CRAMFS_MAGIC)) {
			*start = PAD_SIZE;
		}
	}

	/* superblock tests */
    if (super.magic != CRAMFS_32(CRAMFS_MAGIC)) {
		die(FSCK_UNCORRECTED, 0, "superblock magic not found");
	}
    if (need_swapping){
               super.size = bswap_32(super.size);
               super.flags = bswap_32(super.flags);
               super.future = bswap_32(super.future);
               super.fsid.crc = bswap_32(super.fsid.crc);
               super.fsid.edition = bswap_32(super.fsid.edition);
               super.fsid.blocks = bswap_32(super.fsid.blocks);
               super.fsid.files = bswap_32(super.fsid.files);
       }
	if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
		die(FSCK_ERROR, 0, "unsupported filesystem features");
	}
	if (super.size < PAGE_CACHE_SIZE) {
		die(FSCK_UNCORRECTED, 0, "superblock size (%d) too small", super.size);
	}
	if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
		if (super.fsid.files == 0) {
			die(FSCK_UNCORRECTED, 0, "zero file count");
		}
		if (*length < super.size) {
			die(FSCK_UNCORRECTED, 0, "file length too short");
		}
		else if (*length > super.size) {
			fprintf(stderr, "warning: file extends past end of filesystem\n");
		}
	}
	else {
		fprintf(stderr, "warning: old cramfs format\n");
	}
}
示例#7
0
int cramfs_init(char *filename)
{
	size_t length = 0;
	struct stat st;

	/* find the physical size of the file or block device */
	if (stat(filename, &st) < 0) {
		return FILEERROR;
	}
	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		return FILEERROR;
	}
	if (S_ISBLK(st.st_mode)) {
		if (ioctl(fd, BLKGETSIZE, length) < 0) {
			fprintf(stderr, "unable to determine device size: %s\n", filename);
			return FILEERROR;
		}
		length = length * 512;
	}
	else if (S_ISREG(st.st_mode)) {
		length = st.st_size;
	}
	else {
		fprintf(stderr, "not a block device or file: %s\n", filename);
		return FILEINVALID;
	}

	if (length < sizeof(struct cramfs_super)) {
		fprintf(stderr, "file length too short\n");
		return FILEINVALID;
	}

	/* find superblock */
	if (read(fd, &super, sizeof(super)) != sizeof(super)) {
		fprintf(stderr, "read failed: %s\n", filename);
		return FILEINVALID;
	}
	if (super.magic == CRAMFS_32(CRAMFS_MAGIC)) {
		start = 0;
	}
	else if (length >= (PAD_SIZE + sizeof(super))) {
		lseek(fd, PAD_SIZE, SEEK_SET);
		if (read(fd, &super, sizeof(super)) != sizeof(super)) {
			fprintf(stderr, "read failed: %s\n", filename);
			return FILEINVALID;
		}
		if (super.magic == CRAMFS_32(CRAMFS_MAGIC)) {
			start = PAD_SIZE;
		}
	}

	/* superblock tests */
	if (super.magic != CRAMFS_32(CRAMFS_MAGIC)) {
		fprintf(stderr, "superblock magic not found\n");
		return FILEINVALID;
	}
#if __BYTE_ORDER == __BIG_ENDIAN
	super.size = CRAMFS_32(super.size);
	super.flags = CRAMFS_32(super.flags);
	super.future = CRAMFS_32(super.future);
	super.fsid.crc = CRAMFS_32(super.fsid.crc);
	super.fsid.edition = CRAMFS_32(super.fsid.edition);
	super.fsid.blocks = CRAMFS_32(super.fsid.blocks);
	super.fsid.files = CRAMFS_32(super.fsid.files);
#endif /* __BYTE_ORDER == __BIG_ENDIAN */
	if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
	fprintf(stderr, "unsupported filesystem features\n");
		return FILEINVALID;
	}
	if (super.size < PAGE_CACHE_SIZE) {
		fprintf(stderr, "superblock size (%d) too small\n", super.size);
		return FILEINVALID;
	}
	if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
		if (super.fsid.files == 0) {
			fprintf(stderr, "zero file count\n");
			return FILEINVALID;
		}
		if (length < super.size) {
			fprintf(stderr, "file length too short\n");
			return FILEINVALID;
		}
		else if (length > super.size) {
			fprintf(stderr, "warning: file extends past end of filesystem\n");
		}
	}
	else {
		fprintf(stderr, "warning: old cramfs format\n");
	}

	if (!(super.flags & CRAMFS_FLAG_FSID_VERSION_2)) {
		fprintf(stderr, "unable to test CRC: old cramfs format\n");
		return FILEINVALID;
	}
	return 1;
}