grub_util_fd_t grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags, grub_disk_addr_t *max) { grub_util_fd_t fd; struct grub_util_hostdisk_data *data = disk->data; *max = ~0ULL; flags |= GRUB_UTIL_FD_O_SYNC; if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 && data->access_mode == (flags & O_ACCMODE)) { grub_dprintf ("hostdisk", "reusing open device `%s'\n", data->dev); fd = data->fd; } else { free (data->dev); data->dev = 0; if (GRUB_UTIL_FD_IS_VALID(data->fd)) { if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) grub_util_fd_sync (data->fd); grub_util_fd_close (data->fd); data->fd = GRUB_UTIL_FD_INVALID; } fd = grub_util_fd_open (map[disk->id].device, flags); if (GRUB_UTIL_FD_IS_VALID(fd)) { data->dev = xstrdup (map[disk->id].device); data->access_mode = (flags & O_ACCMODE); data->fd = fd; } } if (!GRUB_UTIL_FD_IS_VALID(data->fd)) { grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"), map[disk->id].device, grub_util_fd_strerror ()); return GRUB_UTIL_FD_INVALID; } if (grub_util_fd_seek (fd, sector << disk->log_sector_size)) { grub_util_fd_close (fd); grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"), map[disk->id].device, grub_util_fd_strerror ()); return GRUB_UTIL_FD_INVALID; } return fd; }
static grub_ssize_t grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_hostfs_data *data; data = file->data; if (grub_util_fd_seek (data->f, file->offset) != 0) { grub_error (GRUB_ERR_OUT_OF_RANGE, N_("cannot seek `%s': %s"), data->filename, grub_util_fd_strerror ()); return -1; } unsigned int s = grub_util_fd_read (data->f, buf, len); if (s != len) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("cannot read `%s': %s"), data->filename, grub_util_fd_strerror ()); return (signed) s; }
int grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags, grub_disk_addr_t *max) { grub_util_fd_t fd; struct grub_util_hostdisk_data *data = disk->data; *max = ~0ULL; #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif #ifdef O_SYNC flags |= O_SYNC; #endif #ifdef O_FSYNC flags |= O_FSYNC; #endif #ifdef O_BINARY flags |= O_BINARY; #endif /* Linux has a bug that the disk cache for a whole disk is not consistent with the one for a partition of the disk. */ { int is_partition = 0; char dev[PATH_MAX]; grub_disk_addr_t part_start = 0; part_start = grub_partition_get_start (disk->partition); strcpy (dev, grub_util_biosdisk_get_osdev (disk)); if (disk->partition && strncmp (dev, "/dev/", 5) == 0) { if (sector >= part_start) is_partition = grub_hostdisk_linux_find_partition (dev, part_start); else *max = part_start - sector; } reopen: if (data->dev && strcmp (data->dev, dev) == 0 && data->access_mode == (flags & O_ACCMODE)) { grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev); fd = data->fd; } else { free (data->dev); data->dev = 0; if (data->fd != -1) { if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) { fsync (data->fd); if (data->is_disk) ioctl (data->fd, BLKFLSBUF, 0); } close (data->fd); data->fd = -1; } /* Open the partition. */ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev); fd = open (dev, flags); if (fd < 0) { grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"), dev, strerror (errno)); return -1; } data->dev = xstrdup (dev); data->access_mode = (flags & O_ACCMODE); data->fd = fd; if (data->is_disk) ioctl (data->fd, BLKFLSBUF, 0); } if (is_partition) { *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, grub_util_biosdisk_get_osdev (disk)); goto reopen; } sector -= part_start; *max -= sector; } } if (grub_util_fd_seek (fd, sector << disk->log_sector_size)) { close (fd); grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"), grub_util_biosdisk_get_osdev (disk), strerror (errno)); return -1; } return fd; }