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
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 972c4ed..0fab703 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -27,7 +27,7 @@
  */
 
 #include "fastboot.h"
-#include "make_ext4fs.h"
+#include "fs.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -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_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 @@
     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 @@
  */
 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 @@
         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 @@
     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 @@
             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() : "");