#include "resolve.h"
#include "node.h"
#include "pipe.h"
#include "file.h"
#include <vm.h>
#include <printk.h>
#include <errno.h>
#include <consts.h>
#include <config.h>
#include <stddef.h>
struct stat_struct;
static struct file_descr_struct {
struct file_struct *file;
unsigned read : 1;
unsigned write : 1;
unsigned close_on_exec : 1;
unsigned long pos;
unsigned int count;
void (*release)(struct file_struct *);
} file_descr_table[NR_OPEN];
static void init_file_descr_table()
{
struct file_descr_struct *fd;
for (fd = &file_descr_table[0]; fd < &file_descr_table[NR_OPEN]; fd++)
fd->file = NULL;
}
static struct file_descr_struct *get_free_file_descr()
{
static struct file_descr_struct *fd = &file_descr_table[0];
unsigned int i;
for (i = NR_OPEN; i > 0; i--) {
if (!fd->file)
return fd;
if (++fd == &file_descr_table[NR_OPEN])
fd = &file_descr_table[0];
}
return NULL;
}
static void init_file_descr(struct file_descr_struct *file_descr, struct file_struct *file, int flags, void (*release)(struct file_struct *))
{
file_descr->file = file;
file_descr->read = flags & O_READ ? 1 : 0;
file_descr->write = flags & O_WRITE ? 1 : 0;
file_descr->close_on_exec = 0;
file_descr->pos = 0;
file_descr->count = 1;
file_descr->release = release;
}
static void release_node_write(struct file_struct *node)
{
node_release_write_access(node);
node_release(node);
}
static int alloc_node_file_descr(struct file_struct *node, int flags, struct file_descr_struct **node_file_descr)
{
int retval;
if (!(*node_file_descr = get_free_file_descr())) {
retval = -ENFILE;
goto error;
}
init_file_descr(*node_file_descr, node, flags, flags & O_WRITE ? release_node_write : node_release);
node_hold(node);
if (flags & O_WRITE)
if ((retval = node_get_write_access(node)) < 0)
goto error_release;
return 0;
error_release:
node_release(node);
error:
return retval;
}
static int alloc_pipe_read_file_descr(struct file_struct *pipe, struct file_descr_struct **pipe_file_descr)
{
if (!(*pipe_file_descr = get_free_file_descr()))
return -ENFILE;
init_file_descr(*pipe_file_descr, pipe, O_READ, pipe_release_read);
pipe_hold_read(pipe);
return 0;
}
static int alloc_pipe_write_file_descr(struct file_struct *pipe, struct file_descr_struct **pipe_file_descr)
{
if (!(*pipe_file_descr = get_free_file_descr()))
return -ENFILE;
init_file_descr(*pipe_file_descr, pipe, O_WRITE, pipe_release_write);
pipe_hold_write(pipe);
return 0;
}
static void free_file_descr(struct file_descr_struct *file_descr)
{
file_descr->release(file_descr->file);
file_descr->file = NULL;
}
static void hold_file_descr(struct file_descr_struct *file_descr)
{
file_descr->count++;
}
static void release_file_descr(struct file_descr_struct *file_descr)
{
file_descr->count--;
if (!file_descr->count)
free_file_descr(file_descr);
}
void fd_init()
{
init_file_descr_table();
}
void fd_print_info()
{
printk("File descriptor table size: %d\n", NR_OPEN);
}
int fd_open(const char *fs_filename, int flags, struct file_descr_struct **file_descr)
{
int retval;
struct file_struct *nd;
if ((retval = resolve(fs_filename, &nd)) < 0)
goto end;
if ((retval = alloc_node_file_descr(nd, flags, file_descr)) < 0)
goto release;
retval = 0;
release:
node_release(nd);
end:
return retval;
}
void fd_close(struct file_descr_struct *file_descr)
{
release_file_descr(file_descr);
}
int fd_get_close_on_exec(struct file_descr_struct *file_descr)
{
return file_descr->close_on_exec;
}
void fd_set_close_on_exec(struct file_descr_struct *file_descr, int close_on_exec)
{
file_descr->close_on_exec = close_on_exec ? 1 : 0;
}
void fd_dup(struct file_descr_struct *file_descr)
{
hold_file_descr(file_descr);
}
int fd_read(struct file_descr_struct *file_descr, char *fs_buf, unsigned int count)
{
if (!file_descr->read)
return -EBADF;
return file_read(file_descr->file, &file_descr->pos, fs_buf, count);
}
int fd_write(struct file_descr_struct *file_descr, const char *fs_buf, unsigned int count)
{
if (!file_descr->write)
return -EBADF;
return file_write(file_descr->file, &file_descr->pos, fs_buf, count);
}
long fd_seek(struct file_descr_struct *file_descr, long offset, int whence)
{
return file_seek(file_descr->file, &file_descr->pos, offset, whence);
}
int fd_pipe(struct file_descr_struct *file_descr[2])
{
int retval;
struct file_struct *p;
if ((retval = alloc_pipe(&p)) < 0)
goto error;
if ((retval = alloc_pipe_read_file_descr(p, &file_descr[0])) < 0)
goto error;
if ((retval = alloc_pipe_write_file_descr(p, &file_descr[1])) < 0)
goto error_release;
return 0;
error_release:
release_file_descr(file_descr[0]);
error:
return retval;
}
int fd_stat(const struct file_descr_struct *file_descr, struct stat_struct *fs_buf)
{
return file_stat(file_descr->file, fs_buf);
}
int fd_ioctl(struct file_descr_struct *file_descr, int request, void *fs_arg)
{
return file_ioctl(file_descr->file, request, fs_arg);
}
int fd_map(struct vm_struct *vm, unsigned long start, unsigned long length, int prot, struct file_descr_struct *file_descr, unsigned long offset)
{
return vm_map_file(vm, start, length, prot, file_descr->file, offset);
}