Nucleus
Barry More VFS functions and structure d3f787c (3 years, 2 months ago)
/*
* This file implements the Files object, which is the namespace for a task's
* files. It stores all the opened files for a task. It also implements many
* of the file-based system calls that need to use a file descriptor.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <nucleus/object.h>
#include <nucleus/task.h>
#include <nucleus/memory.h>
#include <nucleus/vfs.h>
/* Structure for a Files namespace */
struct Files {
Object obj;
File *fd[NFILES];
};
static void files_delete(Object *);
static void files_copy(Object *, Object *);
/* Files object type */
ObjectType filesType = {
.name = "FILES",
.size = sizeof(Files),
.delete = files_delete,
.copy = files_copy,
};
/* Destroy a Files object */
static void
files_delete(Object *obj)
{
Files *files = (void *) obj;
int fd;
for (fd = 0; fd < NFILES; fd++)
if (files->fd[fd])
put(files->fd[fd]);
}
/* Copy a Files object */
static void
files_copy(Object *a, Object *b)
{
Files *parent = (void *) a, *child = (void *) b;
File *file;
int fd;
for (fd = 0; fd < NFILES; fd++) {
file = parent->fd[fd];
if (!file)
continue;
child->fd[fd] = get(file);
}
}
/* Get the file described by fd */
File *
get_file_by_fd(int fd)
{
if (fd < 0 || fd >= NFILES)
return NULL;
return current->files->fd[fd];
}
/* Allocate file descriptor */
int
allocate_fd(void)
{
int fd;
for (fd = 0; fd < NFILES; fd++)
if (!current->files->fd[fd])
break;
if (fd == NFILES)
fd = -1;
return fd;
}
/* Install a file in a file descriptor */
void
install_fd(int fd, File *file)
{
current->files->fd[fd] = file;
}
/* Close a file */
int
close(int fd)
{
if (!get_file_by_fd(fd))
return -EBADF;
put(current->files->fd[fd]);
current->files->fd[fd] = NULL;
return 0;
}
/* Read a file */
int
read(int fd, void *buf, size_t count)
{
if (!buf)
return -EFAULT;
if (!verify_access(buf, count, PROT_WRITE))
return -EFAULT;
File *file = get_file_by_fd(fd);
if (!file)
return -EBADF;
if (file->inode && S_ISDIR(file->inode->mode))
return -EISDIR;
lock(file);
int sz = file_read(file, buf, count);
unlock(file);
return sz;
}
/* Write a file */
int
write(int fd, void *buf, size_t count)
{
if (!buf)
return -EFAULT;
if (!verify_access(buf, count, PROT_READ))
return -EFAULT;
File *file = get_file_by_fd(fd);
if (!file)
return -EBADF;
if (file->inode && S_ISDIR(file->inode->mode))
return -EISDIR;
lock(file);
int sz = file_write(file, buf, count);
unlock(file);
return sz;
}
/* Move a file's position */
off_t
lseek(int fd, off_t offset, int whence)
{
File *file = get_file_by_fd(fd);
if (!file)
return -EBADF;
lock(file);
switch (whence) {
case SEEK_SET:
file->pos = offset;
break;
case SEEK_CUR:
file->pos += offset;
break;
case SEEK_END:
file->pos = file->inode->size + offset;
break;
default:
unlock(file);
return -EINVAL;
}
unlock(file);
return file->pos;
}
/* Perform I/O control on a file */
int
ioctl(int fd, unsigned long request, ...)
{
File *file = get_file_by_fd(fd);
if (!file)
return -EBADF;
va_list args;
va_start(args, request);
uintptr_t argp = va_arg(args, uintptr_t);
va_end(args);
lock(file);
int ret = file_ioctl(file, request, argp);
unlock(file);
return ret;
}