[PATCH 2/2] uncompress: add Android sparse image support

Sascha Hauer sha at pengutronix.de
Thu Sep 21 05:01:58 PDT 2023


On Thu, Sep 14, 2023 at 11:58:59AM +0200, Juergen Borleis wrote:
> An Android sparse image file generated by the 'genimage' tool can be seen as a
> kind of compression, since it contains only the data which should really be
> written to a device.
> 
> This implementation writes only the intended content and skips anything else.
> 
> Signed-off-by: Juergen Borleis <jbe at pengutronix.de>
> ---
>  lib/uncompress.c | 82 +++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 78 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/uncompress.c b/lib/uncompress.c
> index 0608e9f..f17e9ce 100644
> --- a/lib/uncompress.c
> +++ b/lib/uncompress.c
> @@ -25,6 +25,10 @@
>  #include <malloc.h>
>  #include <fs.h>
>  #include <libfile.h>
> +#ifdef CONFIG_IMAGE_SPARSE
> +#include <image-sparse.h>
> +#include <linux/sizes.h>
> +#endif
>  
>  static void *uncompress_buf;
>  static unsigned int uncompress_size;
> @@ -60,6 +64,71 @@ static int uncompress_fill(void *buf, unsigned int len)
>  	return total;
>  }
>  
> +#ifdef CONFIG_IMAGE_SPARSE
> +static int uncompress_sparse(int source, int destination)
> +{
> +	int ret = 0;
> +	struct sparse_image_ctx *sparse;
> +

You could drop all the #ifdefs and add a

	if (!IS_ENABLED(CONFIG_IMAGE_SPARSE)) {
		pr_err("Sparse image support disabled\n");
		return -ENOSYS;
	}

instead.

> +	/* rewind after checking the file type */
> +	lseek(source, 0, SEEK_SET);

Why is this necessary? If this is necessary for sparse images it should
also be necessary for other compression types as well and should be done
by the caller.

> +
> +	sparse = sparse_image_fd(source);
> +	if (IS_ERR(sparse)) {
> +		pr_err("Failed to open or interpret sparse image file: %m\n");
> +		ret = 1;

'1' is not a valid error code. PTR_ERR(sparse) would be suitable here.

> +		goto on_error_dev;
> +	}
> +
> +	const size_t transfer_buffer_length = SZ_128K;
> +	unsigned char *buf = malloc(transfer_buffer_length);
> +	if (!buf) {
> +		pr_err("Failed to alloc memory for the transfers\n");

No need to print. just return -ENOMEM.

Please return valid error codes in the rest of this function as well.

> +		ret = 1;
> +		goto on_error_sparse;
> +	}
> +
> +	while (1) {
> +		loff_t write_offset;
> +		size_t write_length;
> +
> +		int rc = sparse_image_read(sparse, buf, &write_offset, transfer_buffer_length, &write_length);
> +		if (rc) {
> +			ret = 1;
> +			goto on_error_memory;
> +		}
> +		if (!write_length)
> +			break;
> +
> +		discard_range(destination, write_length, write_offset);
> +
> +		write_offset = lseek(destination, write_offset, SEEK_SET);
> +		if (write_offset == -1) {
> +			pr_err("Failed to set next data's destination offset: %m\n");
> +			ret = 1;
> +			goto on_error_memory;
> +
> +		}
> +
> +		rc = write_full(destination, buf, write_length);
> +		if (rc < 0) {
> +			pr_err("Failed to write destination's next data: %m\n");
> +			ret = 1;
> +			goto on_error_memory;
> +		}
> +	}
> +
> +on_error_memory:
> +	free(buf);
> +on_error_sparse:
> +	free(sparse); /* Note: sparse_image_close(sparse); would also close the input file descriptor */
> +on_error_dev:
> +	return ret;
> +}
> +#endif
> +
> +static int uncompress_infd, uncompress_outfd;
> +
>  int uncompress(unsigned char *inbuf, int len,
>  	   int(*fill)(void*, unsigned int),
>  	   int(*flush)(void*, unsigned int),
> @@ -121,6 +190,10 @@ int uncompress(unsigned char *inbuf, int len,
>  	case filetype_xz_compressed:
>  		compfn = decompress_unxz;
>  		break;
> +#endif
> +#ifdef CONFIG_IMAGE_SPARSE
> +	case filetype_android_sparse:
> +		break;
>  #endif
>  	default:
>  		err = basprintf("cannot handle filetype %s",
> @@ -131,16 +204,17 @@ int uncompress(unsigned char *inbuf, int len,
>  		goto err;
>  	}
>  
> -	ret = compfn(inbuf, len, fill ? uncompress_fill : NULL,
> -			flush, output, pos, error_fn);
> +	if (ft == filetype_android_sparse)
> +		ret = uncompress_sparse(uncompress_infd, uncompress_outfd);

This assumes both uncompress_infd and uncompress_outfd are valid
which is the case for uncompress_fd_to_fd() only, but not for
uncompress_buf_to_fd() or uncompress_buf_to_buf(). I think this
limitation is okay for sparse image support, but the other cases
should return an error instead of silently going crazy on invalid
file descriptors.

BTW at least sparse image support for uncompress_fd_to_buf() could be
implemented without much hassle.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list