image: Add support for opening one image from multiple files

This commit is contained in:
Pali Rohár committed 2023-04-15 21:55:48 +02:00
1 parent fa8a03ec5e
commit add1ae03aa
3 files changed
+223 -88

No files matched your search

+208 -80
View File
@@ -30,9 +30,6 @@
#include "device.h" #include "device.h"
#include "image.h" #include "image.h"
#define IMAGE_STORE_CUR(image) do { if ( image->is_shared_fd ) { image->cur = lseek(image->fd, 0, SEEK_CUR) - image->offset; if ( image->cur > image->size ) image->cur = image->size; } } while (0)
#define IMAGE_RESTORE_CUR(image) do { if ( image->is_shared_fd ) { if ( image->cur <= image->size ) lseek(image->fd, image->offset + image->cur, SEEK_SET); else lseek(image->fd, image->offset + image->size, SEEK_SET); } } while (0)
/* format: type-device:hwrevs_version */ /* format: type-device:hwrevs_version */
static void image_missing_values_from_name(struct image * image, const char * name) { static void image_missing_values_from_name(struct image * image, const char * name) {
@@ -238,20 +235,34 @@ static int image_append(struct image * image, const char * type, const char * de
static void image_align(struct image * image) { static void image_align(struct image * image) {
size_t align; struct image_fd * image_fd = image->fds;
size_t align, aligned_size;
uint32_t total_size;
if ( image->type == IMAGE_MMC ) if ( image->type == IMAGE_MMC )
align = 8; align = 8;
else else
align = 7; align = 7;
if ( ( image->size & ( ( 1ULL << align ) - 1 ) ) == 0 ) if ( image_fd && ! image_fd->next && image->size == image_fd->size && ( image->size & ( ( 1ULL << align ) - 1 ) ) == 0 )
return; return;
align = ((image->size >> align) + 1) << align; total_size = 0;
image->align = align - image->size; while ( image_fd ) {
image->size = align;
if ( ( image_fd->size & ( ( 1ULL << align ) - 1 ) ) != 0 ) {
aligned_size = ((image_fd->size >> align) + 1) << align;
image_fd->align = aligned_size - image_fd->size;
image_fd->size = aligned_size;
}
total_size += image_fd->size;
image_fd = image_fd->next;
}
image->size = total_size;
image->hash = image_hash_from_data(image); image->hash = image_hash_from_data(image);
@@ -268,56 +279,98 @@ 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_part * parts) { 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; return image_alloc_from_files(&file, 1, type, device, hwrevs, version, layout, parts);
fd = open(file, O_RDONLY); }
if ( fd < 0 ) {
ERROR_INFO("Cannot open image file %s", file); struct image * image_alloc_from_files(const char ** files, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
struct image * image;
int i;
int * fds = calloc(count, sizeof(int));
if ( ! fds )
ALLOC_ERROR_RETURN(NULL);
for ( i = 0; i < count; ++i ) {
fds[i] = open(files[i], O_RDONLY);
if ( fds[i] < 0 ) {
ERROR_INFO("Cannot open image file %s", files[i]);
free(fds);
return NULL; return NULL;
} }
}
return image_alloc_from_fd(fd, file, type, device, hwrevs, version, layout, parts); image = image_alloc_from_fds(fds, files, count, type, device, hwrevs, version, layout, parts);
free(fds);
return image;
} }
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_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; return image_alloc_from_fds(&fd, &orig_filename, 1, type, device, hwrevs, version, layout, parts);
}
struct image * image_alloc_from_fds(int * fds, const char ** orig_filenames, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
int i;
struct image * image = image_alloc(); struct image * image = image_alloc();
if ( ! image ) { if ( ! image ) {
close(fd); for ( i = 0; i < count; ++i )
close(fds[i]);
return NULL; return NULL;
} }
image->is_shared_fd = 0; for ( i = 0; i < count; ++i ) {
image->fd = fd;
offset = lseek(image->fd, 0, SEEK_END); off_t offset;
struct image_fd * image_fds = image->fds;
struct image_fd * image_fd = calloc(1, sizeof(struct image_fd));
if ( ! image_fd ) {
image_free(image);
return NULL;
}
if ( ! image_fds ) {
image->fds = image_fd;
} else {
while ( image_fds->next )
image_fds = image_fds->next;
image_fds->next = image_fd;
}
image_fd->is_shared_fd = 0;
image_fd->fd = fds[i];
offset = lseek(image_fd->fd, 0, SEEK_END);
if ( offset == (off_t)-1 ) { if ( offset == (off_t)-1 ) {
ERROR_INFO("Cannot seek to end of file %s", orig_filename); ERROR_INFO("Cannot seek to end of file %s", orig_filenames[i]);
close(image->fd); image_free(image);
free(image);
return NULL; return NULL;
} }
image->size = offset; image_fd->size = offset;
image->offset = 0; image_fd->offset = 0;
image->cur = 0; image_fd->is_shared_fd = 0;
image->orig_filename = strdup(orig_filename); image_fd->shared_cur = 0;
image_fd->orig_filename = strdup(orig_filenames[i]);
if ( lseek(image->fd, 0, SEEK_SET) == (off_t)-1 ) { image->size += image_fd->size;
ERROR_INFO("Cannot seek to begin of file %s", orig_filename);
close(image->fd); if ( lseek(image_fd->fd, 0, SEEK_SET) == (off_t)-1 ) {
free(image->orig_filename); ERROR_INFO("Cannot seek to begin of file %s", orig_filenames[i]);
free(image); image_free(image);
return NULL; return NULL;
} }
}
if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 ) if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
return NULL; return NULL;
if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) ) if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) )
image_missing_values_from_name(image, orig_filename); image_missing_values_from_name(image, count > 0 ? orig_filenames[0] : NULL);
image_align(image); image_align(image);
@@ -328,14 +381,20 @@ 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_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) {
struct image * image = image_alloc(); struct image * image = image_alloc();
if ( ! image ) struct image_fd * image_fd = calloc(1, sizeof(struct image_fd));
if ( ! image || ! image_fd ) {
free(image);
free(image_fd);
return NULL; return NULL;
}
image->is_shared_fd = 1; image_fd->is_shared_fd = 1;
image->fd = fd; image_fd->fd = fd;
image->size = size; image_fd->size = size;
image->offset = offset; image_fd->offset = offset;
image->cur = 0; image_fd->shared_cur = 0;
image->fds = image_fd;
image->size = image_fd->size;
if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 ) if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
return NULL; return NULL;
@@ -357,9 +416,13 @@ void image_free(struct image * image) {
if ( ! image ) if ( ! image )
return; return;
if ( ! image->is_shared_fd ) { while ( image->fds ) {
close(image->fd); struct image_fd * next = image->fds->next;
image->fd = -1; if ( ! image->fds->is_shared_fd )
close(image->fds->fd);
free(image->fds->orig_filename);
free(image->fds);
image->fds = next;
} }
while ( image->devices ) { while ( image->devices ) {
@@ -378,7 +441,6 @@ void image_free(struct image * image) {
free(image->version); free(image->version);
free(image->layout); free(image->layout);
free(image->orig_filename);
free(image); free(image);
@@ -387,74 +449,119 @@ void image_free(struct image * image) {
void image_seek(struct image * image, size_t whence) { void image_seek(struct image * image, size_t whence) {
off_t offset; off_t offset;
size_t start = 0;
struct image_fd * image_fd = image->fds;
if ( whence > image->size ) image->cur = whence;
if ( whence > image->size ) {
ERROR("Seek in image failed: Position end of the image");
return; return;
}
if ( whence >= image->size - image->align ) { while ( image_fd ) {
offset = lseek(image->fd, image->size - image->align - 1, SEEK_SET); if ( ( whence >= start && whence < start + image_fd->size ) || ! image_fd->next )
image->acur = whence - ( image->size - image->align ); break;
start += image_fd->size;
image_fd = image_fd->next;
}
if ( whence - start >= image_fd->size - image_fd->align ) {
offset = lseek(image_fd->fd, image_fd->size - image_fd->align, SEEK_SET);
} else { } else {
offset = lseek(image->fd, image->offset + whence, SEEK_SET); offset = lseek(image_fd->fd, image_fd->offset + whence - start, SEEK_SET);
image->acur = 0;
} }
if ( offset == (off_t)-1 ) if ( offset == (off_t)-1 )
ERROR_INFO("Seek in file %s failed", (image->orig_filename ? image->orig_filename : "(unknown)")); ERROR_INFO("Seek in file %s failed", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
else if ( image_fd->is_shared_fd )
IMAGE_STORE_CUR(image); image_fd->shared_cur = offset;
} }
size_t image_read(struct image * image, void * buf, size_t count) { size_t image_read(struct image * image, void * buf, size_t count) {
size_t cur;
ssize_t ret; ssize_t ret;
off_t offset; off_t offset;
size_t new_count = 0; size_t new_count = 0;
size_t ret_count = 0; size_t ret_count = 0;
size_t start = 0;
struct image_fd * image_fd = image->fds;
IMAGE_RESTORE_CUR(image); while ( image_fd ) {
if ( ( image->cur >= start && image->cur < start + image_fd->size ) || ! image_fd->next )
break;
start += image_fd->size;
image_fd = image_fd->next;
}
if ( ! image->is_shared_fd || image->cur < image->size - image->align ) { if ( image_fd->is_shared_fd ) {
if ( lseek(image_fd->fd, image_fd->shared_cur, SEEK_SET) != image_fd->shared_cur ) {
ERROR_INFO("Cannot restore offset of file %s", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
return 0;
}
}
if ( image->is_shared_fd && image->cur + count > image->size - image->align ) while ( count > 0 ) {
new_count = image->size - image->align - image->cur;
if ( image->cur < start + image_fd->size - image_fd->align ) {
if ( image->cur + count > start + image_fd->size - image_fd->align )
new_count = start + image_fd->size - image_fd->align - image->cur;
else else
new_count = count; new_count = count;
ret = read(image->fd, buf, new_count); ret = read(image_fd->fd, buf, new_count);
if ( ret > 0 ) if ( ret <= 0 )
break;
count -= ret;
buf = (unsigned char *)buf + ret;
ret_count += ret; ret_count += ret;
image->cur += ret;
IMAGE_STORE_CUR(image); if ( image_fd->is_shared_fd )
image_fd->shared_cur += ret;
if ( ret < 0 ) if ( (size_t)ret != new_count )
return 0; continue;
} }
if ( ret_count == count ) if ( image_fd->align > 0 && count > 0 ) {
return ret_count;
offset = lseek(image->fd, 0, SEEK_CUR); if ( count > image_fd->align )
if ( offset == (off_t)-1 ) { new_count = image_fd->align;
ERROR_INFO("Cannot get offset of file %s", (image->orig_filename ? image->orig_filename : "(unknown)"));
return 0;
}
cur = offset - image->offset;
if ( image->align && cur == image->size - image->align && image->acur < image->align ) {
if ( image->acur + count - ret_count > image->align )
new_count = image->align - image->acur;
else else
new_count = count - ret_count; new_count = count;
memset((unsigned char *)buf+ret_count, 0xFF, new_count); memset(buf, 0xFF, new_count);
ret_count += new_count; ret = new_count;
image->acur += new_count;
count -= ret;
buf = (unsigned char *)buf + ret;
ret_count += ret;
image->cur += ret;
}
if ( image->cur == start + image_fd->size ) {
start += image_fd->size;
image_fd = image_fd->next;
if ( ! image_fd )
break;
offset = lseek(image_fd->fd, image_fd->offset, SEEK_SET);
if ( offset == (off_t)-1 ) {
ERROR_INFO("Seek in file %s failed", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
break;
} else if ( image_fd->is_shared_fd ) {
image_fd->shared_cur = offset;
}
}
} }
@@ -638,11 +745,18 @@ int image_hwrev_is_valid(struct image * image, int16_t hwrev) {
void image_print_info(struct image * image) { void image_print_info(struct image * image) {
int i = 0;
const char * str; const char * str;
struct image_fd * image_fd = image->fds;
struct image_part * part = image->parts;
struct device_list * device = image->devices; struct device_list * device = image->devices;
if ( image->orig_filename ) if ( image->fds && image->fds->orig_filename ) {
printf("File: %s\n", image->orig_filename); if ( image->fds->next )
printf("Multifile image:\n");
else
printf("File: %s\n", image->fds->orig_filename);
}
str = image_type_to_string(image->type); str = image_type_to_string(image->type);
printf(" Image type: %s\n", str ? str : "unknown"); printf(" Image type: %s\n", str ? str : "unknown");
@@ -654,6 +768,20 @@ void image_print_info(struct image * image) {
if ( image->layout ) if ( image->layout )
printf(" Image layout: included\n"); printf(" Image layout: included\n");
while ( part ) {
if ( image->fds && image->fds->orig_filename && image->fds->next )
printf("File: %s\n", (image_fd && image_fd->orig_filename) ? image_fd->orig_filename : "(unknown)");
printf(" Image part %d name: %s\n", i, part->name ? part->name : "(empty)");
printf(" Image part %d size: %d bytes\n", i, part->size);
part = part->next;
image_fd = image_fd ? image_fd->next : NULL;
++i;
}
while ( device ) { while ( device ) {
char * str2 = NULL; char * str2 = NULL;
+14 -7
View File
@@ -50,6 +50,17 @@ struct image_part {
char * name; char * name;
}; };
struct image_fd {
struct image_fd * next;
int fd;
int is_shared_fd;
off_t shared_cur;
uint32_t size;
uint32_t align;
size_t offset;
char * orig_filename;
};
struct image { struct image {
enum image_type type; enum image_type type;
struct device_list * devices; struct device_list * devices;
@@ -58,14 +69,8 @@ struct image {
uint16_t hash; uint16_t hash;
uint32_t size; uint32_t size;
struct image_part * parts; struct image_part * parts;
struct image_fd * fds;
int fd;
int is_shared_fd;
uint32_t align;
size_t offset;
size_t cur; size_t cur;
size_t acur;
char * orig_filename;
}; };
struct image_list { struct image_list {
@@ -75,7 +80,9 @@ struct image_list {
}; };
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_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_files(const char ** files, int count, 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_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_fds(int * fds, const char ** orig_filenames, int count, 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); 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_free(struct image * image);
void image_seek(struct image * image, size_t whence); void image_seek(struct image * image, size_t whence);
+1 -1
View File
@@ -837,7 +837,7 @@ int main(int argc, char **argv) {
while ( image_ptr ) { while ( image_ptr ) {
struct image_list * next = image_ptr->next; struct image_list * next = image_ptr->next;
if ( image_ptr->image->type == IMAGE_UNKNOWN ) { if ( image_ptr->image->type == IMAGE_UNKNOWN ) {
WARNING("Removing unknown image (specified by %s %s)", image_ptr->image->orig_filename ? "file" : "fiasco", image_ptr->image->orig_filename ? image_ptr->image->orig_filename : "image"); WARNING("Removing unknown image (specified by %s %s)", (image_ptr->image->fds && image_ptr->image->fds->orig_filename) ? "file" : "fiasco", (image_ptr->image->fds && image_ptr->image->fds->orig_filename) ? image_ptr->image->fds->orig_filename : "image");
if ( image_ptr == image_first ) if ( image_ptr == image_first )
image_first = next; image_first = next;
if ( fiasco_in && image_ptr == fiasco_in->first ) if ( fiasco_in && image_ptr == fiasco_in->first )