[BACK]Return to arfs_vnops.c CVS log [TXT][DIR] Up to [local] / prex-old / usr / server / fs / arfs

File: [local] / prex-old / usr / server / fs / arfs / arfs_vnops.c (download)

Revision 1.1, Tue Jun 3 09:38:51 2008 UTC (15 years, 11 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*
 * Copyright (c) 2006-2007, Kohsuke Ohtani
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * arfs_vnops.c - vnode operations for archive file system.
 */

#include <prex/prex.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/dirent.h>
#include <sys/buf.h>

#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <ar.h>

#include "arfs.h"

#define arfs_open	((vnop_open_t)vop_nullop)
#define arfs_close	((vnop_close_t)vop_nullop)
static int arfs_read(vnode_t, file_t, void *, size_t, size_t *);
#define arfs_write	((vnop_write_t)vop_nullop)
static int arfs_seek(vnode_t, file_t, off_t, off_t);
#define arfs_ioctl	((vnop_ioctl_t)vop_einval)
#define arfs_fsync	((vnop_fsync_t)vop_nullop)
static int arfs_readdir(vnode_t, file_t, struct dirent *);
static int arfs_lookup(vnode_t, char *, vnode_t);
#define arfs_create	((vnop_create_t)vop_einval)
#define arfs_remove	((vnop_remove_t)vop_einval)
#define arfs_rename	((vnop_rename_t)vop_einval)
#define arfs_mkdir	((vnop_mkdir_t)vop_einval)
#define arfs_rmdir	((vnop_rmdir_t)vop_einval)
#define arfs_getattr	((vnop_getattr_t)vop_nullop)
#define arfs_setattr	((vnop_setattr_t)vop_nullop)
#define arfs_inactive	((vnop_inactive_t)vop_nullop)
#define arfs_truncate	((vnop_truncate_t)vop_nullop)

static char iobuf[BSIZE*2];

#if CONFIG_FS_THREADS > 1
static mutex_t arfs_lock = MUTEX_INITIALIZER;
#endif

/*
 * vnode operations
 */
const struct vnops arfs_vnops = {
	arfs_open,		/* open */
	arfs_close,		/* close */
	arfs_read,		/* read */
	arfs_write,		/* write */
	arfs_seek,		/* seek */
	arfs_ioctl,		/* ioctl */
	arfs_fsync,		/* fsync */
	arfs_readdir,		/* readdir */
	arfs_lookup,		/* lookup */
	arfs_create,		/* create */
	arfs_remove,		/* remove */
	arfs_rename,		/* remame */
	arfs_mkdir,		/* mkdir */
	arfs_rmdir,		/* rmdir */
	arfs_getattr,		/* getattr */
	arfs_setattr,		/* setattr */
	arfs_inactive,		/* inactive */
	arfs_truncate,		/* truncate */
};

/*
 * Read two blocks.
 * iobuf is filled by read data.
 */
static int
arfs_readblk(mount_t mp, int blkno)
{
	struct buf *bp;
	int err;

	/* Read two blocks for archive header */
	if ((err = bread(mp->m_dev, blkno, &bp)) != 0)
		return err;
	memcpy(iobuf, bp->b_data, BSIZE);
	brelse(bp);

	if ((err = bread(mp->m_dev, blkno + 1, &bp)) != 0)
		return err;
	memcpy(iobuf + BSIZE, bp->b_data, BSIZE);
	brelse(bp);
	return 0;
}

/*
 * Lookup vnode for the specified file/directory.
 * The vnode is filled properly.
 */
static int
arfs_lookup(vnode_t dvp, char *name, vnode_t vp)
{
	struct ar_hdr *hdr;
	int blkno, err;
	off_t off;
	size_t size;
	mount_t mp;
	char *p;

	dprintf("lookup: name=%s\n", name);
	if (*name == '\0')
		return ENOENT;

	mutex_lock(&arfs_lock);

	err = ENOENT;
	mp = vp->v_mount;
	blkno = 0;
	off = SARMAG;	/* offset in archive image */
	for (;;) {
		/* Read two blocks for archive header */
		if (arfs_readblk(mp, blkno) != 0)
			goto out;

		/* Check file header */
		hdr = (struct ar_hdr *)(iobuf + (off % BSIZE));
		if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
			goto out;

		/* Get file size */
		size = (size_t)atol((char *)&hdr->ar_size);
		if (size == 0)
			goto out;

		/* Convert archive name */
		if ((p = memchr(&hdr->ar_name, '/', 16)) != NULL)
			*p = '\0';

		if (strncmp(name, (char *)&hdr->ar_name, 16) == 0)
			break;

		/* Proceed to next archive header */
		off += (sizeof(struct ar_hdr) + size);
		off += (off % 2); /* Pad to even boundary */

		blkno = (int)(off / BSIZE);
	}
	vp->v_type = VREG;

	/* No write access */
	vp->v_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP
		| S_IROTH | S_IXOTH;
	vp->v_size = size;
	vp->v_blkno = blkno;
	vp->v_data = (void *)(off + sizeof(struct ar_hdr));
	err = 0;
 out:
	mutex_unlock(&arfs_lock);
	dprintf("lookup: err=%d\n\n", err);
	return err;
}

static int
arfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
{
	off_t off, file_pos, buf_pos;
	int blkno, err;
	size_t nr_read, nr_copy;
	mount_t mp;
	struct buf *bp;

	dprintf("****read: start size=%d\n", size);
	mutex_lock(&arfs_lock);

	*result = 0;
	mp = vp->v_mount;

	/* Check if current file position is already end of file. */
	file_pos = fp->f_offset;
	if (file_pos >= (off_t)vp->v_size) {
		err = 0;
		goto out;
	}
	/* Get the actual read size. */
	if (vp->v_size - file_pos < size)
		size = vp->v_size - file_pos;

	/* Read and copy data */
	off = (off_t)vp->v_data;
	nr_read = 0;
	for (;;) {
		dprintf("file_pos=%d buf=%x size=%d\n", file_pos, buf, size);

		blkno = (off + file_pos) / BSIZE;
		buf_pos = (off + file_pos) % BSIZE;
		if ((err = bread(mp->m_dev, blkno, &bp)) != 0)
			goto out;
		nr_copy = BSIZE;
		if (buf_pos > 0)
			nr_copy -= buf_pos;
		if (buf_pos + size < BSIZE)
			nr_copy = size;
		ASSERT(nr_copy > 0);
		memcpy(buf, bp->b_data + buf_pos, nr_copy);
		brelse(bp);

		file_pos += nr_copy;
		dprintf("file_pos=%d nr_copy=%d\n", file_pos, nr_copy);

		nr_read += nr_copy;
		size -= nr_copy;
		if (size <= 0)
			break;
		buf = (void *)((u_long)buf + nr_copy);
		buf_pos = 0;
	}
	fp->f_offset = file_pos;
	*result = nr_read;
	err = 0;
 out:
	mutex_unlock(&arfs_lock);
	dprintf("read: err=%d\n\n", err);
	return err;
}

/*
 * Check if the seek offset is valid.
 */
static int
arfs_seek(vnode_t vp, file_t fp, off_t oldoff, off_t newoff)
{

	if (newoff > (off_t)vp->v_size)
		return -1;

	return 0;
}

static int
arfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
{
	struct ar_hdr *hdr;
	int blkno, i, err;
	off_t off;
	size_t size;
	mount_t mp;
	char *p;

	dprintf("readdir: start\n");
	mutex_lock(&arfs_lock);

	i = 0;
	mp = vp->v_mount;
	blkno = 0;
	off = SARMAG;	/* offset in archive image */
	for (;;) {
		/* Read two blocks for archive header */
		if ((err = arfs_readblk(mp, blkno)) != 0)
			goto out;

		hdr = (struct ar_hdr *)(iobuf + (off % BSIZE));

		/* Get file size */
		size = (size_t)atol((char *)&hdr->ar_size);
		if (size == 0) {
			err = ENOENT;
			goto out;
		}
		if (i == fp->f_offset)
			break;

		/* Proceed to next archive header */
		off += (sizeof(struct ar_hdr) + size);
		off += (off % 2); /* Pad to even boundary */

		blkno = off / BSIZE;
		i++;
	}

	/* Convert archive name */
	if ((p = memchr(&hdr->ar_name, '/', 16)) != NULL)
		*p = '\0';

	strcpy((char *)&dir->d_name, (char *)&hdr->ar_name);
	dir->d_namlen = strlen(dir->d_name);
	dir->d_fileno = fp->f_offset;
	dir->d_type = DT_REG;

	fp->f_offset++;
	err = 0;
 out:
	mutex_unlock(&arfs_lock);
	return err;
}


int
arfs_init(void)
{
	return 0;
}