From e6f3e9bd2656fe132f829ed035fdea0cb111369d Mon Sep 17 00:00:00 2001 From: Dmitry Grinberg Date: Tue, 11 Mar 2014 18:28:15 -0700 Subject: [PATCH 1/3] fastboot: allow format on devices with small buffers Formatting large partitions on devices with small transfer buffers did not work before since format used a strange path through the code to send data. It now uses the normal path. Also cleaned up a bit. FS code now lives in a separate file and the custom path for format is gone. Change-Id: If4e01cabc2e250b7c02ca7ce8c268e51d49e1529 --- fastboot/Android.mk | 2 +- fastboot/engine.c | 209 ++------------------------------------------ fastboot/fastboot.c | 77 +++++++++++++++- fastboot/fastboot.h | 2 +- fastboot/fs.c | 56 ++++++++++++ fastboot/fs.h | 12 +++ 6 files changed, 149 insertions(+), 209 deletions(-) create mode 100644 fastboot/fs.c create mode 100644 fastboot/fs.h diff --git a/fastboot/Android.mk b/fastboot/Android.mk index b9b3c92cc..05ddf2ae9 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -18,7 +18,7 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils -LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c +LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c LOCAL_MODULE := fastboot LOCAL_MODULE_TAGS := debug LOCAL_CFLAGS += -std=gnu99 diff --git a/fastboot/engine.c b/fastboot/engine.c index 972c4ed01..0fab7035d 100644 --- a/fastboot/engine.c +++ b/fastboot/engine.c @@ -27,7 +27,7 @@ */ #include "fastboot.h" -#include "make_ext4fs.h" +#include "fs.h" #include #include @@ -51,9 +51,8 @@ #define OP_COMMAND 2 #define OP_QUERY 3 #define OP_NOTICE 4 -#define OP_FORMAT 5 -#define OP_DOWNLOAD_SPARSE 6 -#define OP_WAIT_FOR_DISCONNECT 7 +#define OP_DOWNLOAD_SPARSE 5 +#define OP_WAIT_FOR_DISCONNECT 6 typedef struct Action Action; @@ -79,14 +78,7 @@ static Action *action_list = 0; static Action *action_last = 0; -struct image_data { - long long partition_size; - long long image_size; // real size of image file - void *buffer; -}; -void generate_ext4_image(struct image_data *image); -void cleanup_image(struct image_data *image); int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { @@ -102,24 +94,6 @@ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) return fb_command_response(usb, cmd, response); } -struct generator { - char *fs_type; - - /* generate image and return it as image->buffer. - * size of the buffer returned as image->image_size. - * - * image->partition_size specifies what is the size of the - * file partition we generate image for. - */ - void (*generate)(struct image_data *image); - - /* it cleans the buffer allocated during image creation. - * this function probably does free() or munmap(). - */ - void (*cleanup)(struct image_data *image); -} generators[] = { - { "ext4", generate_ext4_image, cleanup_image } -}; /* Return true if this partition is supported by the fastboot format command. * It is also used to determine if we should first erase a partition before @@ -130,8 +104,7 @@ struct generator { */ int fb_format_supported(usb_handle *usb, const char *partition) { - char response[FB_RESPONSE_SZ+1]; - struct generator *generator = NULL; + char response[FB_RESPONSE_SZ + 1] = {0,}; int status; unsigned int i; @@ -140,18 +113,7 @@ int fb_format_supported(usb_handle *usb, const char *partition) return 0; } - for (i = 0; i < ARRAY_SIZE(generators); i++) { - if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) { - generator = &generators[i]; - break; - } - } - - if (generator) { - return 1; - } - - return 0; + return !!fs_get_generator(response); } static int cb_default(Action *a, int status, char *resp) @@ -205,163 +167,6 @@ void fb_queue_erase(const char *ptn) a->msg = mkmsg("erasing '%s'", ptn); } -/* Loads file content into buffer. Returns NULL on error. */ -static void *load_buffer(int fd, off_t size) -{ - void *buffer; - -#ifdef USE_MINGW - ssize_t count = 0; - - // mmap is more efficient but mingw does not support it. - // In this case we read whole image into memory buffer. - buffer = malloc(size); - if (!buffer) { - perror("malloc"); - return NULL; - } - - lseek(fd, 0, SEEK_SET); - while(count < size) { - ssize_t actually_read = read(fd, (char*)buffer+count, size-count); - - if (actually_read == 0) { - break; - } - if (actually_read < 0) { - if (errno == EINTR) { - continue; - } - perror("read"); - free(buffer); - return NULL; - } - - count += actually_read; - } -#else - buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (buffer == MAP_FAILED) { - perror("mmap"); - return NULL; - } -#endif - - return buffer; -} - -void cleanup_image(struct image_data *image) -{ -#ifdef USE_MINGW - free(image->buffer); -#else - munmap(image->buffer, image->image_size); -#endif -} - -void generate_ext4_image(struct image_data *image) -{ - int fd; - struct stat st; - - fd = fileno(tmpfile()); - make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL); - - fstat(fd, &st); - image->image_size = st.st_size; - image->buffer = load_buffer(fd, st.st_size); - - close(fd); -} - -int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) -{ - const char *partition = a->cmd; - char response[FB_RESPONSE_SZ+1]; - int status = 0; - struct image_data image; - struct generator *generator = NULL; - int fd; - unsigned i; - char cmd[CMD_SIZE]; - - status = fb_getvar(usb, response, "partition-type:%s", partition); - if (status) { - if (skip_if_not_supported) { - fprintf(stderr, - "Erase successful, but not automatically formatting.\n"); - fprintf(stderr, - "Can't determine partition type.\n"); - return 0; - } - fprintf(stderr,"FAILED (%s)\n", fb_get_error()); - return status; - } - - for (i = 0; i < ARRAY_SIZE(generators); i++) { - if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) { - generator = &generators[i]; - break; - } - } - if (!generator) { - if (skip_if_not_supported) { - fprintf(stderr, - "Erase successful, but not automatically formatting.\n"); - fprintf(stderr, - "File system type %s not supported.\n", response); - return 0; - } - fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n", - response); - return -1; - } - - status = fb_getvar(usb, response, "partition-size:%s", partition); - if (status) { - if (skip_if_not_supported) { - fprintf(stderr, - "Erase successful, but not automatically formatting.\n"); - fprintf(stderr, "Unable to get partition size\n."); - return 0; - } - fprintf(stderr,"FAILED (%s)\n", fb_get_error()); - return status; - } - image.partition_size = strtoll(response, (char **)NULL, 16); - - generator->generate(&image); - if (!image.buffer) { - fprintf(stderr,"Cannot generate image.\n"); - return -1; - } - - // Following piece of code is similar to fb_queue_flash() but executes - // actions directly without queuing - fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024); - status = fb_download_data(usb, image.buffer, image.image_size); - if (status) goto cleanup; - - fprintf(stderr, "writing '%s'...\n", partition); - snprintf(cmd, sizeof(cmd), "flash:%s", partition); - status = fb_command(usb, cmd); - if (status) goto cleanup; - -cleanup: - generator->cleanup(&image); - - return status; -} - -void fb_queue_format(const char *partition, int skip_if_not_supported) -{ - Action *a; - - a = queue_action(OP_FORMAT, partition); - a->data = (void*)skip_if_not_supported; - a->msg = mkmsg("formatting '%s' partition", partition); -} - void fb_queue_flash(const char *ptn, void *data, unsigned sz) { Action *a; @@ -589,10 +394,6 @@ int fb_execute_queue(usb_handle *usb) if (status) break; } else if (a->op == OP_NOTICE) { fprintf(stderr,"%s\n",(char*)a->data); - } else if (a->op == OP_FORMAT) { - status = fb_format(a, usb, (int)a->data); - status = a->func(a, status, status ? fb_get_error() : ""); - if (status) break; } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 7d26c6fb6..7f49ae91d 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -49,6 +49,7 @@ #include #include "fastboot.h" +#include "fs.h" #ifndef O_BINARY #define O_BINARY 0 @@ -622,10 +623,13 @@ static int load_buf_fd(usb_handle *usb, int fd, void *data; int64_t limit; + sz64 = file_size(fd); if (sz64 < 0) { return -1; } + + lseek(fd, 0, SEEK_SET); limit = get_sparse_limit(usb, sz64); if (limit) { struct sparse_file **s = load_sparse_files(fd, limit); @@ -872,6 +876,73 @@ static int64_t parse_num(const char *arg) return num; } +void fb_perform_format(const char *partition, int skip_if_not_supported) +{ + char pType[FB_RESPONSE_SZ + 1], pSize[FB_RESPONSE_SZ + 1]; + unsigned int limit = INT_MAX; + struct fastboot_buffer buf; + const char *errMsg = NULL; + const struct fs_generator *gen; + uint64_t pSz; + int status; + int fd; + + if (target_sparse_limit > 0 && target_sparse_limit < limit) + limit = target_sparse_limit; + if (sparse_limit > 0 && sparse_limit < limit) + limit = sparse_limit; + + status = fb_getvar(usb, pType, "partition-type:%s", partition); + if (status) { + errMsg = "Can't determine partition type.\n"; + goto failed; + } + + status = fb_getvar(usb, pSize, "partition-size:%s", partition); + if (status) { + errMsg = "Unable to get partition size\n"; + goto failed; + } + + gen = fs_get_generator(pType); + if (!gen) { + if (skip_if_not_supported) { + fprintf(stderr, "Erase successful, but not automatically formatting.\n"); + fprintf(stderr, "File system type %s not supported.\n", pType); + return; + } + fprintf(stderr, "Formatting is not supported for filesystem with type '%s'.\n", pType); + return; + } + + pSz = strtoll(pSize, (char **)NULL, 16); + + fd = fileno(tmpfile()); + if (fs_generator_generate(gen, fd, pSz)) { + close(fd); + fprintf(stderr, "Cannot generate image.\n"); + return; + } + + if (load_buf_fd(usb, fd, &buf)) { + fprintf(stderr, "Cannot read image.\n"); + close(fd); + return; + } + flash_buf(partition, &buf); + + return; + + +failed: + if (skip_if_not_supported) { + fprintf(stderr, "Erase successful, but not automatically formatting.\n"); + if (errMsg) + fprintf(stderr, "%s", errMsg); + } + fprintf(stderr,"FAILED (%s)\n", fb_get_error()); +} + int main(int argc, char **argv) { int wants_wipe = 0; @@ -1004,7 +1075,7 @@ int main(int argc, char **argv) if (erase_first && needs_erase(argv[1])) { fb_queue_erase(argv[1]); } - fb_queue_format(argv[1], 0); + fb_perform_format(argv[1], 0); skip(2); } else if(!strcmp(*argv, "signature")) { require(2); @@ -1092,9 +1163,9 @@ int main(int argc, char **argv) if (wants_wipe) { fb_queue_erase("userdata"); - fb_queue_format("userdata", 1); + fb_perform_format("userdata", 1); fb_queue_erase("cache"); - fb_queue_format("cache", 1); + fb_perform_format("cache", 1); } if (wants_reboot) { fb_queue_reboot(); diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index 976c397ee..c510a3634 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -49,7 +49,7 @@ int fb_format_supported(usb_handle *usb, const char *partition); void fb_queue_flash(const char *ptn, void *data, unsigned sz); void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz); void fb_queue_erase(const char *ptn); -void fb_queue_format(const char *ptn, int skip_if_not_supported); +void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz); void fb_queue_require(const char *prod, const char *var, int invert, unsigned nvalues, const char **value); void fb_queue_display(const char *var, const char *prettyname); diff --git a/fastboot/fs.c b/fastboot/fs.c new file mode 100644 index 000000000..6a1f9e61e --- /dev/null +++ b/fastboot/fs.c @@ -0,0 +1,56 @@ +#include "fastboot.h" +#include "make_ext4fs.h" +#include "fs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_MINGW +#include +#else +#include +#endif + + + +static int generate_ext4_image(int fd, long long partSize) +{ + make_ext4fs_sparse_fd(fd, partSize, NULL, NULL); + + return 0; +} + +static const struct fs_generator { + + char *fs_type; //must match what fastboot reports for partition type + int (*generate)(int fd, long long partSize); //returns 0 or error value + +} generators[] = { + + { "ext4", generate_ext4_image} + +}; + +const struct fs_generator* fs_get_generator(const char* name) +{ + unsigned i; + + for (i = 0; i < sizeof(generators) / sizeof(*generators); i++) + if (!strcmp(generators[i].fs_type, name)) + return generators + i; + + return NULL; +} + +int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize) +{ + return gen->generate(tmpFileNo, partSize); +} diff --git a/fastboot/fs.h b/fastboot/fs.h new file mode 100644 index 000000000..65b955563 --- /dev/null +++ b/fastboot/fs.h @@ -0,0 +1,12 @@ +#ifndef _FS_H_ +#define _FH_H_ + +#include + +struct fs_generator; + +const struct fs_generator* fs_get_generator(const char* name); +int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize); + +#endif + From 82280594ef7e9dc908aa67f3da8661ff54a96c9e Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 29 Apr 2014 13:45:05 -0700 Subject: [PATCH 2/3] fastboot: Fixed optional entries Previously, if an image was listed as optional, but was not found, flashall would fail. Now it will proceed if optional images are not present. Change-Id: Ic82595cf0cd6ddce4c676de590f03f1a95f32040 Signed-off-by: Daniel Rosenberg --- fastboot/fastboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 7f49ae91d..79d016686 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -657,7 +657,7 @@ static int load_buf(usb_handle *usb, const char *fname, fd = open(fname, O_RDONLY | O_BINARY); if (fd < 0) { - die("cannot open '%s'\n", fname); + return -1; } return load_buf_fd(usb, fd, buf); From 73a4ad288ffdabfbdac0930737def7fdcf65d07c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 29 Apr 2014 13:54:19 -0700 Subject: [PATCH 3/3] fastboot: Added tos as an optional image Change-Id: Ibff1f74ee4a949501ceae0b897f896067f022763 Signed-off-by: Daniel Rosenberg --- fastboot/fastboot.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 79d016686..f98268e4f 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -100,10 +100,11 @@ static struct { char sig_name[13]; char part_name[9]; bool is_optional; -} images[3] = { +} images[4] = { {"boot.img", "boot.sig", "boot", false}, {"recovery.img", "recovery.sig", "recovery", true}, {"system.img", "system.sig", "system", false}, + {"tos.img", "tos.sig", "tos", true}, }; void get_my_path(char *path); @@ -120,6 +121,8 @@ char *find_item(const char *item, const char *product) fn = "recovery.img"; } else if(!strcmp(item,"system")) { fn = "system.img"; + } else if(!strcmp(item,"tos")) { + fn = "tos.img"; } else if(!strcmp(item,"userdata")) { fn = "userdata.img"; } else if(!strcmp(item,"cache")) { @@ -285,7 +288,7 @@ void usage(void) "\n" "commands:\n" " update reflash device from update.zip\n" - " flashall flash boot + recovery + system\n" + " flashall flash boot, system, and if found, recovery, tos\n" " flash [ ] write a file to a flash partition\n" " erase erase a flash partition\n" " format format a flash partition \n"