aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libfsimage/common/fsimage_grub.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/libfsimage/common/fsimage_grub.c')
-rw-r--r--tools/libfsimage/common/fsimage_grub.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/tools/libfsimage/common/fsimage_grub.c b/tools/libfsimage/common/fsimage_grub.c
index 5edb3ba05b..9ea2e35ac6 100644
--- a/tools/libfsimage/common/fsimage_grub.c
+++ b/tools/libfsimage/common/fsimage_grub.c
@@ -204,19 +204,47 @@ int
fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset,
unsigned int bufsize, char *buf)
{
- uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)sector * 512) + offset;
- ssize_t bytes_read = 0;
+ off_t off;
+ ssize_t ret;
+ int n, r;
+ char tmp[SECTOR_SIZE];
+
+ off = ffi->ff_fsi->f_off + ((off_t)sector * SECTOR_SIZE) + offset;
+
+ /*
+ * Make reads from a raw disk sector-aligned. This is a requirement
+ * for NetBSD. Split the read up into to three parts to meet this
+ * requirement.
+ */
+
+ n = (off & (SECTOR_SIZE - 1));
+ if (n > 0) {
+ r = SECTOR_SIZE - n;
+ if (r > bufsize)
+ r = bufsize;
+ ret = pread(ffi->ff_fsi->f_fd, tmp, SECTOR_SIZE, off - n);
+ if (ret < n + r)
+ return (0);
+ memcpy(buf, tmp + n, r);
+ buf += r;
+ bufsize -= r;
+ off += r;
+ }
- while (bufsize) {
- ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read,
- bufsize, (off_t)off);
- if (ret == -1)
+ n = (bufsize & ~(SECTOR_SIZE - 1));
+ if (n > 0) {
+ ret = pread(ffi->ff_fsi->f_fd, buf, n, off);
+ if (ret < n)
return (0);
- if (ret == 0)
+ buf += n;
+ bufsize -= n;
+ off += n;
+ }
+ if (bufsize > 0) {
+ ret = pread(ffi->ff_fsi->f_fd, tmp, SECTOR_SIZE, off);
+ if (ret < bufsize)
return (0);
-
- bytes_read += ret;
- bufsize -= ret;
+ memcpy(buf, tmp, bufsize);
}
return (1);