View of xos/fs/rootfs.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 "file_system_struct.h"
#include "bin.h"
#include "ro_fs.h"
#include "pfs.h"
#include "pfs_structs.h"
 
#include <time.h>
#include <stat_struct.h>
#include <verify_area.h>
#include <areas.h>
#include <usr_hdr.h>
#include <segment.h>
#include <consts.h>
#include <enums.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
 
struct rootfs_file_struct;
 
struct rootfs_file_operations_struct {
  int (*find)(const struct rootfs_file_struct *, const char *, unsigned long *, int *);
  int (*get_name)(const struct rootfs_file_struct *, char []);
  int (*get_size)(const struct rootfs_file_struct *, unsigned long *);
  int (*read_dir)(const struct rootfs_file_struct *, unsigned long, char *, unsigned int);
  int (*read)(const struct rootfs_file_struct *, unsigned long, char *, unsigned int);
};
 
struct rootfs_file_struct {
  struct pfs_dir_entry_struct dir_entry;        /* entree de repertoire */
  union {
    struct pfs_dir_struct dir;                  /* repertoire */
    const void *bin_addr;                       /* addresse de fichier bin */
  };
 
  const struct rootfs_file_operations_struct *operations;
};
 
static int mount_count;                         /* nombre de montages */
static long mount_time;                         /* heure du premier montage */
 
/* Operations sur les fichiers */
 
static int stat(const struct rootfs_file_struct *file, struct stat_struct *fs_buf)
{
  struct stat_struct statbuf;
  int rv;
 
  if (!verify_area(fs_buf, sizeof (struct stat_struct), PF_WRITE))
    return -EFAULT;
 
  statbuf.dev = DEV_NONE;
  statbuf.id = file->dir_entry.info.id;
  statbuf.type = file->dir_entry.info.type;
  statbuf.rdev = DEV_NONE;
  if (file->dir_entry.info.type == FT_REG) {
    if ((rv = file->operations->get_size(file, &statbuf.size)) < 0)
      return rv;
  }
  else
    statbuf.size = 0;
  statbuf.mtime = mount_time;
  memcpy_tofs(fs_buf, &statbuf, sizeof (struct stat_struct));
  return 0;
}
 
static int root_find(const struct rootfs_file_struct *file, const char *fs_basename, unsigned long *id, int *type)
{
  return pfs_find(&file->dir, fs_basename, id, type);
}
 
static int root_get_name(const struct rootfs_file_struct *file, char name[])
{
  strcpy(name, file->dir_entry.info.name);
  return 0;
}
 
static int root_read_dir(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
  return pfs_read_dir(&file->dir, pos, fs_buf, count);
}
 
static int rootfs_bin_find(const struct rootfs_file_struct *file, const char *fs_basename, unsigned long *id, int *type)
{
  return bin_find(file->bin_addr, fs_basename, id, type);
}
 
static int rootfs_bin_get_name(const struct rootfs_file_struct *file, char name[])
{
  return bin_get_name(file->bin_addr, name);
}
 
static int rootfs_bin_read_dir(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
  return bin_read_dir(file->bin_addr, pos, fs_buf, count);
}
 
static int rootfs_bin_get_size(const struct rootfs_file_struct *file, unsigned long *size)
{
  return bin_get_size(file->bin_addr, size);
}
 
static int rootfs_bin_read(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
  return bin_read(file->bin_addr, pos, fs_buf, count);
}
 
static const struct rootfs_file_operations_struct root_dir_operations = {
  .find = root_find,
  .get_name = root_get_name,
  .read_dir = root_read_dir
};
 
static const struct rootfs_file_operations_struct bin_dir_operations = {
  .find = rootfs_bin_find,
  .get_name = root_get_name,
  .read_dir = rootfs_bin_read_dir
};
 
static const struct rootfs_file_operations_struct bin_file_operations = {
  .get_size = rootfs_bin_get_size,
  .get_name = rootfs_bin_get_name,
  .read = rootfs_bin_read
};
 
/* Fichiers */
 
/* racine */
static struct rootfs_file_struct root_dir = {
  .dir_entry = {
    .info = {
      .type = FT_DIR
    }
  },
  .operations = &root_dir_operations
};
 
/* dev */
static struct rootfs_file_struct dev_dir = {
  .dir_entry = {
    .info = {
      .name = "dev",
      .type = FT_DIR
    }
  },
  .operations = &root_dir_operations
};
 
/* proc */
static struct rootfs_file_struct proc_dir = {
  .dir_entry = {
    .info = {
      .name = "proc",
      .type = FT_DIR
    }
  },
  .operations = &root_dir_operations
};
 
/* bin */
static struct rootfs_file_struct bin_dir = {
  .dir_entry = {
    .info = {
      .name = "bin",
      .type = FT_DIR
    }
  },
  .operations = &bin_dir_operations
};
 
/* lib */
static struct rootfs_file_struct lib_dir = {
  .dir_entry = {
    .info = {
      .name = "lib",
      .type = FT_DIR
    }
  },
  .operations = &bin_dir_operations
};
 
/* floppy */
static struct rootfs_file_struct floppy_dir = {
  .dir_entry = {
    .info = {
      .name = "floppy",
      .type = FT_DIR
    }
  },
  .operations = &root_dir_operations
};
 
/* home */
static struct rootfs_file_struct home_dir = {
  .dir_entry = {
    .info = {
      .name = "home",
      .type = FT_DIR
    }
  },
  .operations = &root_dir_operations
};
 
static struct rootfs_file_struct *const root_file_index[] = {
  &root_dir,
  &dev_dir,
  &proc_dir,
  &bin_dir,
  &lib_dir,
  &floppy_dir,
  &home_dir
};
static const unsigned int root_file_index_size = sizeof root_file_index / sizeof root_file_index[0];
 
static void build_bin_file(struct rootfs_file_struct *file, const void *bin_addr)
{
  file->dir_entry.info.id = (unsigned long)bin_addr;
  file->dir_entry.info.type = FT_REG;
  file->bin_addr = bin_addr;
  file->operations = &bin_file_operations;
}
 
static int init()
{
  unsigned int i;
 
  for (i = 0; i < root_file_index_size; i++)
    root_file_index[i]->dir_entry.info.id = i;
  pfs_init_dir(&root_dir.dir);
  pfs_init_dir(&dev_dir.dir);
  pfs_init_dir(&proc_dir.dir);
  bin_dir.bin_addr = usr_start + ((const usr_hdr_t *)usr_start)->bin_offset;
  if (!bin_check(bin_dir.bin_addr))
    return -EINVAL;
  lib_dir.bin_addr = usr_start + ((const usr_hdr_t *)usr_start)->lib_offset;
  if (!bin_check(lib_dir.bin_addr))
    return -EINVAL;
  pfs_init_dir(&floppy_dir.dir);
  pfs_init_dir(&home_dir.dir);
  for (i = 1; i < root_file_index_size; i++)
    pfs_insert_dir_entry(&root_file_index[i]->dir_entry, &root_dir.dir);
  return 0;
}
 
/* resolution des fichiers */
static struct rootfs_file_struct *get_file(unsigned long id, struct rootfs_file_struct *filebuf)
{
  if (id < root_file_index_size)
    return root_file_index[id];
  else {
    build_bin_file(filebuf, (void *)id);
    return filebuf;
  }
}
 
/* Methodes du systeme de fichiers */
 
static int rootfs_mount(const struct device_struct *device, void **data)
{
  int rv;
 
  if (!mount_count) {
    mount_time = get_time();
    if ((rv = init()) < 0)
      return rv;
  }
  mount_count++;
  *data = NULL;
  return 0;
}
 
static void rootfs_umount(void *data)
{
  mount_count--;
}
 
static int rootfs_find(void *data, unsigned long dir_id, const char *fs_basename, unsigned long *id, int *type)
{
  struct rootfs_file_struct filebuf;
  const struct rootfs_file_struct *file;
 
  file = get_file(dir_id, &filebuf);
  return file->operations->find(file, fs_basename, id, type);
}
 
static int rootfs_get_name(void *data, unsigned long id, char name[])
{
  struct rootfs_file_struct filebuf;
  const struct rootfs_file_struct *file;
 
  file = get_file(id, &filebuf);
  return file->operations->get_name(file, name);
}
 
static int rootfs_get_size(void *data, unsigned long reg_id, unsigned long *size)
{
  struct rootfs_file_struct filebuf;
  const struct rootfs_file_struct *file;
 
  file = get_file(reg_id, &filebuf);
  return file->operations->get_size(file, size);
}
 
static int rootfs_stat(void *data, unsigned long id, struct stat_struct *fs_buf)
{
  struct rootfs_file_struct filebuf;
 
  return stat(get_file(id, &filebuf), fs_buf);
}
 
static int rootfs_read_dir(void *data, unsigned long dir_id, unsigned long pos, char *fs_buf, unsigned int count)
{
  struct rootfs_file_struct filebuf;
  const struct rootfs_file_struct *file;
 
  file = get_file(dir_id, &filebuf);
  return file->operations->read_dir(file, pos, fs_buf, count);
}
 
static int rootfs_read(void *data, unsigned long leaf_id, unsigned long pos, char *fs_buf, unsigned int count)
{
  struct rootfs_file_struct filebuf;
  const struct rootfs_file_struct *file;
 
  file = get_file(leaf_id, &filebuf);
  return file->operations->read(file, pos, fs_buf, count);
}
 
const struct file_system_struct rootfs = {
  .name = "rootfs",
  .type = FT_NONE,
  .mount = rootfs_mount,
  .umount = rootfs_umount,
  .find = rootfs_find,
  .get_name = rootfs_get_name,
  .get_device = NULL,
  .get_size = rootfs_get_size,
  .stat = rootfs_stat,
  .read_dir = rootfs_read_dir,
  .read = rootfs_read,
  .write = no_write,
  .ioctl = NULL,
  .create = no_create,
  .mkdir = no_mkdir,
  .can_remove = no_can_remove,
  .remove = no_remove,
  .rmdir = no_rmdir,
  .rename = no_rename
};