/* 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); }