void grub_blocklist_convert (grub_file_t file) { struct read_blocklist_closure c; if ((file->fs == &grub_fs_blocklist) || (! file->device->disk) || (! file->size)) return; file->offset = 0; file->flags = 1; c.num = 0; c.blocks = 0; c.total_size = 0; c.part_start = grub_partition_get_start (file->device->disk->partition); file->read_hook = read_blocklist; file->closure = &c; grub_file_read (file, 0, file->size); file->read_hook = 0; if ((grub_errno) || (c.total_size != file->size)) { grub_errno = 0; grub_free (c.blocks); } else { if (file->fs->close) (file->fs->close) (file); file->fs = &grub_fs_blocklist; file->data = c.blocks; } file->offset = 0; }
/* Helper for scan_disk. */ static int scan_disk_partition_iter (grub_disk_t disk, grub_partition_t p, void *data) { const char *name = data; struct grub_diskfilter_vg *arr; grub_disk_addr_t start_sector; struct grub_diskfilter_pv_id id; grub_diskfilter_t diskfilter; grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n", name); #ifdef GRUB_UTIL grub_util_info ("Scanning for DISKFILTER devices on disk %s", name); #endif disk->partition = p; for (arr = array_list; arr != NULL; arr = arr->next) { struct grub_diskfilter_pv *m; for (m = arr->pvs; m; m = m->next) if (m->disk && m->disk->id == disk->id && m->disk->dev->id == disk->dev->id && m->part_start == grub_partition_get_start (disk->partition) && m->part_size == grub_disk_get_size (disk)) return 0; } for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = diskfilter->next) { #ifdef GRUB_UTIL grub_util_info ("Scanning for %s devices on disk %s", diskfilter->name, name); #endif id.uuid = 0; id.uuidlen = 0; arr = diskfilter->detect (disk, &id, &start_sector); if (arr && (! insert_array (disk, &id, arr, start_sector, diskfilter))) { if (id.uuidlen) grub_free (id.uuid); return 0; } if (arr && id.uuidlen) grub_free (id.uuid); /* This error usually means it's not diskfilter, no need to display it. */ if (grub_errno != GRUB_ERR_OUT_OF_RANGE) grub_print_error (); grub_errno = GRUB_ERR_NONE; } return 0; }
static PyObject *bits_file_data_and_disk_blocks(PyObject *self, PyObject *args) { PyObject *pyfile, *pystr; grub_file_t file; grub_ssize_t bytes_read; if (!PyArg_ParseTuple(args, "O!:file_data_and_disk_blocks", &PyFile_Type, &pyfile)) return NULL; file = PyFile_AsFile(pyfile); if (!file->device->disk) return PyErr_Format(PyExc_RuntimeError, "Can't get disk blocks from non-disk-backed file"); partition_start_sector = grub_partition_get_start(file->device->disk->partition); pyblocklist = PyList_New(0); if (!pyblocklist) return NULL; pystr = PyString_FromStringAndSize(NULL, grub_file_size(file)); if (!pystr) { Py_CLEAR(pyblocklist); return NULL; } file->read_hook = disk_blocks_read_hook; bytes_read = grub_file_read(file, PyString_AsString(pystr), grub_file_size(file)); file->read_hook = NULL; if ((grub_off_t)bytes_read != grub_file_size(file)) { Py_CLEAR(pyblocklist); Py_DECREF(pystr); return PyErr_Format(PyExc_RuntimeError, "Failed to read from file"); } if (!pyblocklist) { Py_DECREF(pystr); return PyErr_NoMemory(); } return Py_BuildValue("(NN)", pystr, pyblocklist); }
static grub_err_t grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { grub_file_t file; char buf[GRUB_DISK_SECTOR_SIZE]; unsigned long start_sector = 0; unsigned num_sectors = 0; int num_entries = 0; grub_disk_addr_t part_start = 0; auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length); auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num, unsigned offset, unsigned length); void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length) { if (num_sectors > 0) { if (start_sector + num_sectors == sector && offset == 0 && length == GRUB_DISK_SECTOR_SIZE) { num_sectors++; return; } print_blocklist (start_sector, num_sectors, 0, 0); num_sectors = 0; } if (offset == 0 && length == GRUB_DISK_SECTOR_SIZE) { start_sector = sector; num_sectors++; } else print_blocklist (sector, 0, offset, length); } void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num, unsigned offset, unsigned length) { if (num_entries++) grub_printf (","); grub_printf ("%llu", (unsigned long long) (sector - part_start)); if (num > 0) grub_printf ("+%u", num); if (offset != 0 || length != 0) grub_printf ("[%u-%u]", offset, offset + length); } if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); file = grub_file_open (args[0]); if (! file) return grub_errno; if (! file->device->disk) return grub_error (GRUB_ERR_BAD_DEVICE, "this command is available only for disk devices"); part_start = grub_partition_get_start (file->device->disk->partition); file->read_hook = read_blocklist; while (grub_file_read (file, buf, sizeof (buf)) > 0) ; if (num_sectors > 0) print_blocklist (start_sector, num_sectors, 0, 0); grub_file_close (file); return grub_errno; }
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; }