1
0
mirror of https://github.com/elua/elua.git synced 2025-01-25 01:02:54 +08:00

Merge pull request #127 from elua/add_niffs

New file system: NIFFS
This commit is contained in:
Bogdan Marinescu 2018-05-19 23:35:17 +03:00 committed by GitHub
commit 660b29e7a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 4056 additions and 18 deletions

View File

@ -18,6 +18,7 @@ return {
dhcp = true,
xmodem = true,
mmcfs = { spi = 0, cs_port = 6, cs_pin = 0 },
niffs = { linear_area = true },
},
config = {
vtmr = { num = 4, freq = 4 },

View File

@ -355,7 +355,7 @@ end )
-- Add uIP files manually because not all of them are included in the build ([TODO] why?)
local uip_files = " " .. utils.prepend_path( "uip_arp.c uip.c uiplib.c dhcpc.c psock.c resolv.c uip-neighbor.c", "src/uip" )
addi{ { 'inc', 'inc/newlib', 'inc/remotefs', 'src/platform', 'src/lua' }, { 'src/modules', 'src/platform/' .. platform, 'src/platform/' .. platform .. '/cpus' }, "src/uip", "src/fatfs" }
addi{ { 'inc', 'inc/newlib', 'inc/remotefs', 'src/platform', 'src/lua' }, { 'src/modules', 'src/platform/' .. platform, 'src/platform/' .. platform .. '/cpus' }, "src/uip", "src/fatfs", "inc/niffs" }
addm( "LUA_OPTIMIZE_MEMORY=" .. ( comp.optram and "2" or "0" ) )
addcf( { '-Os','-fomit-frame-pointer' } )

View File

@ -201,6 +201,14 @@ function init()
components.romfs = { macro = 'BUILD_ROMFS' }
-- WOFS
components.wofs = { macro = "BUILD_WOFS" }
-- NIFFS
components.niffs = {
macro = "BUILD_NIFFS",
attrs = {
linear_area = at.make_optional( at.bool_attr( 'NIFFS_LINEAR_AREA' ) )
}
}
-- All done
return components
end

View File

@ -39,6 +39,7 @@ local elua_generic_modules = {
term = { guards = { "BUILD_TERM" } },
tmr = { guards = { "NUM_TIMER > 0" } },
uart = { guards = { "NUM_UART > 0" } },
fs = { guards = { "BUILD_NIFFS" } }
}
-- All generic modules (Lua and eLua) in a single table

24
inc/niffs/nffs.h Normal file
View File

@ -0,0 +1,24 @@
// Filesystem implementation
#include "romfs.h"
#include <string.h>
#include <errno.h>
#include "romfiles.h"
#include <stdio.h>
#include <stdlib.h>
#include "ioctl.h"
#include <fcntl.h>
#include "platform.h"
#include "platform_conf.h"
#include "niffs.h"
#ifndef NFFS_H_
#define NFFS_H_
int nffs_init( void );
int nffs_format(s32_t linear_bytes);
int nffs_mount();
int nffs_unmount();
int nffs_check();
int nffs_info(s32_t *total, s32_t *used, u8_t *overflow, s32_t *lin_total, s32_t *lin_used, s32_t *lin_free);
#endif /* NFFS_H_ */

457
inc/niffs/niffs.h Normal file
View File

@ -0,0 +1,457 @@
/*
* niffs.h
*
* Created on: Feb 2, 2015
* Author: petera
*/
#ifndef NIFFS_H_
#define NIFFS_H_
#include "niffs_config.h"
#define NIFFS_SEEK_SET (0)
#define NIFFS_SEEK_CUR (1)
#define NIFFS_SEEK_END (2)
/* Any write to the filehandle is appended to end of the file */
#define NIFFS_O_APPEND (1<<0)
/* If the opened file exists, it will be truncated to zero length before opened */
#define NIFFS_O_TRUNC (1<<1)
/* If the opened file does not exist, it will be created before opened */
#define NIFFS_O_CREAT (1<<2)
/* The opened file may only be read */
#define NIFFS_O_RDONLY (1<<3)
/* The opened file may only be writted */
#define NIFFS_O_WRONLY (1<<4)
/* The opened file may be both read and written */
#define NIFFS_O_RDWR (NIFFS_O_RDONLY | NIFFS_O_WRONLY)
/* Any writes to the filehandle will never be cached */
#define NIFFS_O_DIRECT (1<<5)
/* If O_CREAT and O_EXCL are set, open() fails if the file exists. */
#define NIFFS_O_EXCL (1<<6)
/* If O_CREAT and O_LINEAR is enabled, along with config NIFFS_LINEAR_AREA,
the created file will be put in the linear area */
#define NIFFS_O_LINEAR (1<<7)
#ifndef NIFFS_ERR_BASE
#define NIFFS_ERR_BASE (11000)
#endif
#define NIFFS_OK 0
#define ERR_NIFFS_BAD_CONF -(NIFFS_ERR_BASE + 1)
#define ERR_NIFFS_NOT_A_FILESYSTEM -(NIFFS_ERR_BASE + 2)
#define ERR_NIFFS_BAD_SECTOR -(NIFFS_ERR_BASE + 3)
#define ERR_NIFFS_DELETING_FREE_PAGE -(NIFFS_ERR_BASE + 4)
#define ERR_NIFFS_DELETING_DELETED_PAGE -(NIFFS_ERR_BASE + 5)
#define ERR_NIFFS_MOVING_FREE_PAGE -(NIFFS_ERR_BASE + 6)
#define ERR_NIFFS_MOVING_DELETED_PAGE -(NIFFS_ERR_BASE + 7)
#define ERR_NIFFS_MOVING_TO_UNFREE_PAGE -(NIFFS_ERR_BASE + 8)
#define ERR_NIFFS_MOVING_TO_SAME_PAGE -(NIFFS_ERR_BASE + 9)
#define ERR_NIFFS_MOVING_BAD_FLAG -(NIFFS_ERR_BASE + 10)
#define ERR_NIFFS_NO_FREE_PAGE -(NIFFS_ERR_BASE + 11)
#define ERR_NIFFS_SECTOR_UNFORMATTABLE -(NIFFS_ERR_BASE + 12)
#define ERR_NIFFS_NULL_PTR -(NIFFS_ERR_BASE + 13)
#define ERR_NIFFS_NO_FREE_ID -(NIFFS_ERR_BASE + 14)
#define ERR_NIFFS_WR_PHDR_UNFREE_PAGE -(NIFFS_ERR_BASE + 15)
#define ERR_NIFFS_WR_PHDR_BAD_ID -(NIFFS_ERR_BASE + 16)
#define ERR_NIFFS_NAME_CONFLICT -(NIFFS_ERR_BASE + 17)
#define ERR_NIFFS_FULL -(NIFFS_ERR_BASE + 18)
#define ERR_NIFFS_OUT_OF_FILEDESCS -(NIFFS_ERR_BASE + 19)
#define ERR_NIFFS_FILE_NOT_FOUND -(NIFFS_ERR_BASE + 20)
#define ERR_NIFFS_FILEDESC_CLOSED -(NIFFS_ERR_BASE + 21)
#define ERR_NIFFS_FILEDESC_BAD -(NIFFS_ERR_BASE + 22)
#define ERR_NIFFS_INCOHERENT_ID -(NIFFS_ERR_BASE + 23)
#define ERR_NIFFS_PAGE_NOT_FOUND -(NIFFS_ERR_BASE + 24)
#define ERR_NIFFS_END_OF_FILE -(NIFFS_ERR_BASE + 25)
#define ERR_NIFFS_MODIFY_BEYOND_FILE -(NIFFS_ERR_BASE + 26)
#define ERR_NIFFS_TRUNCATE_BEYOND_FILE -(NIFFS_ERR_BASE + 27)
#define ERR_NIFFS_NO_GC_CANDIDATE -(NIFFS_ERR_BASE + 28)
#define ERR_NIFFS_PAGE_DELETED -(NIFFS_ERR_BASE + 29)
#define ERR_NIFFS_PAGE_FREE -(NIFFS_ERR_BASE + 30)
#define ERR_NIFFS_MOUNTED -(NIFFS_ERR_BASE + 31)
#define ERR_NIFFS_NOT_MOUNTED -(NIFFS_ERR_BASE + 32)
#define ERR_NIFFS_NOT_WRITABLE -(NIFFS_ERR_BASE + 33)
#define ERR_NIFFS_NOT_READABLE -(NIFFS_ERR_BASE + 34)
#define ERR_NIFFS_FILE_EXISTS -(NIFFS_ERR_BASE + 35)
#define ERR_NIFFS_OVERFLOW -(NIFFS_ERR_BASE + 36)
#define ERR_NIFFS_LINEAR_FILE -(NIFFS_ERR_BASE + 37)
#define ERR_NIFFS_LINEAR_NO_SPACE -(NIFFS_ERR_BASE + 38)
typedef int (* niffs_hal_erase_f)(u8_t *addr, u32_t len);
typedef int (* niffs_hal_write_f)(u8_t *addr, const u8_t *src, u32_t len);
// dummy type, for posix compliance
typedef u16_t niffs_mode;
// niffs file descriptor flags
typedef u8_t niffs_fd_flags;
// niffs file type
typedef u8_t niffs_file_type;
/* file descriptor */
typedef struct {
// object id
niffs_obj_id obj_id;
// page index for object index
niffs_page_ix obj_pix;
// file type
niffs_file_type type;
// file descriptor offset
u32_t offs;
// page index for current file desc offset
niffs_page_ix cur_pix;
// file descriptor flags
niffs_fd_flags flags;
} niffs_file_desc;
/* fs struct */
typedef struct {
/* static cfg */
// physical address where fs resides
u8_t *phys_addr;
// number of logical sectors
u32_t sectors;
// logical sector size in bytes
u32_t sector_size;
// logical page size in bytes
u32_t page_size;
#if NIFFS_LINEAR_AREA
// number of linear sectors
u32_t lin_sectors;
#endif
// work buffer
u8_t *buf;
// work buffer length
u32_t buf_len;
// HAL write function
niffs_hal_write_f hal_wr;
// HAL erase function
niffs_hal_erase_f hal_er;
/* dynamics */
// pages per sector
u32_t pages_per_sector;
// last seen free page index
niffs_page_ix last_free_pix;
// whether mounted or not
u8_t mounted;
// number of free pages
u32_t free_pages;
// number of deleted pages
u32_t dele_pages;
// file descriptor array
niffs_file_desc *descs;
// number of file descriptors
u32_t descs_len;
// max erase count
niffs_erase_cnt max_era;
} niffs;
/* niffs file status struct */
typedef struct {
// file object id
niffs_obj_id obj_id;
// file size
u32_t size;
// file name
u8_t name[NIFFS_NAME_LEN];
// file type
niffs_file_type type;
} niffs_stat;
/* niffs file directory entry struct */
struct niffs_dirent {
// file object id
niffs_obj_id obj_id;
// file name
u8_t name[NIFFS_NAME_LEN];
// file size
u32_t size;
// file index header whereabouts
niffs_page_ix pix;
// file type
niffs_file_type type;
};
/* niffs file directory struct */
typedef struct {
// the actual fs
niffs *fs;
// current search page index
niffs_page_ix pix;
} niffs_DIR;
/* niffs fs info struct */
typedef struct {
/* total amount of bytes in filesystem (linear parts excluded) */
s32_t total_bytes;
/* used bytes in filesystem (linear parts excluded) */
s32_t used_bytes;
/* If non-zero, this means you should delete some files and run a check.
This can happen if filesystem loses power repeatedly during
garbage collection or check. */
u8_t overflow;
/* total amount of sectors in the linear part of filesystem */
s32_t lin_total_sectors;
/* used sectors in the linear part of filesystem */
s32_t lin_used_sectors;
/* maximum free consecutive area in the linear part of filesystem */
s32_t lin_max_conseq_free;
} niffs_info;
/**
* Initializes and configures the file system.
* The file system needs a ram work buffer being at least a logical page size
* big. In some cases, this needs to be extended. NIFFS will return
* ERR_NIFFS_BAD_CONF on bad configurations. If NIFFS_DBG is enabled, a
* descriptive message will also tell you what's wrong.
*
* @param fs the file system struct
* @param phys_addr the starting address of the filesystem on flash
* @param sectors number of sectors comprised by the filesystem
* @param sector_size logical sector size
* @param page_size logical page size
* @param buf ram work buffer
* @param buf_len ram work buffer length
* @param descs ram file descriptor buffer
* @param file_desc_len number of file descriptors in buffer
* @param erase_f HAL erase function
* @param write_f HAL write function
* @param lin_sectors Ignored if NIFFS_LINEAR_AREA is 0. Otherwise, allocates
* lin_sectors of space for the linear area. This space
* will be allotted after the dynamic fs.
*/
int NIFFS_init(niffs *fs,
u8_t *phys_addr,
u32_t sectors,
u32_t sector_size,
u32_t page_size,
u8_t *buf,
u32_t buf_len,
niffs_file_desc *descs,
u32_t file_desc_len,
niffs_hal_erase_f erase_f,
niffs_hal_write_f write_f,
u32_t lin_sectors
);
/**
* Mounts the filesystem
* @param fs the file system struct
*/
int NIFFS_mount(niffs *fs);
/**
* Returns some general info
* @param fs the file system struct
* @param total will be populated with total amount of bytes in filesystem
* @param used will be populated with used bytes in filesystem
* @param overflow if !0, this means you should delete some files and run a check.
* This can happen if filesystem loses power repeatedly during
* garbage collection or check.
*/
int NIFFS_info(niffs *fs, niffs_info *i);
/**
* Creates a new file.
* @param fs the file system struct
* @param name the name of the new file
* @param mode ignored, for posix compliance
*/
int NIFFS_creat(niffs *fs, const char *name, niffs_mode mode);
#if NIFFS_LINEAR_AREA
/**
* Creates a new file in the linear area.
* @param fs the file system struct
* @param name the name of the new file
* @param resv_size Hint to the filesystem how large this file will be in
* bytes. May be 0 if not known.
* As linear files cannot be chunked up by pages, they
* will be placed after each other on medium. For example,
* when creating linear file A it will be placed on
* sector x. If creating linear file B directly afterwards,
* B will be placed on sector x+1. This constricts file A
* to grow one sector only. However, if A is created with
* resv_size of 10 sectors, B will be created on sector
* x+10, giving A room to grow 10 sectors instead.
* @return file descriptor with flags O_LINEAR | O_RDWR | O_APPEND or error
*/
int NIFFS_mknod_linear(niffs *fs, const char *name, u32_t resv_size);
#endif
/**
* Opens/creates a file.
* @param fs the file system struct
* @param path the path of the new file
* @param flags the flags for the open command, can be combinations of
* NIFFS_O_APPEND, NIFFS_O_TRUNC, NIFFS_O_CREAT, NIFFS_O_RDONLY,
* NIFFS_O_WRONLY, NIFFS_O_RDWR, NIFFS_O_DIRECT, NIFFS_O_LINEAR
* @param mode ignored, for posix compliance
* @return file descriptor or error
*
* Note: when creating files with NIFFS_O_LINEAR, NIFFS_O_APPEND is
* automatically set. Linear files cannot be modified, only appended.
*/
int NIFFS_open(niffs *fs, const char *name, u8_t flags, niffs_mode mode);
/**
* Returns a pointer directly to the flash where data resides, and how many
* bytes which can be read.
* This function does not advance the file descriptor offset, so NIFFS_lseek
* should be called prior to NIFFS_read_ptr.
* @param fs the file system struct
* @param fd the filehandle
* @param ptr ptr which is populated with adress to data
* @param len populated with valid data length
*/
int NIFFS_read_ptr(niffs *fs, int fd, u8_t **ptr, u32_t *len);
/**
* Reads from given filehandle.
* NB: consider using NIFFS_read_ptr instead. This will basically copy from your
* internal flash to your ram. If you're only interested in reading data and not
* modifying it, this will basically waste cycles and ram on memcpy.
* @param fs the file system struct
* @param fd the filehandle
* @param buf where to put read data
* @param len how much to read
* @returns number of bytes read, or error
*/
int NIFFS_read(niffs *fs, int fd, u8_t *dst, u32_t len);
/**
* Moves the read/write file offset
* @param fs the file system struct
* @param fh the filehandle
* @param offs how much/where to move the offset
* @param whence if NIFFS_SEEK_SET, the file offset shall be set to offset bytes
* if NIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
* if NIFFS_SEEK_END, the file offset shall be set to the size of the file plus offset
*/
int NIFFS_lseek(niffs *fs, int fd, s32_t offs, int whence);
/**
* Removes a file by name
* @param fs the file system struct
* @param name the name of the file to remove
*/
int NIFFS_remove(niffs *fs, const char *name);
/**
* Removes a file by filehandle
* @param fs the file system struct
* @param fd the filehandle of the file to remove
*/
int NIFFS_fremove(niffs *fs, int fd);
/**
* Writes to given filehandle.
* @param fs the file system struct
* @param fd the filehandle
* @param buf the data to write
* @param len how much to write
* @returns number of bytes written or error
*/
int NIFFS_write(niffs *fs, int fd, const u8_t *data, u32_t len);
/**
* Flushes all pending write operations from cache for given file
* @param fs the file system struct
* @param fd the filehandle of the file to flush
*/
int NIFFS_fflush(niffs *fs, int fd);
/**
* Gets file status by name
* @param fs the file system struct
* @param path the name of the file to stat
* @param s the stat struct to populate
*/
int NIFFS_stat(niffs *fs, const char *name, niffs_stat *s);
/**
* Gets file status by filehandle
* @param fs the file system struct
* @param fd the filehandle of the file to stat
* @param s the stat struct to populate
*/
int NIFFS_fstat(niffs *fs, int fd, niffs_stat *s);
/**
* Gets current position in stream
* @param fs the file system struct
* @param fd the filehandle of the file to return position from
*/
int NIFFS_ftell(niffs *fs, int fd);
/**
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
* @param fs the file system struct
* @param fd the filehandle of the file to close
*/
int NIFFS_close(niffs *fs, int fd);
/**
* Renames a file.
* @param fs the file system struct
* @param old name of file to rename
* @param new new name of file
*/
int NIFFS_rename(niffs *fs, const char *old_name, const char *new_name);
/**
* Opens a directory stream corresponding to the given name.
* The stream is positioned at the first entry in the directory.
* The name argument is ignored as hydrogen builds always correspond
* to a flat file structure - no directories.
* @param fs the file system struct
* @param name the name of the directory
* @param d pointer the directory stream to be populated
*/
niffs_DIR *NIFFS_opendir(niffs *fs, const char *name, niffs_DIR *d);
/**
* Closes a directory stream
* @param d the directory stream to close
*/
int NIFFS_closedir(niffs_DIR *d);
/**
* Reads a directory into given niffs_dirent struct.
* @param d pointer to the directory stream
* @param e the dirent struct to be populated
* @returns null if error or end of stream, else given dirent is returned
*/
struct niffs_dirent *NIFFS_readdir(niffs_DIR *d, struct niffs_dirent *e);
/**
* Unmounts the file system. All file handles will be flushed of any
* cached writes and closed.
* @param fs the file system struct
*/
int NIFFS_unmount(niffs *fs);
/**
* Formats the entire filesystem.
* @param fs the file system struct
*/
int NIFFS_format(niffs *fs);
/**
* Runs a consistency check on given filesystem and mends any aborted operations.
* @param fs the file system struct
*/
int NIFFS_chk(niffs *fs);
#ifdef NIFFS_DUMP
/**
* Prints out a visualization of the filesystem.
* @param fs the file system struct
*/
void NIFFS_dump(niffs *fs);
#endif
#endif /* NIFFS_H_ */

200
inc/niffs/niffs_config.h Normal file
View File

@ -0,0 +1,200 @@
/*
* niffs_config.h
*
* Created on: Feb 3, 2015
* Author: petera
*/
#ifndef NIFFS_CONFIG_H_
#define NIFFS_CONFIG_H_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "lrotable.h"
#include "common.h"
#include "sermux.h"
#include "platform_conf.h"
#include "utils.h"
#include "elua_int.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
//#define u8_t uint8_t
//#define i16_t int16_t
//typedef int16_t Int16;
//typedef u16 UInt16;
//typedef u32 UInt32;
//typedef int32_t Int32;
//typedef u8 u8_t;
//typedef u16 u16_t;
//typedef u32 u32_t;
//typedef s32 s32_t;
#define u8_t uint8_t
#define u16_t uint16_t
#define u32_t uint32_t
#define s32_t int32_t
//#define NIFFS_DEBUG 1
//#define NIFFS_DBG(...) if (NIFFS_DEBUG) printf(__VA_ARGS__)
#ifdef NIFFS_TEST_MAKE
#include "niffs_test_config.h"
#endif
// for testing
#ifndef TESTATIC
#define TESTATIC static
#endif
// define for getting niffs debug output
#ifndef NIFFS_DBG
#define NIFFS_DBG(_f, ...)
#endif
// define NIFFS_DUMP to be able to visualize filesystem with NIFFS_dump
//#define NIFFS_DUMP
#ifdef NIFFS_DUMP
#ifndef NIFFS_DUMP_OUT
// used to output in NIFFS_dump
#define NIFFS_DUMP_OUT(_f, ...)
#endif
#endif
// max macro
#ifndef NIFFS_MAX
#define NIFFS_MAX(x, y) UMAX(x,y)
#endif
// min macro
#ifndef NIFFS_MIN
#define NIFFS_MIN(x, y) UMIN(x,y)
#endif
// define for assertions within niffs
#ifndef NIFFS_ASSERT
#define NIFFS_ASSERT(x)
#endif
// define maximum name length
#ifndef NIFFS_NAME_LEN
#define NIFFS_NAME_LEN (16)
#endif
// Enable or disable linear area features.
// Files in the linear area are not divided by page headers but are linear on
// medium. To create a linear file, pass NIFFS_O_CREAT and NIFFS_O_CREAT_LINEAR
// when creating the file with open.
// To have more control over the linear file, NIFFS_mknod_linear can also be
// called, see corresponding function for more info.
// The linear area is not wear leveled. Once a linear file is deleted,
// corresponding sectors are immediately erased.
// This implies that each linear file will at least occupy one sector, even if
// the size is 0.
// Linear files can only be appended, never modified. Defragmentation of the
// linear area is up to the user.
#ifndef NIFFS_LINEAR_AREA
#define NIFFS_LINEAR_AREA (1)
#endif
// define number of bits used for object ids, used for uniquely identify a file
#ifndef NIFFS_OBJ_ID_BITS
#define NIFFS_OBJ_ID_BITS (16)
#endif
// define number of bits used for span indices, used for uniquely identify part of a file
#ifndef NIFFS_SPAN_IX_BITS
#define NIFFS_SPAN_IX_BITS (16)
#endif
// word align for target flash, e.g. stm32f1 can only write 16-bit words at a time
// from SiM33U1xx-SiM3C1xx-RM.pdf p.380 para.21.4.2 "Writes to WRDATA must be half-word aligned"
#ifndef NIFFS_WORD_ALIGN
#define NIFFS_WORD_ALIGN (4)
#endif
// garbage collection uses a score system to select sector to erase:
// sector_score = sector_erase_difference * F1 + free_pages * F2 + deleted_pages * F3 + busy_pages * F4
// sector with highest score is selected for garbage collection
// F1: garbage collection score factor for sector erase difference
#ifndef NIFFS_GC_SCORE_ERASE_CNT_DIFF
#define NIFFS_GC_SCORE_ERASE_CNT_DIFF (100)
#endif
// F2: garbage collection score factor for percentage of free pages in sector
#ifndef NIFFS_GC_SCORE_FREE
#define NIFFS_GC_SCORE_FREE (-4)
#endif
// F3: garbage collection score factor for percentage of deleted pages in sector
#ifndef NIFFS_GC_SCORE_DELE
#define NIFFS_GC_SCORE_DELE (2)
#endif
// F4: garbage collection score factor for percentage of busy/written pages in sector
#ifndef NIFFS_GC_SCORE_BUSY
#define NIFFS_GC_SCORE_BUSY (-2)
#endif
// formula for selecting sector to garbage collect
// free, dele and busy is the percentage (0-99) of each type
#ifndef NIFFS_GC_SCORE
#define NIFFS_GC_SCORE(era_cnt_diff, free, dele, busy) \
((era_cnt_diff) * NIFFS_GC_SCORE_ERASE_CNT_DIFF) + \
((free) * NIFFS_GC_SCORE_FREE) + \
((dele) * NIFFS_GC_SCORE_DELE) + \
((busy) * NIFFS_GC_SCORE_BUSY)
#endif
// type sizes, depend of the size of the filesystem and the size of the pages
// must comprise NIFFS_OBJ_ID_BITS
#ifndef NIFFS_TYPE_OBJ_ID_SIZE
#define NIFFS_TYPE_OBJ_ID_SIZE u16_t
#endif
// must comprise NIFFS_SPAN_IX_BITS
#ifndef NIFFS_TYPE_SPAN_IX_SIZE
#define NIFFS_TYPE_SPAN_IX_SIZE u16_t
#endif
// must comprise (NIFFS_OBJ_ID_BITS + NIFFS_SPAN_IX_BITS)
#ifndef NIFFS_TYPE_RAW_PAGE_ID_SIZE
#define NIFFS_TYPE_RAW_PAGE_ID_SIZE u32_t
#endif
// must uniquely address all pages
#ifndef NIFFS_TYPE_PAGE_IX_SIZE
#define NIFFS_TYPE_PAGE_IX_SIZE u32_t
#endif
// magic bits, must be sized on alignment, NIFFS_WORD_ALIGN
#ifndef NIFFS_TYPE_MAGIC_SIZE
#define NIFFS_TYPE_MAGIC_SIZE u32_t
#endif
// sector erase counter, must be sized on alignment, NIFFS_WORD_ALIGN
#ifndef NIFFS_TYPE_ERASE_COUNT_SIZE
#define NIFFS_TYPE_ERASE_COUNT_SIZE u32_t
#endif
// page flag, 3 values, must be sized on alignment, NIFFS_WORD_ALIGN
#ifndef NIFFS_TYPE_PAGE_FLAG_SIZE
#define NIFFS_TYPE_PAGE_FLAG_SIZE u32_t
#endif
typedef NIFFS_TYPE_OBJ_ID_SIZE niffs_obj_id;
typedef NIFFS_TYPE_SPAN_IX_SIZE niffs_span_ix;
typedef NIFFS_TYPE_RAW_PAGE_ID_SIZE niffs_page_id_raw;
typedef NIFFS_TYPE_PAGE_IX_SIZE niffs_page_ix;
typedef NIFFS_TYPE_MAGIC_SIZE niffs_magic;
typedef NIFFS_TYPE_ERASE_COUNT_SIZE niffs_erase_cnt;
typedef NIFFS_TYPE_PAGE_FLAG_SIZE niffs_flag;
#endif /* NIFFS_CONFIG_H_ */

282
inc/niffs/niffs_internal.h Normal file
View File

@ -0,0 +1,282 @@
/*
* niffs_internal.h
*
* FLASH LAYOUT
* SECTOR:
* <sector header size> <page size> <page size>
* | niffs_sector_hdr | niffs_page_hdr : data | niffs_page_hdr : data | ... | fill |
* | magic : era_cnt | id : flag | .... | id : flag | .... | ...
* | | \ obj_id | \ obj_id |
* | | \ spix | \ spix |
*
* Page status:
* FREE niffs_page_hdr.id 0xff..
* DELE niffs_page_hdr.id 0x0
* USED niffs_page_hdr.id != 0 && != 0xff..
* CLEA niffs_page_hdr.flag 0xff..
* WRIT niffs_page_hdr.flag 0x1
* MOVI niffs_page_hdr.flag 0x0
*
* Free pages:
* FREE & CLEA
* Allocated pages:
* USED
* USED & CLEA : allocated but not yet written (semi bad)
* USED & WRIT : allocated and written
* USED & MOVI : allocated and being moved/updated
* Bad pages:
* FREE & WRIT : not allowed
* FREE & MOVI : not allowed
*
* A page life cycle: FREE->CLEAN(->WRITN(->MOVIN))->DELE->FREE
*
* Object header:
* niffs_page_hdr.id != 0 && != 0xff..
* niffs_page_hdr.id.spix 0
*
* Invalid object_ids are 0 and 0xff..
*
* File creation:
* write phdr.flag
* write phdr.id
* ----- page now allocated
* write ohdr (len = -1)
* ----- file now created, size 0
*
* File open:
* * aborted append / updated length:
* If obj header is MOVI:
* try finding a WRIT obj header with id,
* use this if found, delete MOVI. Else, copy MOVI as WRIT and
* delete MOVI. For used obj header: check if there are more spix
* pages than file len allows, delete these
* File append:
* if spix == 0 & len == -1, use same page, update page after full/finished as WRIT
* for following pages:
* mark obj hdr as MOVI
* if free space in last page
* mark MOVI, fill copy, write WRIT, delete MOVI
* create new pages with new spix as WRIT
* store new obj hdr with correct len as WRIT
* delete obj hdr MOVI
*
* File read:
* * aborted rewrite / updated content:
* if a MOVI page is encountered, niffs must check for pages
* WRIT with same id/span index. If found, use this page instead
* and delete MOVI. Else, copy MOVI page to free page as WRIT,
* delete MOVI page, and use dest.
*
* File trunc:
* trunc to zero/rm:
* set obj hdr file len to 0
* delete all pages with same id
* if aborted, check will clean
* delete obj hdr
* trunc to size:
* mark obj hdr MOVi
* create new obj hdr with correct size as WRIT
* if aborted, check will clean
* rewrite last page if trunc to midst of page (MOVI -> WRIT -> delete)
* delete all removed pages
*
* Check:
* sector headers for valid magic
*
* if FREE & (WRIT | MOVI) bad page, delete
* if MOVI and no equal page with same id, copy and delete original
* if MOVI object header => modified during trunc or append, check length and all spix with same id
* file length - remove all pages where spix is beyond file size
*
* remove orphans - check for WRIT && MOVI with ids and spix > 0 having no corresponding page with spix == 0, remove all
* file length - if length == 0, remove all with same id, including obj hdr
* if obj hdr flag is WRIT, but length is UNDEF, fail during append, remove all containing same id
*
* Created on: Feb 3, 2015
* Author: petera
*/
#include "niffs.h"
#include "niffs_config.h"
#ifndef NIFFS_INTERNAL_H_
#define NIFFS_INTERNAL_H_
#define _NIFFS_PAGE_FREE_ID ((niffs_page_id_raw)-1)
#define _NIFFS_PAGE_DELE_ID ((niffs_page_id_raw)0)
#define _NIFFS_FLAG_CLEAN ((niffs_flag)-1)
#define _NIFFS_FLAG_WRITTEN ((niffs_flag)1)
#define _NIFFS_FLAG_MOVING ((niffs_flag)0)
#define NIFFS_FLAG_MOVE_KEEP ((niffs_flag)0xaa)
#define _NIFFS_FTYPE_FILE (0)
#define _NIFFS_FTYPE_LINFILE (1)
// change of magic since file type introduction
#if NIFFS_LINEAR_AREA
//If we are using a partially linear file system, we need to store the linear vs regular page allocations
//somewhere so lets store it in the first 4 bytes of the sector magic!
//LINEAR MAGIC SECTOR DEFINITION
//BYTES 7-6 (0xe1)
//BYTES 5-3 fs->page_size
//BYTES 2-0 fs->linear sectors
#define _NIFFS_SECT_MAGIC_BYTES 0xe1
#define _NIFFS_SECT_MAGIC(_fs) (niffs_magic)((_NIFFS_SECT_MAGIC_BYTES << 24) | (((_fs)->page_size & 0xFFF) << 12) | ((_fs)->lin_sectors & 0xFFF))
//Bytes 5-3 of magic number holds the page size
#define _NIFFS_SECT_PAGE_SIZE(data) (u32_t)((data >> 12) & 0xFFF)
//Lower 3 bytes of magic number holds the linear size
#define _NIFFS_SECT_LINEAR_SIZE(data) (u32_t)(data & 0xFFF)
#else
#define _NIFFS_SECT_MAGIC(_fs) (niffs_magic)(0xfee1c001 ^ (_fs)->page_size)
#endif
#ifndef _NIFFS_ALIGN
#define _NIFFS_ALIGN __attribute__ (( aligned(NIFFS_WORD_ALIGN) ))
#endif
#ifndef _NIFFS_PACKED
#define _NIFFS_PACKED __attribute__ (( packed ))
#endif
// checks if page is free, i.e. not used at all
#define _NIFFS_IS_FREE(_pg_hdr) (((_pg_hdr)->id.raw) == _NIFFS_PAGE_FREE_ID)
// checks if page is deleted
#define _NIFFS_IS_DELE(_pg_hdr) (((_pg_hdr)->id.raw) == _NIFFS_PAGE_DELE_ID)
// checks if page is allocated, but has no data written to it
#define _NIFFS_IS_CLEA(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_CLEAN)
// checks if page is written
#define _NIFFS_IS_WRIT(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_WRITTEN)
// checks if page is moving
#define _NIFFS_IS_MOVI(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_MOVING)
#define _NIFFS_SECTOR_2_ADDR(_fs, _s) \
((_fs)->phys_addr + (_fs)->sector_size * (_s))
#define _NIFFS_ADDR_2_SECTOR(_fs, _addr) \
(((u8_t *)(_addr) - (_fs)->phys_addr) / (_fs)->sector_size)
#define _NIFFS_PIX_2_SECTOR(_fs, _pix) \
((_pix) / (_fs)->pages_per_sector)
#define _NIFFS_PIX_IN_SECTOR(_fs, _pix) \
((_pix) % (_fs)->pages_per_sector)
#define _NIFFS_PIX_AT_SECTOR(_fs, _s) \
((_s) * (_fs)->pages_per_sector)
#define _NIFFS_PIX_2_ADDR(_fs, _pix) (\
_NIFFS_SECTOR_2_ADDR(_fs, _NIFFS_PIX_2_SECTOR(_fs, _pix)) + \
sizeof(niffs_sector_hdr) + \
_NIFFS_PIX_IN_SECTOR(_fs, _pix) * (_fs)->page_size \
)
#define _NIFFS_SPIX_2_PDATA_LEN(_fs, _spix) \
((_fs)->page_size - sizeof(niffs_page_hdr) - ((_spix) == 0 ? sizeof(niffs_object_hdr) : 0))
#define _NIFFS_OFFS_2_SPIX(_fs, _offs) ( \
(_offs) < _NIFFS_SPIX_2_PDATA_LEN(_fs, 0) ? 0 : \
(1 + (((_offs) - _NIFFS_SPIX_2_PDATA_LEN(_fs, 0)) / _NIFFS_SPIX_2_PDATA_LEN(_fs, 1))) \
)
#define _NIFFS_OFFS_2_PDATA_OFFS(_fs, _offs) ( \
(_offs) < _NIFFS_SPIX_2_PDATA_LEN(_fs, 0) ? (_offs) : \
(((_offs) - _NIFFS_SPIX_2_PDATA_LEN(_fs, 0)) % _NIFFS_SPIX_2_PDATA_LEN(_fs, 1)) \
)
#define _NIFFS_RD(_fs, _dst, _src, _len) do {niffs_memcpy((_dst), (_src), (_len));}while(0)
#define _NIFFS_IS_ID_VALID(phdr) ((phdr)->id.obj_id != (niffs_obj_id)-1 && (phdr)-> id.obj_id != 0)
#define _NIFFS_IS_FLAG_VALID(phdr) \
((phdr)->flag == _NIFFS_FLAG_CLEAN || (phdr)->flag == _NIFFS_FLAG_WRITTEN || (phdr)->flag == _NIFFS_FLAG_MOVING)
#define _NIFFS_IS_OBJ_HDR(phdr) (_NIFFS_IS_ID_VALID(phdr) && (phdr->id.spix) == 0)
#define NIFFS_EXCL_SECT_NONE (u32_t)-1
#define NIFFS_UNDEF_LEN (u32_t)-1
#ifndef niffs_memcpy
#define niffs_memcpy(_d, _s, _l) memcpy((_d), (_s), (_l))
#endif
#ifndef niffs_memset
#define niffs_memset(_d, _v, _l) memset((_d), (_v), (_l))
#endif
#ifndef niffs_strncpy
#define niffs_strncpy(_d, _s, _l) strncpy((_d), (_s), (_l))
#endif
typedef struct {
_NIFFS_ALIGN niffs_erase_cnt era_cnt;
_NIFFS_ALIGN niffs_magic abra; // page size xored with magic
} _NIFFS_PACKED niffs_sector_hdr;
typedef struct {
union {
niffs_page_id_raw raw;
struct {
niffs_span_ix spix : NIFFS_SPAN_IX_BITS;
niffs_obj_id obj_id : NIFFS_OBJ_ID_BITS;
};
};
} _NIFFS_PACKED niffs_page_hdr_id;
// keep member order, used in offsetof in internals
typedef struct {
_NIFFS_ALIGN niffs_page_hdr_id id;
_NIFFS_ALIGN niffs_flag flag;
} _NIFFS_PACKED niffs_page_hdr;
// keep member order, used in offsetof in internals
typedef struct {
niffs_page_hdr phdr;
_NIFFS_ALIGN u32_t len;
_NIFFS_ALIGN u8_t name[NIFFS_NAME_LEN];
_NIFFS_ALIGN niffs_file_type type;
} _NIFFS_PACKED niffs_object_hdr;
typedef struct {
niffs_object_hdr ohdr;
_NIFFS_ALIGN u32_t start_sector; // absolute index from fs start
_NIFFS_ALIGN u32_t resv_sectors;
} _NIFFS_PACKED niffs_linear_file_hdr;
// super header containing all header types
typedef union {
niffs_page_hdr_id phdr;
niffs_object_hdr ohdr;
niffs_linear_file_hdr lfhdr;
// .. add more if needed
} niffs_super_hdr;
#define NIFFS_VIS_CONT 1
#define NIFFS_VIS_END 2
typedef int (* niffs_visitor_f)(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, void *v_arg);
#ifdef NIFFS_TEST
TESTATIC int niffs_find_free_id(niffs *fs, niffs_obj_id *id, const char *conflict_name);
TESTATIC int niffs_find_free_page(niffs *fs, niffs_page_ix *pix, u32_t excl_sector);
TESTATIC int niffs_find_page(niffs *fs, niffs_page_ix *pix, niffs_obj_id oid, niffs_span_ix spix, niffs_page_ix start_pix);
TESTATIC int niffs_erase_sector(niffs *fs, u32_t sector_ix);
TESTATIC int niffs_move_page(niffs *fs, niffs_page_ix src_pix, niffs_page_ix dst_pix, const u8_t *data, u32_t len, niffs_flag force_flag);
TESTATIC int niffs_write_page(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, const u8_t *data, u32_t len);
TESTATIC int niffs_write_phdr(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr);
TESTATIC int niffs_delete_page(niffs *fs, niffs_page_ix pix);
#endif
int niffs_traverse(niffs *fs, niffs_page_ix pix_start, niffs_page_ix pix_end, niffs_visitor_f v, void *v_arg);
int niffs_get_filedesc(niffs *fs, int fd_ix, niffs_file_desc **fd);
int niffs_create(niffs *fs, const char *name, niffs_file_type type, void *meta);
int niffs_open(niffs *fs, const char *name, niffs_fd_flags flags);
int niffs_close(niffs *fs, int fd_ix);
int niffs_read_ptr(niffs *fs, int fd_ix, u8_t **data, u32_t *avail);
int niffs_seek(niffs *fs, int fd_ix, s32_t offset, u8_t whence);
int niffs_append(niffs *fs, int fd_ix, const u8_t *src, u32_t len);
int niffs_modify(niffs *fs, int fd_ix, u32_t offs, const u8_t *src, u32_t len);
int niffs_truncate(niffs *fs, int fd_ix, u32_t new_len);
int niffs_rename(niffs *fs, const char *old_name, const char *new_name);
int niffs_gc(niffs *fs, u32_t *freed_pages, u8_t allow_full_pages);
int niffs_chk(niffs *fs);
int niffs_linear_map(niffs *fs);
int niffs_linear_find_space(niffs *fs, u32_t sectors, u32_t *start_sector);
int niffs_linear_avail_size(niffs *fs, int fd_ix, u32_t *available_sectors);
#endif /* NIFFS_INTERNAL_H_ */

View File

@ -79,7 +79,7 @@ static int term_in( int mode )
static int term_translate( int data )
{
int c;
if( isprint( data ) )
return data;
else if( data == 0x1B ) // escape sequence
@ -100,7 +100,7 @@ static int term_translate( int data )
case 0x43:
return KC_RIGHT;
case 0x44:
return KC_LEFT;
return KC_LEFT;
}
else if( c > 48 && c < 55 )
{
@ -116,7 +116,7 @@ static int term_translate( int data )
case 53:
return KC_PAGEUP;
case 54:
return KC_PAGEDOWN;
return KC_PAGEDOWN;
}
}
}
@ -152,7 +152,7 @@ static int term_translate( int data )
case 21:
return KC_CTRL_U;
case 11:
return KC_CTRL_K;
return KC_CTRL_K;
}
}
return KC_UNKNOWN;
@ -183,21 +183,21 @@ void cmn_platform_init(void)
#ifdef BUILD_SERMUX
unsigned i;
unsigned bufsizes[] = SERMUX_BUFFER_SIZES;
unsigned bufsizes[] = SERMUX_BUFFER_SIZES;
// Setup the serial multiplexer
platform_uart_setup( SERMUX_PHYS_ID, SERMUX_PHYS_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_set_flow_control( SERMUX_PHYS_ID, SERMUX_FLOW_TYPE );
cmn_uart_setup_sermux();
// Set buffers for all virtual UARTs
// Set buffers for all virtual UARTs
for( i = 0; i < sizeof( bufsizes ) / sizeof( unsigned ); i ++ )
platform_uart_set_buffer( i + SERMUX_SERVICE_ID_FIRST, bufsizes[ i ] );
#endif // #ifdef BUILD_SERMUX
#if defined( CON_UART_ID ) && ( CON_UART_ID < SERMUX_SERVICE_ID_FIRST ) && ( CON_UART_ID != CDC_UART_ID )
// Setup console UART
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_set_flow_control( CON_UART_ID, CON_FLOW_TYPE );
platform_uart_set_buffer( CON_UART_ID, CON_BUF_SIZE );
#endif // #if defined( CON_UART_ID ) && CON_UART_ID < SERMUX_SERVICE_ID_FIRST
@ -206,16 +206,16 @@ void cmn_platform_init(void)
platform_uart_set_buffer( CDC_UART_ID, CDC_BUF_SIZE );
#endif
// Set the send/recv functions
// Set the send/recv functions
std_set_send_func( uart_send );
std_set_get_func( uart_recv );
#ifdef BUILD_XMODEM
#ifdef BUILD_XMODEM
// Initialize XMODEM
xmodem_init( xmodem_send, xmodem_recv );
xmodem_init( xmodem_send, xmodem_recv );
#endif
#ifdef BUILD_TERM
#ifdef BUILD_TERM
// Initialize terminal
term_init( TERM_LINES, TERM_COLS, term_out, term_in, term_translate );
#endif
@ -239,7 +239,7 @@ int platform_pio_has_port( unsigned port )
const char* platform_pio_get_prefix( unsigned port )
{
static char c[ 3 ];
sprintf( c, "P%c", ( char )( port + PIO_PREFIX ) );
return c;
}
@ -458,14 +458,14 @@ void cmn_int_handler( elua_int_id id, elua_int_resnum resnum )
#endif // #ifdef BUILD_INT_HANDLERS
// ****************************************************************************
// Internal flash support functions (currently used only by WOFS)
// Internal flash support functions (currently used only by WOFS and NIFFS)
#if defined( BUILD_WOFS ) && !defined( ELUA_CPU_LINUX )
#if (defined( BUILD_WOFS ) || defined( BUILD_NIFFS )) && !defined( ELUA_CPU_LINUX )
// This symbol must be exported by the linker command file and must reflect the
// TOTAL size of flash used by the eLua image (not only the code and constants,
// but also .data and whatever else ends up in the eLua image). WOFS will start
// at the next usable (aligned to a flash sector boundary) address after
// at the next usable (aligned to a flash sector boundary) address after
// flash_used_size.
extern char flash_used_size[];
@ -627,7 +627,7 @@ const char* cmn_str64( u64 x )
}
// Read a timeout spec from the user and return it
// The timeout spec has the format [timer_id, timeout]. Both arguments are optional:
// The timeout spec has the format [timer_id, timeout]. Both arguments are optional:
// If none is specified -> defaults to infinite timeout
// If timer_id is specified, but timeout is not specified -> defaults to infinite timeout
// If timeout is PLATFORM_TIMER_INF_TIMEOUT -> also infinite timeout (independent of timer_id)
@ -637,7 +637,7 @@ void cmn_get_timeout_data( lua_State *L, int pidx, unsigned *pid, timer_data_typ
{
lua_Number tempn;
*ptimeout = PLATFORM_TIMER_INF_TIMEOUT;
*ptimeout = PLATFORM_TIMER_INF_TIMEOUT;
*pid = ( unsigned )luaL_optinteger( L, pidx, PLATFORM_TIMER_SYS_ID );
if( lua_type( L, pidx + 1 ) == LUA_TNUMBER )
{

View File

@ -22,6 +22,7 @@
#include "mmcfs.h"
#include "romfs.h"
#include "semifs.h"
#include "nffs.h"
// Define here your autorun/boot files,
// in the order you want eLua to search for them
@ -34,6 +35,10 @@ const char *boot_order[] = {
"/wo/autorun.lua",
"/wo/autorun.lc",
#endif
#if defined(BUILD_NIFFS)
"/f/autorun.lua",
"/f/autorun.lc",
#endif
#if defined(BUILD_ROMFS)
"/rom/autorun.lua",
"/rom/autorun.lc",
@ -94,6 +99,9 @@ int main( void )
// Register the remote filesystem
remotefs_init();
// Register NIFFS
nffs_init();
// Search for autorun files in the defined order and execute the 1st if found
for( i = 0; i < sizeof( boot_order ) / sizeof( *boot_order ); i++ )
{

View File

@ -58,6 +58,9 @@ LUALIB_API int ( luaopen_elua )( lua_State *L );
#define AUXLIB_I2C "i2c"
LUALIB_API int ( luaopen_i2c )( lua_State *L );
#define AUXLIB_FS "fs"
LUALIB_API int ( luaopen_fs )( lua_State *L );
// Helper macros
#define MOD_CHECK_ID( mod, id )\
if( !platform_ ## mod ## _exists( id ) )\

44
src/modules/fs.c Normal file
View File

@ -0,0 +1,44 @@
// Module for interfacing with various file systems
// For now this is enabled only if NIFFS is enabled
#include "platform_conf.h"
#if defined( BUILD_NIFFS )
//#include "lua.h"
#include "lualib.h"
#include "auxmods.h"
#include "lrotable.h"
#include "nffs.h"
// Lua: res = niffs_format( linear_size )
static int fs_nffs_format( lua_State *L )
{
s32 linear_size = -1;
switch ( lua_gettop( L ) ) { /* check number of arguments */
case 1: /* format filesystem with the given linear size */
linear_size = luaL_checkinteger ( L, 1 );
break;
default:
return luaL_error( L, "wrong number of arguments" );
}
lua_pushinteger( L, nffs_format( linear_size ) );
return 1;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE fs_map[] =
{
{ LSTRKEY( "nffs_format" ), LFUNCVAL( fs_nffs_format ) },
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_fs( lua_State* L )
{
LREGISTER( L, AUXLIB_FS, fs_map );
}
#endif // #ifdef BUILD_NIFFS

435
src/niffs/niffs.c Normal file
View File

@ -0,0 +1,435 @@
// Filesystem implementation
#include "romfs.h"
#include <string.h>
#include <errno.h>
#include "romfiles.h"
#include <stdio.h>
#include <stdlib.h>
#include "ioctl.h"
#include <fcntl.h>
#include "platform.h"
#include "platform_conf.h"
#include "niffs.h"
#include "niffs_internal.h"
#if defined( BUILD_NIFFS )
//#define NFFS_DBG(...) printf(__VA_ARGS__)
#ifndef NFFS_DBG
#define NFFS_DBG(...)
#endif
// FIXME: Needs to be adjusted to support non-uniform sector sizes
#define LAST_SECTOR_NUM ( platform_flash_get_num_sectors() - 1 )
#define LAST_SECTOR_END ( INTERNAL_FLASH_SIZE - INTERNAL_FLASH_START_ADDRESS )
niffs fs;
#define NIFFS_BUF_SIZE 128
#define NIFFS_FILE_DESCS 4
static u8_t buf[NIFFS_BUF_SIZE];
static niffs_file_desc descs[NIFFS_FILE_DESCS];
static u8_t * niffs_pbase;
static u32_t niffs_max_size;
static u32_t niffs_total_sectors;
static u32_t niffs_paged_sectors;
static u32_t niffs_lin_sectors;
static int nffs_open_r( struct _reent *r, const char *path, int flags, int mode, void *pdata )
{
u8 lflags = 0;
int ret;
lflags = NIFFS_O_RDONLY;
//check for read/write flags and overwrite read only if so
if(flags & O_RDWR) {
lflags = NIFFS_O_RDWR;
//printf("-S");
}
if(flags & O_WRONLY) {
lflags = NIFFS_O_WRONLY;
//printf("-W");
}
//add other flags
if(flags & O_CREAT) {
lflags |= NIFFS_O_CREAT;
//printf("-C");
}
if(flags & O_TRUNC) {
lflags |= NIFFS_O_TRUNC;
//printf("-T");
}
if(flags & O_APPEND) {
lflags |= NIFFS_O_APPEND;
//printf("-A");
}
if(flags & O_EXCL) {
lflags |= NIFFS_O_EXCL;
//printf("-E");
}
// If file name starts with autorun or lin_, then put it on the linear filesystem
if ((strncmp("lin_", path, 7) == 0) || (strncmp("autorun", path, 7) == 0)) {
lflags |= NIFFS_O_LINEAR;
//printf("-L\n");
}
ret = NIFFS_open(&fs, (char *)path, lflags, mode);
NFFS_DBG("\nN_O:%s,%i,%i,%i,%i\n", path, ret, flags, lflags, mode);
if(ret < 0)
{
r->_errno = ENOENT; //File does not exist
return -1;
}
return ret;
}
static int nffs_close_r( struct _reent *r, int fd, void *pdata )
{
return NIFFS_close(&fs, fd);
}
static _ssize_t nffs_write_r( struct _reent *r, int fd, const void* ptr, size_t len, void *pdata )
{
return NIFFS_write(&fs, fd, (void *)ptr, len);
}
static _ssize_t nffs_read_r( struct _reent *r, int fd, void* ptr, size_t len, void *pdata )
{
return NIFFS_read(&fs, fd, ptr, len);
}
static off_t nffs_lseek_r( struct _reent *r, int fd, off_t off, int whence, void *pdata )
{
// Ensure the whence arg here matches NIFFS_SEEK_SET, NIFFS_SEEK_CUR, NIFFS_SEEK_END?
// niffs adapts to the posix values so should work (Yes)
//#define SEEK_SET 0 /* set file offset to offset */
//#define SEEK_CUR 1 /* set file offset to current plus offset */
//#define SEEK_END 2 /* set file offset to EOF plus offset */
//#define NIFFS_SEEK_SET (0)
//#define NIFFS_SEEK_CUR (1)
//#define NIFFS_SEEK_END (2)
int res;
//Return value will be greater than 0 if file seek occurs, or 0 IE NIFFS_OK if successful but didn't move, and
//less than zero if an error occured.
res = NIFFS_lseek(&fs, fd, off, whence);
if(res >= NIFFS_OK)
{
//printf("Nl r:%i fd:%i o:%li w:%i\n", res, fd, off, whence);
return res;
} else {
//printf("Nl FAIL r:%i fd:%i o:%li w:%i\n", res, fd, off, whence);
return -1;
}
}
// getaddr
static const char* nffs_getaddr_r( struct _reent *r, int fd, void *pdata )
{
u8_t * ptrptr;
u32_t len;
NIFFS_read_ptr(&fs, fd, &ptrptr, &len);
//printf("getaddr %p\n", (u32_t *)ptrptr);
return (char*)ptrptr;
}
// Directory operations
//static u32 romfs_dir_data = 0;
static niffs_DIR niffs_d;
// opendir
static void* nffs_opendir_r( struct _reent *r, const char* dname, void *pdata )
{
return NIFFS_opendir(&fs, (char *)dname, &niffs_d);
}
// TODO peter no clue what I am doing here, but could perhaps work
extern struct dm_dirent dm_shared_dirent;
extern char dm_shared_fname[ DM_MAX_FNAME_LENGTH + 1 ];
static struct dm_dirent *nffs_readdir_r( struct _reent *r, void *d, void *pdata )
{
struct dm_dirent *pent = &dm_shared_dirent;
struct niffs_dirent niffs_ent;
struct niffs_dirent *p_niffs_ent = &niffs_ent;
p_niffs_ent = NIFFS_readdir(&niffs_d, p_niffs_ent);
if (p_niffs_ent) {
pent->fname = dm_shared_fname;
strncpy((char *)pent->fname, (char *)p_niffs_ent->name, UMIN(NIFFS_NAME_LEN, DM_MAX_FNAME_LENGTH));
pent->fsize = p_niffs_ent->size;
pent->flags = 0; // TODO peter don't know what elua uses this for
pent->ftime = 0;
if (p_niffs_ent->type) {
// TODO peter placeholder
// 0x00 = paged file
// 0x01 = linear file
}
}
return p_niffs_ent == NULL ? NULL : pent;
}
/*
NIFFS_readdir
// readdir
extern struct dm_dirent dm_shared_dirent;
extern char dm_shared_fname[ DM_MAX_FNAME_LENGTH + 1 ];
static struct dm_dirent* romfs_readdir_r( struct _reent *r, void *d, void *pdata )
{
u32 off = *( u32* )d;
struct dm_dirent *pent = &dm_shared_dirent;
unsigned j;
FSDATA *pfsdata = ( FSDATA* )pdata;
int is_deleted;
while( 1 )
{
// Check if we're at the end of the FS
if( romfsh_read8( off, pfsdata ) == WOFS_END_MARKER_CHAR )
return NULL;
// Read filename
j = 0;
while( ( dm_shared_fname[ j ++ ] = romfsh_read8( off ++, pfsdata ) ) != '\0' );
pent->fname = dm_shared_fname;
// Move to next aligned offset after name
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
// If WOFS, check if file is marked as deleted
if( romfsh_is_wofs( pfsdata ) )
{
is_deleted = romfsh_read8( off, pfsdata ) == WOFS_FILE_DELETED;
off += WOFS_DEL_FIELD_SIZE;
}
else
is_deleted = 0;
// Get file size file and pack into fsize
pent->fsize = romfsh_read8( off, pfsdata ) + ( romfsh_read8( off + 1, pfsdata ) << 8 );
pent->fsize += ( romfsh_read8( off + 2, pfsdata ) << 16 ) + ( romfsh_read8( off + 3, pfsdata ) << 24 );
if( (( u64 )off + ( u64 )ROMFS_SIZE_LEN + ( u64 )pent->fsize) > ( u64 )pfsdata->max_size )
{
if( romfs_fs_is_flag_set( pfsdata, ROMFS_FS_FLAG_READY_WRITE ) &&
!( romfs_fs_is_flag_set( pfsdata, ROMFS_FS_FLAG_WRITING ) && ( u64 )pent->fsize == 0xFFFFFFFF ) )
{
fprintf(stderr, "[ERROR] Read File too long, making filesystem readonly\n");
romfs_fs_clear_flag( pfsdata, ROMFS_FS_FLAG_READY_WRITE );
}
return NULL;
}
// fill in file time & flags
pent->ftime = 0;
pent->flags = 0;
// Jump offset ahead by length field & file size
off += ROMFS_SIZE_LEN;
off += pent->fsize;
// If WOFS, also advance offset by deleted file field
if( romfsh_is_wofs( pfsdata ) )
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
//If file security is enabled, don't return a matching filename as valid
#ifdef ROMFS_SECURE_FILENAMES_WITH_CHAR
if( !is_deleted && ( romfs_security_lock == 0 || strstr( pent->fname, ROMFS_SECURE_FILENAMES_WITH_CHAR) == NULL ) )
break;
#else
if( !is_deleted )
break;
#endif
}
*( u32* )d = off;
return pent;
}*/
// closedir
static int nffs_closedir_r( struct _reent *r, void *d, void *pdata )
{
*( u32* )d = 0;
return 0;
}
// unlink
static int nffs_unlink_r( struct _reent *r, const char *path, void *pdata )
{
return NIFFS_remove(&fs, (char *)path);
}
static const DM_DEVICE niffs_device =
{
nffs_open_r, // open
nffs_close_r, // close
nffs_write_r, // write
nffs_read_r, // read
nffs_lseek_r, // lseek
nffs_opendir_r, // opendir
nffs_readdir_r, // readdir TODO peter, made an attempt at this
nffs_closedir_r, // closedir
nffs_getaddr_r, // getaddr
NULL, // mkdir
nffs_unlink_r, // unlink
NULL, // rmdir
NULL // rename // TODO peter, this exists in niffs also if you want it
};
static int platform_hal_erase_f(u8_t *addr, u32_t len) {
// flash boundary checks
if ((intptr_t)addr < (intptr_t)niffs_pbase ||
(intptr_t)addr + len > (intptr_t)niffs_pbase + niffs_max_size) {
NFFS_DBG("N_E: OOB %li,%li\n", (u32_t)addr, len);
return -1; // TODO peter better err code?
}
/* if (addr < &_flash[0]) return ERR_NIFFS_TEST_BAD_ADDR;
if (addr+len > &_flash[0] + EMUL_SECTORS * EMUL_SECTOR_SIZE) return ERR_NIFFS_TEST_BAD_ADDR;
if ((addr - &_flash[0]) % EMUL_SECTOR_SIZE) return ERR_NIFFS_TEST_BAD_ADDR;
if (len != EMUL_SECTOR_SIZE) return ERR_NIFFS_TEST_BAD_ADDR;*/
platform_flash_erase_sector(((u32_t)addr)/INTERNAL_FLASH_SECTOR_SIZE); // == PLATFORM_OK;
NFFS_DBG("N_E:%li,%li\n", (u32_t)addr, len);
return NIFFS_OK;
}
static int platform_hal_write_f(u8_t *addr, const u8_t *src, u32_t len) {
if ((intptr_t)addr < (intptr_t)niffs_pbase ||
(intptr_t)addr + len > (intptr_t)niffs_pbase + niffs_max_size) {
NFFS_DBG("N_W: OOB %li,%li\n", (u32_t)addr, len);
return -1; // TODO peter better err code?
}
//TODO: Write actual data to addresses here
// toaddr += ( u32 )pfsdata->pbase;
//platform_flash_write( const void *from, u32 toaddr, u32 size )
platform_flash_write( src, (u32_t)addr, len );
NFFS_DBG("N_W:%li,%li,%li\n", (u32_t)addr, (u32_t)src, len);
return NIFFS_OK;
}
int nffs_check_and_mount()
{
//Check filesystem, and format if it has not been formatted or corrupted...
NIFFS_unmount(&fs);
if(NIFFS_chk(&fs) == ERR_NIFFS_NOT_A_FILESYSTEM)
{
NFFS_DBG("chk NOT FS\n");
NIFFS_format(&fs);
} else
NFFS_DBG("chk OK\n");
if(NIFFS_mount(&fs))
{
printf("FILE SYSTEM MOUNT FAIL\n");
return 0;
}
else
{
NFFS_DBG("MNT OK\n");
return 1;
}
}
int nffs_create( s32_t linear_bytes )
{
niffs_pbase = ( u8* )platform_flash_get_first_free_block_address( NULL );
niffs_max_size = INTERNAL_FLASH_SIZE - ( ( u32 )niffs_pbase - INTERNAL_FLASH_START_ADDRESS ) - (INTERNAL_FLASH_SECTOR_SIZE);
niffs_total_sectors = niffs_max_size / INTERNAL_FLASH_SECTOR_SIZE;
if(linear_bytes == -1)
{
//Look to see if we have a valid magic byte and if so, get the linear page size
//It is stored in the lower 2 bytes of the magic number (abra)
niffs_sector_hdr *shdr = (niffs_sector_hdr *)niffs_pbase;
NFFS_DBG("%08lX %08lX\n",
shdr->abra,
_NIFFS_SECT_LINEAR_SIZE(shdr->abra));
niffs_lin_sectors = 1;
//Get linear sectors stored on flash...if it's set...if not, assume zero linear sectors
//If not, format the file system with no linear page area. User will format it if needed
if ((shdr->abra >> 24) == (_NIFFS_SECT_MAGIC_BYTES))
niffs_lin_sectors = _NIFFS_SECT_LINEAR_SIZE(shdr->abra);
} else {
//We were told to create a linear space, calculate it here
//Division drops the decimal, so we need to divide and add 1 sector
niffs_lin_sectors = (linear_bytes / INTERNAL_FLASH_SECTOR_SIZE) + 1;
//Make sure we leave at least 1 sector for paged sectors
if(niffs_lin_sectors > (niffs_total_sectors - 1))
niffs_lin_sectors = niffs_total_sectors - 1;
}
niffs_paged_sectors = niffs_total_sectors - niffs_lin_sectors;
printf("NIFFS: LIN %li PAGE %li\n", niffs_lin_sectors, niffs_paged_sectors);
NIFFS_init(&fs, niffs_pbase, niffs_paged_sectors, INTERNAL_FLASH_SECTOR_SIZE, NIFFS_BUF_SIZE,
buf, sizeof(buf),
descs, NIFFS_FILE_DESCS,
platform_hal_erase_f, platform_hal_write_f, niffs_lin_sectors);
//If given a specific linear byte size, format flash
if(linear_bytes != -1)
NIFFS_format(&fs);
//Check filesystem, and format if it has not been formatted or corrupted...
return nffs_check_and_mount();
}
int nffs_init( void )
{
nffs_create(-1);
dm_register( "/f", &fs, &niffs_device );
return dm_register( NULL, NULL, NULL );
}
int nffs_format(s32_t linear_bytes)
{
NIFFS_unmount(&fs);
nffs_create(linear_bytes);
NFFS_DBG("N_I:%li,%li,%li,%li\n", (u32_t)niffs_pbase, niffs_max_size, niffs_paged_sectors, niffs_lin_sectors);
return 1;
}
int nffs_mount()
{
return NIFFS_mount(&fs);
}
int nffs_unmount()
{
return NIFFS_unmount(&fs);
}
int nffs_info(s32_t *total, s32_t *used, u8_t *overflow, s32_t *lin_total, s32_t *lin_used, s32_t *lin_free)
{
niffs_sector_hdr *shdr = (niffs_sector_hdr *)_NIFFS_SECTOR_2_ADDR(&fs, 0);
printf("%08lX %08lX %08lX\n",
shdr->abra,
_NIFFS_SECT_MAGIC(&fs),
_NIFFS_SECT_LINEAR_SIZE(shdr->abra));
nffs_check_and_mount();
niffs_info info;
int res = NIFFS_info(&fs, &info);
if (res == NIFFS_OK) {
*total = info.total_bytes;
*used = info.used_bytes;
*overflow = info.overflow;
*lin_total = info.lin_total_sectors * INTERNAL_FLASH_SECTOR_SIZE;
*lin_used = info.lin_used_sectors * INTERNAL_FLASH_SECTOR_SIZE;
*lin_free = info.lin_max_conseq_free * INTERNAL_FLASH_SECTOR_SIZE;
}
return res;
}
#else // #if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
int nffs_init( void )
{
return dm_register( NULL, NULL, NULL );
}
#endif // #if defined( BUILD_NIFFS )

346
src/niffs/niffs_api.c Normal file
View File

@ -0,0 +1,346 @@
/*
* niffs_api.c
*
* Created on: Feb 22, 2015
* Author: petera
*/
#include "niffs.h"
#include "niffs_internal.h"
int NIFFS_info(niffs *fs, niffs_info *i) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
if (i == 0) return ERR_NIFFS_NULL_PTR;
i->total_bytes = (fs->sectors-1) * fs->pages_per_sector * _NIFFS_SPIX_2_PDATA_LEN(fs, 1);
i->used_bytes = ((fs->sectors) * fs->pages_per_sector - (fs->free_pages + fs->dele_pages)) * _NIFFS_SPIX_2_PDATA_LEN(fs, 1);
i->overflow = fs->free_pages < fs->pages_per_sector;
#if NIFFS_LINEAR_AREA
i->lin_total_sectors = fs->lin_sectors;
i->lin_used_sectors = 0;
int res = niffs_linear_map(fs);
if (res) return res;
u32_t lsix;
u32_t max_conseq_free = 0;
u32_t cur_conseq_free = 0;
u8_t taken = 1;
for (lsix = 0; lsix < fs->lin_sectors; lsix++) {
if ((fs->buf[lsix/8] & (1<<(lsix&7)))) {
i->lin_used_sectors++;
cur_conseq_free = 0;
taken = 1;
} else {
cur_conseq_free++;
if (taken) taken = 0;
max_conseq_free = NIFFS_MAX(cur_conseq_free, max_conseq_free);
}
}
i->lin_max_conseq_free = max_conseq_free;
#endif
return NIFFS_OK;
}
int NIFFS_creat(niffs *fs, const char *name, niffs_mode mode) {
(void)mode;
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
res = niffs_create(fs, name, _NIFFS_FTYPE_FILE, 0);
return res;
}
int NIFFS_open(niffs *fs, const char *name, u8_t flags, niffs_mode mode) {
(void)mode;
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res = NIFFS_OK;
niffs_file_type type =
flags & NIFFS_O_LINEAR ? _NIFFS_FTYPE_LINFILE : _NIFFS_FTYPE_FILE;
#if !NIFFS_LINEAR_AREA
if (type == _NIFFS_FTYPE_LINFILE) return ERR_NIFFS_BAD_CONF;
#endif
if (type) {
flags |= NIFFS_O_APPEND; // force append for linear files
}
int fd_ix = niffs_open(fs, name, flags);
if (fd_ix < 0) {
// file not found
if (fd_ix == ERR_NIFFS_FILE_NOT_FOUND && (flags & NIFFS_O_CREAT)) {
res = niffs_create(fs, name, type, 0);
if (res == NIFFS_OK) {
fd_ix = niffs_open(fs, name, flags);
} else {
fd_ix = res;
}
}
res = fd_ix;
} else {
// file found
if ((flags & (NIFFS_O_CREAT | NIFFS_O_EXCL)) == (NIFFS_O_CREAT | NIFFS_O_EXCL)) {
(void)niffs_close(fs, fd_ix);
return ERR_NIFFS_FILE_EXISTS;
}
}
if (res != NIFFS_OK) return res;
if (flags & NIFFS_O_TRUNC) {
niffs_file_desc *fd;
res = niffs_get_filedesc(fs, fd_ix, &fd);
if (res != NIFFS_OK) return res;
niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix);
if (ohdr->len != NIFFS_UNDEF_LEN) {
// only truncate if file len is > 0
res = niffs_truncate(fs, fd_ix, 0);
if (res != NIFFS_OK) {
(void)niffs_close(fs, fd_ix);
return res;
}
res = niffs_create(fs, name, type, 0);
if (res != NIFFS_OK) return res;
fd_ix = niffs_open(fs, name, flags);
}
}
return res < 0 ? res : fd_ix;
}
#if NIFFS_LINEAR_AREA
int NIFFS_mknod_linear(niffs *fs, const char *name, u32_t resv_size) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
u8_t flags = NIFFS_O_LINEAR | NIFFS_O_RDWR | NIFFS_O_APPEND;
int res = NIFFS_OK;
// check free linear space, fetch starting sector
u32_t lsix_start;
u32_t resv_sects = (resv_size + fs->sector_size - 1) / fs->sector_size;
res = niffs_linear_find_space(fs, resv_sects, &lsix_start);
if (res < 0) return res;
int fd_ix = niffs_open(fs, name, flags);
if (fd_ix >= 0) {
// file exists
(void)niffs_close(fs, fd_ix);
return ERR_NIFFS_FILE_EXISTS;
}
if (fd_ix != ERR_NIFFS_FILE_NOT_FOUND) {
// some other error
return fd_ix;
}
// create linear file meta header
niffs_linear_file_hdr lfhdr = {.start_sector = lsix_start, .resv_sectors = resv_sects};
res = niffs_create(fs, name, _NIFFS_FTYPE_LINFILE, &lfhdr);
if (res != NIFFS_OK) return res;
fd_ix = niffs_open(fs, name, flags);
if (fd_ix < 0) return fd_ix;
return fd_ix;
}
#endif // NIFFS_LINEAR_AREA
int NIFFS_read_ptr(niffs *fs, int fd, u8_t **ptr, u32_t *len) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
return niffs_read_ptr(fs, fd, ptr, len);
}
int NIFFS_read(niffs *fs, int fd_ix, u8_t *dst, u32_t len) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res = NIFFS_OK;
s32_t read_len = 0;
do {
u8_t *rptr;
u32_t rlen;
res = niffs_read_ptr(fs, fd_ix, &rptr, &rlen);
if (res >= 0 && rlen == 0) res = ERR_NIFFS_END_OF_FILE;
if (res >= 0) {
u32_t clen = NIFFS_MIN(len, rlen);
niffs_memcpy(dst, rptr, clen);
dst += clen;
len -= clen;
read_len += clen;
res = niffs_seek(fs, fd_ix, clen, NIFFS_SEEK_CUR);
}
} while (len > 0 && res >= 0);
if (res == ERR_NIFFS_END_OF_FILE && read_len >= 0) {
return read_len;
}
return res == NIFFS_OK ? read_len : res;
}
int NIFFS_lseek(niffs *fs, int fd_ix, s32_t offs, int whence) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res = niffs_seek(fs, fd_ix, offs, whence);
if (res == NIFFS_OK) {
niffs_file_desc *fd;
res = niffs_get_filedesc(fs, fd_ix, &fd);
if (res != NIFFS_OK) return res;
return (int)fd->offs;
}
return res;
}
int NIFFS_remove(niffs *fs, const char *name) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
int fd = NIFFS_open(fs, name, NIFFS_O_WRONLY, 0);
if (fd < 0) return fd;
res = niffs_truncate(fs, fd, 0);
(void)niffs_close(fs, fd);
return res;
}
int NIFFS_fremove(niffs *fs, int fd) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
return niffs_truncate(fs, fd, 0);
}
int NIFFS_write(niffs *fs, int fd_ix, const u8_t *data, u32_t len) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
niffs_file_desc *fd;
res = niffs_get_filedesc(fs, fd_ix, &fd);
if (res != NIFFS_OK) return res;
niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix);
s32_t written = 0;
if (fd->flags & NIFFS_O_APPEND) {
// always append
res = niffs_append(fs, fd_ix, data, len);
written += len;
} else {
// check if modify and/or append
u32_t mod_len = (ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len) - fd->offs;
mod_len = NIFFS_MIN(mod_len, len);
if (mod_len > 0) {
res = niffs_modify(fs, fd_ix, fd->offs, data, mod_len);
if (res != NIFFS_OK) return res;
len -= mod_len;
data += mod_len;
written += mod_len;
}
if (len > 0) {
res = niffs_append(fs, fd_ix, data, len);
written += len;
}
}
// if (res == NIFFS_OK) {
// res = niffs_seek(fs, fd_ix, len, NIFFS_SEEK_CUR);
// }
return res == 0 ? written : res;
}
int NIFFS_fflush(niffs *fs, int fd) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
(void)fd;
return NIFFS_OK;
}
int NIFFS_stat(niffs *fs, const char *name, niffs_stat *s) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
int fd = NIFFS_open(fs, name, 0, 0);
if (fd < 0) return fd;
res = NIFFS_fstat(fs, fd, s);
(void)niffs_close(fs, fd);
return res;
}
int NIFFS_fstat(niffs *fs, int fd_ix, niffs_stat *s) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
niffs_file_desc *fd;
res = niffs_get_filedesc(fs, fd_ix, &fd);
if (res != NIFFS_OK) return res;
niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix);
s->obj_id = ohdr->phdr.id.obj_id;
s->size = ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len;
s->type = ohdr->type;
niffs_strncpy((char *)s->name, (char *)ohdr->name, NIFFS_NAME_LEN);
return NIFFS_OK;
}
int NIFFS_ftell(niffs *fs, int fd_ix) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
int res;
niffs_file_desc *fd;
res = niffs_get_filedesc(fs, fd_ix, &fd);
if (res != NIFFS_OK) return res;
return (int)fd->offs;
}
int NIFFS_close(niffs *fs, int fd) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
return niffs_close(fs, fd);
}
int NIFFS_rename(niffs *fs, const char *old_name, const char *new_name) {
if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
return niffs_rename(fs, old_name, new_name);
}
niffs_DIR *NIFFS_opendir(niffs *fs, const char *name, niffs_DIR *d) {
(void)name;
if (!fs->mounted) return 0;
d->fs = fs;
d->pix = 0;
return d;
}
int NIFFS_closedir(niffs_DIR *d) {
if (!d->fs->mounted) return ERR_NIFFS_NOT_MOUNTED;
return NIFFS_OK;
}
static int niffs_readdir_v(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, void *v_arg) {
(void)fs;
struct niffs_dirent *e = (struct niffs_dirent *)v_arg;
if (_NIFFS_IS_FLAG_VALID(phdr) && !_NIFFS_IS_FREE(phdr) && !_NIFFS_IS_DELE(phdr)) {
if (_NIFFS_IS_OBJ_HDR(phdr)) {
// object header page
niffs_object_hdr *ohdr = (niffs_object_hdr *)phdr;
e->obj_id = ohdr->phdr.id.obj_id;
e->pix = pix;
e->size = ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len;
e->type = ohdr->type;
niffs_strncpy((char *)e->name, (char *)ohdr->name, NIFFS_NAME_LEN);
return NIFFS_OK;
}
}
return NIFFS_VIS_CONT;
}
struct niffs_dirent *NIFFS_readdir(niffs_DIR *d, struct niffs_dirent *e) {
if (!d->fs->mounted) return 0;
struct niffs_dirent *ret = 0;
int res = niffs_traverse(d->fs, d->pix, 0, niffs_readdir_v, e);
if (res == NIFFS_OK) {
d->pix = e->pix + 1;
ret = e;
} else if (res == NIFFS_VIS_END) {
// end of stream
}
return ret;
}
int NIFFS_chk(niffs *fs) {
if (fs->mounted) return ERR_NIFFS_MOUNTED;
return niffs_chk(fs);
}

2229
src/niffs/niffs_internal.c Normal file

File diff suppressed because it is too large Load Diff