| /* |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file "COPYING" in the main directory of this archive |
| * for more details. |
| * |
| * Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com |
| */ |
| #include "bootloader.h" |
| |
| /* this is the stupidest "file system" imaginable -- it applies an */ |
| /* offset to the seek pointers and optionally checks against a length */ |
| |
| struct offsets { |
| int fd; |
| __u64 start; |
| __u64 length; |
| } ofd [MAX_FD]; |
| |
| static int offset_read(int fd, char *buf, unsigned count, __u64 devaddr) |
| { |
| struct offsets *o = &ofd[fd]; |
| |
| if (Debug) printf("offset_read(%d, 0x%p, %d, %lld)\r\n", |
| fd, buf, count, devaddr); |
| |
| /* abort early if we reach firmware limit */ |
| if (disk_2gb_limit && ((devaddr + count) >> 31)) { |
| printf("offset_read(%lld): block not reachable via firmware call\r\n", |
| devaddr + count); |
| return -1; |
| } |
| |
| /* truncate 'count' according to max device/file size */ |
| if (o->length > 0 && devaddr < o->length && devaddr + count > o->length) |
| count = o->length - devaddr; |
| else if (o->length > 0 && devaddr + count > o->length) |
| { |
| printf("offset_read(%d, 0x%p, %d, %lld) can't seek past %lld\r\n", |
| fd, buf, count, devaddr, o->length); |
| return -1; |
| } |
| |
| return seekread(o->fd, buf, count, devaddr + o->start); |
| } |
| |
| static void offset_describe(int fd, int *bufalign, |
| int *blocksize) |
| { |
| describe(ofd[fd].fd, bufalign, blocksize); |
| } |
| |
| /* returns true if OK */ |
| int offset_open(int otherfd, __u64 offset, __u64 length) |
| { |
| int fd = fileio_open(offset_describe, offset_read); |
| |
| if (fd >= 0) |
| { |
| struct offsets *o = &ofd[fd]; |
| |
| o->fd = otherfd; |
| o->start = offset; |
| o->length = length; |
| } |
| |
| if (Debug) printf("offset_open(%d, %lld, %lld) = %d\n", |
| otherfd, offset, length, fd); |
| |
| return fd; |
| } |