#include <stdlib.h>
#include "nfs_iio.h"
#include "nfs_fat.h"
static void node_set_value(nfs_fat_FAT* fat, int node_idx, int value) {
int v = value;
nfs_iio_seek(fat->file, fat->channel, node_idx * sizeof(int));
nfs_iio_write(fat->file, fat->channel, &v, sizeof(int));
}
static int node_get_value(nfs_fat_FAT* fat, int node_idx) {
int value;
nfs_iio_seek(fat->file, fat->channel, node_idx * sizeof(int));
nfs_iio_read(fat->file, fat->channel, &value, sizeof(int));
return value;
}
static int node_recover(nfs_fat_FAT* fat, int node_idx) {
if (node_idx > 0)
node_set_value(fat, node_idx, 0);
if ((node_idx < fat->unallocated) && (node_idx > 0))
fat->unallocated = node_idx;
return 1;
}
static int next_free(nfs_fat_FAT* fat, int start) {
int node = start;
while ((node <= 0) || (node_get_value(fat, node) != 0))
node++;
return node;
}
static int find_last_in_chain(nfs_fat_FAT* fat, int start) {
int node = start;
int last_node;
do {
last_node = node;
node = node_get_value(fat, node);
} while (node != nfs_fat_EOC);
return last_node;
}
nfs_fat_FAT* nfs_fat_create(nfs_iio_File* file, int blocks_per_channel) {
int chn;
nfs_fat_FAT* fat;
if (file == NULL)
return NULL;
if (blocks_per_channel == 0)
blocks_per_channel = nfs_fat_DEF_CHANNEL_SIZE;
chn = nfs_iio_allocate_channel(file, blocks_per_channel);
fat = (nfs_fat_FAT*)malloc(sizeof(nfs_fat_FAT));
fat->file = file;
fat->channel = chn;
fat->unallocated = 1;
return fat;
}
nfs_fat_FAT* nfs_fat_open(nfs_iio_File* file, int channel_no) {
nfs_fat_FAT* fat;
if (file == NULL)
return NULL;
fat = (nfs_fat_FAT*)malloc(sizeof(nfs_fat_FAT));
fat->channel = channel_no;
fat->file = file;
fat->unallocated = next_free(fat, 0);
return fat;
}
int nfs_fat_close (nfs_fat_FAT* fat) {
if (fat != NULL)
free(fat);
return 0;
}
int nfs_fat_create_chain(nfs_fat_FAT* fat) {
int node;
if ((fat == NULL) || (fat->file == NULL))
return -1;
node = fat->unallocated;
node_set_value(fat, node, nfs_fat_EOC);
fat->unallocated = next_free(fat, fat->unallocated);
return node;
}
int nfs_fat_destroy_chain(nfs_fat_FAT* fat, int first_node_index) {
if ((fat == NULL) || (fat->file == NULL) || (first_node_index <= 0))
return -1;
nfs_fat_chain_for_each(fat, first_node_index, node_recover);
return 0;
}
int nfs_fat_chain_truncate(nfs_fat_FAT* fat, int first) {
int following;
if ((fat == NULL) || (fat->file == NULL))
return -1;
following = node_get_value(fat, first);
node_set_value(fat, first, nfs_fat_EOC);
if (following != nfs_fat_EOC)
nfs_fat_destroy_chain(fat, following);
return 0;
}
int nfs_fat_chain_extend(nfs_fat_FAT* fat, int first_node_index) {
int node, last_node;
if ((fat == NULL) || (fat->file == NULL))
return -1;
node = fat->unallocated;
node_set_value(fat, node, nfs_fat_EOC);
fat->unallocated = next_free(fat, fat->unallocated);
last_node = find_last_in_chain(fat, first_node_index);
node_set_value(fat, last_node, node);
return node;
}
int nfs_fat_chain_shrink(nfs_fat_FAT* fat, int first_node_index, int last_n) {
int node = first_node_index;
int prev_node = nfs_fat_EOC;
int nth = 0;
int nth2 = 0;
if ((fat == NULL) || (fat->file == NULL))
return -1;
while (node != nfs_fat_EOC) {
node = node_get_value(fat, node);
nth++;
}
node = first_node_index;
nth2 = 0;
while (nth2 < (nth - last_n)) {
prev_node = node;
node = node_get_value(fat, node);
nth2++;
}
nfs_fat_destroy_chain(fat, node);
if (prev_node != nfs_fat_EOC)
node_set_value(fat, prev_node, nfs_fat_EOC);
return 0;
}
void nfs_fat_chain_get(nfs_fat_FAT* fat, int first_node_index, void* buf) {
int node = first_node_index;
int nth = 0;
if ((fat == NULL) || (fat->file == NULL))
return;
while (node != nfs_fat_EOC) {
*((int*)buf + nth) = node;
node = node_get_value(fat, node);
nth++;
}
}
void nfs_fat_chain_get_first_n(nfs_fat_FAT* fat, int first_node_index, int n, void* buf) {
int node = first_node_index;
int nth = 0;
if ((fat == NULL) || (fat->file == NULL))
return;
while ( (nth <= (n-1)) && (node != nfs_fat_EOC) ) {
*((int*)buf + nth) = node;
node = node_get_value(fat, node);
nth++;
}
}
int nfs_fat_chain_get_nth(nfs_fat_FAT* fat, int first_node_index, int n) {
int node = first_node_index;
int nth = 0;
if ((fat == NULL) || (fat->file == NULL))
return -1;
while ( (nth < n) && (node != nfs_fat_EOC) ) {
node = node_get_value(fat, node);
nth++;
}
return node;
}
void nfs_fat_chain_for_each(nfs_fat_FAT* fat, int first_node_index, int (*p)(nfs_fat_FAT*, int)) {
int node = first_node_index;
int node2 = node;
int quit = 0;
if ((fat == NULL) || (fat->file == NULL))
return;
do {
node2 = node_get_value(fat, node);
if (!p(fat, node))
quit = 1;
else {
if (node <= 0)
quit = 1;
node = node2;
}
} while ( !quit && (node != nfs_fat_EOC) );
}