Compare commits
No commits in common. "v0.0.1" and "master" have entirely different histories.
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[submodule "external/cJSON"]
|
||||||
|
path = external/cJSON
|
||||||
|
url = https://github.com/DaveGamble/cJSON.git
|
||||||
|
[submodule "external/googletest"]
|
||||||
|
path = external/googletest
|
||||||
|
url = https://github.com/google/googletest.git
|
||||||
@ -10,15 +10,8 @@ include(GetGitRevisionDescription)
|
|||||||
git_describe(VERSION --tags --dirty=-dirty)
|
git_describe(VERSION --tags --dirty=-dirty)
|
||||||
|
|
||||||
#parse the version information into pieces.
|
#parse the version information into pieces.
|
||||||
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}")
|
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}")
|
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_MICRO "${VERSION}")
|
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}")
|
|
||||||
message("-- Building version ${VERSION}")
|
message("-- Building version ${VERSION}")
|
||||||
add_compile_options(-DV_MAJOR=${VERSION_MAJOR})
|
add_compile_definitions(VERSION="${VERSION}")
|
||||||
add_compile_options(-DV_MINOR=${VERSION_MINOR})
|
|
||||||
add_compile_options(-DV_MICRO=${VERSION_MICRO})
|
|
||||||
add_compile_options(-DV_TEXT="${VERSION_SHA1}")
|
|
||||||
|
|
||||||
|
|
||||||
set(VALID_BUILD_PLATFORM MEMORY FILE)
|
set(VALID_BUILD_PLATFORM MEMORY FILE)
|
||||||
@ -26,16 +19,31 @@ set(BUILD_PLATFORM MEMORY CACHE STRING "Platform to build for")
|
|||||||
set_property(CACHE BUILD_PLATFORM PROPERTY STRINGS ${VALID_BUILD_PLATFORM})
|
set_property(CACHE BUILD_PLATFORM PROPERTY STRINGS ${VALID_BUILD_PLATFORM})
|
||||||
|
|
||||||
option(BUILD_HOST_TOOLS "Build offline tools" ON)
|
option(BUILD_HOST_TOOLS "Build offline tools" ON)
|
||||||
|
option(RUN_TESTS "Run the test suite to verify everything is ok!" ON)
|
||||||
|
|
||||||
string(TOLOWER ${BUILD_PLATFORM} PLATFORM_FILE)
|
string(TOLOWER ${BUILD_PLATFORM} PLATFORM_FILE)
|
||||||
|
|
||||||
add_library(miniffs)
|
add_library(miniffs STATIC)
|
||||||
target_sources(miniffs PRIVATE platform/${PLATFORM_FILE}.c miniffs.c)
|
target_sources(miniffs PRIVATE platform/${PLATFORM_FILE}.c miniffs.c)
|
||||||
target_include_directories(miniffs PUBLIC includes/)
|
target_include_directories(miniffs PUBLIC includes/)
|
||||||
|
target_compile_definitions(miniffs PUBLIC BUILD_PLATFORM_${BUILD_PLATFORM})
|
||||||
|
|
||||||
if (BUILD_HOST_TOOLS)
|
if (BUILD_HOST_TOOLS)
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(external/cJSON)
|
||||||
|
|
||||||
# Offline tools use the file backend so we have to include the lib by hand.
|
# Offline tools use the file backend so we have to include the lib by hand.
|
||||||
add_executable(mffs)
|
add_executable(mffs)
|
||||||
target_sources(mffs PRIVATE platform/file.c miniffs.c mffs.c)
|
target_sources(mffs PRIVATE platform/file.c miniffs.c miniffs_tools.c mffs.c)
|
||||||
target_include_directories(mffs PRIVATE includes/)
|
target_link_libraries(mffs ${CJSON_LIB})
|
||||||
|
target_include_directories(mffs PRIVATE includes/ external/)
|
||||||
|
target_compile_definitions(mffs PRIVATE BUILD_PLATFORM_FILE)
|
||||||
|
target_compile_definitions(mffs PRIVATE BUILD_HOST_TOOLS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(RUN_TESTS)
|
||||||
|
enable_testing()
|
||||||
|
include(GoogleTest)
|
||||||
|
add_subdirectory("${PROJECT_SOURCE_DIR}/external/googletest" "external/googletest")
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
1
external/cJSON
vendored
Submodule
1
external/cJSON
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b45f48e600671feade0b6bd65d1c69de7899f2be
|
||||||
1
external/googletest
vendored
Submodule
1
external/googletest
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 56246cdb94de94f7f43c9df59635db92c41d4064
|
||||||
@ -9,16 +9,22 @@
|
|||||||
#ifndef MINIFFS_H
|
#ifndef MINIFFS_H
|
||||||
#define MINIFFS_H
|
#define MINIFFS_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#if BUILD_TARGET == MEMORY
|
#ifdef __cplusplus
|
||||||
#include <miniffs/platform/memory.h>
|
extern "C" {
|
||||||
#elif BUILD_TARGET == FILE
|
|
||||||
#include <miniffs/platform/file.h>
|
|
||||||
#else
|
|
||||||
#error Unknown build target
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MINIFFS_VERSION_MAJOR (1)
|
||||||
|
#define MINIFFS_VERSION_MINOR (0)
|
||||||
|
#define MINIFFS_FILENAME_LENGTH (8)
|
||||||
|
#define MINIFFS_EXTENSION_LENGTH (3)
|
||||||
|
|
||||||
|
/* the full name is FILENAME + '.' + EXTENSION */
|
||||||
|
#define MINIFFS_FULLNAME_LENGTH (MINIFFS_FILENAME_LENGTH + MINIFFS_EXTENSION_LENGTH + 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pack(1) may not be needed, but better be safe than sorry to
|
* The pack(1) may not be needed, but better be safe than sorry to
|
||||||
* have a consistent binary representation across architectures
|
* have a consistent binary representation across architectures
|
||||||
@ -26,8 +32,8 @@
|
|||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
typedef struct fileentry_t
|
typedef struct fileentry_t
|
||||||
{
|
{
|
||||||
char name[8];
|
char name[MINIFFS_FILENAME_LENGTH];
|
||||||
char ext[3];
|
char ext[MINIFFS_EXTENSION_LENGTH];
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
} fileentry_t;
|
} fileentry_t;
|
||||||
@ -35,27 +41,40 @@ typedef struct fileentry_t
|
|||||||
typedef struct miniffs_header_t
|
typedef struct miniffs_header_t
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
uint8_t fs_version_major;
|
||||||
|
uint8_t fs_version_minor;
|
||||||
|
uint8_t fs_filename_len;
|
||||||
|
uint8_t fs_extention_len;
|
||||||
uint32_t entry_count;
|
uint32_t entry_count;
|
||||||
fileentry_t fent[];
|
fileentry_t fent[];
|
||||||
} miniffs_header_t;
|
} miniffs_header_t;
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
typedef struct miniffs_t miniffs_t;
|
#if BUILD_PLATFORM_MEMORY
|
||||||
|
#include <platform/memory.h>
|
||||||
|
#elif BUILD_PLATFORM_FILE
|
||||||
|
#include <platform/file.h>
|
||||||
|
#else
|
||||||
|
#error Unknown build target.
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Somewhat similar structure to the plain C FILE structure */
|
/* Somewhat similar structure to the plain C FILE structure */
|
||||||
typedef struct file_t
|
typedef struct file_t
|
||||||
{
|
{
|
||||||
void *private;
|
void *private_data;
|
||||||
fileentry_t fent; /***< file linked to this structure */
|
fileentry_t *fent; /***< file linked to this structure */
|
||||||
uint32_t offset; /***< current position in the file */
|
uint32_t offset; /***< current position in the file */
|
||||||
} file_t;
|
} file_t;
|
||||||
|
|
||||||
#define MAKE4(_a, _b, _c, _d) ((_a & 0xFF) << 21) | ((_b & 0xFF) << 16) | ((_c & 0xFF) << 8) | (_d & 0xFF)
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
#define MAKE4(_a, _b, _c, _d) ((((_a) & 0xFF) << 24) | (((_b) & 0xFF) << 16) | (((_c) & 0xFF) << 8) | ((_d) & 0xFF))
|
||||||
|
#else
|
||||||
|
#define MAKE4(_d, _c, _b, _a) ((((_a) & 0xFF) << 24) | (((_b) & 0xFF) << 16) | (((_c) & 0xFF) << 8) | ((_d) & 0xFF))
|
||||||
|
#endif
|
||||||
#define MINIFFS_MAGIC MAKE4('M', 'F', 'F', 'S')
|
#define MINIFFS_MAGIC MAKE4('M', 'F', 'F', 'S')
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
MFFS_SEEK_SET, /***< Seek from beginning of file */
|
MFFS_SEEK_SET, /***< Seek from beginning of file */
|
||||||
MFFS_SEEK_CUR, /***< Seek from current position */
|
MFFS_SEEK_CUR, /***< Seek from current position */
|
||||||
MFFS_SEEK_END /***< Seek from end of file */
|
MFFS_SEEK_END /***< Seek from end of file */
|
||||||
@ -65,26 +84,35 @@ enum {
|
|||||||
* Public functions used reading the filesystem
|
* Public functions used reading the filesystem
|
||||||
* This implementation is system dependant as it relly on how the memory is architectured and where the MiniFFS is stored.
|
* This implementation is system dependant as it relly on how the memory is architectured and where the MiniFFS is stored.
|
||||||
*/
|
*/
|
||||||
miniffs_t *miniffs_openfs(void *address); /***< Open a MiniFFS filesystem */
|
|
||||||
|
|
||||||
file_t *miniffs_open(miniffs_t *fs, char *filename); /***< Open a file */
|
/* miniffs_openfs is backend specific and will be found in the backend header file */
|
||||||
int miniffs_close(file_t *file); /***< Close a file */
|
file_t *miniffs_open(miniffs_t *fs, const char *filename); /***< Open a file */
|
||||||
void *miniffs_map(file_t *file); /***< Map a file to memory */
|
int miniffs_close(file_t *file); /***< Close a file */
|
||||||
int miniffs_read(void *ptr, size_t size, size_t nmemb, file_t *file); /***< Read bytes from a file */
|
void *miniffs_map(file_t *file); /***< Map a file to memory */
|
||||||
int miniffs_seek(file_t *file, size_t offset, int whence); /***< Set position in a file */
|
int miniffs_read_blocks(void *ptr, size_t size, size_t nmemb, file_t *file); /***< Read blocks of bytes from a file */
|
||||||
size_t miniffs_tell(file_t *file); /***< Get current position in a file*/
|
uint8_t miniffs_read(file_t *file); /***< Read a single byte from a file */
|
||||||
|
int miniffs_seek(file_t *file, size_t offset, int whence); /***< Set position in a file */
|
||||||
|
size_t miniffs_tell(file_t *file); /***< Get current position in a file*/
|
||||||
|
|
||||||
|
int miniffs_write(file_t *file, char value);
|
||||||
|
char *miniffs_getversion();
|
||||||
|
|
||||||
typedef enum miniffs_error_t
|
typedef enum miniffs_error_t
|
||||||
{
|
{
|
||||||
MINIFFS_NOERROR = 0,
|
MINIFFS_NOERROR = 0,
|
||||||
MINIFFS_INVALID_FS,
|
MINIFFS_INVALID_FS,
|
||||||
|
MINIFFS_INVALID_NAME,
|
||||||
|
MINIFFS_INVALID_PARAMS,
|
||||||
MINIFFS_FILE_NOT_FOUND,
|
MINIFFS_FILE_NOT_FOUND,
|
||||||
|
MINIFFS_ALLOCATION_ERROR,
|
||||||
|
MINIFFS_SEEK_OUT_OF_BOUNDARIES,
|
||||||
|
MINIFFS_END_OF_FILE,
|
||||||
//MINIFFS_,
|
//MINIFFS_,
|
||||||
} miniffs_error_t;
|
} miniffs_error_t;
|
||||||
|
|
||||||
miniffs_error_t miniffs_geterror(); /***< Return last error */
|
miniffs_error_t miniffs_geterror(); /***< Return last error */
|
||||||
|
|
||||||
#ifdef BUILDING_HOST_TOOLS
|
#ifdef BUILD_HOST_TOOLS
|
||||||
/*
|
/*
|
||||||
* Functions used for offline creation of the filesystem
|
* Functions used for offline creation of the filesystem
|
||||||
*/
|
*/
|
||||||
@ -93,6 +121,20 @@ int miniffs_addfile(miniffs_t *fs, char *name, char *ext, char *host_path);
|
|||||||
int miniffs_delfile(miniffs_t *fs, char *name, char *ext, char *host_path);
|
int miniffs_delfile(miniffs_t *fs, char *name, char *ext, char *host_path);
|
||||||
int miniffs_writeimage(miniffs_t *fs, char *host_path);
|
int miniffs_writeimage(miniffs_t *fs, char *host_path);
|
||||||
int miniffs_closefs(miniffs_t *fs);
|
int miniffs_closefs(miniffs_t *fs);
|
||||||
#endif /* BUILDING_HOST_TOOLS */
|
#endif /* BUILD_HOST_TOOLS */
|
||||||
|
|
||||||
|
#ifdef __miniffs_internal
|
||||||
|
/*
|
||||||
|
* Function that are private to the library
|
||||||
|
*/
|
||||||
|
bool miniffs_isvalidfs(miniffs_t *fs);
|
||||||
|
fileentry_t *miniffs_findfile(miniffs_t *fs, const char *filename);
|
||||||
|
void miniffs_seterror(miniffs_error_t err);
|
||||||
|
void *miniffs_getfileaddr(miniffs_t *fs, fileentry_t *fent);
|
||||||
|
#endif /* __miniffs_internal */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* MINIFFS_H */
|
#endif /* MINIFFS_H */
|
||||||
|
|||||||
@ -1,8 +1,47 @@
|
|||||||
//
|
/******************************************************************************
|
||||||
// Created by Manoel.Trapier on 25/05/2022.
|
* MiniFFS : Mini Flat File System
|
||||||
//
|
* platform/file.h: Specific functions for the File backend
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef MINIFFS_FILE_H
|
#ifndef MINIFFS_PLATFORM_FILE_H
|
||||||
#define MINIFFS_FILE_H
|
#define MINIFFS_PLATFORM_FILE_H
|
||||||
|
|
||||||
#endif //MINIFFS_FILE_H
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef BUILD_HOST_TOOLS
|
||||||
|
typedef struct fs_fent_t
|
||||||
|
{
|
||||||
|
char name[MINIFFS_FILENAME_LENGTH];
|
||||||
|
char ext[MINIFFS_EXTENSION_LENGTH];
|
||||||
|
bool deleted;
|
||||||
|
bool mapped;
|
||||||
|
uint32_t size;
|
||||||
|
char *file_pointer;
|
||||||
|
} fs_fent_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct miniffs_t
|
||||||
|
{
|
||||||
|
miniffs_header_t *header;
|
||||||
|
|
||||||
|
void *memoryOffset;
|
||||||
|
#ifdef BUILD_HOST_TOOLS
|
||||||
|
uint32_t file_count; /***< Number of valid files in the list */
|
||||||
|
uint32_t file_list_count; /***< Number of items in the list */
|
||||||
|
uint32_t file_list_size; /***< Size of the list */
|
||||||
|
fs_fent_t *files; /***< File entry list */
|
||||||
|
#endif
|
||||||
|
} miniffs_t;
|
||||||
|
|
||||||
|
miniffs_t *miniffs_openfs(char *host_file); /***< Open a MiniFFS filesystem */
|
||||||
|
|
||||||
|
#ifdef __miniffs_internal
|
||||||
|
size_t host_map_file(char *filename, char **dest);
|
||||||
|
void host_unmap_file(char **dest, size_t length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MINIFFS_PLATFORM_FILE_H */
|
||||||
|
|||||||
@ -1,8 +1,20 @@
|
|||||||
//
|
/******************************************************************************
|
||||||
// Created by Manoel.Trapier on 25/05/2022.
|
* MiniFFS : Mini Flat File System
|
||||||
//
|
* platform/memory.h: Specific functions for the Memory backend
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef MINIFFS_PLATFORM_MEMORY_H
|
#ifndef MINIFFS_PLATFORM_MEMORY_H
|
||||||
#define MINIFFS_PLATFORM_MEMORY_H
|
#define MINIFFS_PLATFORM_MEMORY_H
|
||||||
|
|
||||||
|
typedef struct miniffs_t
|
||||||
|
{
|
||||||
|
miniffs_header_t *header;
|
||||||
|
void *memoryOffset;
|
||||||
|
} miniffs_t;
|
||||||
|
|
||||||
|
miniffs_t *miniffs_openfs(uintptr_t address); /***< Open a MiniFFS filesystem */
|
||||||
|
|
||||||
#endif /* MINIFFS_PLATFORM_MEMORY_H */
|
#endif /* MINIFFS_PLATFORM_MEMORY_H */
|
||||||
|
|||||||
24
mffs.c
24
mffs.c
@ -1,11 +1,29 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* MiniFFS : Mini Flat File System
|
||||||
|
* mffs.c: Offline tool for building mffs images.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <cJSON.h>
|
#include <miniffs.h>
|
||||||
|
|
||||||
|
#include <cJSON/cJSON.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
miniffs_t *fs;
|
||||||
|
|
||||||
|
printf("mffs version %s\n", VERSION);
|
||||||
|
|
||||||
|
fs = miniffs_createfs();
|
||||||
|
miniffs_addfile(fs, "HELLO", "TXT", "test/hello.txt");
|
||||||
|
|
||||||
|
miniffs_writeimage(fs, "test/output.mffs");
|
||||||
|
miniffs_closefs(fs);
|
||||||
|
|
||||||
int main() {
|
|
||||||
printf("Hello, World!\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
244
miniffs.c
244
miniffs.c
@ -5,3 +5,247 @@
|
|||||||
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
* 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;
|
||||||
|
}
|
||||||
110
miniffs_tools.c
110
miniffs_tools.c
@ -1,8 +1,116 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* MiniFFS : Mini Flat File System
|
* MiniFFS : Mini Flat File System
|
||||||
* miniffs_tools.c: Contain all the funciton needed for offline tools
|
* miniffs_tools.c: Contain all the function needed for offline tools
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define __miniffs_internal
|
||||||
|
#include <miniffs.h>
|
||||||
|
|
||||||
|
miniffs_t *miniffs_createfs()
|
||||||
|
{
|
||||||
|
miniffs_t *fs = (miniffs_t *)calloc(1, sizeof(miniffs_t));
|
||||||
|
|
||||||
|
fs->file_list_size = 2;
|
||||||
|
fs->files = (fs_fent_t *)calloc(2, sizeof(fs_fent_t));
|
||||||
|
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int miniffs_addfile(miniffs_t *fs, char *name, char *ext, char *host_path)
|
||||||
|
{
|
||||||
|
fs_fent_t *cur;
|
||||||
|
uint8_t nameLen = strnlen(name, MINIFFS_FILENAME_LENGTH);
|
||||||
|
uint8_t extLen = strnlen(ext, MINIFFS_EXTENSION_LENGTH);
|
||||||
|
|
||||||
|
if (fs->file_list_count == fs->file_list_size)
|
||||||
|
{
|
||||||
|
fs->file_list_size *= 2;
|
||||||
|
fs->files = realloc(fs->files, sizeof(fs_fent_t) * fs->file_list_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = &fs->files[fs->file_list_count];
|
||||||
|
memset(cur, 0, sizeof(fs_fent_t));
|
||||||
|
memcpy(cur->name, name, nameLen);
|
||||||
|
memcpy(cur->ext, ext, extLen);
|
||||||
|
|
||||||
|
cur->size = host_map_file(host_path, &cur->file_pointer);
|
||||||
|
|
||||||
|
cur->deleted = false;
|
||||||
|
|
||||||
|
fs->file_list_count++;
|
||||||
|
fs->file_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int miniffs_delfile(miniffs_t *fs, char *name, char *ext, char *host_path)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// 1 - find file
|
||||||
|
// 2 - mark as deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
int miniffs_writeimage(miniffs_t *fs, char *host_path)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
miniffs_header_t *header;
|
||||||
|
size_t headerSize = sizeof(miniffs_header_t) + fs->file_count * sizeof(fileentry_t);
|
||||||
|
size_t fileIndex = 0;
|
||||||
|
size_t filePosition = headerSize;
|
||||||
|
|
||||||
|
header = (miniffs_header_t *)calloc(1, headerSize);
|
||||||
|
|
||||||
|
header->magic = MINIFFS_MAGIC;
|
||||||
|
header->fs_version_major = MINIFFS_VERSION_MAJOR;
|
||||||
|
header->fs_version_minor = MINIFFS_VERSION_MINOR;
|
||||||
|
header->fs_filename_len = MINIFFS_FILENAME_LENGTH;
|
||||||
|
header->fs_extention_len = MINIFFS_EXTENSION_LENGTH;
|
||||||
|
header->entry_count = fs->file_count;
|
||||||
|
|
||||||
|
for(i = 0; i < fs->file_list_count; i++)
|
||||||
|
{
|
||||||
|
if (fs->files[i].deleted == false)
|
||||||
|
{
|
||||||
|
memcpy(header->fent[fileIndex].name, fs->files[i].name, MINIFFS_FILENAME_LENGTH);
|
||||||
|
memcpy(header->fent[fileIndex].ext, fs->files[i].ext, MINIFFS_EXTENSION_LENGTH);
|
||||||
|
header->fent[fileIndex].size = fs->files[i].size;
|
||||||
|
header->fent[fileIndex].offset = filePosition;
|
||||||
|
fileIndex ++;
|
||||||
|
filePosition += header->fent[fileIndex].size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopen(host_path, "wb");
|
||||||
|
|
||||||
|
fwrite(header, 1, headerSize, fp);
|
||||||
|
for(i = 0; i < fs->file_count; i++)
|
||||||
|
{
|
||||||
|
if (fs->files[i].deleted == false)
|
||||||
|
{
|
||||||
|
fwrite(fs->files[i].file_pointer, 1, fs->files[i].size, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int miniffs_closefs(miniffs_t *fs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < fs->file_count; i++)
|
||||||
|
{
|
||||||
|
if (fs->files[i].mapped)
|
||||||
|
{
|
||||||
|
host_unmap_file(&fs->files[i].file_pointer, fs->files[i].size);
|
||||||
|
fs->files[i].mapped = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(fs->files);
|
||||||
|
free(fs);
|
||||||
|
}
|
||||||
|
|||||||
101
platform/file.c
101
platform/file.c
@ -5,3 +5,104 @@
|
|||||||
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __miniffs_internal
|
||||||
|
#include <miniffs.h>
|
||||||
|
|
||||||
|
/* Internal functions */
|
||||||
|
size_t host_map_file(char *filename, char **dest)
|
||||||
|
{
|
||||||
|
char *ret_ptr;
|
||||||
|
size_t fileSize;
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* As windows do not provide an easy to use mmap equivalent, let's use the fallback
|
||||||
|
* of opening the file, allocating memory and read the file in the said memory
|
||||||
|
*/
|
||||||
|
FILE *fp;
|
||||||
|
fp = fopen(filename, "rb");
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
fileSize = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
ret_ptr = (char *)calloc(1, fileSize);
|
||||||
|
fread(ret_ptr, 1, fileSize, fp);
|
||||||
|
fclose(fp);
|
||||||
|
#else
|
||||||
|
int fd;
|
||||||
|
struct stat FileStat;
|
||||||
|
|
||||||
|
fd = open(filename, O_RDWR);
|
||||||
|
fstat(fd, &FileStat);
|
||||||
|
ret_ptr = (char *)mmap(NULL, FileStat.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||||
|
close(fd);
|
||||||
|
fileSize = FileStat.st_size;
|
||||||
|
if (ret_ptr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
ret_ptr = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*dest = ret_ptr;
|
||||||
|
return fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void host_unmap_file(char **dest, size_t length)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* As for windows we don't mmap, let's just free! */
|
||||||
|
free(*dest);
|
||||||
|
#else
|
||||||
|
munmap(*dest, length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*dest = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exported API */
|
||||||
|
miniffs_t *miniffs_openfs(char *host_file)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = NULL;
|
||||||
|
|
||||||
|
fs = (miniffs_t *)calloc(1, sizeof(miniffs_t));
|
||||||
|
if (fs == NULL)
|
||||||
|
{
|
||||||
|
miniffs_seterror(MINIFFS_ALLOCATION_ERROR);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
host_map_file(host_file, (char **)&fs->memoryOffset);
|
||||||
|
|
||||||
|
fs->header = (miniffs_header_t *)fs->memoryOffset;
|
||||||
|
|
||||||
|
if (!miniffs_isvalidfs(fs))
|
||||||
|
{
|
||||||
|
miniffs_seterror(MINIFFS_INVALID_FS);
|
||||||
|
goto free_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
free_and_exit:
|
||||||
|
free(fs);
|
||||||
|
fs = NULL;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Some internal functions */
|
||||||
|
void *miniffs_getfileaddr(miniffs_t *fs, fileentry_t *fent)
|
||||||
|
{
|
||||||
|
return fs->memoryOffset + fent->offset;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,3 +5,52 @@
|
|||||||
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define __miniffs_internal
|
||||||
|
#include <miniffs.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
miniffs_t *miniffs_openfs(uintptr_t address)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = NULL;
|
||||||
|
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
miniffs_seterror(MINIFFS_INVALID_FS);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = (miniffs_t *)calloc(1, sizeof(miniffs_t));
|
||||||
|
if (fs == NULL)
|
||||||
|
{
|
||||||
|
miniffs_seterror(MINIFFS_ALLOCATION_ERROR);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs->header = (miniffs_header_t *)address;
|
||||||
|
|
||||||
|
if (!miniffs_isvalidfs(fs))
|
||||||
|
{
|
||||||
|
miniffs_seterror(MINIFFS_INVALID_FS);
|
||||||
|
goto free_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs->memoryOffset = (void *)address;
|
||||||
|
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
free_and_exit:
|
||||||
|
free(fs);
|
||||||
|
fs = NULL;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private API */
|
||||||
|
void *miniffs_getfileaddr(miniffs_t *fs, fileentry_t *fent)
|
||||||
|
{
|
||||||
|
return fs->memoryOffset + fent->offset;
|
||||||
|
}
|
||||||
30
test/CMakeLists.txt
Normal file
30
test/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
project(MiniFFSTests)
|
||||||
|
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
include_directories(../includes)
|
||||||
|
link_libraries(miniffs)
|
||||||
|
|
||||||
|
set(TESTS_SRC fs_opening.cpp file_operations.cpp)
|
||||||
|
|
||||||
|
add_executable(miniffs_test)
|
||||||
|
target_compile_definitions(miniffs_test PUBLIC BUILD_PLATFORM_${BUILD_PLATFORM})
|
||||||
|
target_include_directories(miniffs_test PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
||||||
|
target_sources(miniffs_test PRIVATE ${TESTS_SRC})
|
||||||
|
target_link_libraries(miniffs_test gtest gtest_main Threads::Threads miniffs)
|
||||||
|
|
||||||
|
file(GLOB TEST_FSIMG *.mffs)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET miniffs_test POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${TEST_FSIMG}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/
|
||||||
|
)
|
||||||
|
|
||||||
|
gtest_discover_tests(miniffs_test
|
||||||
|
WORKING_DIRECTORY ${PROJECT_DIR}
|
||||||
|
PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
245
test/file_operations.cpp
Normal file
245
test/file_operations.cpp
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* MiniFFS : Mini Flat File System
|
||||||
|
* This file is part of the test suite of MiniFFS
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <miniffs.h>
|
||||||
|
#include "get_fs.h"
|
||||||
|
|
||||||
|
TEST(FileOperations, OpeningAFile)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
ASSERT_NE(fp, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, OpeningANonExistingFile)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
|
||||||
|
file_t *fp = miniffs_open(fs, "FOO.BAR");
|
||||||
|
|
||||||
|
ASSERT_EQ(fp, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, UsingTheWrongNameCases)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
|
||||||
|
file_t *fp = miniffs_open(fs, "hello.txt");
|
||||||
|
|
||||||
|
ASSERT_EQ(fp, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, TooLongFilename)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
|
||||||
|
file_t *fp = miniffs_open(fs, "THISisNOTaVALIDname.txt");
|
||||||
|
|
||||||
|
ASSERT_EQ(fp, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, TooLongExtension)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.thisIsNotValid");
|
||||||
|
|
||||||
|
ASSERT_EQ(fp, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, ReadABytes)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'e');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, TestingSeek)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'e');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 0, MFFS_SEEK_SET);
|
||||||
|
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'e');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 5, MFFS_SEEK_SET);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), ' ');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'W');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 1, MFFS_SEEK_CUR);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'r');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 0, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 1, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'd');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, LargeOutOfBoundarySeeks)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
miniffs_seek(fp, 100, MFFS_SEEK_SET);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_SEEK_OUT_OF_BOUNDARIES);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_END_OF_FILE);
|
||||||
|
|
||||||
|
miniffs_seek(fp, 100, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_SEEK_OUT_OF_BOUNDARIES);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, SeekingAroundBoundaries)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
miniffs_seek(fp, 10, MFFS_SEEK_SET);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_NOERROR);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'd');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 11, MFFS_SEEK_SET);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_NOERROR);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 12, MFFS_SEEK_SET);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_SEEK_OUT_OF_BOUNDARIES);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 10, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_NOERROR);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'e');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 11, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_NOERROR);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
|
||||||
|
miniffs_seek(fp, 12, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_SEEK_OUT_OF_BOUNDARIES);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'H');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, TestingEndOfFileBoundary)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
|
||||||
|
miniffs_seek(fp, 1, MFFS_SEEK_END);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), 'd');
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_END_OF_FILE);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_END_OF_FILE);
|
||||||
|
ASSERT_EQ(miniffs_read(fp), '!');
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_END_OF_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(FileOperations, ReadBlocks) {
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
char buffer[13];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(buffer, 0, 13);
|
||||||
|
ret = miniffs_read_blocks(buffer, 4, 1, fp);
|
||||||
|
ASSERT_EQ(ret, 1);
|
||||||
|
ASSERT_EQ(buffer[0], 'H');
|
||||||
|
ASSERT_EQ(buffer[1], 'e');
|
||||||
|
ASSERT_EQ(buffer[2], 'l');
|
||||||
|
ASSERT_EQ(buffer[3], 'l');
|
||||||
|
|
||||||
|
memset(buffer, 0, 13);
|
||||||
|
ret = miniffs_read_blocks(buffer, 4, 1, fp);
|
||||||
|
ASSERT_EQ(ret, 1);
|
||||||
|
ASSERT_EQ(buffer[0], 'o');
|
||||||
|
ASSERT_EQ(buffer[1], ' ');
|
||||||
|
ASSERT_EQ(buffer[2], 'W');
|
||||||
|
ASSERT_EQ(buffer[3], 'o');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, ReadMultiplesBlocks) {
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
char buffer[13];
|
||||||
|
int ret;
|
||||||
|
memset(buffer, 0, 13);
|
||||||
|
ret = miniffs_read_blocks(buffer, 4, 2, fp);
|
||||||
|
ASSERT_EQ(ret, 2);
|
||||||
|
ASSERT_EQ(buffer[0], 'H');
|
||||||
|
ASSERT_EQ(buffer[1], 'e');
|
||||||
|
ASSERT_EQ(buffer[2], 'l');
|
||||||
|
ASSERT_EQ(buffer[3], 'l');
|
||||||
|
ASSERT_EQ(buffer[4], 'o');
|
||||||
|
ASSERT_EQ(buffer[5], ' ');
|
||||||
|
ASSERT_EQ(buffer[6], 'W');
|
||||||
|
ASSERT_EQ(buffer[7], 'o');
|
||||||
|
|
||||||
|
memset(buffer, 0, 13);
|
||||||
|
miniffs_seek(fp, 0, MFFS_SEEK_SET);
|
||||||
|
ret = miniffs_read_blocks(buffer, 4, 3, fp);
|
||||||
|
ASSERT_EQ(ret, 3);
|
||||||
|
ASSERT_EQ(buffer[0], 'H');
|
||||||
|
ASSERT_EQ(buffer[1], 'e');
|
||||||
|
ASSERT_EQ(buffer[2], 'l');
|
||||||
|
ASSERT_EQ(buffer[3], 'l');
|
||||||
|
ASSERT_EQ(buffer[4], 'o');
|
||||||
|
ASSERT_EQ(buffer[5], ' ');
|
||||||
|
ASSERT_EQ(buffer[6], 'W');
|
||||||
|
ASSERT_EQ(buffer[7], 'o');
|
||||||
|
ASSERT_EQ(buffer[8], 'r');
|
||||||
|
ASSERT_EQ(buffer[9], 'l');
|
||||||
|
ASSERT_EQ(buffer[10], 'd');
|
||||||
|
ASSERT_EQ(buffer[11], '!');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOperations, ReadTooManyBlocks)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
file_t *fp = miniffs_open(fs, "HELLO.TXT");
|
||||||
|
|
||||||
|
char buffer[13];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(buffer, 0, 13);
|
||||||
|
ret = miniffs_read_blocks(buffer, 4, 4, fp);
|
||||||
|
ASSERT_EQ(ret, 3);
|
||||||
|
ASSERT_EQ(buffer[0], 'H');
|
||||||
|
ASSERT_EQ(buffer[1], 'e');
|
||||||
|
ASSERT_EQ(buffer[2], 'l');
|
||||||
|
ASSERT_EQ(buffer[3], 'l');
|
||||||
|
ASSERT_EQ(buffer[4], 'o');
|
||||||
|
ASSERT_EQ(buffer[5], ' ');
|
||||||
|
ASSERT_EQ(buffer[6], 'W');
|
||||||
|
ASSERT_EQ(buffer[7], 'o');
|
||||||
|
ASSERT_EQ(buffer[8], 'r');
|
||||||
|
ASSERT_EQ(buffer[9], 'l');
|
||||||
|
ASSERT_EQ(buffer[10], 'd');
|
||||||
|
ASSERT_EQ(buffer[11], '!');
|
||||||
|
}
|
||||||
53
test/fs_opening.cpp
Normal file
53
test/fs_opening.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* MiniFFS : Mini Flat File System
|
||||||
|
* This file is part of the test suite of MiniFFS
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <miniffs.h>
|
||||||
|
#include "get_fs.h"
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningAFileSystem)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("simple_test.mffs");
|
||||||
|
ASSERT_NE(fs, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningANonExistingFile)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("i_do_not_exists.mffs");
|
||||||
|
ASSERT_EQ(fs, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_FS);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningFsWithWrongMagic)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("wrong_magic.mffs");
|
||||||
|
ASSERT_EQ(fs, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_FS);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningFsWithWrongVersion)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("wrong_version.mffs");
|
||||||
|
ASSERT_EQ(fs, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_FS);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningFsWithWrongNameLen)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("wrong_namelen.mffs");
|
||||||
|
ASSERT_EQ(fs, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_FS);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FSOpening, OpeningFsWithWrongExtLen)
|
||||||
|
{
|
||||||
|
miniffs_t *fs = get_fs("wrong_extlen.mffs");
|
||||||
|
ASSERT_EQ(fs, nullptr);
|
||||||
|
ASSERT_EQ(miniffs_geterror(), MINIFFS_INVALID_FS);
|
||||||
|
}
|
||||||
54
test/get_fs.h
Normal file
54
test/get_fs.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* MiniFFS : Mini Flat File System
|
||||||
|
* This file is part of the test suite of MiniFFS
|
||||||
|
*
|
||||||
|
* This file abstract the filesystem opening, to be able to test both FILE and
|
||||||
|
* MEMORY backend.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2022 986-Studio. All rights reserved.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static miniffs_t *get_fs(const char *filename)
|
||||||
|
{
|
||||||
|
#ifdef BUILD_PLATFORM_MEMORY
|
||||||
|
char *fs_image;
|
||||||
|
size_t fileSize;
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* As windows do not provide an easy to use mmap equivalent, let's use the fallback
|
||||||
|
* of opening the file, allocating memory and read the file in the said memory
|
||||||
|
*/
|
||||||
|
FILE *fp;
|
||||||
|
fp = fopen(filename, "rb");
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
fileSize = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
fs_image = (char *)calloc(1, fileSize);
|
||||||
|
fread(fs_image, 1, fileSize, fp);
|
||||||
|
fclose(fp);
|
||||||
|
#else
|
||||||
|
int fd;
|
||||||
|
struct stat FileStat;
|
||||||
|
|
||||||
|
fd = open(filename, O_RDWR);
|
||||||
|
fstat(fd, &FileStat);
|
||||||
|
fs_image = (char *)mmap(NULL, FileStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
close(fd);
|
||||||
|
fileSize = FileStat.st_size;
|
||||||
|
if (fs_image == MAP_FAILED)
|
||||||
|
{
|
||||||
|
fs_image = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return miniffs_openfs((uintptr_t)fs_image);
|
||||||
|
#else
|
||||||
|
return miniffs_openfs(filename);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
1
test/hello.txt
Normal file
1
test/hello.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello World!
|
||||||
BIN
test/simple_test.mffs
Normal file
BIN
test/simple_test.mffs
Normal file
Binary file not shown.
11
test/test_image.json
Normal file
11
test/test_image.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"files":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "HELLO",
|
||||||
|
"ext": "TXT",
|
||||||
|
"file": "hello.txt"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"output": "test.mffs"
|
||||||
|
}
|
||||||
BIN
test/wrong_extlen.mffs
Normal file
BIN
test/wrong_extlen.mffs
Normal file
Binary file not shown.
BIN
test/wrong_magic.mffs
Normal file
BIN
test/wrong_magic.mffs
Normal file
Binary file not shown.
BIN
test/wrong_namelen.mffs
Normal file
BIN
test/wrong_namelen.mffs
Normal file
Binary file not shown.
BIN
test/wrong_version.mffs
Normal file
BIN
test/wrong_version.mffs
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user