View of xos/fs/fd.c


XOS | Parent Directory | View | Download

/* 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 <http://www.gnu.org/licenses/>. */
 
#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;
 
/* 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);
}