SBDP02/io.c
2018-12-15 18:41:29 +01:00

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++;
}
}