miniffs/miniffs.c
Godzil 73d9d4b861 Add a primitive write function and function to get the version.
MiniFFS is not really meant to write in the files, but in some cases it could be needed so that was added for that reason. If the changes are applied or not to the actual file is implementation dependent. So be careful.
2022-05-30 15:40:29 +01:00

251 lines
5.6 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_write(file_t *file, char value)
{
miniffs_t *fs = (miniffs_t *) file->private_data;
uint8_t *filePtr = miniffs_getfileaddr(fs, file->fent);
filePtr[file->offset] = value;
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 0;
}
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;
}
char *miniffs_getversion()
{
return VERSION;
}