* grub-core/kern/emu/hostdisk.c (open_device): New argument max. All
users updated. (grub_util_biosdisk_read): Handle Linux partitions not exactly corresponding to GRUB partitions. (grub_util_biosdisk_write): Likewise.
This commit is contained in:
parent
b72d44a11a
commit
cb7f944e44
2 changed files with 102 additions and 72 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2012-04-18 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
* grub-core/kern/emu/hostdisk.c (open_device): New argument max. All
|
||||||
|
users updated.
|
||||||
|
(grub_util_biosdisk_read): Handle Linux partitions not exactly
|
||||||
|
corresponding to GRUB partitions.
|
||||||
|
(grub_util_biosdisk_write): Likewise.
|
||||||
|
|
||||||
2012-04-18 Vladimir Serbinenko <phcoder@gmail.com>
|
2012-04-18 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
Scan mdraid before LVM.
|
Scan mdraid before LVM.
|
||||||
|
|
|
@ -790,11 +790,14 @@ grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
|
||||||
|
grub_disk_addr_t *max)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct grub_util_biosdisk_data *data = disk->data;
|
struct grub_util_biosdisk_data *data = disk->data;
|
||||||
|
|
||||||
|
*max = ~0ULL;
|
||||||
|
|
||||||
#ifdef O_LARGEFILE
|
#ifdef O_LARGEFILE
|
||||||
flags |= O_LARGEFILE;
|
flags |= O_LARGEFILE;
|
||||||
#endif
|
#endif
|
||||||
|
@ -819,9 +822,16 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
||||||
part_start = grub_partition_get_start (disk->partition);
|
part_start = grub_partition_get_start (disk->partition);
|
||||||
|
|
||||||
strcpy (dev, map[disk->id].device);
|
strcpy (dev, map[disk->id].device);
|
||||||
if (disk->partition && sector >= part_start
|
if (disk->partition
|
||||||
&& strncmp (map[disk->id].device, "/dev/", 5) == 0)
|
&& strncmp (map[disk->id].device, "/dev/", 5) == 0)
|
||||||
is_partition = linux_find_partition (dev, part_start);
|
{
|
||||||
|
if (sector >= part_start)
|
||||||
|
is_partition = linux_find_partition (dev, part_start);
|
||||||
|
else
|
||||||
|
*max = part_start - sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
reopen:
|
||||||
|
|
||||||
if (data->dev && strcmp (data->dev, dev) == 0 &&
|
if (data->dev && strcmp (data->dev, dev) == 0 &&
|
||||||
data->access_mode == (flags & O_ACCMODE))
|
data->access_mode == (flags & O_ACCMODE))
|
||||||
|
@ -863,7 +873,21 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_partition)
|
if (is_partition)
|
||||||
sector -= part_start;
|
{
|
||||||
|
*max = grub_util_get_fd_size (fd, dev, 0);
|
||||||
|
*max >>= disk->log_sector_size;
|
||||||
|
if (sector - part_start >= *max)
|
||||||
|
{
|
||||||
|
*max = disk->partition->len - (sector - part_start);
|
||||||
|
if (*max == 0)
|
||||||
|
*max = ~0ULL;
|
||||||
|
is_partition = 0;
|
||||||
|
strcpy (dev, map[disk->id].device);
|
||||||
|
goto reopen;
|
||||||
|
}
|
||||||
|
sector -= part_start;
|
||||||
|
*max -= sector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else /* ! __linux__ */
|
#else /* ! __linux__ */
|
||||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
@ -1009,90 +1033,87 @@ static grub_err_t
|
||||||
grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||||
grub_size_t size, char *buf)
|
grub_size_t size, char *buf)
|
||||||
{
|
{
|
||||||
int fd;
|
while (size)
|
||||||
|
|
||||||
/* Split pre-partition and partition reads. */
|
|
||||||
if (disk->partition && sector < disk->partition->start
|
|
||||||
&& sector + size > disk->partition->start)
|
|
||||||
{
|
{
|
||||||
grub_err_t err;
|
int fd;
|
||||||
err = grub_util_biosdisk_read (disk, sector,
|
grub_disk_addr_t max = ~0ULL;
|
||||||
disk->partition->start - sector,
|
fd = open_device (disk, sector, O_RDONLY, &max);
|
||||||
buf);
|
if (fd < 0)
|
||||||
if (err)
|
return grub_errno;
|
||||||
return err;
|
|
||||||
|
|
||||||
return grub_util_biosdisk_read (disk, disk->partition->start,
|
if (max > size)
|
||||||
size - (disk->partition->start - sector),
|
max = size;
|
||||||
buf + ((disk->partition->start - sector)
|
|
||||||
<< GRUB_DISK_SECTOR_BITS));
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open_device (disk, sector, O_RDONLY);
|
|
||||||
if (fd < 0)
|
|
||||||
return grub_errno;
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (sector == 0 && size > 1)
|
if (sector == 0 && max > 1)
|
||||||
{
|
|
||||||
/* Work around a bug in Linux ez remapping. Linux remaps all
|
|
||||||
sectors that are read together with the MBR in one read. It
|
|
||||||
should only remap the MBR, so we split the read in two
|
|
||||||
parts. -jochen */
|
|
||||||
if (grub_util_fd_read (fd, buf, (1 << disk->log_sector_size))
|
|
||||||
!= (1 << disk->log_sector_size))
|
|
||||||
{
|
{
|
||||||
grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
|
/* Work around a bug in Linux ez remapping. Linux remaps all
|
||||||
map[disk->id].device, strerror (errno));
|
sectors that are read together with the MBR in one read. It
|
||||||
return grub_errno;
|
should only remap the MBR, so we split the read in two
|
||||||
|
parts. -jochen */
|
||||||
|
if (grub_util_fd_read (fd, buf, (1 << disk->log_sector_size))
|
||||||
|
!= (1 << disk->log_sector_size))
|
||||||
|
return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
|
||||||
|
map[disk->id].device, strerror (errno));
|
||||||
|
|
||||||
|
buf += (1 << disk->log_sector_size);
|
||||||
|
size--;
|
||||||
|
max--;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += (1 << disk->log_sector_size);
|
|
||||||
size--;
|
|
||||||
}
|
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
|
||||||
if (grub_util_fd_read (fd, buf, size << disk->log_sector_size)
|
if (grub_util_fd_read (fd, buf, max << disk->log_sector_size)
|
||||||
!= (ssize_t) (size << disk->log_sector_size))
|
!= (ssize_t) (max << disk->log_sector_size))
|
||||||
grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
|
return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
|
||||||
map[disk->id].device, strerror (errno));
|
map[disk->id].device, strerror (errno));
|
||||||
|
size -= max;
|
||||||
return grub_errno;
|
buf += (max << disk->log_sector_size);
|
||||||
|
sector += max;
|
||||||
|
}
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
||||||
grub_size_t size, const char *buf)
|
grub_size_t size, const char *buf)
|
||||||
{
|
{
|
||||||
int fd;
|
while (size)
|
||||||
|
|
||||||
/* Split pre-partition and partition writes. */
|
|
||||||
if (disk->partition && sector < disk->partition->start
|
|
||||||
&& sector + size > disk->partition->start)
|
|
||||||
{
|
{
|
||||||
grub_err_t err;
|
int fd;
|
||||||
err = grub_util_biosdisk_write (disk, sector,
|
grub_disk_addr_t max = ~0ULL;
|
||||||
disk->partition->start - sector,
|
fd = open_device (disk, sector, O_RDONLY, &max);
|
||||||
buf);
|
if (fd < 0)
|
||||||
if (err)
|
return grub_errno;
|
||||||
return err;
|
|
||||||
|
|
||||||
return grub_util_biosdisk_write (disk, disk->partition->start,
|
if (max > size)
|
||||||
size - (disk->partition->start - sector),
|
max = size;
|
||||||
buf + ((disk->partition->start - sector)
|
|
||||||
<< GRUB_DISK_SECTOR_BITS));
|
#ifdef __linux__
|
||||||
|
if (sector == 0 && max > 1)
|
||||||
|
{
|
||||||
|
/* Work around a bug in Linux ez remapping. Linux remaps all
|
||||||
|
sectors that are write together with the MBR in one write. It
|
||||||
|
should only remap the MBR, so we split the write in two
|
||||||
|
parts. -jochen */
|
||||||
|
if (grub_util_fd_write (fd, buf, (1 << disk->log_sector_size))
|
||||||
|
!= (1 << disk->log_sector_size))
|
||||||
|
return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write `%s': %s"),
|
||||||
|
map[disk->id].device, strerror (errno));
|
||||||
|
|
||||||
|
buf += (1 << disk->log_sector_size);
|
||||||
|
size--;
|
||||||
|
max--;
|
||||||
|
}
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
if (grub_util_fd_write (fd, buf, max << disk->log_sector_size)
|
||||||
|
!= (ssize_t) (max << disk->log_sector_size))
|
||||||
|
return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write `%s': %s"),
|
||||||
|
map[disk->id].device, strerror (errno));
|
||||||
|
size -= max;
|
||||||
|
buf += (max << disk->log_sector_size);
|
||||||
}
|
}
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
fd = open_device (disk, sector, O_WRONLY);
|
|
||||||
if (fd < 0)
|
|
||||||
return grub_errno;
|
|
||||||
|
|
||||||
if (grub_util_fd_write (fd, buf, size << disk->log_sector_size)
|
|
||||||
!= (ssize_t) (size << disk->log_sector_size))
|
|
||||||
grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write to `%s': %s"),
|
|
||||||
map[disk->id].device, strerror (errno));
|
|
||||||
|
|
||||||
return grub_errno;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_err_t
|
grub_err_t
|
||||||
|
@ -1104,7 +1125,8 @@ grub_util_biosdisk_flush (struct grub_disk *disk)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
if (data->fd == -1)
|
if (data->fd == -1)
|
||||||
{
|
{
|
||||||
data->fd = open_device (disk, 0, O_RDONLY);
|
grub_disk_addr_t max;
|
||||||
|
data->fd = open_device (disk, 0, O_RDONLY, &max);
|
||||||
if (data->fd < 0)
|
if (data->fd < 0)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue