View of xos/fs/vfat_cluster_set.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 "vfat_cluster_set_struct.h"
 
#include <kmalloc.h>
#include <errno.h>
#include <stddef.h>
 
#define hash(n) (n % CLUSTER_SET_HASH_TABLE_SIZE)
 
int vfat_cluster_set_init(struct vfat_cluster_set_struct *cluster_set, unsigned int size)
{
  struct vfat_cluster_info_struct *ci;
  int i;
 
  if (!(cluster_set->cluster_info_table = kmalloc(size * sizeof (struct vfat_cluster_info_struct))))
    return -ENOMEM;
  cluster_set->cluster_info_table_size = size;
 
  for (ci = &cluster_set->cluster_info_table[0]; ci < &cluster_set->cluster_info_table[size]; ci++)
    ci->next_free = ci + 1 < &cluster_set->cluster_info_table[size] ? ci + 1 : NULL;
 
  cluster_set->first_free = cluster_set->cluster_info_table;
  cluster_set->first_nonfree = NULL;
  cluster_set->last_nonfree = NULL;
  for (i = 0; i < CLUSTER_SET_HASH_TABLE_SIZE; i++)
    cluster_set->hash_table[i] = NULL;
 
  return 0;
}
 
void vfat_cluster_set_destroy(struct vfat_cluster_set_struct *cluster_set)
{
  kfree(cluster_set->cluster_info_table, cluster_set->cluster_info_table_size * sizeof (struct vfat_cluster_info_struct));
}
 
/* n doit etre non nul. */
void vfat_cluster_set_add(struct vfat_cluster_set_struct *cluster_set, unsigned long n)
{
  unsigned long hash_code;
  struct vfat_cluster_info_struct *ci;
 
  hash_code = hash(n);
 
  for (ci = cluster_set->hash_table[hash_code]; ci; ci = ci->next_hash)
    if (ci->n == n)
      return;
 
  if (!(ci = cluster_set->first_free))
    return;
 
  ci->n = n;
 
  if (cluster_set->first_free)
    cluster_set->first_free = cluster_set->first_free->next_free;
  else
    cluster_set->first_free = NULL;
 
  ci->previous_nonfree = cluster_set->last_nonfree;
  ci->next_nonfree = NULL;
  if (cluster_set->last_nonfree)
    cluster_set->last_nonfree->next_nonfree = ci;
  else
    cluster_set->first_nonfree = ci;
  cluster_set->last_nonfree = ci;
 
  ci->next_hash = cluster_set->hash_table[hash_code];
  cluster_set->hash_table[hash_code] = ci;
}
 
/* n doit etre non nul. */
void vfat_cluster_set_del(struct vfat_cluster_set_struct *cluster_set, unsigned long n)
{
  unsigned long hash_code;
  struct vfat_cluster_info_struct *pci, *ci;
 
  hash_code = hash(n);
 
  pci = NULL;
  ci = cluster_set->hash_table[hash_code];
  while (ci) {
    if (ci->n == n)
      goto found;
    pci = ci;
    ci = ci->next_hash;
  }
  return;
 
 found:
  if (pci)
    pci->next_hash = ci->next_hash;
  else
    cluster_set->hash_table[hash_code] = ci->next_hash;
 
  if (ci->previous_nonfree)
    ci->previous_nonfree->next_nonfree = ci->next_nonfree;
  else
    cluster_set->first_nonfree = ci->next_nonfree;
  if (ci->next_nonfree)
    ci->next_nonfree->previous_nonfree = ci->previous_nonfree;
  else
    cluster_set->last_nonfree = ci->previous_nonfree;
 
  ci->next_free = cluster_set->first_free;
  cluster_set->first_free = ci;
}
 
/* Retourne 0 si la liste est vide. */
unsigned long vfat_cluster_set_get(const struct vfat_cluster_set_struct *cluster_set)
{
  return cluster_set->first_nonfree ? cluster_set->first_nonfree->n : 0;
}