Пример #1
0
int main(int argc, char *argv[])
{
    // basic assertions
    assert(sizeof(gpt_partition_t) == 128);
    assert(sizeof(gpt_header_t)    == 512);

    // require root privilege
    if (geteuid() != 0)
    {
        printf("Must run as root user.\n");
        exit(4);
    }

    // get disk size
    uint64_t size = get_disk_size("/dev/sdb");

    // create partitions entry
    gpt_partition_t partitions[2];
    createPartitions(&partitions[0]);

    // create the header
    gpt_header_t gpt;
    initGPTHeader(&gpt, size, &partitions[0]);

    // save in disk
    partition_write("/dev/sdb", &gpt, &partitions[0]);

    return 0;
}
Пример #2
0
ULONGLONG EndlessISO::GetExtractedSize(const CString & image, const BOOL isInstallerImage)
{
    auto extractor = SevenZip::SevenZipExtractor(pImpl->sevenZip, image.GetString());
    extractor.SetCompressionFormat(SevenZip::CompressionFormat::SquashFS);

    auto n = extractor.GetNumberOfItems();
    IFFALSE_RETURN_VALUE(n == 1, "not exactly 1 item in squashfs image", 0);
    UINT32 i = 0;

    auto name = extractor.GetItemsNames()[i];
    IFFALSE_RETURN_VALUE(name == ENDLESS_IMG_FILE_NAME, "squashfs item has wrong name", 0);

    struct ptable pt;
    auto gotPt = extractor.ExtractBytes(i, &pt, sizeof(pt));
    IFFALSE_RETURN_VALUE(gotPt, "Failed to read partition table", 0);

    if (!is_eos_gpt_valid(&pt, isInstallerImage)) {
        return 0;
    }

    return get_disk_size(&pt);
}
Пример #3
0
// compression_type: an element of bled_compression_type
uint64_t get_eos_archive_disk_image_size(const char *filepath, int compression_type, BOOL isInstallerImage)
{
    int64_t bytes_read = 0;
    int64_t result = 0;
    struct ptable pt;
    const int size = sizeof(pt); // should be 2048

    if (NULL == filepath) return 0;

    if (compression_type == BLED_COMPRESSION_NONE) {
        FILE *file = NULL;
        errno_t err = fopen_s(&file, filepath, "rb");
        if (err == 0) {
            // The 'size' and 'count' arguments are "backwards" because this
            // function returns the number of items read; by making the item
            // size 1 we get the number of bytes
            bytes_read = fread((void *)&pt, 1, size, file);
            fclose(file);
        } else {
            uprintf("Error opening %s: %d", filepath, err);
        }
    } else {
        bled_init(_uprintf, NULL, NULL);
        bytes_read = bled_uncompress_to_buffer(filepath, (char*)&pt, size, compression_type);
        bled_exit();
    }

    if (bytes_read < size) {
        // not enough bytes read
        return 0;
    }

    if (!is_eos_gpt_valid(&pt, isInstallerImage)) {
        return 0;
    }

    return get_disk_size(&pt);
}
Пример #4
0
/*
 * Gets a dmgt_disk_t for the given disk dm_descriptor_t.
 *
 * Results:
 *
 *  1. Success: error is set to 0 and a dmgt_disk_t is returned
 *
 *  2. Failure: error is set to -1 and NULL is returned
 */
static dmgt_disk_t *
get_disk(dm_descriptor_t disk, int *error)
{
    dmgt_disk_t *dp;
    *error = 0;

    dp = (dmgt_disk_t *)calloc(1, sizeof (dmgt_disk_t));
    if (dp == NULL) {
        handle_error("out of memory");
        *error = -1;
    } else {

        /* Get name */
        dp->name = get_device_name(disk, error);
        if (!*error) {

            /* Get aliases */
            dp->aliases = get_disk_aliases(disk, dp->name, error);
            if (!*error) {

                /* Get media */
                dm_descriptor_t *media =
                    dm_get_associated_descriptors(disk,
                                                  DM_MEDIA, error);
                if (*error != 0 || media == NULL ||
                        *media == NULL) {
                    handle_error(
                        "could not get media from disk %s",
                        dp->name);
                    *error = -1;
                } else {
                    /* Get size */
                    get_disk_size(media[0], dp->name,
                                  &(dp->size), &(dp->blocksize),
                                  error);
                    if (!*error) {
                        /* Get free slices */
                        dp->slices =
                            get_disk_usable_slices(
                                media[0], dp->name,
                                dp->blocksize,
                                &(dp->in_use), error);
                    }
                    dm_free_descriptors(media);
                }
            }
        }
    }

    if (*error) {
        /* Normalize error */
        *error = -1;

        if (dp != NULL) {
            dmgt_free_disk(dp);
            dp = NULL;
        }
    }

    return (dp);
}
Пример #5
0
disk_info_t *create_disk(const char *device_name, disk_info_t **new_disk_info)
{
	disk_info_t *follow_disk_info;
	u32 major, minor;
	u64 size_in_kilobytes = 0;
	int len;
	char buf[128], *vendor, *model, *ptr;
	partition_info_t *new_partition_info, **follow_partition_list;

	if(!new_disk_info)
		return NULL;

	*new_disk_info = NULL; // initial value.
	vendor = NULL;
	model = NULL;

	if(!device_name || !is_disk_name(device_name))
		return NULL;

	if(!initial_disk_data(&follow_disk_info))
		return NULL;

	len = strlen(device_name);
	follow_disk_info->device = (char *)malloc(len+1);
	if (!follow_disk_info->device){
		free_disk_data(follow_disk_info);
		return NULL;
	}
	strcpy(follow_disk_info->device, device_name);

	if(!get_disk_major_minor(device_name, &major, &minor)){
		free_disk_data(follow_disk_info);
		return NULL;
	}
	follow_disk_info->major = major;
	follow_disk_info->minor = minor;

	if(!get_disk_size(device_name, &size_in_kilobytes)){
		free_disk_data(follow_disk_info);
		return NULL;
	}
	follow_disk_info->size_in_kilobytes = size_in_kilobytes;

	if(!strncmp(device_name, "sd", 2)){
		if(!get_usb_root_port_by_device(device_name, buf, sizeof(buf))){
			free_disk_data(follow_disk_info);
			return NULL;
		}
		
		len = strlen(buf);
		if(len > 0){
			int port_num = get_usb_root_port_number(buf);
			if (port_num < 0)
				port_num = 0;
			
			follow_disk_info->port_root = port_num;
		}
		
		// start get vendor.
		if(!get_disk_vendor(device_name, buf, sizeof(buf))){
			free_disk_data(follow_disk_info);
			return NULL;
		}
		
		len = strlen(buf);
		if(len > 0){
			vendor = (char *)malloc(len+1);
			if(!vendor){
				free_disk_data(follow_disk_info);
				return NULL;
			}
			strcpy(vendor, buf);
			strntrim(vendor);
			sanity_name(vendor);
			follow_disk_info->vendor = vendor;
		}
		
		// start get model.
		if(get_disk_model(device_name, buf, sizeof(buf)) == NULL){
			free_disk_data(follow_disk_info);
			return NULL;
		}
		
		len = strlen(buf);
		if(len > 0){
			model = (char *)malloc(len+1);
			if(!model){
				free_disk_data(follow_disk_info);
				return NULL;
			}
			strcpy(model, buf);
			strntrim(model);
			sanity_name(model);
			follow_disk_info->model = model;
		}
		
		// get USB's tag
		memset(buf, 0, sizeof(buf));
		len = 0;
		ptr = buf;
		if(vendor){
			len += strlen(vendor);
			strcpy(ptr, vendor);
			ptr += len;
		}
		if(model){
			if(len > 0){
				++len; // Add a space between vendor and model.
				strcpy(ptr, " ");
				++ptr;
			}
			len += strlen(model);
			strcpy(ptr, model);
			ptr += len;
		}
		
		if(len > 0){
			follow_disk_info->tag = (char *)malloc(len+1);
			if(!follow_disk_info->tag){
				free_disk_data(follow_disk_info);
				return NULL;
			}
			strcpy(follow_disk_info->tag, buf);
		}
		else{
			len = strlen(DEFAULT_USB_TAG);
			follow_disk_info->tag = (char *)malloc(len+1);
			if(!follow_disk_info->tag){
				free_disk_data(follow_disk_info);
				return NULL;
			}
			strcpy(follow_disk_info->tag, DEFAULT_USB_TAG);
		}
		
		follow_partition_list = &(follow_disk_info->partitions);
		while(*follow_partition_list)
			follow_partition_list = &((*follow_partition_list)->next);
		
		new_partition_info = create_partition(device_name, follow_partition_list);
		if(new_partition_info){
			new_partition_info->disk = follow_disk_info;
			
			++(follow_disk_info->partition_number);
			++(follow_disk_info->mounted_number);
		}
	}

	if(follow_disk_info->partition_number == 0)
		get_disk_partitionnumber(device_name, &(follow_disk_info->partition_number), &(follow_disk_info->mounted_number));

	*new_disk_info = follow_disk_info;

	return *new_disk_info;
}
Пример #6
0
disk_info_t *create_disk(const char *device_name, disk_info_t **new_disk_info){
	disk_info_t *follow_disk_info;
	u32 major, minor;
	u64 size_in_kilobytes = 0;
	int len;
	char usb_node[32], port_path[8];
	char buf[64], *port, *vendor = NULL, *model = NULL, *ptr;
	partition_info_t *new_partition_info, **follow_partition_list;

	if(new_disk_info == NULL){
		usb_dbg("Bad input!!\n");
		return NULL;
	}

	*new_disk_info = NULL; // initial value.

	if(device_name == NULL || !is_disk_name(device_name))
		return NULL;

	if(initial_disk_data(&follow_disk_info) == NULL){
		usb_dbg("No memory!!(follow_disk_info)\n");
		return NULL;
	}

	len = strlen(device_name);
	follow_disk_info->device = (char *)malloc(len+1);
	if(follow_disk_info->device == NULL){
		usb_dbg("No memory!!(follow_disk_info->device)\n");
		free_disk_data(&follow_disk_info);
		return NULL;
	}
	strcpy(follow_disk_info->device, device_name);
	follow_disk_info->device[len] = 0;

	if(!get_disk_major_minor(device_name, &major, &minor)){
		usb_dbg("Fail to get disk's major and minor: %s.\n", device_name);
		free_disk_data(&follow_disk_info);
		return NULL;
	}
	follow_disk_info->major = major;
	follow_disk_info->minor = minor;

	if(!get_disk_size(device_name, &size_in_kilobytes)){
		usb_dbg("Fail to get disk's size_in_kilobytes: %s.\n", device_name);
		free_disk_data(&follow_disk_info);
		return NULL;
	}
	follow_disk_info->size_in_kilobytes = size_in_kilobytes;

	if(!strncmp(device_name, "sd", 2)){
		// Get USB node.
		if(get_usb_node_by_device(device_name, usb_node, 32) == NULL){
			usb_dbg("(%s): Fail to get usb node.\n", device_name);
			free_disk_data(&follow_disk_info);
			return NULL;
		}

		if(get_path_by_node(usb_node, port_path, 8) == NULL){
			usb_dbg("(%s): Fail to get usb path.\n", usb_node);
			free_disk_data(&follow_disk_info);
			return NULL;
		}

		// Get USB port.
		if(get_usb_port_by_string(usb_node, buf, 64) == NULL){
			usb_dbg("Fail to get usb port: %s.\n", usb_node);
			free_disk_data(&follow_disk_info);
			return NULL;
		}

		len = strlen(buf);
		if(len > 0){
			port = (char *)malloc(8);
			if(port == NULL){
				usb_dbg("No memory!!(port)\n");
				free_disk_data(&follow_disk_info);
				return NULL;
			}
			memset(port, 0, 8);
			strncpy(port, port_path, 8);

			follow_disk_info->port = port;
		}

		// start get vendor.
		if(get_disk_vendor(device_name, buf, 64) == NULL){
			usb_dbg("Fail to get disk's vendor: %s.\n", device_name);
			free_disk_data(&follow_disk_info);
			return NULL;
		}

		len = strlen(buf);
		if(len > 0){
			vendor = (char *)malloc(len+1);
			if(vendor == NULL){
				usb_dbg("No memory!!(vendor)\n");
				free_disk_data(&follow_disk_info);
				return NULL;
			}
			strncpy(vendor, buf, len);
			vendor[len] = 0;
			strntrim(vendor);

			follow_disk_info->vendor = vendor;
		}

		// start get model.
		if(get_disk_model(device_name, buf, 64) == NULL){
			usb_dbg("Fail to get disk's model: %s.\n", device_name);
			free_disk_data(&follow_disk_info);
			return NULL;
		}

		len = strlen(buf);
		if(len > 0){
			model = (char *)malloc(len+1);
			if(model == NULL){
				usb_dbg("No memory!!(model)\n");
				free_disk_data(&follow_disk_info);
				return NULL;
			}
			strncpy(model, buf, len);
			model[len] = 0;
			strntrim(model);

			follow_disk_info->model = model;
		}

		// get USB's tag
		memset(buf, 0, 64);
		len = 0;
		ptr = buf;
		if(vendor != NULL){
			len += strlen(vendor);
			strcpy(ptr, vendor);
			ptr += len;
		}
		if(model != NULL){
			if(len > 0){
				++len; // Add a space between vendor and model.
				strcpy(ptr, " ");
				++ptr;
			}
			len += strlen(model);
			strcpy(ptr, model);
			ptr += len;
		}

		if(len > 0){
			follow_disk_info->tag = (char *)malloc(len+1);
			if(follow_disk_info->tag == NULL){
				usb_dbg("No memory!!(follow_disk_info->tag)\n");
				free_disk_data(&follow_disk_info);
				return NULL;
			}
			strcpy(follow_disk_info->tag, buf);
			follow_disk_info->tag[len] = 0;
		}
		else{
			len = strlen(DEFAULT_USB_TAG);

			follow_disk_info->tag = (char *)malloc(len+1);
			if(follow_disk_info->tag == NULL){
				usb_dbg("No memory!!(follow_disk_info->tag)\n");
				free_disk_data(&follow_disk_info);
				return NULL;
			}
			strcpy(follow_disk_info->tag, DEFAULT_USB_TAG);
			follow_disk_info->tag[len] = 0;
		}

		follow_partition_list = &(follow_disk_info->partitions);
		while(*follow_partition_list != NULL)
			follow_partition_list = &((*follow_partition_list)->next);

		new_partition_info = create_partition(device_name, follow_partition_list);
		if(new_partition_info != NULL){
			new_partition_info->disk = follow_disk_info;

			++(follow_disk_info->partition_number);
			++(follow_disk_info->mounted_number);
			if(!strcmp(new_partition_info->device, follow_disk_info->device))
				new_partition_info->size_in_kilobytes = follow_disk_info->size_in_kilobytes-4;
		}
	}

	if(!strcmp(follow_disk_info->device, follow_disk_info->partitions->device))
		get_disk_partitionnumber(device_name, &(follow_disk_info->partition_number), &(follow_disk_info->mounted_number));

	*new_disk_info = follow_disk_info;

	return *new_disk_info;
}
Пример #7
0
static UINTN analyze(int optind, int argc, char **argv)
{
    UINTN   action;
    UINTN   i, k, count_active, detected_parttype;
    CHARN   *fsname;
    UINT64  min_start_lba, max_end_lba, block_count, last_disk_lba;
    UINTN   status;
    BOOLEAN have_esp;
    
    new_mbr_part_count = 0;
    
	block_count = get_disk_size();
	last_disk_lba = block_count - 1;
	if (block_count == 0) {
		error("can't retrieve disk size");
		return 1;
	}

    // determine correct MBR types for GPT partitions
    if (gpt_part_count == 0) {
        Print(L"Status: No GPT partitions defined, nothing to sync.\n");
        return 1;
    }
    have_esp = FALSE;
    for (i = 0; i < gpt_part_count; i++) {
        gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type;
        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) {
            // Basic Data: need to look at data in the partition
            status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
            if (detected_parttype)
                gpt_parts[i].mbr_type = detected_parttype;
            else
                gpt_parts[i].mbr_type = 0x0b;  // fallback: FAT32
        } else if (gpt_parts[i].mbr_type == 0xef) {
            // EFI System Partition: GNU parted can put this on any partition,
            // need to detect file systems
            status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
            if (!have_esp && (detected_parttype == 0x01 || detected_parttype == 0x0e || detected_parttype == 0x0c))
                ;  // seems to be a legitimate ESP, don't change
            else if (detected_parttype)
                gpt_parts[i].mbr_type = detected_parttype;
            else if (have_esp)    // make sure there's no more than one ESP per disk
                gpt_parts[i].mbr_type = 0x83;  // fallback: Linux
        }
        // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems
        
        if (gpt_parts[i].mbr_type == 0xef)
            have_esp = TRUE;
    }
    
    // generate the new table
    
	new_mbr_part_count = 1;
	count_active = 0;
	
	if (! create_empty_mbr) {
		if (optind < argc) {
			for (i = optind; i < argc; i++) {
				char *separator, csep = 0;
				BOOLEAN active   = FALSE;
				UINT8 force_type = 0;
				separator = strchr (argv[i], '+');
				if (! separator)
					separator = strchr (argv[i], '-');
				if (separator)
				{
					csep = *separator;
					*separator = 0;
				}
			
				int part = atoi(argv[i]);
				if (part < 1 || part > gpt_part_count) {
					error("invalid argument '%s', partition number must be between 1-%d !", argv[i], gpt_part_count);
					return 1;
				}
				part--; // 0 base partition number
				if (csep == '+') {
					active = TRUE;
					count_active ++;
					if (count_active == 2) {
						error("only one partition can be active !");
						return 1;
					}
				}

				if (separator && *(separator + 1)) {
					char *str_type = separator + 1;
					if(xtoi (str_type, &force_type) != 0) {
						error("invalid hex type: %s !", str_type);
						return 1;
					}
				}
			
				// Check that a partition has not already enter
				for (k = 1; k < new_mbr_part_count; k++) {
					if (new_mbr_parts[k].start_lba == gpt_parts[part].start_lba ||
						new_mbr_parts[k].end_lba   == gpt_parts[part].end_lba ) {
							error("you already add partition %d !",part+1);
							return 1;
					}
				}
			
				add_gpt_partition_to_mbr(new_mbr_part_count, part, force_type, active);
				new_mbr_part_count++;
			}
		}
		else {
			// add other GPT partitions until the table is full
			// TODO: in the future, prioritize partitions by kind
			if (gpt_parts[0].mbr_type == 0xef)
				i = 1;
			else
				i = 0;
		
			for (; i < gpt_part_count && new_mbr_part_count < 4; i++) {
				add_gpt_partition_to_mbr(new_mbr_part_count, i, 0, FALSE);
        
				new_mbr_part_count++;
			}
		}
	}
	
	// get the first and last used lba
	if ( new_mbr_part_count == 1) { // Only one EFI Protective partition
		min_start_lba = max_end_lba  = last_disk_lba + 1; // Take whole disk
	}
	else {
		min_start_lba = new_mbr_parts[1].start_lba;
		max_end_lba   = new_mbr_parts[1].end_lba;
		for (k = 2; k < new_mbr_part_count; k++) {
			if (max_end_lba < new_mbr_parts[k].end_lba)
				max_end_lba = new_mbr_parts[k].end_lba;
			if (min_start_lba > new_mbr_parts[k].start_lba)
				min_start_lba = new_mbr_parts[k].start_lba;
		}
	}
	
	// Reserved last part if not used
	if (new_mbr_part_count < 4 && max_end_lba < last_disk_lba && fill_mbr) {
		new_mbr_parts[new_mbr_part_count].index = new_mbr_part_count;
		new_mbr_parts[new_mbr_part_count].start_lba = max_end_lba + 1;
		new_mbr_parts[new_mbr_part_count].end_lba   = last_disk_lba;
		new_mbr_parts[new_mbr_part_count].mbr_type  = 0xee; // another protective area
		new_mbr_parts[new_mbr_part_count].active    = FALSE;
		new_mbr_part_count ++;
	}
    
    // first entry: EFI Protective
    new_mbr_parts[0].index     = 0;
    new_mbr_parts[0].start_lba = 1;
    new_mbr_parts[0].end_lba   = min_start_lba - 1;
    new_mbr_parts[0].mbr_type  = 0xee;
        
	action = ACTION_NOP;

	// Check if we need to rewrite MBR
	for (i = 0; i < 4; i ++) {
		if (new_mbr_parts[i].index     != mbr_parts[i].index     ||
			new_mbr_parts[i].start_lba != mbr_parts[i].start_lba ||
			new_mbr_parts[i].end_lba   != mbr_parts[i].end_lba   ||
			new_mbr_parts[i].mbr_type  != mbr_parts[i].mbr_type  ||
			new_mbr_parts[i].active    != mbr_parts[i].active) {
			action = ACTION_REWRITE;
			break;
		}
	}
	
    if (action == ACTION_NOP) {
        Print(L"Status: Tables are synchronized, no need to sync.\n");
        return 1;
    }
	else {
        Print(L"Status: MBR table must be updated.\n");
    }
    
    // dump table
    Print(L"\nProposed new MBR partition table:\n");
    Print(L" # A    Start LBA      End LBA  Type\n");
    for (i = 0; i < new_mbr_part_count; i++) {
        Print(L" %d %s %12lld %12lld  %02x  %s\n",
              new_mbr_parts[i].index + 1,
              new_mbr_parts[i].active ? STR("*") : STR(" "),
              new_mbr_parts[i].start_lba,
              new_mbr_parts[i].end_lba,
              new_mbr_parts[i].mbr_type,
              mbr_parttype_name(new_mbr_parts[i].mbr_type));
    }
    
    return 0;
}
Пример #8
0
int main(int argc, char** argv) {
    if (argc < 3) {
        usage();
    }

    unsigned i = 1;
    const char* path = argv[i++];    // Output path
    const char* command = argv[i++]; // Command

    size_t length = 0;
    size_t offset = 0;
    size_t slice_size = DEFAULT_SLICE_SIZE;
    size_t disk_size = 0;
    bool should_unlink = true;
    uint32_t flags = 0;
    while (i < argc) {
        if (!strcmp(argv[i], "--slice") && i + 1 < argc) {
            if (parse_size(argv[++i], &slice_size) < 0) {
                return -1;
            }
            if (!slice_size ||
                slice_size % blobfs::kBlobfsBlockSize ||
                slice_size % minfs::kMinfsBlockSize) {
                fprintf(stderr, "Invalid slice size - must be a multiple of %u and %u\n",
                        blobfs::kBlobfsBlockSize, minfs::kMinfsBlockSize);
                return -1;
            }
        } else if (!strcmp(argv[i], "--offset") && i + 1 < argc) {
            should_unlink = false;
            if (parse_size(argv[++i], &offset) < 0) {
                return -1;
            }
        } else if (!strcmp(argv[i], "--length") && i + 1 < argc) {
            if (parse_size(argv[++i], &length) < 0) {
                return -1;
            }
        } else if (!strcmp(argv[i], "--compress")) {
            if (!strcmp(argv[++i], "lz4")) {
                flags |= fvm::kSparseFlagLz4;
            } else {
                fprintf(stderr, "Invalid compression type\n");
                return -1;
            }
        } else if (!strcmp(argv[i], "--disk")) {
            if (parse_size(argv[++i], &disk_size) < 0) {
                return -1;
            }
        } else {
            break;
        }

        ++i;
    }

    if (!strcmp(command, "create") && should_unlink) {
        unlink(path);
    }

    // If length was not specified, use remainder of file after offset
    if (length == 0) {
        length = get_disk_size(path, offset);
    }

    if (!strcmp(command, "create")) {
        // If length was specified, an offset was not, we were asked to create a
        // file, and the file does not exist, truncate it to the given length.
        if (length != 0 && offset == 0) {
            fbl::unique_fd fd(open(path, O_CREAT | O_EXCL | O_WRONLY, 0644));

            if (fd) {
                ftruncate(fd.get(), length);
            }
        }

        fbl::unique_ptr<FvmContainer> fvmContainer;
        if (FvmContainer::Create(path, slice_size, offset, length, &fvmContainer) != ZX_OK) {
            return -1;
        }

        if (add_partitions(fvmContainer.get(), argc - i, argv + i) < 0) {
            return -1;
        }

        if (fvmContainer->Commit() != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "add")) {
        fbl::unique_ptr<FvmContainer> fvmContainer(new FvmContainer(path, slice_size, offset,
                                                                    length));

        if (add_partitions(fvmContainer.get(), argc - i, argv + i) < 0) {
            return -1;
        }

        if (fvmContainer->Commit() != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "extend")) {
        if (length == 0 || offset > 0) {
            usage();
        }

        size_t disk_size = get_disk_size(path, 0);

        if (length <= disk_size) {
            fprintf(stderr, "Cannot extend to a value %zu less than current size %zu\n", length,
                    disk_size);
            usage();
        }

        fbl::unique_ptr<FvmContainer> fvmContainer(new FvmContainer(path, slice_size, offset,
                                                                    disk_size));

        if (fvmContainer->Extend(length) != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "sparse")) {
        if (offset) {
            fprintf(stderr, "Invalid sparse flags\n");
            return -1;
        }

        fbl::unique_ptr<SparseContainer> sparseContainer;
        if (SparseContainer::Create(path, slice_size, flags, &sparseContainer) != ZX_OK) {
            return -1;
        }

        if (add_partitions(sparseContainer.get(), argc - i, argv + i) < 0) {
            return -1;
        }

        if (sparseContainer->Commit() != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "verify")) {
        fbl::unique_ptr<Container> containerData;
        if (Container::Create(path, offset, length, flags, &containerData) != ZX_OK) {
            return -1;
        }

        if (containerData->Verify() != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "decompress")) {
        if (argc - i != 2) {
            usage();
            return -1;
        }

        char* input_type = argv[i];
        char* input_path = argv[i + 1];

        if (strcmp(input_type, "--sparse")) {
            usage();
            return -1;
        }

        SparseContainer compressedContainer(input_path, slice_size, flags);
        if (compressedContainer.Decompress(path) != ZX_OK) {
            return -1;
        }

        SparseContainer sparseContainer(path, slice_size, flags);
        if (sparseContainer.Verify() != ZX_OK) {
            return -1;
        }
    } else if (!strcmp(command, "size")) {
        SparseContainer sparseContainer(path, slice_size, flags);

        if (disk_size == 0) {
            printf("%" PRIu64 "\n", sparseContainer.CalculateDiskSize());
        } else if (sparseContainer.CheckDiskSize(disk_size) != ZX_OK) {
            fprintf(stderr, "Sparse container will not fit in target disk size\n");
            return -1;
        }
    } else if (!strcmp(command, "pave")) {
        char* input_type = argv[i];
        char* input_path = argv[i + 1];

        if (strcmp(input_type, "--sparse")) {
            fprintf(stderr, "pave command only accepts --sparse input option\n");
            usage();
            return -1;
        }

        SparseContainer sparseData(input_path, slice_size, flags);
        if (sparseData.Pave(path, offset, length) != ZX_OK) {
            return -1;
        }
    } else {
        usage();
    }

    return 0;
}