/* 
 * 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;
}
