miniffs/miniffs.c

223 lines
5.2 KiB
C

/******************************************************************************
* MiniFFS : Mini Flat File System
* miniffs.c: Shared code for all platforms.
*
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
*
******************************************************************************/
#include <stdlib.h>
#include <string.h>
#define __miniffs_internal
#include <miniffs.h>
static miniffs_error_t last_error = MINIFFS_NOERROR;
/* Public API */
file_t *miniffs_open(miniffs_t *fs, const char *filename)
{
file_t *ret = (file_t *)calloc(1, sizeof(file_t));
if (ret == NULL)
{
miniffs_seterror(MINIFFS_ALLOCATION_ERROR);
goto exit;
}
ret->private_data = fs;
ret->fent = miniffs_findfile(fs, filename);
if (!ret->fent)
{
if (miniffs_geterror() != MINIFFS_INVALID_NAME)
{
miniffs_seterror(MINIFFS_FILE_NOT_FOUND);
}
goto free_and_exit;
}
ret->offset = 0;
miniffs_seterror(MINIFFS_NOERROR);
goto exit;
free_and_exit:
free(ret);
ret = NULL;
exit:
return ret;
}
int miniffs_close(file_t *file)
{
/* Let's poison the struct */
file->private_data = NULL;
file->offset = 0;
file->fent = NULL;
free(file);
miniffs_seterror(MINIFFS_NOERROR);
}
void *miniffs_map(file_t *file)
{
miniffs_t *fs = (miniffs_t *)file->private_data;
miniffs_seterror(MINIFFS_NOERROR);
return miniffs_getfileaddr(fs, file->fent);
}
uint8_t miniffs_read(file_t *file)
{
miniffs_t *fs = (miniffs_t *) file->private_data;
uint8_t *filePtr = miniffs_getfileaddr(fs, file->fent);
uint8_t ret = filePtr[file->offset];
file->offset++;
if (file->offset >= file->fent->size)
{
miniffs_seterror(MINIFFS_END_OF_FILE);
file->offset = file->fent->size - 1;
}
else
{
miniffs_seterror(MINIFFS_NOERROR);
}
return ret;
}
int miniffs_read_blocks(void *ptr, size_t size, size_t nmemb, file_t *file)
{
int i;
miniffs_t *fs = (miniffs_t *) file->private_data;
uint8_t *filePtr = miniffs_getfileaddr(fs, file->fent);
size_t fileOffset = file->offset;
size_t bufferOffset = 0;
int blockCount = 0;
for(i = 0; i < nmemb; i++)
{
if (file->fent->size >= (fileOffset + size))
{
memcpy(ptr + bufferOffset, &filePtr[fileOffset], size);
bufferOffset += size;
fileOffset += size;
blockCount++;
}
}
file->offset = fileOffset;
miniffs_seterror(MINIFFS_NOERROR);
return blockCount;
}
int miniffs_seek(file_t *file, size_t offset, int whence)
{
bool noError = true;
switch(whence) {
default:
miniffs_seterror(MINIFFS_INVALID_PARAMS);
return -1;
case MFFS_SEEK_SET:
file->offset = offset;
break;
case MFFS_SEEK_CUR:
file->offset += offset;
break;
case MFFS_SEEK_END:
if (file->fent->size <= offset)
{
/* Negative boundary check */
noError = false;
miniffs_seterror(MINIFFS_SEEK_OUT_OF_BOUNDARIES);
file->offset = 0;
}
else
{
file->offset = file->fent->size - 1 - offset;
}
break;
}
if (file->offset >= file->fent->size)
{
/* Positive Boundary check */
noError = false;
miniffs_seterror(MINIFFS_SEEK_OUT_OF_BOUNDARIES);
file->offset = file->fent->size - 1;
}
if (noError)
{
miniffs_seterror(MINIFFS_NOERROR);
}
}
size_t miniffs_tell(file_t *file)
{
miniffs_seterror(MINIFFS_NOERROR);
return file->offset;
}
miniffs_error_t miniffs_geterror()
{
return last_error;
}
/* Private API */
bool miniffs_isvalidfs(miniffs_t *fs)
{
return (fs->header->magic == MINIFFS_MAGIC) &&
(fs->header->fs_version_major == MINIFFS_VERSION_MAJOR) &&
(fs->header->fs_version_minor == MINIFFS_VERSION_MINOR) &&
(fs->header->fs_filename_len == MINIFFS_FILENAME_LENGTH) &&
(fs->header->fs_extention_len == MINIFFS_EXTENSION_LENGTH);
}
static void make_fullname(char *name, char *ext, char *out)
{
uint8_t nameLen = strnlen(name, MINIFFS_FILENAME_LENGTH);
uint8_t extLen = strnlen(ext, MINIFFS_EXTENSION_LENGTH);
memcpy(out, name, nameLen);
memcpy(out + nameLen, ".", 1);
memcpy(out + nameLen + 1, ext, extLen);
}
fileentry_t *miniffs_findfile(miniffs_t *fs, const char *filename)
{
int i;
char entryFullName[MINIFFS_FULLNAME_LENGTH];
uint8_t filenameLength = strlen(filename);
fileentry_t *ret = NULL;
if (filenameLength > MINIFFS_FULLNAME_LENGTH)
{
miniffs_seterror(MINIFFS_INVALID_NAME);
goto exit;
}
for(i = 0; i < fs->header->entry_count; i++)
{
fileentry_t *cur = &fs->header->fent[i];
make_fullname(cur->name, cur->ext, entryFullName);
if (memcmp(filename, entryFullName, filenameLength) == 0)
{
/* File found! */
ret = cur;
break;
}
}
exit:
return ret;
}
void miniffs_seterror(miniffs_error_t err)
{
last_error = err;
}