BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / master / vfs / inode.c

// Related

Orion

Barry Adding pipes e59e4fe (2 years, 4 months ago)
/*
 * This file deals with inode operations.  Most of the functions here are just
 * wrappers for the inode operations.  They generally check if the operation
 * exists and use it if it does.  If it doesn't they may implement a generic
 * action, or just simply return.  They also perform the necessary validation to
 * ensure the operation can be called on the particular inode.
 */

#include <string.h>
#include <errno.h>
#include "vfs.h"
#include "cache.h"
#include "inode.h"
#include "super.h"
#include "../mem/heap.h"
#include "../screen.h"

/* Get an Inode */
Inode *
inode_get(Inode *inode)
{
	/* Add the inode to the Inode List */
	if (!inode->usage && inode->super) {
		if (!inode->super->inodes) {
			inode->super->inodes = inode;
		} else {
			inode->lnext = inode->super->inodes;
			inode->super->inodes = inode;
		}
		inode->super->cachedInodes++;
	}

	inode->usage++;
	return inode;
}

/* Put an Inode */
void
inode_put(Inode *inode)
{
	ASSERT(inode->usage);
	if (--inode->usage)
		return;

	/* Remove the inode from the Inode List */
	Inode *search, *prev = NULL;
	if (inode->super) {
		for (search = inode->super->inodes; search;
		     prev = search, search = search->lnext)
			if (search == inode)
				break;
		if (search) {
			if (prev)
				prev->lnext = search->lnext;
			else
				inode->super->inodes = search->lnext;
		}
	}

	/* Clean up */
	if (inode->free_extra)
		inode->free_extra(inode);
	if (S_ISDIR(inode->mode))
		entry_clean(inode);
	else
		page_clean(inode);

	kfree(inode);
}

/* Create an inode */
int
inode_create(Inode *inode, DirEntry *entry, mode_t mode)
{
	if (!inode->ops)
		return -EINVAL;
	if (!inode->ops->create)
		return -EINVAL;
	acquire(&inode->lock);
	int err = inode->ops->create(inode, entry, mode);
	if (!err) {
		entry_add(inode, entry);
		entry->inode = super_alloc_inode(inode->super);
		entry->inode->mode = mode | S_IFREG;
	}
	release(&inode->lock);
	return err;
}

/* Find a child inode in a directory inode */
DirEntry *
inode_lookup(Inode *inode, const char *name)
{
	if (!S_ISDIR(inode->mode))
		return NULL;

	acquire(&inode->lock);

	/* Check cache first */
	DirEntry *de = entry_find(inode, name);
	if (de) {
		entry_get(de);
		if (de->inode) {
			release(&inode->lock);
			return de;
		}
	}
	/* Try file system lookup */
	if (!inode->ops) {
		release(&inode->lock);
		return NULL;
	}
	if (!inode->ops->lookup) {
		release(&inode->lock);
		return NULL;
	}
	Inode *child = inode->ops->lookup(inode, name);

	/* The file doesn't exist */
	if (!child) {
		if (de)
			entry_remove(inode, name);
		release(&inode->lock);
		return NULL;
	}

	/* Fill in DirEntry */
	if (!de) {
		de = kmalloc(sizeof(DirEntry));
		strncpy(de->name, name, NAME_MAX);
		de->super = inode->super;
		entry_add(inode, de);
	}
	de->inode = inode_get(child);
	de->mnt = NULL;
	release(&inode->lock);

	return entry_get(de);
}

/* Make a directory */
int
inode_mkdir(Inode *inode, DirEntry *entry, mode_t mode)
{
	if (!inode->ops)
		return -EINVAL;
	if (!inode->ops->mkdir)
		return -EINVAL;
	acquire(&inode->lock);
	int err = inode->ops->mkdir(inode, entry, mode);
	if (!err) {
		entry_add(inode, entry);
		entry->inode = super_alloc_inode(inode->super);
		entry->inode->mode = mode | S_IFDIR;
	}
	release(&inode->lock);
	return err;
}

/* Remove a directory */
int
inode_rmdir(Inode *inode, DirEntry *entry)
{
	if (!inode->ops)
		return -EINVAL;
	if (!inode->ops->rmdir)
		return -EINVAL;
	acquire(&inode->lock);
	int err = inode->ops->rmdir(inode, entry);
	if (!err)
		entry_remove(inode, entry->name);
	release(&inode->lock);
	return err;
}

/* Make a node */
int
inode_mknod(Inode *inode, DirEntry *entry, mode_t mode, dev_t dev)
{
	if (!inode->ops)
		return -EINVAL;
	if (!inode->ops->mknod)
		return -EINVAL;
	acquire(&inode->lock);

	int err = inode->ops->mknod(inode, entry, mode, dev);
	if (!err) {
		entry_add(inode, entry);
		entry->inode = super_alloc_inode(inode->super);
		entry->inode->mode = mode; /* FIXME */
		entry->inode->dev = dev;
	}
	release(&inode->lock);
	return err;
}

/* Rename/mode a directory entry */
int
inode_rename(Inode *si, DirEntry *sde, Inode *di, DirEntry *dde)
{
	if (!si->ops)
		return -EINVAL;
	if (!si->ops->rename)
		return -EINVAL;
	return 0;
}