BarryServer : Git

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

// Related

Nucleus

Barry System headers (remove libc dependency) 18495cf (3 years, 2 months ago)
/*
 * This file implements the Inode object and associated inode operations.  Most
 * of the functions here are just wrappers for the file system specific inode
 * operations.  They generally check if the operation exists and use it if it
 * does.  If one does not exist, a function 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 <sys/errno.h>
#include <sys/stat.h>
#include <nucleus/lib.h>
#include <nucleus/memory.h>
#include <nucleus/object.h>
#include <nucleus/task.h>
#include <nucleus/vfs.h>

static void inode_new(Object *);
static void inode_delete(Object *);
static void inode_copy(Object *, Object *);

/* Inode object type */
ObjectType inodeType = {
	.name = "INODE",
	.size = sizeof(Inode),
	.new = inode_new,
	.delete = inode_delete,
	.copy = inode_copy,
};

/* Create a new Inode */
static void
inode_new(Object *obj)
{
	Inode *inode = (void *) obj;
	inode->dirEntries = create_list(&dirEntryType, LIST_NORMAL);
	inode->pages = create_list(&pageType, LIST_NORMAL);
}

/* Destroy an Inode */
static void
inode_delete(Object *obj)
{
	Inode *inode = (void *) obj;

	/* Remove inode from the SuperBlock's list */
	if (inode->super) {
		remove(inode->super->inodes, inode);
		put(inode->super);
	}

	/* Clean cache */
	destroy_list(inode->pages);
}

/* Copy an Inode */
static void
inode_copy(Object *a, Object *b)
{
	Inode *parent = (void *) a, *child = (void *) b;
	child->ino = parent->ino;
	child->uid = parent->uid;
	child->gid = parent->gid;
	child->mode = parent->mode;
	child->nlink = parent->nlink;
	child->size = parent->size;
	child->dev = parent->dev;
	child->ops = parent->ops;
	child->fileOps = parent->fileOps;
	if (parent->super)
		child->super = get(parent->super);
	if (parent->dirEntries)
		child->dirEntries = copy_list(parent->dirEntries);
	if (parent->pages)
		child->pages = copy_list(parent->pages);
}

/* Check if a process has permission to access an inode */
int
permission(Inode *inode, int mask)
{
	if (!inode)
		return 0;

	int mode = inode->mode;
	if (current->euid == inode->uid)
		mode >>= 6;
	else if (current->egid == inode->gid)
		mode >>= 3;

	if (((mode & mask & 0007) == mask) || super_user())
		return 1;
	return 0;
}

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

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

	/* Check cache first */
	DirEntry *entry = find_direntry(inode->dirEntries, name);
	if (entry) {
		get(entry);
		if (entry->inode)
			goto end;
	}
	/* Try file system lookup */
	if (!inode->ops || !inode->ops->lookup) {
		entry = NULL;
		goto end;
	}
	Inode *child = inode->ops->lookup(inode, name);

	/* The file doesn't exist */
	if (!child) {
		if (entry) {
			remove(inode->dirEntries, entry);
			put(entry);
		}
		entry = NULL;
		goto end;
	}

	/* Fill in DirEntry */
	if (!entry) {
		entry = new(&dirEntryType);
		strncpy(entry->name, name, NAME_MAX);
		entry->super = inode->super;
		add(inode->dirEntries, entry);
	}
	entry->inode = get(child);

end:
	unlock(inode);
	return entry;
}

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


/* Remove a directory wrapper */
int
inode_rmdir(Inode *inode, DirEntry *entry)
{
	if (!inode->ops || !inode->ops->mkdir)
		return -EINVAL;
	lock(inode);
	int err = inode->ops->rmdir(inode, entry);
	if (!err)
		remove(inode->dirEntries, entry);
	unlock(inode);
	return err;
}

/* Make a special node wrapper */
int
inode_mknod(Inode *inode, DirEntry *entry, mode_t mode, dev_t dev)
{
	if (!inode->ops || !inode->ops->mknod)
		return -EINVAL;
	lock(inode);
	int err = inode->ops->mknod(inode, entry, mode, dev);
	if (!err) {
		add(inode->dirEntries, entry);
		entry->inode = super_alloc_inode(inode->super);
		entry->inode->mode = mode;
		entry->inode->dev = dev;
	}
	unlock(inode);
	return err;
}