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;
}