void nand_add_dev(const char *arg) { uint64_t dev_size = 0; const char *next_arg; const char *value; size_t arg_len, value_len; nand_dev *new_devs, *dev; char *devname = NULL; size_t devname_len = 0; char *initfilename = NULL; char *rwfilename = NULL; int initfd = -1; int rwfd = -1; int read_only = 0; int pad; ssize_t read_size; uint32_t page_size = 2048; uint32_t extra_size = 64; uint32_t erase_pages = 64; VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg); while(arg) { next_arg = strchr(arg, ','); value = strchr(arg, '='); if(next_arg != NULL) { arg_len = next_arg - arg; next_arg++; if(value >= next_arg) value = NULL; } else arg_len = strlen(arg); if(value != NULL) { size_t new_arg_len = value - arg; value_len = arg_len - new_arg_len - 1; arg_len = new_arg_len; value++; } else value_len = 0; if(devname == NULL) { if(value != NULL) goto bad_arg_and_value; devname_len = arg_len; devname = malloc(arg_len+1); if(devname == NULL) goto out_of_memory; memcpy(devname, arg, arg_len); devname[arg_len] = 0; } else if(value == NULL) { if(arg_match("readonly", arg, arg_len)) { read_only = 1; } else { XLOG("bad arg: %.*s\n", arg_len, arg); exit(1); } } else { if(arg_match("size", arg, arg_len)) { char *ep; dev_size = strtoull(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("pagesize", arg, arg_len)) { char *ep; page_size = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("extrasize", arg, arg_len)) { char *ep; extra_size = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("erasepages", arg, arg_len)) { char *ep; erase_pages = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("initfile", arg, arg_len)) { initfilename = malloc(value_len + 1); if(initfilename == NULL) goto out_of_memory; memcpy(initfilename, value, value_len); initfilename[value_len] = '\0'; } else if(arg_match("file", arg, arg_len)) { rwfilename = malloc(value_len + 1); if(rwfilename == NULL) goto out_of_memory; memcpy(rwfilename, value, value_len); rwfilename[value_len] = '\0'; } else { goto bad_arg_and_value; } } arg = next_arg; } if (rwfilename == NULL) { /* we create a temporary file to store everything */ TempFile* tmp = tempfile_create(); if (tmp == NULL) { XLOG("could not create temp file for %.*s NAND disk image: %s\n", devname_len, devname, strerror(errno)); exit(1); } rwfilename = (char*) tempfile_path(tmp); if (VERBOSE_CHECK(init)) dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename); } if(rwfilename) { if (initfilename) { /* Overwrite with content of the 'initfilename'. */ if (read_only) { /* Cannot be readonly when initializing the device from another file. */ XLOG("incompatible read only option is requested while initializing %.*s from %s\n", devname_len, devname, initfilename); exit(1); } rwfd = open(rwfilename, O_BINARY | O_TRUNC | O_RDWR); } else { rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR)); } if(rwfd < 0) { XLOG("could not open file %s, %s\n", rwfilename, strerror(errno)); exit(1); } /* this could be a writable temporary file. use atexit_close_fd to ensure * that it is properly cleaned up at exit on Win32 */ if (!read_only) atexit_close_fd(rwfd); } if(initfilename) { initfd = open(initfilename, O_BINARY | O_RDONLY); if(initfd < 0) { XLOG("could not open file %s, %s\n", initfilename, strerror(errno)); exit(1); } if(dev_size == 0) { dev_size = do_lseek(initfd, 0, SEEK_END); do_lseek(initfd, 0, SEEK_SET); } } new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1)); if(new_devs == NULL) goto out_of_memory; nand_devs = new_devs; dev = &new_devs[nand_dev_count]; dev->page_size = page_size; dev->extra_size = extra_size; dev->erase_size = erase_pages * (page_size + extra_size); pad = dev_size % dev->erase_size; if (pad != 0) { dev_size += (dev->erase_size - pad); D("rounding devsize up to a full eraseunit, now %llx\n", dev_size); } dev->devname = devname; dev->devname_len = devname_len; dev->max_size = dev_size; dev->data = malloc(dev->erase_size); if(dev->data == NULL) goto out_of_memory; dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0; #ifdef TARGET_I386 dev->flags |= NAND_DEV_FLAG_BATCH_CAP; #endif if (initfd >= 0) { do { read_size = do_read(initfd, dev->data, dev->erase_size); if(read_size < 0) { XLOG("could not read file %s, %s\n", initfilename, strerror(errno)); exit(1); } if(do_write(rwfd, dev->data, read_size) != read_size) { XLOG("could not write file %s, %s\n", rwfilename, strerror(errno)); exit(1); } } while(read_size == dev->erase_size); close(initfd); } dev->fd = rwfd; nand_dev_count++; return; out_of_memory: XLOG("out of memory\n"); exit(1); bad_arg_and_value: XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value); exit(1); }
void nand_add_dev(const char *arg) { uint64_t dev_size = 0; const char *next_arg; const char *value; size_t arg_len, value_len; nand_dev *new_devs, *dev; char *devname = NULL; size_t devname_len = 0; char *initfilename = NULL; char *rwfilename = NULL; int initfd = -1; int rwfd = -1; int read_only = 0; int pad; ssize_t read_size; uint32_t page_size = 2048; uint32_t extra_size = 64; uint32_t erase_pages = 64; //VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg); while(arg) { next_arg = strchr(arg, ','); value = strchr(arg, '='); if(next_arg != NULL) { arg_len = next_arg - arg; next_arg++; if(value >= next_arg) value = NULL; } else arg_len = strlen(arg); if(value != NULL) { size_t new_arg_len = value - arg; value_len = arg_len - new_arg_len - 1; arg_len = new_arg_len; value++; } else value_len = 0; if(devname == NULL) { if(value != NULL) goto bad_arg_and_value; devname_len = arg_len; devname = malloc(arg_len+1); if(devname == NULL) goto out_of_memory; memcpy(devname, arg, arg_len); devname[arg_len] = 0; } else if(value == NULL) { if(arg_match("readonly", arg, arg_len)) { read_only = 1; } else { XLOG("bad arg: %.*s\n", arg_len, arg); exit(1); } } else { if(arg_match("size", arg, arg_len)) { char *ep; dev_size = strtoull(value, &ep, 0); D("Dev size 0x%X came from argument\n", dev_size); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("pagesize", arg, arg_len)) { char *ep; page_size = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("extrasize", arg, arg_len)) { char *ep; extra_size = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("erasepages", arg, arg_len)) { char *ep; erase_pages = strtoul(value, &ep, 0); if(ep != value + value_len) goto bad_arg_and_value; } else if(arg_match("initfile", arg, arg_len)) { initfilename = malloc(value_len + 1); if(initfilename == NULL) goto out_of_memory; memcpy(initfilename, value, value_len); initfilename[value_len] = '\0'; } else if(arg_match("file", arg, arg_len)) { rwfilename = malloc(value_len + 1); if(rwfilename == NULL) goto out_of_memory; memcpy(rwfilename, value, value_len); rwfilename[value_len] = '\0'; } else { goto bad_arg_and_value; } } arg = next_arg; } if (rwfilename == NULL) { /* we create a temporary file to store everything */ TempFile* tmp = tempfile_create(); if (tmp == NULL) { XLOG("could not create temp file for %.*s NAND disk image: %s\n", devname_len, devname, strerror(errno)); exit(1); } rwfilename = (char*) tempfile_path(tmp); // if (VERBOSE_CHECK(init)) // dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename); } if(rwfilename) { rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR)); if(rwfd < 0) { XLOG("could not open file %s, %s\n", rwfilename, strerror(errno)); exit(1); } /* this could be a writable temporary file. use atexit_close_fd to ensure * that it is properly cleaned up at exit on Win32 */ if (!read_only) atexit_close_fd(rwfd); } if(initfilename) { uint64_t dev_bigger; initfd = open(initfilename, O_BINARY | O_RDONLY); if(initfd < 0) { XLOG("could not open file %s, %s\n", initfilename, strerror(errno)); exit(1); } //if(dev_size == 0) { D("calculating dev_size from lseek of %s\n", initfilename); dev_bigger = do_lseek(initfd, 0, SEEK_END); do_lseek(initfd, 0, SEEK_SET); if (dev_bigger > dev_size) { dev_size = dev_bigger; } } new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1)); if(new_devs == NULL) goto out_of_memory; nand_devs = new_devs; dev = &new_devs[nand_dev_count]; dev->page_size = page_size; dev->extra_size = extra_size; dev->erase_size = erase_pages * (page_size + extra_size); dev->data = malloc(dev->erase_size); if(dev->data == NULL) goto out_of_memory; dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0; #ifdef TARGET_I386 dev->flags |= NAND_DEV_FLAG_BATCH_CAP; #endif if (initfd >= 0) { do { read_size = do_read(initfd, dev->data, dev->erase_size); if(read_size < 0) { XLOG("could not read file %s, %s\n", initfilename, strerror(errno)); exit(1); } if(do_write(rwfd, dev->data, read_size) != read_size) { XLOG("could not write file %s, %s\n", rwfilename, strerror(errno)); exit(1); } } while(read_size == dev->erase_size); close(initfd); } #if defined ANDROID_QCOW close(rwfd); dev->bdrv = bdrv_new(rwfilename); if (0 > bdrv_open(dev->bdrv, rwfilename, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, NULL)) { //if (0 > bdrv_file_open(&dev->bdrv,rwfilename, BDRV_O_RDWR)) { XLOG("failed to open block driver %s\n", rwfilename); exit(1); } dev_size = 0; //dev_size = bdrv_getlength(dev->bdrv->file); // gets allocated file size // This is how qemu-img gets the virtual disk size: bdrv_get_geometry(dev->bdrv, &dev_size); dev_size *= 512; #else dev->fd = rwfd; #endif pad = dev_size % dev->erase_size; if (pad != 0) { //dev_size += (dev->erase_size - pad); dev_size -= pad; D("rounding devsize up to a full eraseunit, now %llx\n", dev_size); } dev->devname = devname; dev->devname_len = devname_len; dev->max_size = dev_size; D("Dev size of %s is %llx\n", rwfilename, dev_size); nand_dev_count++; return; out_of_memory: XLOG("out of memory\n"); exit(1); bad_arg_and_value: XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value); exit(1); }