BarryServer : Git

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

// Related

Nucleus

Barry Device file system 88d672a (3 years, 3 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 <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <nucleus/object.h>
#include <nucleus/memory.h>
#include <nucleus/task.h>
#include <nucleus/vfs.h>

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

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

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

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

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

	/* Clean cache */
	destroy_list(inode->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);
		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;
}