void do_update(usb_handle *usb, char *fn, int erase_first)
{
    void *zdata;
    unsigned zsize;
    void *data;
    unsigned sz;
    zipfile_t zip;
    int fd;
    int rc;
    struct fastboot_buffer buf;
    size_t i;

    queue_info_dump();

    fb_queue_query_save("product", cur_product, sizeof(cur_product));

    zdata = load_file(fn, &zsize);
    if (zdata == 0) die("failed to load '%s': %s", fn, strerror(errno));

    zip = init_zipfile(zdata, zsize);
    if(zip == 0) die("failed to access zipdata in '%s'");

    data = unzip_file(zip, "android-info.txt", &sz);
    if (data == 0) {
        char *tmp;
        /* fallback for older zipfiles */
        data = unzip_file(zip, "android-product.txt", &sz);
        if ((data == 0) || (sz < 1)) {
            die("update package has no android-info.txt or android-product.txt");
        }
        tmp = malloc(sz + 128);
        if (tmp == 0) die("out of memory");
        sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
        data = tmp;
        sz = strlen(tmp);
    }

    setup_requirements(data, sz);

    for (i = 0; i < ARRAY_SIZE(images); i++) {
        fd = unzip_to_file(zip, images[i].img_name);
        if (fd < 0) {
            if (images[i].is_optional)
                continue;
            die("update package missing %s", images[i].img_name);
        }
        rc = load_buf_fd(usb, fd, &buf);
        if (rc) die("cannot load %s from flash", images[i].img_name);
        do_update_signature(zip, images[i].sig_name);
        if (erase_first && needs_erase(images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }
        flash_buf(images[i].part_name, &buf);
        /* not closing the fd here since the sparse code keeps the fd around
         * but hasn't mmaped data yet. The tmpfile will get cleaned up when the
         * program exits.
         */
    }
}
static int load_buf(usb_handle *usb, const char *fname,
        struct fastboot_buffer *buf)
{
    int fd;

    fd = open(fname, O_RDONLY | O_BINARY);
    if (fd < 0) {
        return -1;
    }

    return load_buf_fd(usb, fd, buf);
}
void do_update(usb_handle *usb, const char *filename, int erase_first)
{
    queue_info_dump();

    fb_queue_query_save("product", cur_product, sizeof(cur_product));

    ZipArchiveHandle zip;
    int error = OpenArchive(filename, &zip);
    if (error != 0) {
        CloseArchive(zip);
        die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
    }

    unsigned sz;
    void* data = unzip_file(zip, "android-info.txt", &sz);
    if (data == 0) {
        CloseArchive(zip);
        die("update package '%s' has no android-info.txt", filename);
    }

    setup_requirements(reinterpret_cast<char*>(data), sz);

    for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
        int fd = unzip_to_file(zip, images[i].img_name);
        if (fd == -1) {
            if (images[i].is_optional) {
                continue;
            }
            CloseArchive(zip);
            exit(1); // unzip_to_file already explained why.
        }
        fastboot_buffer buf;
        int rc = load_buf_fd(usb, fd, &buf);
        if (rc) die("cannot load %s from flash", images[i].img_name);
        do_update_signature(zip, images[i].sig_name);
        if (erase_first && needs_erase(usb, images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }
        flash_buf(images[i].part_name, &buf);
        /* not closing the fd here since the sparse code keeps the fd around
         * but hasn't mmaped data yet. The tmpfile will get cleaned up when the
         * program exits.
         */
    }

    CloseArchive(zip);
}
void fb_perform_format(usb_handle* usb,
                       const char *partition, int skip_if_not_supported,
                       const char *type_override, const char *size_override)
{
    char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
    char *pType = pTypeBuff;
    char *pSize = pSizeBuff;
    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;
    }
    if (type_override) {
        if (strcmp(type_override, pType)) {
            fprintf(stderr,
                    "Warning: %s type is %s, but %s was requested for formating.\n",
                    partition, pType, type_override);
        }
        pType = (char *)type_override;
    }

    status = fb_getvar(usb, pSize, "partition-size:%s", partition);
    if (status) {
        errMsg = "Unable to get partition size\n";
        goto failed;
    }
    if (size_override) {
        if (strcmp(size_override, pSize)) {
            fprintf(stderr,
                    "Warning: %s size is %s, but %s was requested for formating.\n",
                    partition, pSize, size_override);
        }
        pSize = (char *)size_override;
    }

    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());
}