static int vbr_write(struct exfat_dev* dev)
{
	struct exfat_super_block sb;
	uint32_t checksum;
	le32_t* sector = malloc(get_sector_size());
	size_t i;

	if (sector == NULL)
	{
		exfat_error("failed to allocate sector-sized block of memory");
		return 1;
	}

	init_sb(&sb);
	if (exfat_write(dev, &sb, sizeof(struct exfat_super_block)) < 0)
	{
		free(sector);
		exfat_error("failed to write super block sector");
		return 1;
	}
	checksum = exfat_vbr_start_checksum(&sb, sizeof(struct exfat_super_block));

	memset(sector, 0, get_sector_size());
	sector[get_sector_size() / sizeof(sector[0]) - 1] =
			cpu_to_le32(0xaa550000);
	for (i = 0; i < 8; i++)
	{
		if (exfat_write(dev, sector, get_sector_size()) < 0)
		{
			free(sector);
			exfat_error("failed to write a sector with boot signature");
			return 1;
		}
		checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
	}

	memset(sector, 0, get_sector_size());
	for (i = 0; i < 2; i++)
	{
		if (exfat_write(dev, sector, get_sector_size()) < 0)
		{
			free(sector);
			exfat_error("failed to write an empty sector");
			return 1;
		}
		checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
	}

	for (i = 0; i < get_sector_size() / sizeof(sector[0]); i++)
		sector[i] = cpu_to_le32(checksum);
	if (exfat_write(dev, sector, get_sector_size()) < 0)
	{
		free(sector);
		exfat_error("failed to write checksum sector");
		return 1;
	}

	free(sector);
	return 0;
}
Beispiel #2
0
static ssize_t
read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
{
	int sector_size = get_sector_size(fd);
	off_t offset = lba * sector_size;
	uint64_t lastlba;
        ssize_t bytesread;

	lseek(fd, offset, SEEK_SET);
	bytesread = read(fd, buffer, bytes);

	lastlba = last_lba(fd);
	if (!lastlba)
		return bytesread;

        /* Kludge.  This is necessary to read/write the last
           block of an odd-sized disk, until Linux 2.5.x kernel fixes.
           This is only used by gpt.c, and only to read
           one sector, so we don't have to be fancy.
        */
        if (!bytesread && !(lastlba & 1) && lba == lastlba) {
                bytesread = read_lastoddsector(fd, lba, buffer, bytes);
        }
        return bytesread;
}
static void init_sb(struct exfat_super_block* sb)
{
	uint32_t clusters_max;
	uint32_t fat_sectors;

	clusters_max = get_volume_size() / get_cluster_size();
	fat_sectors = DIV_ROUND_UP((loff_t) clusters_max * sizeof(cluster_t),
			get_sector_size());

	memset(sb, 0, sizeof(struct exfat_super_block));
	sb->jump[0] = 0xeb;
	sb->jump[1] = 0x76;
	sb->jump[2] = 0x90;
	memcpy(sb->oem_name, "EXFAT   ", sizeof(sb->oem_name));
	sb->sector_start = cpu_to_le64(get_first_sector());
	sb->sector_count = cpu_to_le64(get_volume_size() / get_sector_size());
	sb->fat_sector_start = cpu_to_le32(
			fat.get_alignment() / get_sector_size());
	sb->fat_sector_count = cpu_to_le32(ROUND_UP(
			le32_to_cpu(sb->fat_sector_start) + fat_sectors,
				1 << get_spc_bits()) -
			le32_to_cpu(sb->fat_sector_start));
	sb->cluster_sector_start = cpu_to_le32(
			get_position(&cbm) / get_sector_size());
	sb->cluster_count = cpu_to_le32(clusters_max -
			((le32_to_cpu(sb->fat_sector_start) +
			  le32_to_cpu(sb->fat_sector_count)) >> get_spc_bits()));
	sb->rootdir_cluster = cpu_to_le32(
			(get_position(&rootdir) - get_position(&cbm)) / get_cluster_size()
			+ EXFAT_FIRST_DATA_CLUSTER);
	sb->volume_serial = cpu_to_le32(get_volume_serial());
	sb->version.major = 1;
	sb->version.minor = 0;
	sb->volume_state = cpu_to_le16(0);
	sb->sector_bits = get_sector_bits();
	sb->spc_bits = get_spc_bits();
	sb->fat_count = 1;
	sb->drive_no = 0x80;
	sb->allocated_percent = 0;
	sb->boot_signature = cpu_to_le16(0xaa55);
}
Beispiel #4
0
/************************************************************
 * _get_num_sectors
 * Requires:
 *  - filedes is an open file descriptor, suitable for reading
 * Modifies: nothing
 * Returns:
 *  Last LBA value on success 
 *  0 on error
 *
 * Try getting BLKGETSIZE64 and BLKSSZGET first,
 * then BLKGETSIZE if necessary.
 *  Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
 *  which returns the number of 512-byte sectors, not the size of
 *  the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
 ************************************************************/
static uint64_t
_get_num_sectors(int filedes)
{
	int rc;
	uint64_t bytes=0;

	rc = ioctl(filedes, BLKGETSIZE64, &bytes);
	if (!rc)
		return bytes / get_sector_size(filedes);

	return 0;
}
Beispiel #5
0
static int
read_extended_partition(int fd, struct partition *ep, int en,
			struct slice *sp, int ns)
{
	struct partition p;
	unsigned long start, here, next;
	unsigned char *bp;
	int loopct = 0;
	int moretodo = 1;
	int i, n=0;

	int sector_size_mul = get_sector_size(fd)/512;

	next = start = sector_size_mul * le32_to_cpu(ep->start_sect);

	while (moretodo) {
		here = next;
		moretodo = 0;
		if (++loopct > 100)
			return n;

		bp = (unsigned char *)getblock(fd, here);
		if (bp == NULL)
			return n;

		if (bp[510] != 0x55 || bp[511] != 0xaa)
			return n;

		for (i=0; i<2; i++) {
			memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
			if (is_extended(p.sys_type)) {
				if (p.start_sect && p.nr_sects && !moretodo) {
					next = start + sector_size_mul * le32_to_cpu(p.start_sect);
					moretodo = 1;
				}
				continue;
			}
			if (n < ns) {
				sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect);
				sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects);
				sp[n].container = en + 1;
				n++;
			} else {
				fprintf(stderr,
				    "dos_extd_partition: too many slices\n");
				return n;
			}
			loopct = 0;
		}
	}
	return n;
}
Beispiel #6
0
static int
get_partition_info(int fd, uint32_t options,
		   uint32_t part, uint64_t *start, uint64_t *size,
		   uint8_t *signature, uint8_t *mbr_type,
		   uint8_t *signature_type)
{
	legacy_mbr *mbr;
	void *mbr_sector;
	size_t mbr_size;
	off_t offset __attribute__((unused));
	int this_bytes_read = 0;
	int gpt_invalid=0, mbr_invalid=0;
	int rc=0;
	int sector_size = get_sector_size(fd);

	mbr_size = lcm(sizeof(*mbr), sector_size);
	if ((rc = posix_memalign(&mbr_sector, sector_size, mbr_size)) != 0)
		goto error;
	memset(mbr_sector, '\0', mbr_size);

	offset = lseek(fd, 0, SEEK_SET);
	this_bytes_read = read(fd, mbr_sector, mbr_size);
	if (this_bytes_read < (ssize_t)sizeof(*mbr)) {
		rc=1;
		goto error_free_mbr;
	}
	mbr = (legacy_mbr *)mbr_sector;
	gpt_invalid = gpt_disk_get_partition_info(fd, part,
						  start, size,
						  signature,
						  mbr_type,
						  signature_type,
			(options & EFIBOOT_OPTIONS_IGNORE_PMBR_ERR)?1:0);
	if (gpt_invalid) {
		mbr_invalid = msdos_disk_get_partition_info(fd,
			(options & EFIBOOT_OPTIONS_WRITE_SIGNATURE)?1:0,
							    mbr, part,
							    start, size,
							    signature,
							    mbr_type,
							    signature_type);
		if (mbr_invalid) {
			rc=1;
			goto error_free_mbr;
		}
	}
 error_free_mbr:
	free(mbr_sector);
 error:
	return rc;
}
Beispiel #7
0
/************************************************************
 * _get_num_sectors
 * Requires:
 *  - filedes is an open file descriptor, suitable for reading
 * Modifies: nothing
 * Returns:
 *  Last LBA value on success
 *  0 on error
 *
 * Try getting BLKGETSIZE64 and BLKSSZGET first,
 * then BLKGETSIZE if necessary.
 *  Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
 *  which returns the number of 512-byte sectors, not the size of
 *  the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
 ************************************************************/
static uint64_t
_get_num_sectors(int filedes)
{
	unsigned long sectors=0;
	uint64_t bytes=0;
	int rc;
	if (kernel_has_blkgetsize64()) {
		rc = ioctl(filedes, BLKGETSIZE64, &bytes);
		if (!rc)
			return bytes / get_sector_size(filedes);
	}

	rc = ioctl(filedes, BLKGETSIZE, &sectors);
	if (rc)
		return 0;

	return sectors;
}
Beispiel #8
0
/************************************************************
 * _get_num_sectors
 * Requires:
 *  - filedes is an open file descriptor, suitable for reading
 * Modifies: nothing
 * Returns:
 *  Last LBA value on success 
 *  0 on error
 *
 * Try getting BLKGETSIZE64 and BLKSSZGET first,
 * then BLKGETSIZE if necessary.
 *  Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
 *  which returns the number of 512-byte sectors, not the size of
 *  the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
 ************************************************************/
static uint64_t
_get_num_sectors(int filedes)
{
	unsigned long sectors=0;
	int rc;
#if 0
        uint64_t bytes=0;

 	rc = ioctl(filedes, BLKGETSIZE64, &bytes);
	if (!rc)
		return bytes / get_sector_size(filedes);
#endif
        rc = ioctl(filedes, BLKGETSIZE, &sectors);
        if (rc)
                return 0;
        
	return sectors;
}
Beispiel #9
0
int
read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
	struct partition p;
	unsigned long offset = all.start;
	int i, n=4;
	unsigned char *bp;
	uint64_t  sector_size_mul = get_sector_size(fd)/512;

	bp = (unsigned char *)getblock(fd, offset);
	if (bp == NULL)
		return -1;

	if (bp[510] != 0x55 || bp[511] != 0xaa)
		return -1;

	for (i=0; i<4; i++) {
		memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
		if (is_gpt(p.sys_type))
			return 0;
		if (i < ns) {
			sp[i].start =  sector_size_mul * le32_to_cpu(p.start_sect);
			sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects);
		} else {
			fprintf(stderr,
				"dos_partition: too many slices\n");
			break;
		}
		if (is_extended(p.sys_type)) {
			/* extended partitions only get one or
			   two sectors mapped for LILO to install,
			   whichever is needed to have 1kb of space */
			if (sector_size_mul == 1)
				sp[i].size = 2;
			else sp[i].size = sector_size_mul;
			n += read_extended_partition(fd, &p, i, sp+n, ns-n);
		}
	}
	return n;
}
Beispiel #10
0
/**
 * read_gpt_pt() 
 * @fd
 * @all - slice with start/size of whole disk
 *
 *  0 if this isn't our partition table
 *  number of partitions if successful
 *
 */
int
read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns)
{
	gpt_header *gpt = NULL;
	gpt_entry *ptes = NULL;
	uint32_t i;
	int n = 0;
        int last_used_index=-1;
	int sector_size_mul = get_sector_size(fd)/512;

	if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
		if (gpt)
			free (gpt);
		if (ptes)
			free (ptes);
		return 0;
	}

	for (i = 0; i < __le32_to_cpu(gpt->num_partition_entries) && i < ns; i++) {
		if (!efi_guidcmp (NULL_GUID, ptes[i].partition_type_guid)) {
			sp[n].start = 0;
			sp[n].size = 0;
			n++;
		} else {
			sp[n].start = sector_size_mul *
				      __le64_to_cpu(ptes[i].starting_lba);
			sp[n].size  = sector_size_mul *
				      (__le64_to_cpu(ptes[i].ending_lba) -
				       __le64_to_cpu(ptes[i].starting_lba) + 1);
                        last_used_index=n;
			n++;
		}
	}
	free (ptes);
	free (gpt);
	return last_used_index+1;
}
Beispiel #11
0
int get_device_info(int fd, struct device_info *info)
{
    struct stat stat;
    int ret;

    *info = device_info_clueless;

    ret = fstat(fd, &stat);
    if (ret < 0) {
	perror("fstat on target failed");
	return -1;
    }

    if (S_ISREG(stat.st_mode)) {
	/* there is nothing more to discover for an image file */
	info->type = TYPE_FILE;
	info->partition = 0;
	info->size = stat.st_size;
	return 0;
    }

    if (!S_ISBLK(stat.st_mode)) {
	/* neither regular file nor block device? not usable */
	info->type = TYPE_BAD;
	return 0;
    }

    get_block_device_size(info, fd);
    get_block_geometry(info, fd);
    get_sector_size(info, fd);

    /* use udev information if available */
    udev_fill_info(info, &stat);

    return 0;
}
Beispiel #12
0
static ssize_t
read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
{
	int sector_size = get_sector_size(fd);
	off_t offset = lba * sector_size;
	ssize_t bytesread;
	void *iobuf;
	size_t iobuf_size;
	int rc;
	off_t new_offset;

	iobuf_size = lcm(bytes, sector_size);
	rc = posix_memalign(&iobuf, sector_size, iobuf_size);
	if (rc)
		return rc;
	memset(iobuf, 0, bytes);

	new_offset = lseek(fd, offset, SEEK_SET);
	if (new_offset == (off_t)-1) {
		free(iobuf);
		return 0;
	}
	bytesread = read(fd, iobuf, iobuf_size);
	memcpy(buffer, iobuf, bytes);
	free(iobuf);

	/* Kludge.  This is necessary to read/write the last
	   block of an odd-sized disk, until Linux 2.5.x kernel fixes.
	   This is only used by gpt.c, and only to read
	   one sector, so we don't have to be fancy.
	*/
	if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
		bytesread = read_lastoddsector(fd, lba, buffer, bytes);
	}
	return bytesread;
}
static loff_t vbr_size(void)
{
	return 12 * get_sector_size();
}
Beispiel #14
0
static off_t fat_alignment(void)
{
	return (off_t) 128 * get_sector_size();
}
static loff_t vbr_alignment(void)
{
	return get_sector_size();
}
static off64_t vbr_size(void)
{
	return 12 * get_sector_size();
}
Beispiel #17
0
int main(int argc, char *argv[])
{
	int ret;
	int i, j;
	int dev_fd;
	struct master_boot_sector mbs;
	struct hd_geometry geo;
	u32 total_secs;
	u64 total_bytes;
	u32 part_secs;
	u32 sec_size;
	u32 start_sec;

	assert(argc > 2);

	dev_fd = open(argv[1], O_RDWR | O_BINARY);
	if (dev_fd < 0)
	{
		print_error("open device \"%s\"", argv[1]);
		return -1;
	}

	ret = fread_master_boot_sector(dev_fd, &mbs);
	if (ret < 0)
	{
		error_msg("fread_master_boot_sector");
		goto out_close_dev;
	}

	ret = fget_device_geometry(dev_fd, &geo);
	if (ret < 0)
	{
		error_msg("fget_device_geometry");
		goto out_close_dev;
	}

	ret = get_sector_size(dev_fd, &sec_size);
	if (ret < 0)
	{
		error_msg("get_sector_size");
		goto out_close_dev;
	}

	ret = fget_device_size(dev_fd, &total_bytes);
	if (ret < 0)
	{
		error_msg("fget_device_size");
		goto out_close_dev;
	}

	total_secs = total_bytes / sec_size;

	println("device size = %s = %d(sector)", size2text(total_bytes), total_secs);

	show_geometry(&geo);

	memset(mbs.disk_part_tables, 0, 64);

	start_sec = sector_cylinder_lalignment(text2size(argv[2], NULL) / sec_size, &geo);

	println("start_sec = %d(sector)", start_sec);

	if (start_sec == 0)
	{
		start_sec = 1;
	}

	for (i = 0, j = 3; i < 4 && j < argc; i++, j++)
	{
		part_secs = sector_cylinder_alignment_auto(text2size(argv[j], NULL) / sec_size, &geo);

		println("partition start address = %d(sector), size = %d(sector)", start_sec, part_secs);

		if (start_sec + part_secs > total_secs)
		{
			ret = -1;
			error_msg("partition size is too large");
			goto out_close_dev;
		}

		set_part_address(mbs.disk_part_tables + i, &geo, start_sec, calculate_partition_size(start_sec, part_secs, &geo));
		mbs.disk_part_tables[i].file_system_mark = 0x83;

		start_sec += part_secs;
	}

	if (i < 4 && start_sec < total_secs)
	{
		part_secs = sector_cylinder_lalignment(total_secs - start_sec, &geo);

		set_part_address(mbs.disk_part_tables + i, &geo, start_sec, calculate_partition_size(start_sec, part_secs, &geo));
		mbs.disk_part_tables[i].file_system_mark = 0x83;
	}

	mbs.magic_number = 0xAA55;

	ret = fwrite_master_boot_sector(dev_fd, &mbs);
	if (ret < 0)
	{
		error_msg("fwrite_master_boot_sector");
		goto out_close_dev;
	}

	ret = freread_part_table(dev_fd);
	if (ret < 0)
	{
		error_msg("freread_part_table_retry");
		goto out_close_dev;
	}

out_close_dev:
	close(dev_fd);

	return ret;
}
Beispiel #18
0
int get_cluster_size(void)
{
	return get_sector_size() << get_spc_bits();
}
Beispiel #19
0
int
get_sector_bits(int drive)
{
	int sector_size = get_sector_size(drive);
	return log2(sector_size);
}