summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2021-05-02 17:01:48 +0200
committerPali Rohár <pali.rohar@gmail.com>2021-05-02 17:01:48 +0200
commitdf8e50a8243ad7003988efca3e4840d15030977c (patch)
tree3ac8406f04efcf327ad9bb9bea37eb4dda428de6
parent4f45b045c305efdb216a24912aedceba0cd23670 (diff)
download0xFFFF-df8e50a8243ad7003988efca3e4840d15030977c.tar.bz2
fiasco: Add support for unpacking multiple parts of one image
Fiasco mmc image contains layout and two parts in one data section. First part is FAT32 partition (MyDocs) and second part is tar archive for second ext3 partition (/home). This change extends fiasco parser to load all parts from one data section and correctly unpack all parts.
-rw-r--r--src/fiasco.c152
-rw-r--r--src/image.c45
-rw-r--r--src/image.h16
-rw-r--r--src/main.c24
4 files changed, 169 insertions, 68 deletions
diff --git a/src/fiasco.c b/src/fiasco.c
index 890e1c0..a0caf1a 100644
--- a/src/fiasco.c
+++ b/src/fiasco.c
@@ -74,6 +74,8 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
uint16_t hash;
off_t offset;
struct image * image;
+ struct image_part * image_part;
+ struct image_part * image_parts;
char hwrev[9];
unsigned char buf[512];
@@ -188,6 +190,8 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
memset(hwrevs, 0, sizeof(hwrevs));
memset(version, 0, sizeof(version));
memset(layout, 0, sizeof(layout));
+ image_part = NULL;
+ image_parts = NULL;
while ( count8 > 0 ) {
@@ -237,6 +241,36 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
memset(layout, 0, sizeof(layout));
strncpy(layout, (char *)buf, length8);
VERBOSE("layout\n");
+ } else if ( byte == '4' ) {
+ VERBOSE("data part\n");
+ if ( length8 < 16 ) {
+ VERBOSE(" (damaged)\n");
+ } else {
+ if ( image_parts ) {
+ image_part->next = calloc(1, sizeof(struct image_part));
+ if ( ! image_part->next )
+ FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
+ image_part = image_part->next;
+ } else {
+ image_parts = calloc(1, sizeof(struct image_part));
+ if ( ! image_parts )
+ FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
+ image_part = image_parts;
+ }
+ image_part->offset = ntohl(*(uint32_t *)&buf[4]);
+ image_part->size = ntohl(*(uint32_t *)&buf[12]);
+ if ( length8 > 16 ) {
+ image_part->name = calloc(1, length8-16+1);
+ if ( image_part->name )
+ memcpy(image_part->name, &buf[16], length8-16);
+ }
+ VERBOSE(" unknown: 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[0], buf[1], buf[2], buf[3]);
+ VERBOSE(" offset: %u bytes\n", image_part->offset);
+ VERBOSE(" unknown: 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[8], buf[9], buf[10], buf[11]);
+ VERBOSE(" size: %u bytes\n", image_part->size);
+ if ( image_part->name )
+ VERBOSE(" partition name: %s\n", image_part->name);
+ }
} else {
VERBOSE("unknown ('%c':%#x)\n", byte, byte);
}
@@ -262,7 +296,7 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
VERBOSE(" hwrevs: %s\n", hwrevs);
VERBOSE(" data at: %#08x\n", (unsigned int)offset);
- image = image_alloc_from_shared_fd(fiasco->fd, length, offset, hash, type, device, hwrevs, version, layout);
+ image = image_alloc_from_shared_fd(fiasco->fd, length, offset, hash, type, device, hwrevs, version, layout, image_parts);
if ( ! image )
FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
@@ -516,8 +550,10 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
char * name;
char * layout_name;
struct image * image;
+ struct image_part * image_part;
struct image_list * image_list;
- uint32_t size;
+ uint32_t offset, size, need, total_size, written;
+ int part_num;
char cwd[256];
unsigned char buf[4096];
@@ -543,69 +579,29 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
while ( image_list ) {
- fd = -1;
- name = NULL;
- layout_name = NULL;
-
image = image_list->image;
- name = image_name_alloc_from_values(image);
- if ( ! name )
- return -1;
-
printf("\n");
printf("Unpacking image...\n");
image_print_info(image);
if ( image->layout ) {
- layout_name = calloc(1, strlen(name) + sizeof(".layout")-1 + 1);
+ name = image_name_alloc_from_values(image, -1);
+ if ( ! name )
+ ALLOC_ERROR_RETURN(-1);
+
+ layout_name = calloc(1, strlen(name) + sizeof("_layout")-1 + 1);
if ( ! layout_name ) {
free(name);
ALLOC_ERROR_RETURN(-1);
}
- sprintf(layout_name, "%s.layout", name);
+ sprintf(layout_name, "%s_layout", name);
+ free(name);
printf(" Layout file: %s\n", layout_name);
- }
-
- printf(" Output file: %s\n", name);
-
- if ( ! simulate ) {
- fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644);
- if ( fd < 0 ) {
- ERROR_INFO("Cannot create output file %s", name);
- free(name);
- free(layout_name);
- return -1;
- }
- }
-
- image_seek(image, 0);
- while ( 1 ) {
- size = image_read(image, buf, sizeof(buf));
- if ( size == 0 )
- break;
- if ( ! simulate ) {
- if ( write(fd, buf, size) != (ssize_t)size ) {
- ERROR_INFO_STR(name, "Cannot write %d bytes", size);
- close(fd);
- free(name);
- free(layout_name);
- return -1;
- }
- }
- }
-
- free(name);
-
- if ( ! simulate )
- close(fd);
-
- if ( image->layout ) {
-
if ( ! simulate ) {
fd = open(layout_name, O_RDWR|O_CREAT|O_TRUNC, 0644);
if ( fd < 0 ) {
@@ -631,6 +627,64 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
}
+ part_num = 0;
+ image_part = image->parts;
+
+ do {
+
+ offset = image_part ? image_part->offset : 0;
+ total_size = image_part ? image_part->size : image->size;
+
+ name = image_name_alloc_from_values(image, image_part ? part_num : -1);
+ if ( ! name )
+ ALLOC_ERROR_RETURN(-1);
+
+ if ( image_part && ( part_num > 0 || image_part->next ) )
+ printf(" Output file part %d: %s\n", part_num+1, name);
+ else
+ printf(" Output file: %s\n", name);
+
+ if ( ! simulate ) {
+ fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if ( fd < 0 ) {
+ ERROR_INFO("Cannot create output file %s", name);
+ free(name);
+ return -1;
+ }
+ }
+
+ written = 0;
+ image_seek(image, offset);
+ while ( written < total_size ) {
+ need = total_size - written;
+ if ( need > sizeof(buf) )
+ need = sizeof(buf);
+ size = image_read(image, buf, need);
+ if ( size == 0 )
+ break;
+ if ( ! simulate ) {
+ if ( write(fd, buf, size) != (ssize_t)size ) {
+ ERROR_INFO_STR(name, "Cannot write %d bytes", size);
+ close(fd);
+ free(name);
+ return -1;
+ }
+ }
+ written += size;
+ }
+
+ free(name);
+
+ if ( ! simulate )
+ close(fd);
+
+ if ( image_part ) {
+ image_part = image_part->next;
+ part_num++;
+ }
+
+ } while ( image_part );
+
image_list = image_list->next;
}
diff --git a/src/image.c b/src/image.c
index b78633b..f9d8059 100644
--- a/src/image.c
+++ b/src/image.c
@@ -100,7 +100,7 @@ static void image_missing_values_from_name(struct image * image, const char * na
}
/* format: type-device:hwrevs_version */
-char * image_name_alloc_from_values(struct image * image) {
+char * image_name_alloc_from_values(struct image * image, int part_num) {
char * name;
char * ptr;
@@ -108,6 +108,8 @@ char * image_name_alloc_from_values(struct image * image) {
size_t length;
const char * type;
const char * device;
+ struct image_part * part;
+ int i;
type = image_type_to_string(image->type);
@@ -124,6 +126,14 @@ char * image_name_alloc_from_values(struct image * image) {
else
hwrevs = NULL;
+ part = image->parts;
+
+ if ( part && ( !part->next || part_num < 0 ) )
+ part = NULL;
+
+ for ( i = 0; i < part_num && part; i++ )
+ part = part->next;
+
length = 1 + strlen(type);
if ( device )
@@ -132,6 +142,10 @@ char * image_name_alloc_from_values(struct image * image) {
length += 1 + strlen(hwrevs);
if ( image->version )
length += 1 + strlen(image->version);
+ if ( part )
+ length += 4 + 3; /* 3 <= strlen(part_num) */
+ if ( part && part->name )
+ length += 1 + strlen(part->name);
name = calloc(1, length);
if ( ! name ) {
@@ -149,13 +163,19 @@ char * image_name_alloc_from_values(struct image * image) {
if ( image->version )
ptr += sprintf(ptr, "_%s", image->version);
+ if ( part ) {
+ ptr += sprintf(ptr, "_part%d", part_num+1);
+ if ( part->name )
+ ptr += sprintf(ptr, "_%s", part->name);
+ }
+
free(hwrevs);
return name;
}
-static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
enum image_type detected_type;
@@ -210,6 +230,8 @@ static int image_append(struct image * image, const char * type, const char * de
else
image->layout = NULL;
+ image->parts = parts;
+
return 0;
}
@@ -244,7 +266,7 @@ static struct image * image_alloc(void) {
}
-struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
int fd;
@@ -254,11 +276,11 @@ struct image * image_alloc_from_file(const char * file, const char * type, const
return NULL;
}
- return image_alloc_from_fd(fd, file, type, device, hwrevs, version, layout);
+ return image_alloc_from_fd(fd, file, type, device, hwrevs, version, layout, parts);
}
-struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
off_t offset;
struct image * image = image_alloc();
@@ -291,7 +313,7 @@ struct image * image_alloc_from_fd(int fd, const char * orig_filename, const cha
return NULL;
}
- if ( image_append(image, type, device, hwrevs, version, layout) < 0 )
+ if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
return NULL;
if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) )
@@ -303,7 +325,7 @@ struct image * image_alloc_from_fd(int fd, const char * orig_filename, const cha
}
-struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
struct image * image = image_alloc();
if ( ! image )
@@ -315,7 +337,7 @@ struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, ui
image->offset = offset;
image->cur = 0;
- if ( image_append(image, type, device, hwrevs, version, layout) < 0 )
+ if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
return NULL;
if ( ! noverify && image->hash != hash ) {
@@ -347,6 +369,13 @@ void image_free(struct image * image) {
image->devices = next;
}
+ while ( image->parts ) {
+ struct image_part * next = image->parts->next;
+ free(image->parts->name);
+ free(image->parts);
+ image->parts = next;
+ }
+
free(image->version);
free(image->layout);
free(image->orig_filename);
diff --git a/src/image.h b/src/image.h
index 42111bf..2535a14 100644
--- a/src/image.h
+++ b/src/image.h
@@ -40,6 +40,13 @@ enum image_type {
IMAGE_COUNT,
};
+struct image_part {
+ struct image_part * next;
+ uint32_t offset;
+ uint32_t size;
+ char * name;
+};
+
struct image {
enum image_type type;
struct device_list * devices;
@@ -47,6 +54,7 @@ struct image {
char * layout;
uint16_t hash;
uint32_t size;
+ struct image_part * parts;
int fd;
int is_shared_fd;
@@ -63,9 +71,9 @@ struct image_list {
struct image_list * next;
};
-struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
-struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
-struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
+struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
+struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
+struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
void image_free(struct image * image);
void image_seek(struct image * image, size_t whence);
size_t image_read(struct image * image, void * buf, size_t count);
@@ -76,7 +84,7 @@ void image_list_unlink(struct image_list * list);
uint16_t image_hash_from_data(struct image * image);
enum image_type image_type_from_data(struct image * image);
-char * image_name_alloc_from_values(struct image * image);
+char * image_name_alloc_from_values(struct image * image, int part_num);
enum image_type image_type_from_string(const char * type);
const char * image_type_to_string(enum image_type type);
int image_hwrev_is_valid(struct image * image, int16_t hwrev);
diff --git a/src/main.c b/src/main.c
index 9b9e4a5..55467ca 100644
--- a/src/main.c
+++ b/src/main.c
@@ -143,7 +143,7 @@ int simulate;
int noverify;
int verbose;
-/* arg = [[[dev:[hw:]]ver:]type:]file[%%lay] */
+/* arg = [[[dev:[hw:]]ver:]type:]file[%file2%file3...%lay] */
static void parse_image_arg(char * arg, struct image_list ** image_first) {
struct stat st;
@@ -154,14 +154,16 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
char * hwrevs;
char * version;
char * layout;
+ char * parts;
char * layout_file;
+ char * ptr;
int fd;
/* First check if arg is file, then try to parse arg format */
fd = open(arg, O_RDONLY);
if ( fd >= 0 ) {
if ( fstat(fd, &st) == 0 && !S_ISDIR(st.st_mode) ) {
- image = image_alloc_from_fd(fd, arg, NULL, NULL, NULL, NULL, NULL);
+ image = image_alloc_from_fd(fd, arg, NULL, NULL, NULL, NULL, NULL, NULL);
if ( ! image ) {
ERROR("Cannot load image file %s", arg);
exit(1);
@@ -175,9 +177,13 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
exit(1);
}
- layout_file = strchr(arg, '%');
- if ( layout_file )
- *(layout_file++) = 0;
+ parts = strchr(arg, '%');
+ if ( parts )
+ *(parts++) = 0;
+
+ layout_file = parts;
+ while ( ( ptr = strchr(layout_file, '%') ) )
+ layout_file = ptr+1;
type = NULL;
device = NULL;
@@ -237,7 +243,9 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
close(fd);
}
- image = image_alloc_from_file(file, type, device, hwrevs, version, layout);
+ /* TODO: alloc parts */
+
+ image = image_alloc_from_file(file, type, device, hwrevs, version, layout, NULL);
if ( layout )
free(layout);
@@ -1298,7 +1306,9 @@ int main(int argc, char **argv) {
break;
}
- image_dump = image_alloc_from_file(image_tmp_name(i), image_type_to_string(i), device_to_string(dev->detected_device), buf, ptr, NULL);
+ /* TODO: add support for dumping mmc layout and also other mmc partitions as image data parts */
+
+ image_dump = image_alloc_from_file(image_tmp_name(i), image_type_to_string(i), device_to_string(dev->detected_device), buf, ptr, NULL, NULL);
if ( ! image_dump )
continue;