diff options
| -rw-r--r-- | difftool/compare_dir.c | 26 | ||||
| -rw-r--r-- | difftool/compare_files.c | 30 | ||||
| -rw-r--r-- | difftool/extract.c | 19 | ||||
| -rw-r--r-- | difftool/node_compare.c | 56 | ||||
| -rw-r--r-- | difftool/sqfsdiff.c | 104 | ||||
| -rw-r--r-- | difftool/sqfsdiff.h | 29 | ||||
| -rw-r--r-- | difftool/util.c | 7 | ||||
| -rw-r--r-- | include/data_reader.h | 16 | ||||
| -rw-r--r-- | lib/sqfshelper/data_reader.c | 155 | 
9 files changed, 260 insertions, 182 deletions
| diff --git a/difftool/compare_dir.c b/difftool/compare_dir.c index 99a0a37..477346a 100644 --- a/difftool/compare_dir.c +++ b/difftool/compare_dir.c @@ -6,16 +6,18 @@   */  #include "sqfsdiff.h" -int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *old, tree_node_t *new) +int compare_dir_entries(sqfsdiff_t *sd, sqfs_tree_node_t *old, +			sqfs_tree_node_t *new)  { -	tree_node_t *old_it = old->data.dir->children, *old_prev = NULL; -	tree_node_t *new_it = new->data.dir->children, *new_prev = NULL; +	sqfs_tree_node_t *old_it = old->children, *old_prev = NULL; +	sqfs_tree_node_t *new_it = new->children, *new_prev = NULL;  	int ret, result = 0;  	char *path;  	while (old_it != NULL || new_it != NULL) {  		if (old_it != NULL && new_it != NULL) { -			ret = strcmp(old_it->name, new_it->name); +			ret = strcmp((const char *)old_it->name, +				     (const char *)new_it->name);  		} else if (old_it == NULL) {  			ret = 1;  		} else { @@ -29,8 +31,8 @@ int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *old, tree_node_t *new)  				return -1;  			if ((sd->compare_flags & COMPARE_EXTRACT_FILES) && -			    S_ISREG(old_it->mode)) { -				if (extract_files(sd, old_it->data.file, +			    S_ISREG(old_it->inode->base.mode)) { +				if (extract_files(sd, old_it->inode,  						  NULL, path)) {  					free(path);  					return -1; @@ -41,9 +43,9 @@ int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *old, tree_node_t *new)  			free(path);  			if (old_prev == NULL) { -				old->data.dir->children = old_it->next; +				old->children = old_it->next;  				free(old_it); -				old_it = old->data.dir->children; +				old_it = old->children;  			} else {  				old_prev->next = old_it->next;  				free(old_it); @@ -56,8 +58,8 @@ int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *old, tree_node_t *new)  				return -1;  			if ((sd->compare_flags & COMPARE_EXTRACT_FILES) && -			    S_ISREG(new_it->mode)) { -				if (extract_files(sd, NULL, new_it->data.file, +			    S_ISREG(new_it->inode->base.mode)) { +				if (extract_files(sd, NULL, new_it->inode,  						  path)) {  					free(path);  					return -1; @@ -68,9 +70,9 @@ int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *old, tree_node_t *new)  			free(path);  			if (new_prev == NULL) { -				new->data.dir->children = new_it->next; +				new->children = new_it->next;  				free(new_it); -				new_it = new->data.dir->children; +				new_it = new->children;  			} else {  				new_prev->next = new_it->next;  				free(new_it); diff --git a/difftool/compare_files.c b/difftool/compare_files.c index 6138569..591fc2c 100644 --- a/difftool/compare_files.c +++ b/difftool/compare_files.c @@ -10,12 +10,12 @@ static unsigned char old_buf[MAX_WINDOW_SIZE];  static unsigned char new_buf[MAX_WINDOW_SIZE];  static int read_blob(const char *prefix, const char *path, -		     data_reader_t *rd, file_info_t *fi, void *buffer, -		     off_t offset, size_t size) +		     data_reader_t *rd, const sqfs_inode_generic_t *inode, +		     void *buffer, uint64_t offset, size_t size)  {  	ssize_t ret; -	ret = data_reader_read(rd, fi, offset, buffer, size); +	ret = data_reader_read(rd, inode, offset, buffer, size);  	ret = (ret < 0 || (size_t)ret < size) ? -1 : 0;  	if (ret) { @@ -27,20 +27,32 @@ static int read_blob(const char *prefix, const char *path,  	return 0;  } -int compare_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, -		  const char *path) +int compare_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, +		  const sqfs_inode_generic_t *new, const char *path)  { -	uint64_t offset, diff; +	uint64_t offset, diff, oldsz, newsz;  	int status = 0, ret; -	if (old->size != new->size) +	if (old->base.type == SQFS_INODE_EXT_FILE) { +		oldsz = old->data.file_ext.file_size; +	} else { +		oldsz = old->data.file.file_size; +	} + +	if (new->base.type == SQFS_INODE_EXT_FILE) { +		newsz = new->data.file_ext.file_size; +	} else { +		newsz = new->data.file.file_size; +	} + +	if (oldsz != newsz)  		goto out_different;  	if (sd->compare_flags & COMPARE_NO_CONTENTS)  		return 0; -	for (offset = 0; offset < old->size; offset += diff) { -		diff = old->size - offset; +	for (offset = 0; offset < oldsz; offset += diff) { +		diff = oldsz - offset;  		if (diff > MAX_WINDOW_SIZE)  			diff = MAX_WINDOW_SIZE; diff --git a/difftool/extract.c b/difftool/extract.c index 2e92710..45c5560 100644 --- a/difftool/extract.c +++ b/difftool/extract.c @@ -6,7 +6,7 @@   */  #include "sqfsdiff.h" -static int extract(data_reader_t *data, file_info_t *fi, +static int extract(data_reader_t *data, const sqfs_inode_generic_t *inode,  		   const char *prefix, const char *path)  {  	char *ptr, *temp; @@ -27,7 +27,7 @@ static int extract(data_reader_t *data, file_info_t *fi,  		return -1;  	} -	if (data_reader_dump_file(data, fi, fd, true)) { +	if (data_reader_dump(data, inode, fd, true)) {  		close(fd);  		return -1;  	} @@ -36,14 +36,19 @@ static int extract(data_reader_t *data, file_info_t *fi,  	return 0;  } -int extract_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, +int extract_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, +		  const sqfs_inode_generic_t *new,  		  const char *path)  { -	if (extract(sd->sqfs_old.data, old, "old", path)) -		return -1; +	if (old != NULL) { +		if (extract(sd->sqfs_old.data, old, "old", path)) +			return -1; +	} -	if (extract(sd->sqfs_new.data, new, "new", path)) -		return -1; +	if (new != NULL) { +		if (extract(sd->sqfs_new.data, new, "new", path)) +			return -1; +	}  	return 0;  } diff --git a/difftool/node_compare.c b/difftool/node_compare.c index 504c9cf..7638805 100644 --- a/difftool/node_compare.c +++ b/difftool/node_compare.c @@ -6,23 +6,24 @@   */  #include "sqfsdiff.h" -int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b) +int node_compare(sqfsdiff_t *sd, sqfs_tree_node_t *a, sqfs_tree_node_t *b)  { -	char *path = node_path(a); -	tree_node_t *ait, *bit; +	char *path = sqfs_tree_node_get_path(a); +	sqfs_tree_node_t *ait, *bit;  	int ret, status = 0;  	if (path == NULL)  		return -1; -	if ((a->mode & S_IFMT) != (b->mode & S_IFMT)) { +	if (a->inode->base.type != b->inode->base.type) {  		fprintf(stdout, "%s has a different type\n", path);  		free(path);  		return 1;  	}  	if (!(sd->compare_flags & COMPARE_NO_PERM)) { -		if ((a->mode & ~S_IFMT) != (b->mode & ~S_IFMT)) { +		if ((a->inode->base.mode & ~S_IFMT) != +		    (b->inode->base.mode & ~S_IFMT)) {  			fprintf(stdout, "%s has different permissions\n",  				path);  			status = 1; @@ -37,39 +38,53 @@ int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b)  	}  	if (sd->compare_flags & COMPARE_TIMESTAMP) { -		if (a->mod_time != b->mod_time) { +		if (a->inode->base.mod_time != b->inode->base.mod_time) {  			fprintf(stdout, "%s has a different timestamp\n", path);  			status = 1;  		}  	}  	if (sd->compare_flags & COMPARE_INODE_NUM) { -		if (a->inode_num != b->inode_num) { +		if (a->inode->base.inode_number != +		    b->inode->base.inode_number) {  			fprintf(stdout, "%s has a different inode number\n",  				path);  			status = 1;  		}  	} -	switch (a->mode & S_IFMT) { -	case S_IFSOCK: -	case S_IFIFO: +	switch (a->inode->base.type) { +	case SQFS_INODE_SOCKET: +	case SQFS_INODE_EXT_SOCKET: +	case SQFS_INODE_FIFO: +	case SQFS_INODE_EXT_FIFO:  		break; -	case S_IFBLK: -	case S_IFCHR: -		if (a->data.devno != b->data.devno) { +	case SQFS_INODE_BDEV: +	case SQFS_INODE_CDEV: +		if (a->inode->data.dev.devno != b->inode->data.dev.devno) {  			fprintf(stdout, "%s has different device number\n",  				path);  			status = 1;  		}  		break; -	case S_IFLNK: -		if (strcmp(a->data.slink_target, b->data.slink_target) != 0) { +	case SQFS_INODE_EXT_BDEV: +	case SQFS_INODE_EXT_CDEV: +		if (a->inode->data.dev_ext.devno != +		    b->inode->data.dev_ext.devno) { +			fprintf(stdout, "%s has different device number\n", +				path); +			status = 1; +		} +		break; +	case SQFS_INODE_SLINK: +	case SQFS_INODE_EXT_SLINK: +		if (strcmp(a->inode->slink_target, b->inode->slink_target)) {  			fprintf(stdout, "%s has a different link target\n",  				path);  		}  		break; -	case S_IFDIR: +	case SQFS_INODE_DIR: +	case SQFS_INODE_EXT_DIR:  		ret = compare_dir_entries(sd, a, b);  		if (ret < 0) {  			status = -1; @@ -81,8 +96,8 @@ int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b)  		free(path);  		path = NULL; -		ait = a->data.dir->children; -		bit = b->data.dir->children; +		ait = a->children; +		bit = b->children;  		while (ait != NULL && bit != NULL) {  			ret = node_compare(sd, ait, bit); @@ -95,8 +110,9 @@ int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b)  			bit = bit->next;  		}  		break; -	case S_IFREG: -		ret = compare_files(sd, a->data.file, b->data.file, path); +	case SQFS_INODE_FILE: +	case SQFS_INODE_EXT_FILE: +		ret = compare_files(sd, a->inode, b->inode, path);  		if (ret < 0) {  			status = -1;  		} else if (ret > 0) { diff --git a/difftool/sqfsdiff.c b/difftool/sqfsdiff.c index a661223..6d1a9af 100644 --- a/difftool/sqfsdiff.c +++ b/difftool/sqfsdiff.c @@ -6,6 +6,100 @@   */  #include "sqfsdiff.h" +static int open_sfqs(sqfs_state_t *state, const char *path) +{ +	state->file = sqfs_open_file(path, SQFS_FILE_OPEN_READ_ONLY); +	if (state->file == NULL) { +		perror(path); +		return -1; +	} + +	if (sqfs_super_read(&state->super, state->file)) { +		fprintf(stderr, "error reading super block from %s\n", +			path); +		goto fail_file; +	} + +	if (!sqfs_compressor_exists(state->super.compression_id)) { +		fprintf(stderr, "%s: unknown compressor used.\n", +			path); +		goto fail_file; +	} + +	sqfs_compressor_config_init(&state->cfg, state->super.compression_id, +				    state->super.block_size, +				    SQFS_COMP_FLAG_UNCOMPRESS); + +	state->cmp = sqfs_compressor_create(&state->cfg); +	if (state->cmp == NULL) { +		fprintf(stderr, "%s: error creating compressor.\n", path); +		goto fail_file; +	} + +	if (state->super.flags & SQFS_FLAG_COMPRESSOR_OPTIONS) { +		if (state->cmp->read_options(state->cmp, state->file)) { +			fprintf(stderr, "%s: error loading compressor " +				"options.\n", path); +			goto fail_cmp; +		} +	} + +	state->idtbl = sqfs_id_table_create(); +	if (state->idtbl == NULL) { +		perror("error creating ID table"); +		goto fail_cmp; +	} + +	if (sqfs_id_table_read(state->idtbl, state->file, +			       &state->super, state->cmp)) { +		fprintf(stderr, "%s: error loading ID table\n", path); +		goto fail_id; +	} + +	state->dr = sqfs_dir_reader_create(&state->super, state->cmp, +					   state->file); +	if (state->dr == NULL) { +		perror("creating directory reader"); +		goto fail_dr; +	} + +	if (sqfs_dir_reader_get_full_hierarchy(state->dr, state->idtbl, +					       NULL, 0, &state->root)) { +		fprintf(stderr, "%s: error loading file system tree\n", path); +		goto fail_dr; +	} + +	state->data = data_reader_create(state->file, &state->super, +					 state->cmp); +	if (state->data == NULL) { +		fprintf(stderr, "%s: error loading file system tree\n", path); +		goto fail_tree; +	} + +	return 0; +fail_tree: +	sqfs_dir_tree_destroy(state->root); +fail_dr: +	sqfs_dir_reader_destroy(state->dr); +fail_id: +	sqfs_id_table_destroy(state->idtbl); +fail_cmp: +	state->cmp->destroy(state->cmp); +fail_file: +	state->file->destroy(state->file); +	return -1; +} + +static void close_sfqs(sqfs_state_t *state) +{ +	data_reader_destroy(state->data); +	sqfs_dir_tree_destroy(state->root); +	sqfs_dir_reader_destroy(state->dr); +	sqfs_id_table_destroy(state->idtbl); +	state->cmp->destroy(state->cmp); +	state->file->destroy(state->file); +} +  int main(int argc, char **argv)  {  	int status, ret = 0; @@ -19,10 +113,10 @@ int main(int argc, char **argv)  			return 2;  	} -	if (sqfs_reader_open(&sd.sqfs_old, sd.old_path)) +	if (open_sfqs(&sd.sqfs_old, sd.old_path))  		return 2; -	if (sqfs_reader_open(&sd.sqfs_new, sd.new_path)) { +	if (open_sfqs(&sd.sqfs_new, sd.new_path)) {  		status = 2;  		goto out_sqfs_old;  	} @@ -35,7 +129,7 @@ int main(int argc, char **argv)  		}  	} -	ret = node_compare(&sd, sd.sqfs_old.fs.root, sd.sqfs_new.fs.root); +	ret = node_compare(&sd, sd.sqfs_old.root, sd.sqfs_new.root);  	if (ret != 0)  		goto out; @@ -53,8 +147,8 @@ out:  	} else {  		status = 0;  	} -	sqfs_reader_close(&sd.sqfs_new); +	close_sfqs(&sd.sqfs_new);  out_sqfs_old: -	sqfs_reader_close(&sd.sqfs_old); +	close_sfqs(&sd.sqfs_old);  	return status;  } diff --git a/difftool/sqfsdiff.h b/difftool/sqfsdiff.h index d9a01c2..40c0fc5 100644 --- a/difftool/sqfsdiff.h +++ b/difftool/sqfsdiff.h @@ -23,11 +23,22 @@  #define MAX_WINDOW_SIZE (1024 * 1024 * 4)  typedef struct { +	sqfs_compressor_config_t cfg; +	sqfs_compressor_t *cmp; +	sqfs_super_t super; +	sqfs_file_t *file; +	sqfs_id_table_t *idtbl; +	sqfs_dir_reader_t *dr; +	sqfs_tree_node_t *root; +	data_reader_t *data; +} sqfs_state_t; + +typedef struct {  	const char *old_path;  	const char *new_path;  	int compare_flags; -	sqfs_reader_t sqfs_old; -	sqfs_reader_t sqfs_new; +	sqfs_state_t sqfs_old; +	sqfs_state_t sqfs_new;  	bool compare_super;  	const char *extract_dir;  } sqfsdiff_t; @@ -41,18 +52,20 @@ enum {  	COMPARE_EXTRACT_FILES = 0x20,  }; -int compare_dir_entries(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b); +int compare_dir_entries(sqfsdiff_t *sd, sqfs_tree_node_t *old, +			sqfs_tree_node_t *new); -char *node_path(tree_node_t *n); +char *node_path(const sqfs_tree_node_t *n); -int compare_files(sqfsdiff_t *sd, file_info_t *a, file_info_t *b, -		  const char *path); +int compare_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, +		  const sqfs_inode_generic_t *new, const char *path); -int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b); +int node_compare(sqfsdiff_t *sd, sqfs_tree_node_t *a, sqfs_tree_node_t *b);  int compare_super_blocks(const sqfs_super_t *a, const sqfs_super_t *b); -int extract_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, +int extract_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, +		  const sqfs_inode_generic_t *new,  		  const char *path);  void process_options(sqfsdiff_t *sd, int argc, char **argv); diff --git a/difftool/util.c b/difftool/util.c index 2883a2f..5e9161a 100644 --- a/difftool/util.c +++ b/difftool/util.c @@ -6,9 +6,9 @@   */  #include "sqfsdiff.h" -char *node_path(tree_node_t *n) +char *node_path(const sqfs_tree_node_t *n)  { -	char *path = fstree_get_path(n); +	char *path = sqfs_tree_node_get_path(n);  	if (path == NULL) {  		perror("get path"); @@ -16,8 +16,7 @@ char *node_path(tree_node_t *n)  	}  	if (canonicalize_name(path)) { -		fputs("[BUG] canonicalization of fstree_get_path failed!!\n", -		      stderr); +		fprintf(stderr, "failed to canonicalization '%s'\n", path);  		free(path);  		return NULL;  	} diff --git a/include/data_reader.h b/include/data_reader.h index 63bd539..77bdd82 100644 --- a/include/data_reader.h +++ b/include/data_reader.h @@ -32,26 +32,14 @@ int data_reader_dump(data_reader_t *data, const sqfs_inode_generic_t *inode,  		     int outfd, bool allow_sparse);  /* -  Use a file_info_t to locate and extract all blocks of the coresponding -  file and its fragment, if it has one. The entire data is dumped to the -  given file descriptor. - -  If allow_sparse is true, try to truncate and seek forward on outfd if a -  zero block is found. If false, always write blocks of zeros to outfd. - -  Returns 0 on success, prints error messages to stderr on failure. - */ -int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd, -			  bool allow_sparse); - -/*    Read a chunk of data from a file. Starting from 'offset' into the    uncompressed file, read 'size' bytes into 'buffer'.    Returns the number of bytes read, 0 if EOF, -1 on failure. Prints an    error message to stderr on failure.   */ -ssize_t data_reader_read(data_reader_t *data, file_info_t *fi, +ssize_t data_reader_read(data_reader_t *data, +			 const sqfs_inode_generic_t *inode,  			 uint64_t offset, void *buffer, size_t size);  #endif /* DATA_READER_H */ diff --git a/lib/sqfshelper/data_reader.c b/lib/sqfshelper/data_reader.c index 0c982d7..0780da0 100644 --- a/lib/sqfshelper/data_reader.c +++ b/lib/sqfshelper/data_reader.c @@ -247,113 +247,64 @@ fail_sparse:  	return -1;  } -int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd, -			  bool allow_sparse) -{ -	uint64_t filesz = fi->size; -	size_t fragsz = fi->size % data->block_size; -	size_t count = fi->size / data->block_size; -	off_t off = fi->startblock; -	size_t i, diff; - -	if (fragsz != 0 && (fi->fragment_offset >= data->block_size || -			    fi->fragment == 0xFFFFFFFF)) { -		fragsz = 0; -		++count; -	} - -	if (allow_sparse && ftruncate(outfd, filesz)) -		goto fail_sparse; - -	for (i = 0; i < count; ++i) { -		diff = filesz > data->block_size ? data->block_size : filesz; -		filesz -= diff; - -		if (SQFS_IS_SPARSE_BLOCK(fi->block_size[i])) { -			if (allow_sparse) { -				if (lseek(outfd, diff, SEEK_CUR) == (off_t)-1) -					goto fail_sparse; -				continue; -			} -			memset(data->block, 0, diff); -		} else { -			if (precache_data_block(data, off, fi->block_size[i])) -				return -1; -			off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i]); -		} - -		if (write_data("writing uncompressed block", -			       outfd, data->block, diff)) { -			return -1; -		} -	} - -	if (fragsz > 0) { -		if (precache_fragment_block(data, fi->fragment)) -			return -1; - -		if (fi->fragment_offset >= data->frag_used) -			goto fail_range; - -		if ((fi->fragment_offset + fragsz - 1) >= data->frag_used) -			goto fail_range; - -		if (write_data("writing uncompressed fragment", outfd, -			       (char *)data->frag_block + fi->fragment_offset, -			       fragsz)) { -			return -1; -		} -	} - -	return 0; -fail_range: -	fputs("attempted to read past fragment block limits\n", stderr); -	return -1; -fail_sparse: -	perror("creating sparse output file"); -	return -1; -} - -ssize_t data_reader_read(data_reader_t *data, file_info_t *fi, +ssize_t data_reader_read(data_reader_t *data, +			 const sqfs_inode_generic_t *inode,  			 uint64_t offset, void *buffer, size_t size)  { -	size_t i, diff, fragsz, count, total = 0; -	off_t off; +	uint32_t frag_idx, frag_off; +	size_t i, diff, total = 0; +	uint64_t off, filesz;  	char *ptr; -	/* work out block count and fragment size */ -	fragsz = fi->size % data->block_size; -	count = fi->size / data->block_size; - -	if (fragsz != 0 && (fi->fragment_offset >= data->block_size || -			    fi->fragment == 0xFFFFFFFF)) { -		fragsz = 0; -		++count; +	/* work out file location and size */ +	if (inode->base.type == SQFS_INODE_EXT_FILE) { +		off = inode->data.file_ext.blocks_start; +		filesz = inode->data.file_ext.file_size; +		frag_idx = inode->data.file_ext.fragment_idx; +		frag_off = inode->data.file_ext.fragment_offset; +	} else { +		off = inode->data.file.blocks_start; +		filesz = inode->data.file.file_size; +		frag_idx = inode->data.file.fragment_index; +		frag_off = inode->data.file.fragment_offset;  	} -	/* work out block index and on-disk location */ -	off = fi->startblock; +	/* find location of the first block */  	i = 0; -	while (offset > data->block_size && i < count) { -		off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i++]); +	while (offset > data->block_size && i < inode->num_file_blocks) { +		off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i++]);  		offset -= data->block_size; + +		if (filesz >= data->block_size) { +			filesz -= data->block_size; +		} else { +			filesz = 0; +		}  	}  	/* copy data from blocks */ -	while (i < count && size > 0) { +	while (i < inode->num_file_blocks && size > 0 && filesz > 0) {  		diff = data->block_size - offset;  		if (size < diff) -			size = diff; +			diff = size; -		if (SQFS_IS_SPARSE_BLOCK(fi->block_size[i])) { +		if (SQFS_IS_SPARSE_BLOCK(inode->block_sizes[i])) {  			memset(buffer, 0, diff);  		} else { -			if (precache_data_block(data, off, fi->block_size[i])) +			if (precache_data_block(data, off, +						inode->block_sizes[i])) {  				return -1; +			}  			memcpy(buffer, (char *)data->block + offset, diff); -			off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i]); +			off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i]); +		} + +		if (filesz >= data->block_size) { +			filesz -= data->block_size; +		} else { +			filesz = 0;  		}  		++i; @@ -364,32 +315,30 @@ ssize_t data_reader_read(data_reader_t *data, file_info_t *fi,  	}  	/* copy from fragment */ -	if (i == count && size > 0 && fragsz > 0) { -		if (precache_fragment_block(data, fi->fragment)) +	if (i == inode->num_file_blocks && size > 0 && filesz > 0) { +		if (precache_fragment_block(data, frag_idx))  			return -1; -		if (fi->fragment_offset >= data->frag_used) +		if (frag_off >= data->frag_used)  			goto fail_range; -		if ((fi->fragment_offset + fragsz - 1) >= data->frag_used) +		if (frag_off + filesz > data->frag_used)  			goto fail_range; -		ptr = (char *)data->frag_block + fi->fragment_offset; -		ptr += offset; +		if (offset >= filesz) +			return total; -		if (offset >= fragsz) { -			offset = 0; -			size = 0; -		} +		if (offset + size > filesz) +			size = filesz - offset; -		if (offset + size > fragsz) -			size = fragsz - offset; +		if (size == 0) +			return total; -		if (size > 0) { -			memcpy(buffer, ptr + offset, size); -			total += size; -		} +		ptr = (char *)data->frag_block + frag_off + offset; +		memcpy(buffer, ptr, size); +		total += size;  	} +  	return total;  fail_range:  	fputs("attempted to read past fragment block limits\n", stderr); | 
