/* Copyright (C) 2008 Emmanuel Varoquaux
This file is part of XOS.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include "resolve.h"
#include "node.h"
#include "pipe.h"
#include "file.h"
#include
#include
#include
#include
#include
#include
struct stat_struct;
/* Une entree est consideree comme libre dans la table des fichiers ouverts si
* son fichier est nul. */
static struct file_descr_struct {
struct file_struct *file; /* fichier */
unsigned read : 1; /* ouvert en lecture */
unsigned write : 1; /* ouvert en ecriture */
unsigned close_on_exec : 1; /* fermeture lors d'un exec() */
unsigned long pos; /* position dans le fichier */
unsigned int count; /* nombre de references */
void (*release)(struct file_struct *); /* fonction de relachement */
} file_descr_table[NR_OPEN];
/* Fichiers ouverts */
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; /* table pleine */
}
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);
}
/* Fonctions exportees */
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;
}
/* dup ne duplique pas le descripteur de fichier proprement dit, il lui compte
* juste une reference supplementaire. */
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);
}