Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ LIB_SRCS = \
LIB_OBJS = $(LIB_SRCS:%.cpp=%.o)
LIB_INCS = -Iinclude -Iandroid-base/include

LDFLAGS += -L. -l$(LIB_NAME) -lm -lz
LDFLAGS += -L. -l$(LIB_NAME) -lm -lz -llz4

BINS = simg2img simg2simg img2simg append2simg
HEADERS = include/sparse/sparse.h
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ $ file /output/path/system.raw.img
system.raw.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)
```

Vendor extensions
-----------------

Sparse library was additionally patched to support Sony SIN images containing LZ4 compressed chunks of 0xCAC5 type.

Windows
-------

If you want to build simg2img on Windows you'll need to [install MinGW](http://www.mingw.org/wiki/howto_install_the_mingw_gcc_compiler_suite)
and also zlib and libasprintf (go to MinGW Libraries in the installer and check `mingw32-libz` and `mingw32-libasprintf`).
and also zlib, liblz4, and libasprintf (go to MinGW Libraries in the installer and check `mingw32-libz`, `mingw32-lz4`, and `mingw32-libasprintf`).
Once you've done that run the following command to build simg2img:

```
Expand All @@ -31,8 +36,8 @@ CFLAGS=-DUSE_MINGW LDFLAGS=-lasprintf mingw32-make
Linux
------

If zlib.h is missing then install it using
If zlib.h and (or) lz4.h are missing then install them using

Ubuntu: ```sudo apt-get install libz-dev```
Ubuntu: ```sudo apt-get install libz-dev liblz4-dev```

Fedora: ```sudo dnf install libz-devel```
Fedora: ```sudo dnf install libz-devel lz4-devel```
1 change: 1 addition & 0 deletions sparse_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef struct sparse_header {
#define CHUNK_TYPE_FILL 0xCAC2
#define CHUNK_TYPE_DONT_CARE 0xCAC3
#define CHUNK_TYPE_CRC32 0xCAC4
#define CHUNK_TYPE_SIN_LZ4 0xCAC5 /* Sony Xperia (SIN image) specific type */

typedef struct chunk_header {
__le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
Expand Down
58 changes: 58 additions & 0 deletions sparse_read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <unistd.h>
#include <algorithm>
#include <string>
#include <lz4.h>

#include <sparse/sparse.h>

Expand Down Expand Up @@ -283,6 +284,55 @@ static int process_crc32_chunk(SparseFileSource* source, unsigned int chunk_size
return 0;
}

static int process_sin_lz4_chunk(struct sparse_file* s, unsigned int chunk_size,
SparseFileSource* source, unsigned int blocks, unsigned int block,
uint32_t* crc32) {
int64_t len = blocks * s->block_size;
char* ibuf = (char*)malloc(chunk_size);
char* obuf = (char*)malloc(len);
int ret = 0;

if (!ibuf || !obuf) {
ret = -ENOMEM;
goto exit;
}

ret = source->ReadValue(ibuf, chunk_size);
if (ret < 0)
goto exit;

/* Chunk data is a huge (tens of megabytes) LZ4 block, so pass it directly
* to the LZ4 decompress.
*
* NB: there are 12 trailing bytes of unclear nature. LZ4 decompress code
* deals with them by properly stop at the final 5-literals sequence so it's
* safe to pass the whole blob as it is. Subject for future study.
*/
ret = LZ4_decompress_safe(ibuf, obuf, chunk_size, len);
if (ret < 0 || ret != len) {
ret = -EINVAL;
goto exit;
}

free(ibuf); /* Release input memory ASAP */
ibuf = nullptr;

ret = sparse_file_add_data(s, obuf, len, block);
if (ret < 0)
goto exit;

if (crc32)
*crc32 = sparse_crc32(*crc32, obuf, len);

obuf = nullptr; /* Forget (prevent freeing of) delivered block */

exit:
free(ibuf);
free(obuf);

return ret;
}

static int process_chunk(struct sparse_file* s, SparseFileSource* source, unsigned int chunk_hdr_sz,
chunk_header_t* chunk_header, unsigned int cur_block, uint32_t* crc_ptr) {
int ret;
Expand Down Expand Up @@ -325,6 +375,14 @@ static int process_chunk(struct sparse_file* s, SparseFileSource* source, unsign
return ret;
}
return 0;
case CHUNK_TYPE_SIN_LZ4:
ret = process_sin_lz4_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
crc_ptr);
if (ret < 0) {
verbose_error(s->verbose, -EINVAL, "lz4 block at %" PRId64, offset);
return ret;
}
return chunk_header->chunk_sz;
default:
verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64, chunk_header->chunk_type,
offset);
Expand Down