|
|
@ -1,876 +0,0 @@ |
|
|
|
#ifndef LSFS_DISK_CONTROLLER_H |
|
|
|
#define LSFS_DISK_CONTROLLER_H |
|
|
|
|
|
|
|
#include <errno.h> |
|
|
|
#include <assert.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <string.h> |
|
|
|
#include <stdint.h> |
|
|
|
#include <stdbool.h> |
|
|
|
#include <time.h> |
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
#include "lsfs_string.h" |
|
|
|
|
|
|
|
typedef struct Directory_Table Directory_Table; |
|
|
|
typedef struct struct_table_entry struct_table_entry; |
|
|
|
typedef struct struct_partition_control partition_control; |
|
|
|
typedef struct File_System_Control_Information FSCI; |
|
|
|
typedef struct meta_information_format mif; |
|
|
|
typedef struct tag_record tag_record; |
|
|
|
typedef struct lsfs_file lsfs_file; |
|
|
|
typedef enum Table_Entry_Kind Table_Entry_Kind; |
|
|
|
|
|
|
|
typedef uint64_t lsfs_sector_offset; |
|
|
|
typedef lsfs_sector_offset lsfs_file_id; |
|
|
|
|
|
|
|
//typedef uint64_t sector_index; |
|
|
|
static FILE* disk; |
|
|
|
static partition_control p_control; |
|
|
|
static time_t timestamp_loading; |
|
|
|
|
|
|
|
int create_file_system(char* disk_name, char* hdd_or_partition, uint64_t filesystem_size_in_MB); |
|
|
|
int lsfs_disk_create_entry(const char* path, Table_Entry_Kind entry_kind); |
|
|
|
Directory_Table* lsfs_find_directory(const char* path, bool drop_filename); |
|
|
|
int lsfs_disk_getattr(lsfs_file* find_file, const char *path); |
|
|
|
int lsfs_disk_delete_entry(lsfs_file *file); |
|
|
|
int get_free_sectors_table(); |
|
|
|
int get_free_sectors(int num_sectors_needed, lsfs_sector_offset* output_array); |
|
|
|
int lsfs_disk_read_data_from_file(lsfs_file *file, int data_length, char *data, size_t offset_to_next_entry); |
|
|
|
int lsfs_disk_write_data_to_file(lsfs_file* file, int data_length, char *data, size_t offset_to_next_entry); |
|
|
|
int lsfs_disk_rename_file(const char* old_filename_, const char* new_filename); |
|
|
|
int lsfs_disk_load_disk(); |
|
|
|
int write_data_to_disk(lsfs_sector_offset at_sector, uint32_t number_sectors, void* data_to_write); |
|
|
|
int write_data_to_disk_off(lsfs_sector_offset index, uint32_t number_sectors, void* data_to_write, int offset); |
|
|
|
int read_data_from_disk(lsfs_sector_offset index, uint32_t number_sectors, void* data_buffer); |
|
|
|
int read_data_from_disk_off(lsfs_sector_offset index, uint32_t number_sectors, void* data_to_write, int offset); |
|
|
|
int save_modified_file_information(lsfs_file* file); |
|
|
|
|
|
|
|
#define SPACE_MBR_RECORD 2048 // Sectors |
|
|
|
#define SPACE_VBR_RECORD 2048 // Sectors |
|
|
|
#define SIZE_FSCI_RECORD 1 // Sectors |
|
|
|
#define DEFAULT_ENTRY_SIZE 1 // Sectors |
|
|
|
#define SECTOR_SIZE 512 // BYTES |
|
|
|
#define NUMBER_OF_MBR_PARTITIONS 4 |
|
|
|
#define DEFAULT_DATA_POINTER_SIZE 8 // This is in sectors |
|
|
|
#define DEFAULT_TABLE_SIZE 16 |
|
|
|
#define NUM_DATA_POINTERS 27 |
|
|
|
|
|
|
|
typedef enum Table_Entry_Kind |
|
|
|
{ |
|
|
|
// These are specific values since, is has to corrospond to the implementation in assembly |
|
|
|
ENTRY_EMPTY = 0, |
|
|
|
ENTRY_FILE = 1, |
|
|
|
ENTRY_DIRECTORY = 2, |
|
|
|
} Table_Entry_Kind; |
|
|
|
|
|
|
|
typedef struct Partition_Entry |
|
|
|
{ |
|
|
|
uint8_t active_falg; // This has value 0x80 if it is a bootable partition / it is an active partition. |
|
|
|
uint8_t CHS_start_addr[3]; // [0] = H, [1] = S, [2] = C |
|
|
|
uint8_t partition_type; // This has a value such that one can idenfity which file system the partition is. |
|
|
|
uint8_t CHS_last_addr[3]; // [0] = H, [1] = S, [2] = C |
|
|
|
uint32_t LBA_abs_first_sector; |
|
|
|
uint32_t number_of_sectors; |
|
|
|
|
|
|
|
} __attribute__((packed)) Partition_Entry; |
|
|
|
|
|
|
|
typedef struct Master_Boot_record |
|
|
|
{ |
|
|
|
uint8_t code[446]; // The code for the bootloader |
|
|
|
Partition_Entry partitions[4]; |
|
|
|
uint16_t mbr_signature; // Signature |
|
|
|
} __attribute__((packed)) Master_Boot_record; |
|
|
|
|
|
|
|
typedef struct Volume_Boot_record |
|
|
|
{ |
|
|
|
uint8_t code[446]; // The code for the bootloader |
|
|
|
uint64_t vbr_size_in_bytes; // Signature |
|
|
|
uint64_t vbr_LBA_address; |
|
|
|
uint64_t vbr_LBA_FSCI_position; |
|
|
|
uint64_t not_used[5]; |
|
|
|
uint16_t vbr_signature; // Signature |
|
|
|
} __attribute__((packed)) Volume_Boot_record; |
|
|
|
|
|
|
|
typedef struct struct_table_entry |
|
|
|
{ |
|
|
|
char filename[256]; |
|
|
|
lsfs_file_id file_id; |
|
|
|
uint64_t file_size; |
|
|
|
mif* ext_file_data; |
|
|
|
uint32_t number_sectors; // This tells how many block there are allocated for the specific file. eg. we read this amount of bloks for the file. |
|
|
|
uint8_t entry_kind; |
|
|
|
uint8_t extra_control_bits1; |
|
|
|
uint8_t extra_control_bits2; |
|
|
|
uint8_t extra_control_bits3; |
|
|
|
lsfs_sector_offset table_entry_sector_index; |
|
|
|
lsfs_sector_offset data_pointer[NUM_DATA_POINTERS]; // if it is a directory, the first pointer will be to the next table. |
|
|
|
} __attribute__((packed)) Table_Entry; |
|
|
|
|
|
|
|
typedef struct Directory_Table |
|
|
|
{ |
|
|
|
struct_table_entry entries[DEFAULT_TABLE_SIZE]; |
|
|
|
|
|
|
|
} __attribute__((packed)) Directory_Table; |
|
|
|
|
|
|
|
typedef struct File_System_Control_Information |
|
|
|
{ |
|
|
|
char filesystem_information[256]; |
|
|
|
lsfs_sector_offset master_table_index; |
|
|
|
lsfs_sector_offset this_partition_offset_on_disk; |
|
|
|
lsfs_sector_offset next_free_sector; |
|
|
|
uint64_t next_uniqe_id; // both files and directories gets this. |
|
|
|
lsfs_sector_offset next_sector_reuse_pointer; |
|
|
|
lsfs_sector_offset last_sector_index_on_partition; |
|
|
|
lsfs_sector_offset maximum_sectors_on_disk; |
|
|
|
lsfs_sector_offset sector_size_on_disk; |
|
|
|
uint64_t not_used[24]; |
|
|
|
|
|
|
|
} __attribute__((packed)) FSCI; |
|
|
|
|
|
|
|
typedef struct struct_partition_control |
|
|
|
{ |
|
|
|
FSCI fsci; |
|
|
|
Directory_Table master_table; |
|
|
|
} __attribute__((packed)) partition_control; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct meta_information_format { |
|
|
|
char filename[246]; // remeber that the 246 bytes has to be a /0 terminator.. |
|
|
|
uint32_t owner_id; |
|
|
|
lsfs_file_id tags[32]; |
|
|
|
uint64_t file_size; |
|
|
|
uint32_t control_bits; |
|
|
|
/* not pressent - Permission key table 64 bytes sha-265 pr. key*/ |
|
|
|
uint64_t creation_date; |
|
|
|
uint64_t last_modification_data; |
|
|
|
uint64_t last_access_date; |
|
|
|
/* |
|
|
|
* 256 first pointers in direct mapping to data |
|
|
|
* 94 next pointers is a pointer |
|
|
|
* 94 next pointers to pointers to data |
|
|
|
*/ |
|
|
|
lsfs_sector_offset one_level_pointer_data[NUM_DATA_POINTERS]; |
|
|
|
lsfs_sector_offset two_level_pointer_data[94]; |
|
|
|
lsfs_sector_offset three_level_pointer_data[94]; |
|
|
|
|
|
|
|
} __attribute__((packed)) mif; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct tag_record { |
|
|
|
/* SIZE 16 bytes */ |
|
|
|
lsfs_file_id mif_record; |
|
|
|
struct { |
|
|
|
uint64_t is_filename : 1; |
|
|
|
} control_bits; |
|
|
|
|
|
|
|
} __attribute__((packed)) tag_record; |
|
|
|
|
|
|
|
typedef struct lsfs_file { |
|
|
|
lsfs_file_id file_id; |
|
|
|
lsfs_sector_offset table_entry_pointer; |
|
|
|
Table_Entry_Kind entry_kind; |
|
|
|
char* filename; |
|
|
|
uint32_t owner_id; |
|
|
|
uint64_t size; |
|
|
|
uint64_t creation_date; |
|
|
|
uint64_t access_time; |
|
|
|
uint64_t modification_time; |
|
|
|
uint32_t number_sectors; |
|
|
|
lsfs_sector_offset table_entry_sector_index; |
|
|
|
lsfs_sector_offset data_pointer[NUM_DATA_POINTERS]; |
|
|
|
} lsfs_file; |
|
|
|
|
|
|
|
|
|
|
|
Directory_Table* lsfs_find_directory(const char *path, bool drop_filename) |
|
|
|
{ |
|
|
|
|
|
|
|
Directory_Table *dir_table = calloc(1, sizeof(Directory_Table)); |
|
|
|
printf("Table index: %lu \n",p_control.fsci.master_table_index ); |
|
|
|
read_data_from_disk(p_control.fsci.master_table_index, DEFAULT_TABLE_SIZE, dir_table); |
|
|
|
lsfs_string_array split_path = lsfs_string_split_c(path, '/', false); |
|
|
|
|
|
|
|
int number_of_traversal = split_path.length; |
|
|
|
|
|
|
|
if (drop_filename) |
|
|
|
{ |
|
|
|
number_of_traversal -= 1; |
|
|
|
} |
|
|
|
|
|
|
|
// Start from the master table |
|
|
|
for (int i = 0; i < number_of_traversal; ++i) |
|
|
|
{ |
|
|
|
for (int j = 0; j < DEFAULT_TABLE_SIZE; ++j) |
|
|
|
{ |
|
|
|
if (strcmp(dir_table->entries[j].filename, split_path.strings[i].chars) == 0) |
|
|
|
{ |
|
|
|
int index_sector = dir_table->entries[j].data_pointer[0]; |
|
|
|
printf("Table index: %lu \n",index_sector ); |
|
|
|
read_data_from_disk(index_sector, DEFAULT_TABLE_SIZE, dir_table); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return dir_table; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_getattr(lsfs_file* find_file, const char* path) { |
|
|
|
lsfs_string_array split_path = lsfs_string_split_c(path, '/', false); |
|
|
|
lsfs_string filename = split_path.strings[split_path.length-1]; |
|
|
|
|
|
|
|
// Start from the master table |
|
|
|
Directory_Table *dir_table = lsfs_find_directory(path, true); |
|
|
|
|
|
|
|
for (int i = 0; i < DEFAULT_TABLE_SIZE; ++i) |
|
|
|
{ |
|
|
|
if(strcmp( filename.chars, dir_table->entries[i].filename ) == 0) { |
|
|
|
find_file->file_id = dir_table->entries[i].file_id; |
|
|
|
find_file->entry_kind = dir_table->entries[i].entry_kind; |
|
|
|
find_file->table_entry_pointer = i; |
|
|
|
find_file->filename = dir_table->entries[i].filename; |
|
|
|
find_file->table_entry_sector_index = dir_table->entries[i].table_entry_sector_index; |
|
|
|
find_file->owner_id = getuid(); |
|
|
|
find_file->size = dir_table->entries[i].file_size; // dir_table->entries[i].data_pointer[0]; //; |
|
|
|
find_file->creation_date = (uint64_t) timestamp_loading; |
|
|
|
find_file->access_time = (uint64_t) timestamp_loading; |
|
|
|
find_file->modification_time = (uint64_t) timestamp_loading; |
|
|
|
memcpy(find_file->data_pointer, dir_table->entries[i].data_pointer, NUM_DATA_POINTERS * 8); |
|
|
|
find_file->number_sectors = 1; // TODO: should be loaded from disk. |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int lsfs_disk_read_data_from_file(lsfs_file *file, int buffer_size, char *data, size_t offset_to_next_entry) |
|
|
|
{ |
|
|
|
int data_length = file->size - offset_to_next_entry; |
|
|
|
int amount_read = 0; |
|
|
|
int amount_to_read = 0; |
|
|
|
int remaining_offset = offset_to_next_entry; |
|
|
|
//printf("READ: buffer_size: %d\n", buffer_size); |
|
|
|
//printf("READ: Data length: %d\n", data_length); |
|
|
|
//printf("READ: Offset length: %d\n", offset_to_next_entry); |
|
|
|
|
|
|
|
|
|
|
|
int data_pointer_index = 0; // start at first data pointer. |
|
|
|
|
|
|
|
if (data_length > buffer_size) |
|
|
|
{ |
|
|
|
data_length = buffer_size; |
|
|
|
} |
|
|
|
|
|
|
|
while(data_length > 0) // We have more to write |
|
|
|
{ |
|
|
|
//printf("READ: Remaing Data length: %d\n", data_length); |
|
|
|
if (remaining_offset == 0) |
|
|
|
{ |
|
|
|
char *tmp_buffer = calloc(DEFAULT_DATA_POINTER_SIZE, SECTOR_SIZE); |
|
|
|
assert(tmp_buffer); |
|
|
|
|
|
|
|
if (data_length < (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)) |
|
|
|
{ |
|
|
|
amount_to_read = data_length; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
amount_to_read = (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE); |
|
|
|
} |
|
|
|
//read_data_from_disk(lsfs_sector_offset index, uint32_t number_sectors, void* data_buffer) |
|
|
|
if (file->data_pointer[data_pointer_index] == 0) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
read_data_from_disk(file->data_pointer[data_pointer_index], DEFAULT_DATA_POINTER_SIZE, tmp_buffer); |
|
|
|
memcpy((data + amount_read), tmp_buffer, amount_to_read); |
|
|
|
data_length -= amount_to_read; |
|
|
|
amount_read += amount_to_read; |
|
|
|
data_pointer_index++; |
|
|
|
free(tmp_buffer); |
|
|
|
} |
|
|
|
else if (remaining_offset < (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)) |
|
|
|
{ |
|
|
|
char *tmp_buffer = calloc(1, (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)); |
|
|
|
assert(tmp_buffer); |
|
|
|
|
|
|
|
if (data_length < ((DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE) - remaining_offset) ) |
|
|
|
{ |
|
|
|
amount_to_read = data_length; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
amount_to_read = ((DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE) - remaining_offset); |
|
|
|
} |
|
|
|
|
|
|
|
read_data_from_disk(file->data_pointer[data_pointer_index], DEFAULT_DATA_POINTER_SIZE, tmp_buffer); |
|
|
|
|
|
|
|
memcpy(data, (tmp_buffer + remaining_offset), amount_to_read); |
|
|
|
data_length -= amount_to_read; |
|
|
|
amount_read += amount_to_read; |
|
|
|
remaining_offset -= amount_to_read; |
|
|
|
|
|
|
|
data_pointer_index++; |
|
|
|
free(tmp_buffer); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// We have to skip a whole data pointer: |
|
|
|
remaining_offset -= (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE); |
|
|
|
data_pointer_index++; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
time_t current_time; |
|
|
|
time ( ¤t_time ); |
|
|
|
file->access_time = current_time; |
|
|
|
|
|
|
|
return amount_read; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static inline time_t lsfs_disk_update_timestamps(lsfs_file *file) { |
|
|
|
return file->modification_time = file->access_time = time(NULL); |
|
|
|
} |
|
|
|
|
|
|
|
#define lsfs_num_sectors_for_size(x) (((x)+SECTOR_SIZE-1)&~(SECTOR_SIZE-1)) |
|
|
|
|
|
|
|
int lsfs_disk_write_data_to_file(lsfs_file *file, int data_length, char *data, size_t offset_to_next_entry) |
|
|
|
{ |
|
|
|
int new_filesize = data_length + offset_to_next_entry; |
|
|
|
int amount_written = 0; |
|
|
|
int amount_to_write = 0; |
|
|
|
//printf("Data length: %d\n", data_length); |
|
|
|
//printf("Offset length: %d\n", offset_to_next_entry); |
|
|
|
|
|
|
|
int data_pointer_index = 0; // start at first data pointer. |
|
|
|
while(data_length > 0) // We have more to write |
|
|
|
{ |
|
|
|
while (file->data_pointer[data_pointer_index] == 0) |
|
|
|
{ |
|
|
|
// we have to assign a free sector |
|
|
|
if (get_free_sectors(1, file->data_pointer)) |
|
|
|
{ |
|
|
|
// This is a fail case, we cannot assign a new sector: |
|
|
|
return amount_written; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (offset_to_next_entry == 0) |
|
|
|
{ |
|
|
|
char *tmp_buffer = calloc(DEFAULT_DATA_POINTER_SIZE, SECTOR_SIZE); |
|
|
|
assert(tmp_buffer); |
|
|
|
|
|
|
|
if (data_length < (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)) |
|
|
|
{ |
|
|
|
amount_to_write = data_length; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
amount_to_write = (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE); |
|
|
|
} |
|
|
|
|
|
|
|
memcpy(tmp_buffer, (data + amount_written), amount_to_write); |
|
|
|
data_length -= amount_to_write; |
|
|
|
amount_written += amount_to_write; |
|
|
|
|
|
|
|
write_data_to_disk(file->data_pointer[data_pointer_index], DEFAULT_DATA_POINTER_SIZE, tmp_buffer); |
|
|
|
data_pointer_index++; |
|
|
|
free(tmp_buffer); |
|
|
|
} |
|
|
|
else if (offset_to_next_entry < (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)) |
|
|
|
{ |
|
|
|
char *tmp_buffer = calloc(1, (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE)); |
|
|
|
assert(tmp_buffer); |
|
|
|
read_data_from_disk(file->data_pointer[data_pointer_index], DEFAULT_DATA_POINTER_SIZE, tmp_buffer); |
|
|
|
|
|
|
|
if (data_length < ((DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE) - offset_to_next_entry) ) |
|
|
|
{ |
|
|
|
amount_to_write = data_length; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
amount_to_write = ((DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE) - offset_to_next_entry); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
memcpy(tmp_buffer + offset_to_next_entry, data, amount_to_write); |
|
|
|
data_length -= amount_to_write; |
|
|
|
amount_written += amount_to_write; |
|
|
|
offset_to_next_entry -= amount_to_write; |
|
|
|
|
|
|
|
write_data_to_disk(file->data_pointer[data_pointer_index], DEFAULT_DATA_POINTER_SIZE, tmp_buffer); |
|
|
|
data_pointer_index++; |
|
|
|
free(tmp_buffer); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// We have to skip a whole data pointer: |
|
|
|
offset_to_next_entry -= (DEFAULT_DATA_POINTER_SIZE * SECTOR_SIZE); |
|
|
|
//printf("Skip, offset is now: %d\n", offset_to_next_entry); |
|
|
|
data_pointer_index++; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
time_t current_time; |
|
|
|
time ( ¤t_time ); |
|
|
|
//lsfs_disk_update_timestamps(&mif_record); |
|
|
|
file->size = new_filesize; // update file size |
|
|
|
|
|
|
|
file->access_time = current_time; |
|
|
|
file->modification_time = current_time; |
|
|
|
|
|
|
|
save_modified_file_information(file); |
|
|
|
//write_data_to_disk(file->file_id, 4, &p_control.master_table[file->file_id]); |
|
|
|
|
|
|
|
// Should return the total new file size |
|
|
|
//printf("We Think that we have written: %d \n", amount_written); |
|
|
|
return amount_written; |
|
|
|
} |
|
|
|
|
|
|
|
time_t lsfs_disk_truncate_file(lsfs_file *file, off_t offset) { |
|
|
|
//mif file_mif; |
|
|
|
//read_data_from_disk(file_id, &file_mif); |
|
|
|
|
|
|
|
time_t result = lsfs_disk_update_timestamps(file); |
|
|
|
file->size = (int) offset; // p_control.master_table.entries[i].data_pointer[0]; //; |
|
|
|
|
|
|
|
save_modified_file_information(file); |
|
|
|
//write_data_to_disk(file->file_id, 4, NULL); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_rename_file(const char* old_filename, const char* new_filename) { |
|
|
|
|
|
|
|
lsfs_file *old_file = calloc(1, sizeof(lsfs_file)); |
|
|
|
lsfs_file *new_file = calloc(1, sizeof(lsfs_file)); |
|
|
|
|
|
|
|
lsfs_disk_getattr(old_file, old_filename); |
|
|
|
if (old_file->entry_kind == ENTRY_FILE) |
|
|
|
{ |
|
|
|
lsfs_disk_create_entry(new_filename, ENTRY_FILE); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
lsfs_disk_create_entry(new_filename, ENTRY_DIRECTORY); |
|
|
|
} |
|
|
|
lsfs_disk_getattr(new_file, new_filename); |
|
|
|
|
|
|
|
new_file->file_id = old_file->file_id; |
|
|
|
new_file->size = old_file->size; |
|
|
|
// TODO(Jørn) The data pointer assignt to the new file should be released. |
|
|
|
memcpy(new_file->data_pointer, old_file->data_pointer, NUM_DATA_POINTERS * 8); |
|
|
|
save_modified_file_information(new_file); |
|
|
|
lsfs_disk_delete_entry(old_file); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_delete_entry(lsfs_file *file) { |
|
|
|
//printf("file: %s - has been deleted \n", file->filename); |
|
|
|
Table_Entry *zero_buffer = calloc(1, (DEFAULT_ENTRY_SIZE * SECTOR_SIZE)); |
|
|
|
//read_data_from_disk(file_id, 1, mif_record); |
|
|
|
write_data_to_disk(file->table_entry_sector_index, DEFAULT_ENTRY_SIZE, zero_buffer); |
|
|
|
|
|
|
|
free(zero_buffer); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_delete_directory(const char *path) { |
|
|
|
// Find the directory and check if this is empty for entries: |
|
|
|
Directory_Table *directory_table = calloc(1, (DEFAULT_ENTRY_SIZE * SECTOR_SIZE)); |
|
|
|
directory_table = lsfs_find_directory(path, false); |
|
|
|
bool empty = true; |
|
|
|
|
|
|
|
for (int i = 0; i < DEFAULT_TABLE_SIZE; ++i) |
|
|
|
{ |
|
|
|
if (directory_table->entries[i].entry_kind != 0) |
|
|
|
{ |
|
|
|
empty = false; |
|
|
|
} |
|
|
|
} |
|
|
|
free(directory_table); |
|
|
|
|
|
|
|
if (!empty) |
|
|
|
{ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
lsfs_file *file = calloc(1, sizeof(lsfs_file)); |
|
|
|
lsfs_disk_getattr(file, path); |
|
|
|
|
|
|
|
Table_Entry *zero_buffer = calloc(1, (DEFAULT_ENTRY_SIZE * SECTOR_SIZE)); |
|
|
|
//read_data_from_disk(file_id, 1, mif_record); |
|
|
|
write_data_to_disk(file->table_entry_sector_index, DEFAULT_ENTRY_SIZE, zero_buffer); |
|
|
|
|
|
|
|
free(zero_buffer); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int get_free_sectors_table() { |
|
|
|
// We need DEFAULT_TABLE_SIZE sectors straight contigious for a table |
|
|
|
// Otherwise the file system cannot make a new table. |
|
|
|
// We return the offset where the table is starting. |
|
|
|
// If we cannot assing DEFAULT_TABLE_SIZE sectors, we report errror. |
|
|
|
|
|
|
|
int return_index = p_control.fsci.next_free_sector; |
|
|
|
|
|
|
|
if ((p_control.fsci.next_free_sector + DEFAULT_TABLE_SIZE) > p_control.fsci.last_sector_index_on_partition) |
|
|
|
{ |
|
|
|
// We don't have space, report error |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
p_control.fsci.next_free_sector += DEFAULT_TABLE_SIZE; |
|
|
|
|
|
|
|
fseek ( disk , ((p_control.fsci.this_partition_offset_on_disk) * SECTOR_SIZE), SEEK_SET ); |
|
|
|
fwrite(&p_control.fsci, 1, SECTOR_SIZE, disk); |
|
|
|
//printf("Table has got assigned Sector: %d\n", return_index); |
|
|
|
return return_index; |
|
|
|
} |
|
|
|
|
|
|
|
int get_free_sectors(int num_sectors_needed, lsfs_sector_offset* output_array) { |
|
|
|
|
|
|
|
if ((p_control.fsci.next_free_sector + num_sectors_needed) > p_control.fsci.last_sector_index_on_partition ) |
|
|
|
{ |
|
|
|
// We cannot assign what we want. |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
while (num_sectors_needed > 0) |
|
|
|
{ |
|
|
|
if (i > NUM_DATA_POINTERS) |
|
|
|
{ |
|
|
|
return -EINVAL; // We don't have any more data pointers. |
|
|
|
} |
|
|
|
|
|
|
|
if (output_array[i] == 0) |
|
|
|
{ |
|
|
|
// If free we can assign: |
|
|
|
output_array[i] = p_control.fsci.next_free_sector; |
|
|
|
p_control.fsci.next_free_sector += DEFAULT_DATA_POINTER_SIZE; |
|
|
|
num_sectors_needed--; |
|
|
|
} |
|
|
|
i++; |
|
|
|
} |
|
|
|
|
|
|
|
fseek ( disk , (p_control.fsci.this_partition_offset_on_disk) * SECTOR_SIZE, SEEK_SET ); |
|
|
|
fwrite(&p_control.fsci, 1, SECTOR_SIZE, disk); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int create_file_system(char* disk_name, char* hdd_or_partition, uint64_t filesystem_size_in_MB) { |
|
|
|
//char* sector_to_write; |
|
|
|
// make default File System Control information (FSCI) |
|
|
|
// first integer says how many pointers we got |
|
|
|
// to master tag tables |
|
|
|
// Second and forward is the pointers to the master Tag Tables |
|
|
|
// we need the first number to allocate memory at one go. |
|
|
|
FSCI *fsci = calloc(1, sizeof(FSCI)); |
|
|
|
// Create disk on host system: |
|
|
|
|
|
|
|
disk = fopen ( disk_name , "wb" ); |
|
|
|
ftruncate(fileno(disk), (filesystem_size_in_MB * 2048 * 512)); |
|
|
|
|
|
|
|
if (hdd_or_partition[0] == '1') |
|
|
|
{ |
|
|
|
// This is the create hdd case |
|
|
|
// This means that we setup the partition table. |
|
|
|
Master_Boot_record *mbr = calloc(1, sizeof(Master_Boot_record)); |
|
|
|
mbr->partitions[0].partition_type = 0x18; |
|
|
|
mbr->partitions[0].LBA_abs_first_sector = 2048; |
|
|
|
mbr->partitions[0].number_of_sectors = filesystem_size_in_MB * 2048; |
|
|
|
mbr->mbr_signature = 0xaa55; |
|
|
|
write_data_to_disk(0, 1, mbr); // Write this to the first sector of the disk. |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((hdd_or_partition[0] == '1') || (hdd_or_partition[0] == '2')) |
|
|
|
{ |
|
|
|
// This is just a single partition |
|
|
|
// And then the file system is the only thing in the system. |
|
|
|
sprintf(fsci->filesystem_information, "LSFS v1.0.0-a1\r\n(LessSimpelFileSystem)(Generated by the disk_manager_utility.c)\r\nDeveloped to SingOS\r\nby Jorn Guldberg\r\n"); |
|
|
|
|
|
|
|
if (hdd_or_partition[0] == '1') |
|
|
|
{ |
|
|
|
fsci->this_partition_offset_on_disk = SPACE_MBR_RECORD + SPACE_VBR_RECORD; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fsci->this_partition_offset_on_disk = SPACE_VBR_RECORD; |
|
|
|
} |
|
|
|
|
|
|
|
fsci->master_table_index = fsci->this_partition_offset_on_disk + 1; |
|
|
|
fsci->next_free_sector = fsci->master_table_index + DEFAULT_TABLE_SIZE; |
|
|
|
fsci->next_uniqe_id = 1; |
|
|
|
fsci->next_sector_reuse_pointer = 0; |
|
|
|
fsci->last_sector_index_on_partition = filesystem_size_in_MB * 2048; // Todo, this is the ssectors pr MB, this should not be hardcoded. |
|
|
|
fsci->maximum_sectors_on_disk = filesystem_size_in_MB * 2048; //TODO(Jørn) Not in use yet |
|
|
|
fsci->sector_size_on_disk = SECTOR_SIZE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// This is an error case, and we should not hit this case. |
|
|
|
assert(NULL); |
|
|
|
} |
|
|
|
|
|
|
|
write_data_to_disk(fsci->this_partition_offset_on_disk, 1, fsci); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_install_bootloader(char *bootloader_name) |
|
|
|
{ |
|
|
|
FILE *bootloader = fopen ( bootloader_name , "r+b" ); |
|
|
|
Master_Boot_record *bootloader_mbr = calloc(1, sizeof(Master_Boot_record)); |
|
|
|
fseek(bootloader, 0 * SECTOR_SIZE, SEEK_SET); |
|
|
|
fread(bootloader_mbr, 1, SECTOR_SIZE, bootloader); |
|
|
|
|
|
|
|
Master_Boot_record *mbr = calloc(1, sizeof(Master_Boot_record)); |
|
|
|
fseek( disk , 0 * SECTOR_SIZE, SEEK_SET ); |
|
|
|
fread(mbr, 1, SECTOR_SIZE, disk); |
|
|
|
memcpy(mbr->code, bootloader_mbr->code, 446); |
|
|
|
write_data_to_disk(0, 1, mbr); // Write this to the first sector of the disk. |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int lsfs_disk_install_vbr(char *vbr_path) |
|
|
|
{ |
|
|
|
struct stat st; |
|
|
|
stat(vbr_path, &st); |
|
|
|
FILE *vbr = fopen ( vbr_path , "r+b" ); |
|
|
|
Volume_Boot_record *vbr_first_sector = calloc(1, SECTOR_SIZE); |
|
|
|
void *vbr_buffer_rest = calloc(1, (SPACE_VBR_RECORD * SECTOR_SIZE - 1)); |
|
|
|
|
|
|
|
// First load first sector |
|
|
|
fseek(vbr, 0, SEEK_SET); |
|
|
|
fread(vbr_first_sector, 1, SECTOR_SIZE, vbr); |
|
|
|
|
|
|
|
fseek(vbr, SECTOR_SIZE, SEEK_SET); |
|
|
|
fread(vbr_buffer_rest, 1, (st.st_size - SECTOR_SIZE), vbr); |
|
|
|
|
|
|
|
vbr_first_sector->vbr_size_in_bytes = st.st_size; |
|
|
|
vbr_first_sector->vbr_LBA_address = p_control.fsci.this_partition_offset_on_disk - SPACE_VBR_RECORD; |
|
|
|
vbr_first_sector->vbr_LBA_FSCI_position = p_control.fsci.this_partition_offset_on_disk; |
|
|
|
vbr_first_sector->vbr_signature = 0x1818; |
|
|
|
|
|
|
|
printf("VBR size: %d\n", vbr_first_sector->vbr_size_in_bytes); |
|
|
|
printf("VBR lba address: %d\n", vbr_first_sector->vbr_LBA_address); |
|
|
|
printf("VBR FSCI: %d\n", vbr_first_sector->vbr_LBA_FSCI_position); |
|
|
|
|
|
|
|
write_data_to_disk((p_control.fsci.this_partition_offset_on_disk - SPACE_VBR_RECORD), 1, vbr_first_sector); // Write this to the first sector of the disk. |
|
|
|
write_data_to_disk((p_control.fsci.this_partition_offset_on_disk - SPACE_VBR_RECORD + 1), (SPACE_VBR_RECORD - 1), vbr_buffer_rest); // Write this to the first sector of the disk. |
|
|
|
|
|
|
|
Master_Boot_record mbr; |
|
|
|
fseek( disk , 0 * SECTOR_SIZE, SEEK_SET ); |
|
|
|
fread(&mbr, 1, sizeof(mbr), disk); |
|
|
|
|
|
|
|
|
|
|
|
if (mbr.mbr_signature == 0xaa55 ) |
|
|
|
{ |
|
|
|
mbr.partitions[0].active_falg = 0x80; // TODO(Jørn) Hardcoded partition. |
|
|
|
write_data_to_disk(0, 1, &mbr); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int lsfs_disk_load_disk() { |
|
|
|
// Find the partition talbe: |
|
|
|
// This makes is BIOS dependent. |
|
|
|
// UEFI is not supported. |
|
|
|
time(×tamp_loading); |
|
|
|
|
|
|
|
Master_Boot_record mbr; |
|
|
|
fseek( disk , 0 * SECTOR_SIZE, SEEK_SET ); |
|
|
|
fread(&mbr, 1, sizeof(mbr), disk); |
|
|
|
if (mbr.mbr_signature != 0xaa55 ) |
|
|
|
{ |
|
|
|
// Means that it is a sigle partition we try to mount |
|
|
|
fseek(disk, (SPACE_VBR_RECORD * SECTOR_SIZE), SEEK_SET ); |
|
|
|
fread(&p_control.fsci, 1, SECTOR_SIZE , disk); |
|
|
|
//printf("next free sector: %d\n", p_control.fsci.next_free_sector); |
|
|
|
//printf("next free ID: %d\n", p_control.fsci.next_uniqe_id); |
|
|
|
|
|
|
|
// next we find the Mater Table. |
|
|
|
fseek (disk, (p_control.fsci.master_table_index * SECTOR_SIZE), SEEK_SET ); |
|
|
|
fread(&p_control.master_table, 1, DEFAULT_TABLE_SIZE * SECTOR_SIZE , disk); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < NUMBER_OF_MBR_PARTITIONS; ++i) |
|
|
|
{ |
|
|
|
// TODO (Jørn) We maybe wnat to optimize, such that we can detect if we have more than one partition opn the system. |
|
|
|
if (mbr.partitions[i].partition_type == 0x18) |
|
|
|
{ |
|
|
|
// First we find the File system control information. |
|
|
|
fseek(disk , ((mbr.partitions[i].LBA_abs_first_sector + SPACE_VBR_RECORD) * SECTOR_SIZE), SEEK_SET ); |
|
|
|
fread(&p_control.fsci, 1, SECTOR_SIZE , disk); |
|
|
|
|
|
|
|
// next we find the Mater Table. |
|
|
|
fseek (disk, (p_control.fsci.master_table_index * SECTOR_SIZE), SEEK_SET ); |
|
|
|
fread(&p_control.master_table, 1, DEFAULT_TABLE_SIZE * SECTOR_SIZE , disk); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int lsfs_disk_create_entry(const char* path, Table_Entry_Kind entry_kind) |
|
|
|
{ |
|
|
|
|
|
|
|
// First check if file exist: |
|
|
|
lsfs_file *file = calloc(1, sizeof(lsfs_file)); |
|
|
|
if (lsfs_disk_getattr(file, path)) |
|
|
|
{ |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
free(file); |
|
|
|
|
|
|
|
// Start from the master table |
|
|
|
int free_index = -1; // -1 is no index found. |
|
|
|
Directory_Table *dir_table = calloc(1, sizeof(Directory_Table)); |
|
|
|
read_data_from_disk(p_control.fsci.master_table_index, DEFAULT_TABLE_SIZE, dir_table); |
|
|
|
lsfs_sector_offset table_disk_position = p_control.fsci.master_table_index; |
|
|
|
|
|
|
|
|
|
|
|
lsfs_string_array split_path = lsfs_string_split_c(path, '/', false); |
|
|
|
lsfs_string filename = split_path.strings[split_path.length-1]; |
|
|
|
|
|
|
|
//printf("spilt length: %d\n", split_path.length); |
|
|
|
|
|
|
|
for (int i = 0; i < split_path.length -1; ++i) |
|
|
|
{ |
|
|
|
for (int j = 0; j < DEFAULT_TABLE_SIZE; ++j) |
|
|
|
{ |
|
|
|
if (strcmp(dir_table->entries[j].filename, split_path.strings[i].chars) == 0) |
|
|
|
{ |
|
|
|
// We have found the next directory to traverse. |
|
|
|
//printf("Get next dir at sector: "); |
|
|
|
table_disk_position = dir_table->entries[j].data_pointer[0]; |
|
|
|
//printf("%d\n", table_disk_position); |
|
|
|
read_data_from_disk(table_disk_position, DEFAULT_TABLE_SIZE, dir_table); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int table_index = 0; table_index < DEFAULT_TABLE_SIZE; ++table_index) |
|
|
|
{ |
|
|
|
// Find free index. |
|
|
|
if (dir_table->entries[table_index].entry_kind == ENTRY_EMPTY) |
|
|
|
{ |
|
|
|
// Set the free index, continue to see if the filename exist. |
|
|
|
// if not -1, we have found a better index. |
|
|
|
if (free_index == -1) |
|
|
|
{ |
|
|
|
//printf("Index found for file: %d\n", table_index); |
|
|
|
table_disk_position += table_index; // Abselout index in file system |
|
|
|
free_index = table_index; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (free_index == -1) |
|
|
|
{ |
|
|
|
// The table is full, and we cannot create an entry |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
// Find the entry for the file in the table structure: |
|
|
|
dir_table->entries[free_index].file_id = p_control.fsci.next_uniqe_id; |
|
|
|
p_control.fsci.next_uniqe_id++; |
|
|
|
|
|
|
|
sprintf(dir_table->entries[free_index].filename, "%s", filename.chars); |
|
|
|
dir_table->entries[free_index].entry_kind = entry_kind; |
|
|
|
dir_table->entries[free_index].table_entry_sector_index = table_disk_position; |
|
|
|
if (entry_kind == ENTRY_DIRECTORY) |
|
|
|
{ |
|
|
|
dir_table->entries[free_index].data_pointer[0] = get_free_sectors_table(); |
|
|
|
dir_table->entries[free_index].file_size = DEFAULT_TABLE_SIZE * SECTOR_SIZE; |
|
|
|
} |
|
|
|
else if (entry_kind == ENTRY_FILE) |
|
|
|
{ |
|
|
|
// We assign one data pointer consiting of DEFAULT_DATA_POINTER_SIZE sectors |
|
|
|
dir_table->entries[free_index].file_size = 0; |
|
|
|
get_free_sectors(1, dir_table->entries[free_index].data_pointer); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
return -EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
find_file->creation_date = (uint64_t) current_time; |
|
|
|
find_file->access_time = (uint64_t) current_time; |
|
|
|
find_file->modification_time = (uint64_t) current_time; |
|
|
|
find_file->data = p_control.master_table.entries[i].data_pointer; |
|
|
|
find_file->owner_id = getuid(); |
|
|
|
new_file_data.owner_id = getuid(); |
|
|
|
time_t current_time; |
|
|
|
time ( ¤t_time ); |
|
|
|
*/ |
|
|
|
//printf("File is written to sector: %d\n", table_disk_position); |
|
|
|
write_data_to_disk(table_disk_position, DEFAULT_ENTRY_SIZE, &dir_table->entries[free_index]); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int save_modified_file_information(lsfs_file* file) { |
|
|
|
// Write the file struct into the table_entry, such that we can save the data correct. |
|
|
|
|
|
|
|
Table_Entry *entry = calloc(1, sizeof(Table_Entry)); |
|
|
|
read_data_from_disk(file->table_entry_sector_index, DEFAULT_ENTRY_SIZE, entry); |
|
|
|
|
|
|
|
|
|
|
|
//entry.file_id = file->file_id; |
|
|
|
memcpy(entry->filename, file->filename, 256); |
|
|
|
entry->file_size = file->size; // p_control.master_table.entries[i].data_pointer[0]; //; |
|
|
|
memcpy(entry->data_pointer, file->data_pointer, NUM_DATA_POINTERS * 8); |
|
|
|
|
|
|
|
write_data_to_disk(file->table_entry_sector_index, DEFAULT_ENTRY_SIZE, entry); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int write_data_to_disk(lsfs_sector_offset index, uint32_t number_sectors, void* data_to_write) { |
|
|
|
fseek ( disk, (index * SECTOR_SIZE), SEEK_SET ); // SEEK_SET start offset at index 0 and move 1 * SECTOR_SIZE, and write here. |
|
|
|
int written = fwrite(data_to_write, 1, (number_sectors * SECTOR_SIZE), disk); |
|
|
|
return written; |
|
|
|
} |
|
|
|
|
|
|
|
int write_data_to_disk_off(lsfs_sector_offset index, uint32_t number_sectors, void* data_to_write, int offset) { |
|
|
|
fseek ( disk, ((index * SECTOR_SIZE) + offset), SEEK_SET ); // SEEK_SET start offset at index 0 and move 1 * SECTOR_SIZE, and write here. |
|
|
|
int written = fwrite(data_to_write, 1, ((number_sectors * SECTOR_SIZE) - offset), disk); |
|
|
|
return written; |
|
|
|
} |
|
|
|
|
|
|
|
int read_data_from_disk(lsfs_sector_offset index, uint32_t number_sectors, void* data_buffer) { |
|
|
|
fseek ( disk, (index * SECTOR_SIZE ), SEEK_SET ); // SEEK_SET start offset at index 0 and move 1 * SECTOR_SIZE, and write here. |
|
|
|
int read = fread(data_buffer, 1, (number_sectors * SECTOR_SIZE), disk); |
|
|
|
return read; |
|
|
|
} |
|
|
|
|
|
|
|
int read_data_from_disk_off(lsfs_sector_offset index, uint32_t number_sectors, void* data_to_write, int offset) { |
|
|
|
fseek ( disk, ((index * SECTOR_SIZE) + offset), SEEK_SET ); // SEEK_SET start offset at index 0 and move 1 * SECTOR_SIZE, and write here. |
|
|
|
int written = fread(data_to_write, 1, ((number_sectors * SECTOR_SIZE) - offset), disk); |
|
|
|
return written; |
|
|
|
} |
|
|
|
#endif |