/* Open a file named NAME and initialize FILE. */ static grub_err_t grub_hostfs_open (struct grub_file *file, const char *name) { grub_util_fd_t f; struct grub_hostfs_data *data; f = grub_util_fd_open (name, GRUB_UTIL_FD_O_RDONLY); if (! GRUB_UTIL_FD_IS_VALID (f)) return grub_error (GRUB_ERR_BAD_FILENAME, N_("can't open `%s': %s"), name, strerror (errno)); data = grub_malloc (sizeof (*data)); if (!data) { grub_util_fd_close (f); return grub_errno; } data->filename = grub_strdup (name); if (!data->filename) { grub_free (data); grub_util_fd_close (f); return grub_errno; } data->f = f; file->data = data; file->size = grub_util_get_fd_size (f, name, NULL); return GRUB_ERR_NONE; }
static grub_err_t grub_util_biosdisk_open (const char *name, grub_disk_t disk) { int drive; struct grub_util_hostdisk_data *data; drive = find_grub_drive (name); grub_util_info ("drive = %d", drive); if (drive < 0) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no mapping exists for `%s'", name); disk->id = drive; disk->data = data = xmalloc (sizeof (struct grub_util_hostdisk_data)); data->dev = NULL; data->access_mode = 0; data->fd = GRUB_UTIL_FD_INVALID; data->is_disk = 0; data->device_map = map[drive].device_map; /* Get the size. */ { grub_util_fd_t fd; fd = grub_util_fd_open (map[drive].device, GRUB_UTIL_FD_O_RDONLY); if (!GRUB_UTIL_FD_IS_VALID(fd)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("cannot open `%s': %s"), map[drive].device, grub_util_fd_strerror ()); disk->total_sectors = grub_util_get_fd_size (fd, map[drive].device, &disk->log_sector_size); disk->total_sectors >>= disk->log_sector_size; #if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL { struct stat st; # if GRUB_DISK_DEVS_ARE_CHAR if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode)) # else if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode)) # endif data->is_disk = 1; } #endif grub_util_fd_close (fd); grub_util_info ("the size of %s is %" PRIuGRUB_UINT64_T, name, disk->total_sectors); return GRUB_ERR_NONE; } }
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; }