[BACK]Return to lif.c CVS log [TXT][DIR] Up to [local] / sys / arch / hppa64 / stand / libsa

File: [local] / sys / arch / hppa64 / stand / libsa / lif.c (download)

Revision 1.1, Tue Mar 4 16:05:56 2008 UTC (16 years, 3 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*	$OpenBSD: lif.c,v 1.1 2005/04/01 10:40:48 mickey Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/disklabel.h>
#include "libsa.h"

extern int debug;

struct file {
	char f_buf[LIF_FILESTART];/* buffer for lif volume header and dir */
	struct lifvol *f_lp;	/* lif volume header pointer */
	struct lifdir *f_ld;	/* lif dir pointer */
	int	f_nfiles;	/* gross number for lif dir entries */

	off_t	f_seek;		/* seek pointer for file read */
	struct lifdir *f_rd;	/* lif dir pointer for readdir */

	int	f_isdir;	/* special hacky flag for '.' dir */
	int	f_count;	/* this file length */
	int	f_off;		/* this file offset */
};

int
lif_open (path, f)
	char *path;
	struct open_file *f;
{
	struct file *fp;
	struct lifdir *dp;
	char *p, *q;
	struct lif_load load;
	size_t buf_size;
	int err, l;

#ifdef LIFDEBUG
	if (debug)
		printf("lif_open(%s, %p)\n", path, f);
#endif

	fp = alloc(sizeof(*fp));
	/* XXX we're assuming here that sizeof(fp->f_buf) >= LIF_FILESTART */
	if ((err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0,
	    sizeof(fp->f_buf), &fp->f_buf, &buf_size)) ||
	    buf_size != sizeof(fp->f_buf)) {
#ifdef LIFDEBUG
		if (debug)
			printf("lif_open: unable to read LIF header (%d)\n", err);
#endif
	} else if ((fp->f_lp = (struct lifvol *)fp->f_buf)->vol_id == LIF_VOL_ID) {
		f->f_fsdata = fp;
		fp->f_ld = (struct lifdir *)(fp->f_buf + LIF_DIRSTART);
		fp->f_seek = 0;
		fp->f_rd = fp->f_ld;
		fp->f_nfiles = lifstob(fp->f_lp->vol_dirsize) /
			sizeof(struct lifdir);

		/* no dirs on the lif */
		for (p = path + (l = strlen(path)); p >= path; p--)
			if (*p == '/') {
				p++;
				break;
			}
		if (p > path)
			path = p;
	} else
		err = EINVAL;

	if (!err && *path != '.') {
		fp->f_isdir = 0;
		err = ENOENT;
		for (dp = fp->f_ld; dp < &fp->f_ld[fp->f_nfiles]; dp++) {
#ifdef LIFDEBUG
			if (debug)
				printf("lif_open: "
				       "%s <--> '%c%c%c%c%c%c%c%c%c%c'\n",
				       path, dp->dir_name[0], dp->dir_name[1],
				       dp->dir_name[2], dp->dir_name[3],
				       dp->dir_name[4], dp->dir_name[5],
				       dp->dir_name[6], dp->dir_name[7],
				       dp->dir_name[8], dp->dir_name[9]);
#endif
			for (p = path, q = dp->dir_name;
			     *q && *q != ' '; q++, p++)
				if (tolower(*q) != tolower(*p))
					break;
			if ((!*q || *q == ' ') && !*p) {
				err = 0;
				break;
			}
		}
		if (!err) {
			fp->f_off = lifstodb(dp->dir_addr);
			if (!(err =(f->f_dev->dv_strategy)(f->f_devdata, F_READ,
			      fp->f_off, sizeof(load), &load, &buf_size)) &&
			    buf_size == sizeof(load)) {
				/* no checksum */
				fp->f_count = load.count - sizeof(int);
				fp->f_off = dbtob(fp->f_off) + sizeof(load);
#ifdef LIFDEBUG
				if (debug)
					printf("lif_open: %u @ %u [%x]\n",
					       fp->f_count, fp->f_off,
					       load.address);
#endif
			} else if (!err)
				err = EIO;
		}
	} else
		fp->f_isdir = 1;

	if (err) {
		free (fp, sizeof(*fp));
		f->f_fsdata = NULL;
	}
#ifdef LIFDEBUG
	if (debug)
		printf("ret(%d)\n", err);
#endif
	return err;
}

int
lif_close(f)
	struct open_file *f;
{
	free (f->f_fsdata, sizeof(struct file));
	f->f_fsdata = NULL;
	return 0;
}

int
lif_read(f, buf, size, resid)
	struct open_file *f;
	void *buf;
	size_t size;
	size_t *resid;
{
	struct file *fp = (struct file *)f->f_fsdata;
	char *p;
	char bbuf[DEV_BSIZE];
	size_t bsize, count = sizeof(bbuf);
	int err = 0;
	int foff;

#ifdef LIFDEBUG
	if (debug)
		printf("lif_read(%p, %p, %u, %p)\n", f, buf, size, resid);
#endif

	for (p = bbuf; size; fp->f_seek += bsize, p += bsize) {
		twiddle();
		foff = fp->f_off + fp->f_seek;
		if (fp->f_seek >= fp->f_count ||
		    (err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
		     btodb(foff), count, p, &bsize)))
			break;
		if (p == bbuf) {
			bsize = sizeof(bbuf) - (foff & (sizeof(bbuf) - 1));
			bsize = min(bsize, size);
			bcopy(bbuf + (foff & (sizeof(bbuf) - 1)), buf, bsize);
			p = buf;
		}
		count = size -= bsize;
	}
	if (resid)
		*resid = size;

	return err;
}

int
lif_write(f, buf, size, resid)
	struct open_file *f;
	void *buf;
	size_t size;
	size_t *resid;
{
	return EOPNOTSUPP;
}

off_t
lif_seek(f, offset, where)
	struct open_file *f;
	off_t offset;
	int where;
{
	struct file *fp = (struct file *)f->f_fsdata;

	switch (where) {
	case SEEK_SET:
		fp->f_seek = offset;
		break;
	case SEEK_CUR:
		fp->f_seek += offset;
		break;
	case SEEK_END:
		fp->f_seek = fp->f_count - offset;
		break;
	default:
		return (-1);
	}
	return (fp->f_seek);
}

int
lif_stat(f, sb)
	struct open_file *f;
	struct stat *sb;
{
	struct file *fp = (struct file *)f->f_fsdata;

	sb->st_mode = 0755 | (fp->f_isdir? S_IFDIR: 0);	/* XXX */
	sb->st_uid = 0;
	sb->st_gid = 0;
	sb->st_size = fp->f_count;
	return 0;
}

int
lif_readdir(f, name)
	struct open_file *f;
	char *name;
{
	struct file *fp = (struct file *)f->f_fsdata;
	char *p;

	if (name) {
		while ((fp->f_rd->dir_name[0] == ' ' ||
			!fp->f_rd->dir_name[0]) &&
		       (fp->f_rd - fp->f_ld) < fp->f_nfiles)
			fp->f_rd++;
		if ((fp->f_rd - fp->f_ld) >= fp->f_nfiles) {
			*name = '\0';
			return -1;
		}
		strncpy(name, fp->f_rd->dir_name, sizeof(fp->f_rd->dir_name));
		if ((p = strchr(name, ' ')))
			*p = '\0';
		fp->f_rd++;
	} else
		fp->f_rd = fp->f_ld;

	return 0;
}