You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							893 lines
						
					
					
						
							32 KiB
						
					
					
				
			
		
		
	
	
							893 lines
						
					
					
						
							32 KiB
						
					
					
				| #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 uint64_t lsfs_sector_offset; | |
| typedef lsfs_sector_offset lsfs_file_id; | |
|  | |
| typedef enum | |
| { | |
|     // 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 uint64_t sector_index; | |
| static FILE* disk = NULL; | |
| 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, struct_table_entry* table_entry); | |
| int lsfs_disk_read_data_from_file(lsfs_file *file, int data_length, char *data, int64_t offset_to_next_entry); | |
| int lsfs_disk_write_data_to_file(lsfs_file* file, int data_length, char *data, int64_t offset_to_next_entry); | |
| int lsfs_disk_rename_file(const char* old_filename_, const char* new_filename); | |
| int lsfs_disk_load_disk(char* diskname); | |
| 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 32 // 2048 // Sectors | |
| #define SPACE_VBR_RECORD 32 // 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 8 // 16  | |
| #define NUM_DATA_POINTERS 27  | |
|  | |
| 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; | |
|     struct_table_entry* table_backpointer; | |
|     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->table_backpointer = &(dir_table->entries[i]); | |
|             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, int64_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, int64_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->table_backpointer)) | |
|             { | |
|                 // 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, struct_table_entry* table_entry) { | |
|  | |
|     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 (table_entry->data_pointer[i] == 0)  | |
|         { | |
|             // If free we can assign:  | |
|             table_entry->data_pointer[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 == '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 = SPACE_MBR_RECORD; | |
|         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 == '1') || (hdd_or_partition == '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-a4\r\n(LessSimpelFileSystem)(Generated by the disk_manager_utility.c)\r\nDeveloped to SingOS and QuasiOS\r\nby Jorn Guldberg\r\n"); | |
|          | |
|         if (hdd_or_partition == '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); | |
|  | |
|     lsfs_disk_load_disk(NULL); // Reload disk | |
|     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.  | |
|  | |
|     lsfs_disk_load_disk(NULL); // Reload 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: %lu\n", vbr_first_sector->vbr_size_in_bytes); | |
|     printf("VBR lba address: %lu\n", vbr_first_sector->vbr_LBA_address); | |
|     printf("VBR FSCI: %lu\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(char* diskname)  | |
| { | |
|     // Find the partition talbe:  | |
|     // This makes is BIOS dependent.  | |
|     // UEFI is not supported.  | |
|     if (diskname != NULL)  | |
|     { | |
|         disk = fopen ( diskname , "r+b" ); | |
|  | |
|     } | |
|     else if (disk == NULL ) | |
|     { | |
|         return -1; | |
|     } | |
|  | |
|     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])); | |
|     } | |
|     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
 | |
| 
 |