Espresso 0.0.1b
This commit is contained in:
@ -1,93 +1,806 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/duckfs.h>
|
||||
|
||||
|
||||
#define DFS_MAGIC 0xDF1984CC
|
||||
static duckfs_superblock_t super;
|
||||
|
||||
#define DFS_BLOCK_SIZE 512
|
||||
extern int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count);
|
||||
extern int32_t disk_read(uint64_t lba, void* buffer, uint32_t count);
|
||||
|
||||
#define DFS_VERSION_0 "DuckFS, wheresDax?"
|
||||
#define DFS_VERSION_1 "DuckFS, Terminator"
|
||||
#define DFS_VERSION_2 "DuckFS-Terminator2"
|
||||
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
|
||||
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
|
||||
|
||||
|
||||
#define DFS_FILE_ERROR -8
|
||||
#define DFS_FILE_UNUSED -1
|
||||
#define DFS_FILE_USED 0
|
||||
#define DFS_FILE_TEXT 0
|
||||
#define DFS_FILE_BINARY 1
|
||||
#define DFS_FILE_DIRECTORY 2
|
||||
|
||||
/* encryption algorithms */
|
||||
#define DFS_CAESAR_5 88
|
||||
#define DFS_CAESAR_8 84
|
||||
#define DFS_CAESAR_2 09
|
||||
#define DFS_QUACK_32 99
|
||||
|
||||
#define DFS_MAX_FILENAME_LEN 64
|
||||
#define DFS_MAX_FILES 256
|
||||
|
||||
|
||||
typedef struct duckfs_file_header {
|
||||
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
|
||||
char permissions[3]; /* Same thing here */
|
||||
|
||||
/*
|
||||
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
|
||||
Only valid if this file is not a directory.
|
||||
*/
|
||||
int32_t num_sectors;
|
||||
|
||||
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
|
||||
|
||||
uint16_t _reserved0; /* (align to 4) */
|
||||
|
||||
struct duckfs_file_header* next; /* Next file in the directory this file is in. */
|
||||
struct duckfs_file_header* contents; /* contains the first file in the directory. only valid if this file is a directory. */
|
||||
struct duckfs_file_header* parent; /* The directory this file is in. */
|
||||
|
||||
uint64_t next_lba; /* The LBA of the next file's file header on the disk. */
|
||||
uint64_t contents_lba;
|
||||
uint64_t parent_lba;
|
||||
|
||||
uint64_t lba_start; /* only is valid if this file is not a directory. */
|
||||
uint64_t lba_end; /* only is valid if this file is not a directory. */
|
||||
|
||||
uint8_t _reserved1[126]; /* padding to 256 bytes total */
|
||||
} duckfs_file_header_t;
|
||||
|
||||
typedef struct duckfs_superblock {
|
||||
int32_t duckfs_magic; /* must be DFS_MAGIC. */
|
||||
char duckfs_version_string[19];
|
||||
char volume_label[19]; /* 18 characters and a null zero. */
|
||||
|
||||
int16_t encryption;
|
||||
|
||||
uint64_t duckfs_root; /* LBA of the root directory's file header */
|
||||
|
||||
uint32_t _padding[115]; /* padding to 512 bytes total */
|
||||
} duckfs_superblock_t;
|
||||
|
||||
|
||||
static uint16_t duckfs_initialized = 0;
|
||||
|
||||
static duckfs_file_header_t duckfs_root;
|
||||
|
||||
const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 };
|
||||
|
||||
void duckfs_init(void)
|
||||
int32_t duckfs_mount(void)
|
||||
{
|
||||
printf("\t%i\n", (sizeof(duckfs_file_header_t)));
|
||||
printf("\t\t%i\n", (sizeof(duckfs_superblock_t)));
|
||||
/* int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) */
|
||||
/* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
|
||||
|
||||
/*uint8_t superblock_sector[512] = { 0 };
|
||||
|
||||
ide_read*/
|
||||
if (disk_read(8, &super, 1) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(super.magic, DUCKFS_MAGIC, 7) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t read_header(uint64_t lba, duckfs_file_header_t* hdr)
|
||||
{
|
||||
uint8_t sector[512];
|
||||
if (disk_read(lba, sector, 1) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memcpy(hdr, sector, sizeof(duckfs_file_header_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* next_token(const char* path, char* token)
|
||||
{
|
||||
while (*path == '/')
|
||||
{
|
||||
path++;
|
||||
}
|
||||
|
||||
if (*path == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
while (*path && *path != '/')
|
||||
{
|
||||
token[len++] = *path++;
|
||||
}
|
||||
token[len] = 0;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static int32_t duckfs_alloc_block(uint64_t* out_lba)
|
||||
{
|
||||
if (super.free_list_lba == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_lba = super.free_list_lba;
|
||||
|
||||
uint64_t next;
|
||||
if (disk_read(*out_lba, &next, 1) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
super.free_list_lba = next;
|
||||
|
||||
/* Persist the updated superblock */
|
||||
if (disk_write(8, &super, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t duckfs_alloc_file_data(const void* content, size_t size, uint64_t* first_lba)
|
||||
{
|
||||
const uint8_t* src = (const uint8_t*)content;
|
||||
size_t remaining = size;
|
||||
uint64_t prev_lba = 0;
|
||||
uint64_t head_lba = 0;
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
uint64_t block_lba;
|
||||
if (duckfs_alloc_block(&block_lba) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write next block LBA at start (for linking) */
|
||||
uint64_t next = 0;
|
||||
if (remaining > super.block_size - sizeof(uint64_t))
|
||||
{
|
||||
if (duckfs_alloc_block(&next) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t buffer[512] = {0};
|
||||
memcpy(buffer, &next, sizeof(uint64_t));
|
||||
|
||||
size_t copy_len = super.block_size - sizeof(uint64_t);
|
||||
if (copy_len > remaining)
|
||||
{
|
||||
copy_len = remaining;
|
||||
}
|
||||
memcpy(buffer + sizeof(uint64_t), src, copy_len);
|
||||
|
||||
if (disk_write(block_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (prev_lba != 0) {
|
||||
if (disk_write(prev_lba, &block_lba, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
head_lba = block_lba;
|
||||
}
|
||||
|
||||
prev_lba = block_lba;
|
||||
src += copy_len;
|
||||
remaining -= copy_len;
|
||||
}
|
||||
|
||||
*first_lba = head_lba;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t duckfs_find(const char* path, duckfs_file_header_t* out)
|
||||
{
|
||||
char token[DUCKFS_NAME_LEN];
|
||||
duckfs_file_header_t current;
|
||||
|
||||
if (read_header(super.root_header_lba, ¤t) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* p = path;
|
||||
while ((p = next_token(p, token)))
|
||||
{
|
||||
if (current.type != DUCKFS_TYPE_DIR)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint64_t child = current.child_lba;
|
||||
int32_t found = 0;
|
||||
while (child != 0)
|
||||
{
|
||||
duckfs_file_header_t entry;
|
||||
if (read_header(child, &entry) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (strncmp(entry.name, token, DUCKFS_NAME_LEN) == 0)
|
||||
{
|
||||
current = entry;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
child = entry.next_file_lba;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
*out = current;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t duckfs_create_file(const char* name, const void* content, size_t size, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
|
||||
{
|
||||
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for existing file */
|
||||
duckfs_file_header_t child;
|
||||
uint64_t current = parent_dir->child_lba;
|
||||
uint64_t prev_lba = 0;
|
||||
|
||||
while (current != 0)
|
||||
{
|
||||
if (disk_read(current, &child, 1) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
|
||||
{
|
||||
/* Overwrite content */
|
||||
uint64_t data_lba;
|
||||
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
child.first_block_lba = data_lba;
|
||||
child.size = size;
|
||||
child.modified = 0; /* TODO: timestamp */
|
||||
return disk_write(current, &child, 1);
|
||||
}
|
||||
prev_lba = current;
|
||||
current = child.next_file_lba;
|
||||
}
|
||||
|
||||
/* Allocate header */
|
||||
uint64_t file_hdr_lba;
|
||||
if (duckfs_alloc_block(&file_hdr_lba) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Write content */
|
||||
uint64_t data_lba;
|
||||
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
duckfs_file_header_t new_file = {0};
|
||||
strncpy(new_file.name, name, DUCKFS_NAME_LEN);
|
||||
new_file.type = DUCKFS_TYPE_FILE;
|
||||
new_file.permissions = perms;
|
||||
new_file.uid = uid;
|
||||
new_file.gid = gid;
|
||||
new_file.size = size;
|
||||
new_file.first_block_lba = data_lba;
|
||||
new_file.modified = 0;
|
||||
|
||||
/* Add to dir */
|
||||
if (prev_lba == 0)
|
||||
{
|
||||
parent_dir->child_lba = file_hdr_lba;
|
||||
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
child.next_file_lba = file_hdr_lba;
|
||||
if (disk_write(prev_lba, &child, 1) != 0)
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
}
|
||||
|
||||
return disk_write(file_hdr_lba, &new_file, 1);
|
||||
}
|
||||
|
||||
int32_t duckfs_create_dir(const char* name, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
|
||||
{
|
||||
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate header */
|
||||
uint64_t hdr_lba;
|
||||
if (duckfs_alloc_block(&hdr_lba) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
duckfs_file_header_t new_dir = {0};
|
||||
strncpy(new_dir.name, name, DUCKFS_NAME_LEN);
|
||||
new_dir.type = DUCKFS_TYPE_DIR;
|
||||
new_dir.permissions = perms;
|
||||
new_dir.uid = uid;
|
||||
new_dir.gid = gid;
|
||||
new_dir.modified = 0;
|
||||
new_dir.size = 0;
|
||||
|
||||
/* Write header */
|
||||
if (disk_write(hdr_lba, &new_dir, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Add to parent */
|
||||
duckfs_file_header_t sibling;
|
||||
uint64_t current = parent_dir->child_lba;
|
||||
uint64_t prev = 0;
|
||||
|
||||
while (current != 0)
|
||||
{
|
||||
if (disk_read(current, &sibling, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
prev = current;
|
||||
current = sibling.next_file_lba;
|
||||
}
|
||||
|
||||
if (prev == 0)
|
||||
{
|
||||
parent_dir->child_lba = hdr_lba;
|
||||
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sibling.next_file_lba = hdr_lba;
|
||||
if (disk_write(prev, &sibling, 1) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t duckfs_read_file(const duckfs_file_header_t* file, void* buffer, size_t size)
|
||||
{
|
||||
if (file->type != DUCKFS_TYPE_FILE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t to_read = size;
|
||||
if (to_read > file->size)
|
||||
{
|
||||
to_read = file->size;
|
||||
}
|
||||
|
||||
uint64_t blocks = (to_read + super.block_size - 1) / super.block_size;
|
||||
return disk_read(file->first_block_lba, buffer, blocks);
|
||||
}
|
||||
|
||||
int32_t duckfs_write_data(duckfs_file_header_t* file, const void* data, size_t offset, size_t length)
|
||||
{
|
||||
if (!file || file->type != DUCKFS_TYPE_FILE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t final_size = offset + length;
|
||||
if (final_size > file->size)
|
||||
{
|
||||
/* Grow */
|
||||
if (duckfs_append_data(file, ((const uint8_t*)data) + (file->size - offset), final_size - file->size) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
size_t block_size = super.block_size;
|
||||
size_t remaining = length;
|
||||
const uint8_t* src = (const uint8_t*)data;
|
||||
|
||||
uint64_t current_lba = file->first_block_lba;
|
||||
uint64_t block_offset = 0;
|
||||
|
||||
/* Traverse to block containing `offset` */
|
||||
size_t logical = 0;
|
||||
while (logical + (block_size - 8) <= offset)
|
||||
{
|
||||
uint64_t next;
|
||||
if (disk_read(current_lba, &next, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
current_lba = next;
|
||||
if (current_lba == 0)
|
||||
{
|
||||
return -4; /* ran out */
|
||||
}
|
||||
|
||||
logical += block_size - 8;
|
||||
}
|
||||
|
||||
/* Start writing */
|
||||
while (remaining > 0)
|
||||
{
|
||||
uint8_t buffer[512];
|
||||
if (disk_read(current_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
uint64_t next_lba;
|
||||
memcpy(&next_lba, buffer, sizeof(uint64_t));
|
||||
|
||||
size_t block_start = (offset > logical) ? (offset - logical) : 0;
|
||||
size_t to_copy = block_size - 8 - block_start;
|
||||
if (to_copy > remaining) to_copy = remaining;
|
||||
|
||||
memcpy(buffer + 8 + block_start, src, to_copy);
|
||||
if (disk_write(current_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
src += to_copy;
|
||||
remaining -= to_copy;
|
||||
offset += to_copy;
|
||||
logical += block_size - 8;
|
||||
current_lba = next_lba;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t duckfs_append_data(duckfs_file_header_t* file, const void* data, size_t length)
|
||||
{
|
||||
if (!file || file->type != DUCKFS_TYPE_FILE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t block_size = super.block_size;
|
||||
size_t data_per_block = block_size - sizeof(uint64_t);
|
||||
|
||||
uint64_t last_lba = file->first_block_lba;
|
||||
if (last_lba == 0)
|
||||
{
|
||||
/* Allocate first block */
|
||||
if (duckfs_alloc_block(&last_lba) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
file->first_block_lba = last_lba;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Traverse to last block */
|
||||
uint64_t next;
|
||||
while (1)
|
||||
{
|
||||
if (disk_read(last_lba, &next, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
memcpy(&next, &next, sizeof(uint64_t));
|
||||
if (next == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
last_lba = next;
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset_in_block = file->size % data_per_block;
|
||||
size_t remaining = length;
|
||||
const uint8_t* src = (const uint8_t*)data;
|
||||
|
||||
/* Write to the partially filled last block */
|
||||
if (offset_in_block != 0)
|
||||
{
|
||||
uint8_t buffer[512];
|
||||
if (disk_read(last_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
size_t to_copy = data_per_block - offset_in_block;
|
||||
if (to_copy > remaining)
|
||||
{
|
||||
to_copy = remaining;
|
||||
}
|
||||
|
||||
memcpy(buffer + sizeof(uint64_t) + offset_in_block, src, to_copy);
|
||||
if (disk_write(last_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
file->size += to_copy;
|
||||
remaining -= to_copy;
|
||||
src += to_copy;
|
||||
}
|
||||
|
||||
/* Write remaining data to new blocks */
|
||||
while (remaining > 0)
|
||||
{
|
||||
uint64_t new_lba;
|
||||
if (duckfs_alloc_block(&new_lba) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Link previous block to this one */
|
||||
if (disk_write(last_lba, &new_lba, 1) != 0)
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
|
||||
uint8_t buffer[512] = {0};
|
||||
uint64_t next = 0;
|
||||
memcpy(buffer, &next, sizeof(uint64_t));
|
||||
|
||||
size_t to_copy = (remaining > data_per_block) ? data_per_block : remaining;
|
||||
memcpy(buffer + sizeof(uint64_t), src, to_copy);
|
||||
if (disk_write(new_lba, buffer, 1) != 0)
|
||||
{
|
||||
return -8;
|
||||
}
|
||||
|
||||
last_lba = new_lba;
|
||||
src += to_copy;
|
||||
remaining -= to_copy;
|
||||
file->size += to_copy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t duckfs_truncate(duckfs_file_header_t* file, size_t new_size)
|
||||
{
|
||||
if (!file || file->type != DUCKFS_TYPE_FILE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t block_size = super.block_size;
|
||||
size_t data_per_block = block_size - sizeof(uint64_t);
|
||||
|
||||
size_t needed_blocks = (new_size + data_per_block - 1) / data_per_block;
|
||||
uint64_t current = file->first_block_lba;
|
||||
uint64_t prev = 0;
|
||||
|
||||
for (size_t i = 0; i < needed_blocks; i++)
|
||||
{
|
||||
if (current == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t next;
|
||||
if (disk_read(current, &next, 1) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
memcpy(&next, &next, sizeof(uint64_t));
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
|
||||
/* `current` is now first block to free */
|
||||
while (current != 0)
|
||||
{
|
||||
uint64_t next;
|
||||
if (disk_read(current, &next, 1) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
memcpy(&next, &next, sizeof(uint64_t));
|
||||
|
||||
/* Write freelist entry */
|
||||
if (disk_write(current, &super.free_list_lba, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
super.free_list_lba = current;
|
||||
current = next;
|
||||
}
|
||||
|
||||
/* Finalize */
|
||||
if (disk_write(8, &super, 1) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Cut block chain */
|
||||
if (prev != 0)
|
||||
{
|
||||
uint64_t zero = 0;
|
||||
if (disk_write(prev, &zero, 1) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
file->size = new_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t duckfs_delete_file(const char* name, duckfs_file_header_t* parent_dir)
|
||||
{
|
||||
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
duckfs_file_header_t child;
|
||||
uint64_t prev_lba = 0;
|
||||
uint64_t current_lba = parent_dir->child_lba;
|
||||
|
||||
/* Search for file by name */
|
||||
while (current_lba != 0)
|
||||
{
|
||||
if (disk_read(current_lba, &child, 1) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
prev_lba = current_lba;
|
||||
current_lba = child.next_file_lba;
|
||||
}
|
||||
|
||||
if (current_lba == 0)
|
||||
{
|
||||
return -3; /* not found */
|
||||
}
|
||||
|
||||
/* Remove from parent's linked list */
|
||||
if (prev_lba == 0)
|
||||
{
|
||||
/* It's the first child */
|
||||
parent_dir->child_lba = child.next_file_lba;
|
||||
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duckfs_file_header_t prev;
|
||||
if (disk_read(prev_lba, &prev, 1) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
prev.next_file_lba = child.next_file_lba;
|
||||
if (disk_write(prev_lba, &prev, 1) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free file data blocks */
|
||||
uint64_t current = child.first_block_lba;
|
||||
while (current != 0)
|
||||
{
|
||||
uint64_t next;
|
||||
if (disk_read(current, &next, 1) != 0)
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
|
||||
/* Insert this block into the freelist */
|
||||
if (disk_write(current, &super.free_list_lba, 1) != 0)
|
||||
{
|
||||
return -8;
|
||||
}
|
||||
|
||||
super.free_list_lba = current;
|
||||
current = next;
|
||||
}
|
||||
|
||||
/* Free file header block */
|
||||
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
|
||||
{
|
||||
return -9;
|
||||
}
|
||||
|
||||
super.free_list_lba = current_lba;
|
||||
|
||||
/* Save updated superblock */
|
||||
if (disk_write(8, &super, 1) != 0)
|
||||
{
|
||||
return -10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t duckfs_delete_dir(const char* name, duckfs_file_header_t* parent_dir)
|
||||
{
|
||||
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
duckfs_file_header_t dir;
|
||||
uint64_t prev_lba = 0;
|
||||
uint64_t current_lba = parent_dir->child_lba;
|
||||
|
||||
/* Find directory */
|
||||
while (current_lba != 0)
|
||||
{
|
||||
if (disk_read(current_lba, &dir, 1) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (strncmp(dir.name, name, DUCKFS_NAME_LEN) == 0 && dir.type == DUCKFS_TYPE_DIR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
prev_lba = current_lba;
|
||||
current_lba = dir.next_file_lba;
|
||||
}
|
||||
|
||||
if (current_lba == 0)
|
||||
{
|
||||
return -3; /* not found */
|
||||
}
|
||||
|
||||
/* Delete contents recursively */
|
||||
uint64_t child_lba = dir.child_lba;
|
||||
while (child_lba != 0)
|
||||
{
|
||||
duckfs_file_header_t child;
|
||||
if (disk_read(child_lba, &child, 1) != 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
uint64_t next_lba = child.next_file_lba;
|
||||
|
||||
if (child.type == DUCKFS_TYPE_FILE)
|
||||
{
|
||||
if (duckfs_delete_file(child.name, &dir) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
else if (child.type == DUCKFS_TYPE_DIR)
|
||||
{
|
||||
if (duckfs_delete_dir(child.name, &dir) != 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
child_lba = next_lba;
|
||||
}
|
||||
|
||||
/* Remove dir from parent */
|
||||
if (prev_lba == 0)
|
||||
{
|
||||
parent_dir->child_lba = dir.next_file_lba;
|
||||
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duckfs_file_header_t prev;
|
||||
if (disk_read(prev_lba, &prev, 1) != 0)
|
||||
{
|
||||
return -8;
|
||||
}
|
||||
|
||||
prev.next_file_lba = dir.next_file_lba;
|
||||
if (disk_write(prev_lba, &prev, 1) != 0)
|
||||
{
|
||||
return -9;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free directory header block */
|
||||
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
|
||||
{
|
||||
return -10;
|
||||
}
|
||||
|
||||
super.free_list_lba = current_lba;
|
||||
|
||||
/* Save updated superblock */
|
||||
return disk_write(8, &super, 1);
|
||||
}
|
||||
|
||||
|
50
drivers/fs/duckfs_disk_io.c
Normal file
50
drivers/fs/duckfs_disk_io.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <fs/duckfs.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer);
|
||||
extern int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer);
|
||||
|
||||
static uint8_t duckfs_drive = 0;
|
||||
|
||||
void duckfs_set_drive(uint8_t drive)
|
||||
{
|
||||
duckfs_drive = drive;
|
||||
}
|
||||
|
||||
int32_t disk_read(uint64_t lba, void* buffer, uint32_t count)
|
||||
{
|
||||
/* IDE spec only allows up to 256 sectors in one call */
|
||||
while (count > 0)
|
||||
{
|
||||
uint8_t sectors = (count > 256) ? 256 : count;
|
||||
int32_t result = ide_read48(duckfs_drive, lba, sectors, buffer);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lba += sectors;
|
||||
count -= sectors;
|
||||
buffer = (void*)((uintptr_t)buffer + 512 * sectors);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count)
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
uint8_t sectors = (count > 256) ? 256 : count;
|
||||
int32_t result = ide_write48(duckfs_drive, lba, sectors, buffer);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lba += sectors;
|
||||
count -= sectors;
|
||||
buffer = (const void*)((uintptr_t)buffer + 512 * sectors);
|
||||
}
|
||||
return 0;
|
||||
}
|
248
drivers/fs/fat16.c
Normal file
248
drivers/fs/fat16.c
Normal file
@ -0,0 +1,248 @@
|
||||
#include <drivers/ide.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fs/fat16.h>
|
||||
|
||||
static fat16_t fat;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t jmp[3];
|
||||
char oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sectors;
|
||||
uint8_t fat_count;
|
||||
uint16_t root_entries;
|
||||
uint16_t total_sectors_short;
|
||||
uint8_t media_desc;
|
||||
uint16_t fat_size_sectors;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_long;
|
||||
// Extended Boot Record...
|
||||
} fat16_bpb_t;
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
char ext[3];
|
||||
uint8_t attr;
|
||||
uint8_t reserved;
|
||||
uint8_t create_time_tenth;
|
||||
uint16_t create_time;
|
||||
uint16_t create_date;
|
||||
uint16_t access_date;
|
||||
uint16_t first_cluster_hi;
|
||||
uint16_t write_time;
|
||||
uint16_t write_date;
|
||||
uint16_t first_cluster_lo;
|
||||
uint32_t size;
|
||||
} fat16_direntry_raw_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
static uint8_t sector_buffer[512];
|
||||
|
||||
uint32_t cluster_to_lba(uint16_t cluster)
|
||||
{
|
||||
return fat.data_start + ((cluster - 2) * fat.sectors_per_cluster);
|
||||
}
|
||||
|
||||
|
||||
int32_t fat16_init(uint8_t drive)
|
||||
{
|
||||
if (ide_read48(drive, 0, 1, sector_buffer) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fat16_bpb_t* bpb = (fat16_bpb_t*)sector_buffer;
|
||||
|
||||
fat.drive = drive;
|
||||
fat.bytes_per_sector = bpb->bytes_per_sector;
|
||||
fat.sectors_per_cluster = bpb->sectors_per_cluster;
|
||||
fat.root_entry_count = bpb->root_entries;
|
||||
|
||||
fat.fat_start = bpb->reserved_sectors;
|
||||
fat.root_dir_start = fat.fat_start + bpb->fat_count * bpb->fat_size_sectors;
|
||||
fat.data_start = fat.root_dir_start + ((bpb->root_entries * 32 + fat.bytes_per_sector - 1) / fat.bytes_per_sector);
|
||||
fat.current_dir_cluster = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t fat16_get_fat_entry(uint16_t cluster)
|
||||
{
|
||||
uint32_t fat_offset = cluster * 2;
|
||||
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
|
||||
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
|
||||
|
||||
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0)
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
return *(uint16_t*)§or_buffer[ent_offset];
|
||||
}
|
||||
|
||||
uint16_t fat16_alloc_cluster(void)
|
||||
{
|
||||
for (uint16_t cluster = 2; cluster < 0xFFF0; ++cluster) {
|
||||
uint16_t entry = fat16_get_fat_entry(cluster);
|
||||
if (entry == 0x0000) {
|
||||
// Mark as end of chain
|
||||
uint32_t fat_offset = cluster * 2;
|
||||
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
|
||||
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
|
||||
|
||||
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
|
||||
*(uint16_t*)§or_buffer[ent_offset] = 0xFFFF;
|
||||
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
|
||||
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t fat16_list_dir(fat16_dir_entry_t* entries, size_t max_entries)
|
||||
{
|
||||
size_t count = 0;
|
||||
if (fat.current_dir_cluster == 0)
|
||||
{
|
||||
uint16_t root_sectors = ((fat.root_entry_count * 32) + (fat.bytes_per_sector - 1)) / fat.bytes_per_sector;
|
||||
for (uint32_t i = 0; i < root_sectors && count < max_entries; ++i)
|
||||
{
|
||||
if (ide_read48(fat.drive, fat.root_dir_start + i, 1, sector_buffer) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fat16_direntry_raw_t* de = (fat16_direntry_raw_t*)sector_buffer;
|
||||
for (int32_t j = 0; j < 512 / 32 && count < max_entries; ++j, ++de)
|
||||
{
|
||||
if (de->name[0] == 0x00 || de->name[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(entries[count].name, de->name, 8);
|
||||
entries[count].name[8] = '\0';
|
||||
entries[count].attr = de->attr;
|
||||
entries[count].cluster = de->first_cluster_lo;
|
||||
entries[count].size = de->size;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TODO: Add support for listing subdirectories if current_dir_cluster != 0 */
|
||||
return count;
|
||||
}
|
||||
|
||||
int32_t fat16_read_file(const char* filename, void* buffer, size_t max_size) {
|
||||
fat16_dir_entry_t entries[64];
|
||||
int32_t n = fat16_list_dir(entries, 64);
|
||||
for (int32_t i = 0; i < n; ++i) {
|
||||
if (!(entries[i].attr & FAT16_ATTR_DIRECTORY) &&
|
||||
strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
|
||||
|
||||
uint16_t cluster = entries[i].cluster;
|
||||
uint8_t* out = (uint8_t*)buffer;
|
||||
size_t remaining = entries[i].size < max_size ? entries[i].size : max_size;
|
||||
|
||||
while (cluster >= 0x0002 && cluster < 0xFFF8 && remaining > 0) {
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
size_t to_read = fat.bytes_per_sector * fat.sectors_per_cluster;
|
||||
|
||||
if (ide_read48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
|
||||
return -1;
|
||||
|
||||
size_t copy_size = (remaining < to_read) ? remaining : to_read;
|
||||
memcpy(out, sector_buffer, copy_size);
|
||||
out += copy_size;
|
||||
remaining -= copy_size;
|
||||
|
||||
cluster = fat16_get_fat_entry(cluster);
|
||||
}
|
||||
|
||||
return (int32_t)(out - (uint8_t*)buffer);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int32_t fat16_write_file(const char* filename, const void* data, size_t size) {
|
||||
fat16_dir_entry_t entries[64];
|
||||
int32_t n = fat16_list_dir(entries, 64);
|
||||
for (int32_t i = 0; i < n; ++i) {
|
||||
if (strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
|
||||
uint16_t cluster = entries[i].cluster;
|
||||
const uint8_t* src = (const uint8_t*)data;
|
||||
size_t remaining = size;
|
||||
|
||||
while (remaining > 0) {
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
size_t cluster_bytes = fat.sectors_per_cluster * fat.bytes_per_sector;
|
||||
size_t to_write = remaining < cluster_bytes ? remaining : cluster_bytes;
|
||||
|
||||
memset(sector_buffer, 0, cluster_bytes); // Clear old data
|
||||
memcpy(sector_buffer, src, to_write);
|
||||
if (ide_write48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
|
||||
return -1;
|
||||
|
||||
src += to_write;
|
||||
remaining -= to_write;
|
||||
|
||||
// Last chunk?
|
||||
if (remaining == 0)
|
||||
break;
|
||||
|
||||
// Check next cluster
|
||||
uint16_t next = fat16_get_fat_entry(cluster);
|
||||
if (next >= 0xFFF8 || next == 0x0000) {
|
||||
// Need to allocate a new cluster
|
||||
uint16_t new_cluster = fat16_alloc_cluster();
|
||||
if (new_cluster == 0) return -1;
|
||||
|
||||
// Update FAT to point to new cluster
|
||||
uint32_t fat_offset = cluster * 2;
|
||||
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
|
||||
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
|
||||
|
||||
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
|
||||
*(uint16_t*)§or_buffer[ent_offset] = new_cluster;
|
||||
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
|
||||
|
||||
next = new_cluster;
|
||||
}
|
||||
|
||||
cluster = next;
|
||||
}
|
||||
|
||||
return (int32_t)size;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t fat16_change_dir(const char* dirname)
|
||||
{
|
||||
fat16_dir_entry_t entries[64];
|
||||
int32_t n = fat16_list_dir(entries, 64);
|
||||
for (int32_t i = 0; i < n; ++i)
|
||||
{
|
||||
if ((entries[i].attr & FAT16_ATTR_DIRECTORY) && strncmp(entries[i].name, dirname, FAT16_MAX_FILENAME) == 0)
|
||||
{
|
||||
fat.current_dir_cluster = entries[i].cluster;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -5,24 +5,24 @@
|
||||
#include <fs/fat32.h>
|
||||
|
||||
struct __attribute__((packed)) fat32_bpb {
|
||||
uint8_t jmp[3];
|
||||
uint8_t oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sector_count;
|
||||
uint8_t num_fats;
|
||||
uint16_t root_entry_count;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media;
|
||||
uint16_t fat_size_16;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
uint32_t fat_size_32;
|
||||
uint16_t ext_flags;
|
||||
uint16_t fs_version;
|
||||
uint32_t root_cluster;
|
||||
uint8_t jmp[3];
|
||||
uint8_t oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sector_count;
|
||||
uint8_t num_fats;
|
||||
uint16_t root_entry_count;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media;
|
||||
uint16_t fat_size_16;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
uint32_t fat_size_32;
|
||||
uint16_t ext_flags;
|
||||
uint16_t fs_version;
|
||||
uint32_t root_cluster;
|
||||
};
|
||||
|
||||
static int32_t fat32_drive = 0;
|
||||
@ -37,9 +37,10 @@ int32_t fat32_init(int32_t drive)
|
||||
{
|
||||
fat32_drive = drive;
|
||||
int err = ide_read48(drive, 0, 1, sector);
|
||||
if (err != 0) {
|
||||
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||
return -1;
|
||||
if (err != 0)
|
||||
{
|
||||
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&bpb, sector, sizeof(bpb));
|
||||
@ -47,56 +48,79 @@ int32_t fat32_init(int32_t drive)
|
||||
fat_start_lba = bpb.reserved_sector_count;
|
||||
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
||||
current_directory_cluster = bpb.root_cluster;
|
||||
printf("========= Start FAT info =========\n");
|
||||
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
|
||||
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
|
||||
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
|
||||
printf("Number of FATs: %u\n", bpb.num_fats);
|
||||
printf("FAT size (32): %u\n", bpb.fat_size_32);
|
||||
printf("Root cluster: %u\n", bpb.root_cluster);
|
||||
printf("========= End FAT info =========\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_83(const char *s) {
|
||||
for (int i = 0; i < 11; i++) {
|
||||
char c = s[i];
|
||||
if (c >= 32 && c <= 126) {
|
||||
printf("%c", c); // or your kernel's character output function
|
||||
} else {
|
||||
printf("\\x%02X", (unsigned char)c); // hex-escape non-printables
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
static uint32_t cluster_to_lba(uint32_t cluster)
|
||||
{
|
||||
printf("cluster_heap_lba: %u\n", cluster_heap_lba);
|
||||
return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster;
|
||||
}
|
||||
|
||||
static void format_83_name(const char *input, char out[11]) {
|
||||
memset(out, ' ', 11);
|
||||
int i = 0, j = 0;
|
||||
void format_83_name(const char* input, char* output)
|
||||
{
|
||||
printf("Input name: %s, Input length: %i\n", input, strlen(input));
|
||||
|
||||
// Copy name part (up to 8 chars)
|
||||
while (input[i] && input[i] != '.' && j < 8) {
|
||||
out[j++] = toupper((unsigned char)input[i++]);
|
||||
memset(output, ' ', 11);
|
||||
int32_t i = 0, j = 0;
|
||||
while (input[i] && j < 11)
|
||||
{
|
||||
if (input[i] == '.')
|
||||
{
|
||||
j = 8;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip dot
|
||||
if (input[i] == '.') i++;
|
||||
|
||||
// Copy extension (up to 3 chars)
|
||||
int k = 8;
|
||||
while (input[i] && j < 11) {
|
||||
out[k++] = toupper((unsigned char)input[i++]);
|
||||
j++;
|
||||
if (j < 11)
|
||||
{
|
||||
output[j++] = toupper((unsigned char)input[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t find_free_cluster() {
|
||||
// Read FAT sectors one by one
|
||||
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++) {
|
||||
uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512;
|
||||
uint32_t fat_offset = (cluster * 4) % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return 0;
|
||||
static uint32_t find_free_cluster(void)
|
||||
{
|
||||
/* Read FAT sectors one by one */
|
||||
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++)
|
||||
{
|
||||
uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512;
|
||||
uint32_t fat_offset = (cluster * 4) % 512;
|
||||
|
||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
if (entry == 0x00000000) {
|
||||
return cluster;
|
||||
}
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0; // No free cluster found
|
||||
|
||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
if (entry == 0x00000000)
|
||||
{
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return 0; // No free cluster found
|
||||
}
|
||||
|
||||
|
||||
@ -148,70 +172,336 @@ int32_t fat32_list_root(void)
|
||||
|
||||
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
char formatted[11];
|
||||
memset(formatted, 0xAB, sizeof(formatted));
|
||||
format_83_name(name, formatted);
|
||||
|
||||
uint32_t dir_cluster = current_directory_cluster;
|
||||
|
||||
while (dir_cluster < 0x0FFFFFF8)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(dir_cluster);
|
||||
|
||||
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
|
||||
{
|
||||
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint8_t)entry[0] == 0xE5 || (uint8_t)entry[11] == 0x0F)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("here\n");
|
||||
|
||||
char entry_name[12] = { '\0' };
|
||||
memcpy((void*)entry_name, (void*)entry, 11);
|
||||
|
||||
int32_t err = memcmp(entry_name, formatted, (size_t)11);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
printf("memcmp: %i\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* File found */
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t size = *(uint32_t *)(entry + 28);
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||
{
|
||||
uint32_t file_lba = cluster_to_lba(cluster);
|
||||
if (ide_read48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_read += bpb.sectors_per_cluster * 512;
|
||||
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next directory cluster */
|
||||
uint32_t fat_sector = dir_cluster * 4 / 512;
|
||||
uint32_t fat_offset = dir_cluster * 4 % 512;
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
return -2; /* File not found */
|
||||
}
|
||||
|
||||
|
||||
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
uint8_t fat_sector_buf[512];
|
||||
|
||||
char formatted[11];
|
||||
memset(formatted, 0xAB, sizeof(formatted));
|
||||
format_83_name(name, formatted);
|
||||
|
||||
uint32_t dir_cluster = current_directory_cluster;
|
||||
|
||||
while (dir_cluster < 0x0FFFFFF8)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(dir_cluster);
|
||||
|
||||
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
|
||||
{
|
||||
// Read directory sector
|
||||
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find matching entry offset inside this sector
|
||||
int32_t entry_offset = -1;
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint8_t)entry[0] == 0xE5 || (uint8_t)entry[11] == 0x0F)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char entry_name[12] = {0};
|
||||
memcpy(entry_name, entry, 11);
|
||||
|
||||
if (memcmp(entry_name, formatted, 11) == 0)
|
||||
{
|
||||
entry_offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry_offset == -1)
|
||||
{
|
||||
// Not found in this sector, continue to next
|
||||
continue;
|
||||
}
|
||||
|
||||
// Entry found, write file data clusters
|
||||
uint8_t *entry = §or[entry_offset];
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_written < len)
|
||||
{
|
||||
uint32_t file_lba = cluster_to_lba(cluster);
|
||||
if (ide_write48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_written += bpb.sectors_per_cluster * 512;
|
||||
|
||||
if (bytes_written < len)
|
||||
{
|
||||
// Read FAT sector for current cluster
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t next_cluster = find_free_cluster();
|
||||
if (next_cluster == 0)
|
||||
{
|
||||
return -3; // No free cluster
|
||||
}
|
||||
|
||||
*(uint32_t *)(fat_sector_buf + fat_offset) = next_cluster & 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = next_cluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mark end of cluster chain
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// **Re-read the directory sector before updating file size**
|
||||
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update file size in directory entry again after re-read
|
||||
entry = §or[entry_offset];
|
||||
*(uint32_t *)(entry + 28) = len;
|
||||
|
||||
// Write back updated directory sector
|
||||
if (ide_write48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Debug print updated directory entry
|
||||
printf("Directory entry after write (offset %d):\n", entry_offset);
|
||||
for (int j = 0; j < 32; j++) {
|
||||
uint8_t b = (uint8_t)entry[j];
|
||||
printf("%02X ", b);
|
||||
if ((j + 1) % 16 == 0) printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
for (int j = 0; j < 32; j++) {
|
||||
char c = entry[j];
|
||||
printf("%c", (c >= 32 && c <= 126) ? c : '.');
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
// Move to next cluster of the directory
|
||||
uint32_t fat_sector = dir_cluster * 4 / 512;
|
||||
uint32_t fat_offset = dir_cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
return -2; // File not found
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t fat32_create_file(const char *name)
|
||||
{
|
||||
uint8_t dir_sector[512];
|
||||
uint8_t fat_sector_buf[512];
|
||||
|
||||
uint32_t root_lba = cluster_to_lba(current_directory_cluster);
|
||||
|
||||
if (ide_read48(fat32_drive, root_lba, 1, dir_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char formatted_name[11];
|
||||
format_83_name(name, formatted_name);
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
uint8_t *entry = &dir_sector[i];
|
||||
if (entry[0] == 0x00 || entry[0] == 0xE5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
printf("Writing entry at offset %d\n", i);
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, formatted_name, 11);
|
||||
entry[11] = 0x20;
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int32_t j = 0; j < 11; j++)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
uint32_t free_cluster = find_free_cluster();
|
||||
if (free_cluster == 0)
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
|
||||
uint32_t fat_offset = (free_cluster * 4) % 512;
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t size = *(uint32_t *)(entry + 28);
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_read += bpb.sectors_per_cluster * 512;
|
||||
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
|
||||
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
if (ide_write48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
/* Set first cluster */
|
||||
entry[20] = (free_cluster >> 16) & 0xFF;
|
||||
entry[21] = (free_cluster >> 24) & 0xFF;
|
||||
entry[26] = free_cluster & 0xFF;
|
||||
entry[27] = (free_cluster >> 8) & 0xFF;
|
||||
|
||||
/* File size = 0 */
|
||||
memset(entry + 28, 0, 4);
|
||||
|
||||
if (ide_write48(fat32_drive, root_lba, 1, dir_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t temp[512];
|
||||
ide_read48(fat32_drive, cluster_to_lba(bpb.root_cluster), 1, temp);
|
||||
printf("Root directory cluster 2 dump (first 64 bytes):\n");
|
||||
for (int i = 0; i < 64; i++) {
|
||||
printf("%02X ", temp[i]);
|
||||
if ((i + 1) % 16 == 0) printf("\n");
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
return -2;
|
||||
|
||||
return -8;
|
||||
}
|
||||
|
||||
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
int32_t fat32_create_directory(const char *name)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
@ -222,206 +512,90 @@ int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00) break;
|
||||
if ((uint8_t)entry[0] == 0xE5) continue;
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int j = 0; j < 11; j++)
|
||||
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
|
||||
entry[11] = FAT32_ATTR_DIRECTORY;
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t bytes_written = 0;
|
||||
uint32_t cluster = 6;
|
||||
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
|
||||
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
|
||||
*(uint32_t *)(entry + 28) = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_written < len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
if (ide_write48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_written += bpb.sectors_per_cluster * 512;
|
||||
|
||||
if (bytes_written < len)
|
||||
{
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t next_cluster = find_free_cluster();
|
||||
if (next_cluster == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = next_cluster & 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = next_cluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(uint32_t *)(entry + 28) = len;
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t fat32_create_file(const char *name) {
|
||||
uint32_t root_lba = cluster_to_lba(bpb.root_cluster);
|
||||
int32_t fat32_change_directory(const char *name)
|
||||
{
|
||||
uint32_t dir_cluster = current_directory_cluster;
|
||||
|
||||
// Read root directory cluster sector (assuming 1 sector here for simplicity)
|
||||
if (ide_read48(fat32_drive, root_lba, 1, sector) != 0)
|
||||
while (dir_cluster < 0x0FFFFFF8)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(dir_cluster);
|
||||
|
||||
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
|
||||
{
|
||||
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char formatted_name[11];
|
||||
format_83_name(name, formatted_name);
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
uint8_t *entry = §or[i];
|
||||
if (entry[0] == 0x00 || entry[0] == 0xE5) {
|
||||
// Found free directory entry, clear it
|
||||
memset(entry, 0, 32);
|
||||
|
||||
// Copy formatted filename
|
||||
memcpy(entry, formatted_name, 11);
|
||||
|
||||
// Set attributes to Archive (normal file)
|
||||
entry[11] = 0x20;
|
||||
|
||||
// Allocate first cluster for the file
|
||||
uint32_t free_cluster = find_free_cluster();
|
||||
if (free_cluster == 0) {
|
||||
return -2; // No free cluster
|
||||
}
|
||||
|
||||
// Mark cluster as end-of-chain in FAT
|
||||
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
|
||||
uint32_t fat_offset = (free_cluster * 4) % 512;
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF; // end of cluster chain
|
||||
if (ide_write48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
// Set first cluster in directory entry (split high and low 16 bits)
|
||||
entry[20] = (free_cluster >> 16) & 0xFF;
|
||||
entry[21] = (free_cluster >> 24) & 0xFF;
|
||||
entry[26] = free_cluster & 0xFF;
|
||||
entry[27] = (free_cluster >> 8) & 0xFF;
|
||||
|
||||
// Set file size = 0
|
||||
entry[28] = 0;
|
||||
entry[29] = 0;
|
||||
entry[30] = 0;
|
||||
entry[31] = 0;
|
||||
|
||||
// Write back directory sector
|
||||
if (ide_write48(fat32_drive, root_lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
return 0; // Success
|
||||
}
|
||||
}
|
||||
|
||||
return -3; // No free directory entry found
|
||||
}
|
||||
|
||||
int32_t fat32_create_directory(const char *name) {
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5) {
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
|
||||
entry[11] = FAT32_ATTR_DIRECTORY;
|
||||
|
||||
uint32_t cluster = 6;
|
||||
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
|
||||
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
|
||||
*(uint32_t *)(entry + 28) = 0;
|
||||
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t fat32_change_directory(const char *name) {
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00) break;
|
||||
if ((uint8_t)entry[0] == 0xE5) continue;
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int32_t j = 0; j < 11; j++)
|
||||
if (entry_name[j] == ' ') entry_name[j] = 0;
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0) continue;
|
||||
for (int j = 0; j < 11; j++)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(entry[11] & FAT32_ATTR_DIRECTORY))
|
||||
return -2;
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -3;
|
||||
|
||||
uint32_t fat_sector = dir_cluster * 4 / 512;
|
||||
uint32_t fat_offset = dir_cluster * 4 % 512;
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
206
drivers/fs/vfs.c
206
drivers/fs/vfs.c
@ -1,8 +1,8 @@
|
||||
#include <fs/ramfs.h>
|
||||
/*#include <fs/fat16.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/vfs.h>*/
|
||||
|
||||
|
||||
/*
|
||||
@ -11,7 +11,7 @@
|
||||
-33 means stdout (which can be read)
|
||||
*/
|
||||
|
||||
bool vfs_initialized = false;
|
||||
/*bool vfs_initialized = false;
|
||||
ramfs_file_header_t* vfs_current_dir = NULL;
|
||||
|
||||
void vfs_init(void)
|
||||
@ -27,204 +27,4 @@ void vfs_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent); */
|
||||
|
||||
FILE create_file(char* filename, char type, char encryption, FILE parent)
|
||||
{
|
||||
if (!filename)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parent == -128)
|
||||
{
|
||||
parent = vfs_current_dir->fd;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* file = ramfs_create_file(filename, type, encryption, ramfs_resolve_fd(parent));
|
||||
if (!file)
|
||||
{
|
||||
return -4; /* error code for failed creation */
|
||||
}
|
||||
|
||||
return file->fd;
|
||||
}
|
||||
|
||||
int32_t delete_file(FILE file)
|
||||
{
|
||||
/*
|
||||
XXX WARNING: ANY AND ALL PROCESSES CAN DELETE A FILE VIA THIS INTERFACE!!! XXX
|
||||
XXX THIS MUST BE PACHED SOON!!! OR AT LEAST ADD PERMISSION CHECKING IN THE SYSCALL INTERFACE XXX
|
||||
XXX OR IN THE C LIBRARIES!!! XXX
|
||||
*/
|
||||
|
||||
if (file < 1)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
return ramfs_delete_file(_file);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open a file based on a string.
|
||||
Return a file descriptor on success, a negative value on failure.
|
||||
|
||||
return values:
|
||||
(positive non-zero value) - File descriptor
|
||||
-1 - Insufficient permissions to open file
|
||||
-2 - File does not exist ( or at least, File not found. )
|
||||
-3 - No filesystem is initialized
|
||||
-4 - Internal error, perhaps try again
|
||||
*/
|
||||
FILE open_file(char* filename)
|
||||
{
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
ramfs_file_header_t* _file = ramfs_resolve_path(filename);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return (FILE)-2;
|
||||
}
|
||||
|
||||
return (FILE)_file->fd;
|
||||
}
|
||||
|
||||
return (FILE)-3;
|
||||
}
|
||||
|
||||
|
||||
FILE write_file(FILE file, void* data, size_t len)
|
||||
{
|
||||
|
||||
if (file < 1 || !data || len == 0)
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (_file->type == RAMFS_FILE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_file->data_begin)
|
||||
{
|
||||
free(_file->data_begin);
|
||||
_file->data_begin = NULL;
|
||||
_file->data_end = NULL;
|
||||
}
|
||||
|
||||
void* new_buf = malloc(len);
|
||||
if (!new_buf)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
memcpy(new_buf, data, len);
|
||||
|
||||
_file->data_begin = new_buf;
|
||||
_file->data_end = (void*)((uint8_t*)new_buf + len);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
int32_t read_file(FILE file, void* buf, size_t buflen)
|
||||
{
|
||||
if (file < 1 || !buf || buflen == 0)
|
||||
{
|
||||
return -1; /* Invalid arguments */
|
||||
}
|
||||
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file || _file->type == RAMFS_FILE_DIR)
|
||||
{
|
||||
return -2; /* Not a file or trying to read a directory */
|
||||
}
|
||||
|
||||
if (!_file->data_begin || !_file->data_end)
|
||||
{
|
||||
return 0; /* Empty file */
|
||||
}
|
||||
|
||||
size_t total_len = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
|
||||
|
||||
if (_file->read_offset >= (int32_t)total_len)
|
||||
{
|
||||
return 0; /* End of file */
|
||||
}
|
||||
|
||||
size_t available = total_len - _file->read_offset;
|
||||
size_t to_copy = (buflen < available) ? buflen : available;
|
||||
|
||||
memcpy(buf, (uint8_t*)_file->data_begin + _file->read_offset, to_copy);
|
||||
|
||||
_file->read_offset += to_copy;
|
||||
|
||||
return (int32_t)to_copy;
|
||||
}
|
||||
|
||||
return -3; /* FS not initialized */
|
||||
}
|
||||
|
||||
int32_t reset_read_offset(FILE file)
|
||||
{
|
||||
if (file < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
_file->read_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t seek_file(FILE file, int32_t offset)
|
||||
{
|
||||
if (file < 0 && file != -32 && file != -33)
|
||||
{
|
||||
return -1; /* Invalid file descriptor */
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file || _file->type == RAMFS_FILE_DIR)
|
||||
return -2; // Invalid file or directory
|
||||
|
||||
if (!_file->data_begin || !_file->data_end)
|
||||
return -3; // Empty file
|
||||
|
||||
size_t file_size = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
|
||||
|
||||
if (offset < 0 || (size_t)offset > file_size)
|
||||
return -4; // Offset out of bounds
|
||||
|
||||
_file->read_offset = offset;
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user