Loading fastboot/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading fastboot/engine.c +5 −204 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ */ #include "fastboot.h" #include "make_ext4fs.h" #include "fs.h" #include <errno.h> #include <stdio.h> Loading @@ -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; Loading @@ -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, ...) { Loading @@ -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 Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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() : ""); Loading fastboot/fastboot.c +74 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <zipfile/zipfile.h> #include "fastboot.h" #include "fs.h" #ifndef O_BINARY #define O_BINARY 0 Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -1000,7 +1071,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); Loading Loading @@ -1088,9 +1159,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(); Loading fastboot/fastboot.h +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading fastboot/fs.c 0 → 100644 +56 −0 Original line number Diff line number Diff line #include "fastboot.h" #include "make_ext4fs.h" #include "fs.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sparse/sparse.h> #include <unistd.h> #ifdef USE_MINGW #include <fcntl.h> #else #include <sys/mman.h> #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); } Loading
fastboot/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
fastboot/engine.c +5 −204 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ */ #include "fastboot.h" #include "make_ext4fs.h" #include "fs.h" #include <errno.h> #include <stdio.h> Loading @@ -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; Loading @@ -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, ...) { Loading @@ -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 Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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() : ""); Loading
fastboot/fastboot.c +74 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <zipfile/zipfile.h> #include "fastboot.h" #include "fs.h" #ifndef O_BINARY #define O_BINARY 0 Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -1000,7 +1071,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); Loading Loading @@ -1088,9 +1159,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(); Loading
fastboot/fastboot.h +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
fastboot/fs.c 0 → 100644 +56 −0 Original line number Diff line number Diff line #include "fastboot.h" #include "make_ext4fs.h" #include "fs.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sparse/sparse.h> #include <unistd.h> #ifdef USE_MINGW #include <fcntl.h> #else #include <sys/mman.h> #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); }