120 lines
3.1 KiB
C
120 lines
3.1 KiB
C
#include "io.h"
|
|
#include "common.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
unsigned reads = 0, reads_all = 0, writes = 0, writes_all = 0;
|
|
|
|
page_cache_entry_t *_file_load_page(file_t* file, page_t page);
|
|
void _file_flush_page(file_t *file, page_cache_entry_t *entry);
|
|
|
|
file_t* file_open(const char* filename, const char* mode)
|
|
{
|
|
FILE* handle = fopen(filename, mode);
|
|
|
|
if (!handle) {
|
|
printfv(VERBOSITY_NORMAL, "[io] Can't open file %s.\n", filename);
|
|
return NULL;
|
|
}
|
|
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] File %s opened in %s with page size %zu.\n", filename, mode, PAGE_SIZE);
|
|
file_t* result = malloc(sizeof(file_t));
|
|
memset(result, 0, sizeof(file_t));
|
|
|
|
result->file = handle;
|
|
result->filename = malloc(strlen(filename) + 1);
|
|
|
|
strcpy(result->filename, filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
void file_close(file_t* file)
|
|
{
|
|
file_flush(file);
|
|
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] Closing file %s.\n", file->filename);
|
|
fclose(file->file);
|
|
|
|
free(file->filename);
|
|
free(file);
|
|
}
|
|
|
|
size_t file_read(file_t* file, page_t page, void* buffer, size_t length)
|
|
{
|
|
reads_all++;
|
|
|
|
page_cache_entry_t *entry = _file_load_page(file, page);
|
|
memcpy(buffer, entry->data, length);
|
|
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] Reading page %zu in %s (%zu bytes).\n", page, file->filename, entry->size);
|
|
|
|
return entry->size;
|
|
}
|
|
|
|
size_t file_write(file_t* file, page_t page, const void* buffer, size_t length)
|
|
{
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] Writing page %zu in %s (%zu bytes).\n", page, file->filename, length);
|
|
writes_all++;
|
|
|
|
page_cache_entry_t *entry = _file_load_page(file, page);
|
|
|
|
memset(entry->data, 0, PAGE_SIZE);
|
|
memcpy(entry->data, buffer, length);
|
|
|
|
entry->flags |= PAGE_DIRTY;
|
|
entry->size = length;
|
|
|
|
return entry->size;
|
|
}
|
|
|
|
void file_flush(file_t* file)
|
|
{
|
|
for (unsigned i = 0; i < CACHE_ENTRIES; i++) {
|
|
_file_flush_page(file, file->cache + i);
|
|
}
|
|
}
|
|
|
|
page_cache_entry_t *_file_load_page(file_t* file, page_t page)
|
|
{
|
|
page_cache_entry_t *entry = file->cache + (page % CACHE_ENTRIES);
|
|
|
|
if (entry->page == page && entry->flags & PAGE_PRESENT) {
|
|
// already in cache
|
|
return entry;
|
|
}
|
|
|
|
_file_flush_page(file, entry);
|
|
|
|
int result = fseek(file->file, page * PAGE_SIZE, SEEK_SET);
|
|
|
|
memset(entry->data, 0, PAGE_SIZE);
|
|
entry->size = fread(entry->data, 1, PAGE_SIZE, file->file);
|
|
if (entry->size) {
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] Loading page %u of %s (%zu bytes).\n", page, file->filename, entry->size);
|
|
reads++;
|
|
}
|
|
|
|
entry->page = page;
|
|
entry->flags |= PAGE_PRESENT;
|
|
|
|
return entry;
|
|
}
|
|
|
|
void _file_flush_page(file_t *file, page_cache_entry_t *entry)
|
|
{
|
|
if (entry->flags & PAGE_PRESENT && entry->flags & PAGE_DIRTY) {
|
|
printfv(VERBOSITY_VERY_VERBOSE, "[io] Flushing page %u to %s (%zu bytes).\n", entry->page, file->filename, entry->size);
|
|
|
|
fseek(file->file, entry->page * PAGE_SIZE, SEEK_SET);
|
|
fwrite(entry->data, 1, entry->size, file->file);
|
|
|
|
// disable dirty flag
|
|
entry->flags &= ~PAGE_DIRTY;
|
|
|
|
writes++;
|
|
}
|
|
}
|