Commit 7b160da1 authored by devsaurus's avatar devsaurus
Browse files

Merge remote-tracking branch 'upstream/dev' into dev

parents b172f628 d28a2c9e
...@@ -8,13 +8,21 @@ install: ...@@ -8,13 +8,21 @@ install:
script: script:
- make all - make all
- cd bin/ - cd bin/
- file_name="nodemcu-firmware_v${TRAVIS_TAG}.${TRAVIS_BUILD_NUMBER}.bin" - file_name_float="nodemcu_float_${TRAVIS_TAG}.bin"
- srec_cat -output ${file_name} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000 - srec_cat -output ${file_name_float} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
- cd ../
- make clean
- make EXTRA_CCFLAGS="-DLUA_NUMBER_INTEGRAL"
- cd bin/
- file_name_integer="nodemcu_integer_${TRAVIS_TAG}.bin"
- srec_cat -output ${file_name_integer} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
deploy: deploy:
provider: releases provider: releases
api_key: api_key:
secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw= secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw=
file: "$TRAVIS_BUILD_DIR/bin/${file_name}" file:
- "$TRAVIS_BUILD_DIR/bin/${file_name_float}"
- "$TRAVIS_BUILD_DIR/bin/${file_name_integer}"
skip_cleanup: true skip_cleanup: true
on: on:
tags: true tags: true
......
# **NodeMCU** # # **NodeMCU** #
version 0.9.5 version 0.9.5
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Download](https://img.shields.io/badge/download-~400k-orange.svg)](https://github.com/nodemcu/nodemcu-firmware/releases/latest)
###A lua based firmware for wifi-soc esp8266 ###A lua based firmware for wifi-soc esp8266
Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br /> Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
...@@ -33,6 +33,19 @@ Tencent QQ group: 309957875<br /> ...@@ -33,6 +33,19 @@ Tencent QQ group: 309957875<br />
- cross compiler (done) - cross compiler (done)
# Change log # Change log
2015-03-11<br />
fix bugs of spiffs.<br />
build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).<br />
fix tmr.time().<br />
fix memory leak when DNS fail.
2015-03-10<br />
update to the recent spiffs.<br />
add file.fsinfo() api, usage: remain, used, total = file.fsinfo().<br />
add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).<br />
add math lib, partial api work.<br />
u8g module, ws2812 module default enabled in dev-branch build.
2015-02-13<br /> 2015-02-13<br />
add node.compile() api to compile lua text file into lua bytecode file.<br /> add node.compile() api to compile lua text file into lua bytecode file.<br />
this will reduce memory usage noticeably when require modules into NodeMCU.<br /> this will reduce memory usage noticeably when require modules into NodeMCU.<br />
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
#define NODE_VERSION_INTERNAL 0U #define NODE_VERSION_INTERNAL 0U
#define NODE_VERSION "NodeMCU 0.9.5" #define NODE_VERSION "NodeMCU 0.9.5"
#define BUILD_DATE "build 20150306" #define BUILD_DATE "build 20150311"
#endif /* __USER_VERSION_H__ */ #endif /* __USER_VERSION_H__ */
...@@ -175,6 +175,22 @@ static int file_rename( lua_State* L ) ...@@ -175,6 +175,22 @@ static int file_rename( lua_State* L )
return 1; return 1;
} }
// Lua: fsinfo()
static int file_fsinfo( lua_State* L )
{
uint32_t total, used;
SPIFFS_info(&fs, &total, &used);
NODE_DBG("total: %d, used:%d\n", total, used);
if(total>0x7FFFFFFF || used>0x7FFFFFFF || used > total)
{
return luaL_error(L, "file system error");;
}
lua_pushinteger(L, total-used);
lua_pushinteger(L, used);
lua_pushinteger(L, total);
return 3;
}
#endif #endif
// g_read() // g_read()
...@@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] = ...@@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] =
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) }, { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
// { LSTRKEY( "check" ), LFUNCVAL( file_check ) }, // { LSTRKEY( "check" ), LFUNCVAL( file_check ) },
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) }, { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
#endif #endif
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
......
...@@ -200,10 +200,15 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -200,10 +200,15 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
return; return;
} }
if(nud->self_ref == LUA_NOREF){
NODE_DBG("self_ref null.\n");
return;
}
if(ipaddr == NULL) if(ipaddr == NULL)
{ {
NODE_ERR( "DNS Fail!\n" ); NODE_ERR( "DNS Fail!\n" );
return; goto end;
} }
// ipaddr->addr is a uint32_t ip // ipaddr->addr is a uint32_t ip
...@@ -214,16 +219,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -214,16 +219,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr))); c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr)));
} }
if(nud->self_ref == LUA_NOREF){
NODE_DBG("self_ref null.\n");
return;
}
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
lua_pushstring(gL, ip_str); // the ip para lua_pushstring(gL, ip_str); // the ip para
lua_call(gL, 2, 0); lua_call(gL, 2, 0);
end:
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0) if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
|| (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){ || (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){
lua_gc(gL, LUA_GCSTOP, 0); lua_gc(gL, LUA_GCSTOP, 0);
...@@ -597,12 +598,22 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) ...@@ -597,12 +598,22 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
NODE_DBG("pesp_conn null.\n"); NODE_DBG("pesp_conn null.\n");
return; return;
} }
lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse;
if(nud == NULL)
return;
if(gL == NULL)
return;
if(ipaddr == NULL) if(ipaddr == NULL)
{ {
dns_reconn_count++; dns_reconn_count++;
if( dns_reconn_count >= 5 ){ if( dns_reconn_count >= 5 ){
NODE_ERR( "DNS Fail!\n" ); NODE_ERR( "DNS Fail!\n" );
lua_gc(gL, LUA_GCSTOP, 0);
if(nud->self_ref != LUA_NOREF){
luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref);
nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self
}
lua_gc(gL, LUA_GCRESTART, 0);
return; return;
} }
NODE_ERR( "DNS retry %d!\n", dns_reconn_count ); NODE_ERR( "DNS retry %d!\n", dns_reconn_count );
......
...@@ -148,24 +148,30 @@ static int tmr_wdclr( lua_State* L ) ...@@ -148,24 +148,30 @@ static int tmr_wdclr( lua_State* L )
} }
static os_timer_t rtc_timer_updator; static os_timer_t rtc_timer_updator;
static uint64_t cur_count = 0; static uint32_t cur_count = 0;
static uint64_t rtc_us = 0; static uint32_t rtc_10ms = 0;
void rtc_timer_update_cb(void *arg){ void rtc_timer_update_cb(void *arg){
uint64_t t = (uint64_t)system_get_rtc_time(); uint32_t t = (uint32_t)system_get_rtc_time();
uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count); uint32_t delta = 0;
if(t>=cur_count){
delta = t-cur_count;
}else{
delta = 0xFFFFFFF - cur_count + t + 1;
}
// uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
// NODE_ERR("%x\n",t); // NODE_ERR("%x\n",t);
cur_count = t; cur_count = t;
unsigned c = system_rtc_clock_cali_proc(); uint32_t c = system_rtc_clock_cali_proc();
uint64_t itg = c >> 12; uint32_t itg = c >> 12; // ~=5
uint64_t dec = c & 0xFFF; uint32_t dec = c & 0xFFF; // ~=2ff
rtc_us += (delta*itg + ((delta*dec)>>12)); rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000;
// TODO: store rtc_us to rtc memory. // TODO: store rtc_10ms to rtc memory.
} }
// Lua: time() , return rtc time in second // Lua: time() , return rtc time in second
static int tmr_time( lua_State* L ) static int tmr_time( lua_State* L )
{ {
uint64_t local = rtc_us; uint32_t local = rtc_10ms;
lua_pushinteger( L, ((uint32_t)(local/1000000)) & 0x7FFFFFFF ); lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF );
return 1; return 1;
} }
......
...@@ -160,7 +160,7 @@ int myspiffs_error( int fd ){ ...@@ -160,7 +160,7 @@ int myspiffs_error( int fd ){
return SPIFFS_errno(&fs); return SPIFFS_errno(&fs);
} }
void myspiffs_clearerr( int fd ){ void myspiffs_clearerr( int fd ){
fs.errno = SPIFFS_OK; SPIFFS_clearerr(&fs);
} }
int myspiffs_rename( const char *old, const char *newname ){ int myspiffs_rename( const char *old, const char *newname ){
return SPIFFS_rename(&fs, (char *)old, (char *)newname); return SPIFFS_rename(&fs, (char *)old, (char *)newname);
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#ifndef SPIFFS_H_ #ifndef SPIFFS_H_
#define SPIFFS_H_ #define SPIFFS_H_
#if defined(__cplusplus)
extern "C" {
#endif
#include "c_stdio.h" #include "c_stdio.h"
#include "spiffs_config.h" #include "spiffs_config.h"
...@@ -181,7 +185,7 @@ typedef struct { ...@@ -181,7 +185,7 @@ typedef struct {
u32_t fd_count; u32_t fd_count;
// last error // last error
s32_t errno; s32_t err_code;
// current number of free blocks // current number of free blocks
u32_t free_blocks; u32_t free_blocks;
...@@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh); ...@@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh);
* Renames a file * Renames a file
* @param fs the file system struct * @param fs the file system struct
* @param old path of file to rename * @param old path of file to rename
* @param new new path of file * @param newPath new path of file
*/ */
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath);
/** /**
* Returns last error of last file operation. * Returns last error of last file operation.
...@@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new); ...@@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new);
*/ */
s32_t SPIFFS_errno(spiffs *fs); s32_t SPIFFS_errno(spiffs *fs);
/**
* Clears last error.
* @param fs the file system struct
*/
void SPIFFS_clearerr(spiffs *fs);
/** /**
* Opens a directory stream corresponding to the given name. * Opens a directory stream corresponding to the given name.
* The stream is positioned at the first entry in the directory. * The stream is positioned at the first entry in the directory.
...@@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); ...@@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
*/ */
s32_t SPIFFS_check(spiffs *fs); s32_t SPIFFS_check(spiffs *fs);
/**
* Returns number of total bytes available and number of used bytes.
* This is an estimation, and depends on if there a many files with little
* data or few files with much data.
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
* run. This indicates a power loss in midst of things. In worst case
* (repeated powerlosses in mending or gc) you might have to delete some files.
*
* @param fs the file system struct
* @param total total number of bytes in filesystem
* @param used used number of bytes in filesystem
*/
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
/** /**
* Check if EOF reached. * Check if EOF reached.
* @param fs the file system struct * @param fs the file system struct
...@@ -468,4 +493,8 @@ int myspiffs_check( void ); ...@@ -468,4 +493,8 @@ int myspiffs_check( void );
int myspiffs_rename( const char *old, const char *newname ); int myspiffs_rename( const char *old, const char *newname );
size_t myspiffs_size( int fd ); size_t myspiffs_size( int fd );
#if defined(__cplusplus)
}
#endif
#endif /* SPIFFS_H_ */ #endif /* SPIFFS_H_ */
...@@ -30,19 +30,19 @@ typedef uint8_t u8_t; ...@@ -30,19 +30,19 @@ typedef uint8_t u8_t;
// Set generic spiffs debug output call. // Set generic spiffs debug output call.
#ifndef SPIFFS_DGB #ifndef SPIFFS_DGB
#define SPIFFS_DBG(...) #define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for garbage collecting. // Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DGB #ifndef SPIFFS_GC_DGB
#define SPIFFS_GC_DBG(...) #define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for caching. // Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DGB #ifndef SPIFFS_CACHE_DGB
#define SPIFFS_CACHE_DBG(...) #define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Set spiffs debug output call for system consistency checks. // Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DGB #ifndef SPIFFS_CHECK_DGB
#define SPIFFS_CHECK_DBG(...) #define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#endif #endif
// Enable/disable API functions to determine exact number of bytes // Enable/disable API functions to determine exact number of bytes
...@@ -77,7 +77,7 @@ typedef uint8_t u8_t; ...@@ -77,7 +77,7 @@ typedef uint8_t u8_t;
// Define maximum number of gc runs to perform to reach desired free pages. // Define maximum number of gc runs to perform to reach desired free pages.
#ifndef SPIFFS_GC_MAX_RUNS #ifndef SPIFFS_GC_MAX_RUNS
#define SPIFFS_GC_MAX_RUNS 3 #define SPIFFS_GC_MAX_RUNS 5
#endif #endif
// Enable/disable statistics on gc. Debug/test purpose only. // Enable/disable statistics on gc. Debug/test purpose only.
......
...@@ -119,16 +119,21 @@ s32_t spiffs_gc_check( ...@@ -119,16 +119,21 @@ s32_t spiffs_gc_check(
spiffs *fs, spiffs *fs,
u32_t len) { u32_t len) {
s32_t res; s32_t res;
u32_t free_pages = s32_t free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
int tries = 0; int tries = 0;
if (fs->free_blocks > 3 && if (fs->free_blocks > 3 &&
len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) { (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
return SPIFFS_OK; return SPIFFS_OK;
} }
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
return SPIFFS_ERR_FULL;
}
//printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len); //printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len);
do { do {
...@@ -168,16 +173,22 @@ s32_t spiffs_gc_check( ...@@ -168,16 +173,22 @@ s32_t spiffs_gc_check(
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
free_pages = free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted; - fs->stats_p_allocated - fs->stats_p_deleted;
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
SPIFFS_GC_DBG("gc_check: finished\n");
free_pages =
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted;
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
res = SPIFFS_ERR_FULL;
}
//printf("gcing finished %i dirty, blocks %i free, %i pages free, %i tries, res %i\n", SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
// fs->stats_p_allocated + fs->stats_p_deleted, fs->stats_p_allocated + fs->stats_p_deleted,
// fs->free_blocks, free_pages, tries, res); fs->free_blocks, free_pages, tries, res);
return res; return res;
} }
......
...@@ -103,7 +103,11 @@ void SPIFFS_unmount(spiffs *fs) { ...@@ -103,7 +103,11 @@ void SPIFFS_unmount(spiffs *fs) {
} }
s32_t SPIFFS_errno(spiffs *fs) { s32_t SPIFFS_errno(spiffs *fs) {
return fs->errno; return fs->err_code;
}
void SPIFFS_clearerr(spiffs *fs) {
fs->err_code = SPIFFS_OK;
} }
s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) {
...@@ -314,8 +318,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { ...@@ -314,8 +318,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
#endif #endif
} }
SPIFFS_DBG("SPIFFS_write %i %04x offs:%i len %i\n", fh, fd->obj_id, offset, len);
#if SPIFFS_CACHE_WR #if SPIFFS_CACHE_WR
if ((fd->flags & SPIFFS_DIRECT) == 0) { if ((fd->flags & SPIFFS_DIRECT) == 0) {
if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
...@@ -328,12 +330,13 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { ...@@ -328,12 +330,13 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
{ {
// boundary violation, write back cache first and allocate new // boundary violation, write back cache first and allocate new
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:&04x, boundary viol, offs:%i size:%i\n", SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, boundary viol, offs:%i size:%i\n",
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
res = spiffs_hydro_write(fs, fd, res = spiffs_hydro_write(fs, fd,
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
fd->cache_page->offset, fd->cache_page->size); fd->cache_page->offset, fd->cache_page->size);
spiffs_cache_fd_release(fs, fd->cache_page); spiffs_cache_fd_release(fs, fd->cache_page);
SPIFFS_API_CHECK_RES(fs, res);
} else { } else {
// writing within cache // writing within cache
alloc_cpage = 0; alloc_cpage = 0;
...@@ -379,6 +382,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) { ...@@ -379,6 +382,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
fd->cache_page->offset, fd->cache_page->size); fd->cache_page->offset, fd->cache_page->size);
spiffs_cache_fd_release(fs, fd->cache_page); spiffs_cache_fd_release(fs, fd->cache_page);
SPIFFS_API_CHECK_RES(fs, res);
res = spiffs_hydro_write(fs, fd, buf, offset, len); res = spiffs_hydro_write(fs, fd, buf, offset, len);
SPIFFS_API_CHECK_RES(fs, res); SPIFFS_API_CHECK_RES(fs, res);
} }
...@@ -580,7 +584,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { ...@@ -580,7 +584,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
fd->cache_page->offset, fd->cache_page->size); fd->cache_page->offset, fd->cache_page->size);
if (res < SPIFFS_OK) { if (res < SPIFFS_OK) {
fs->errno = res; fs->err_code = res;
} }
spiffs_cache_fd_release(fs, fd->cache_page); spiffs_cache_fd_release(fs, fd->cache_page);
} }
...@@ -605,7 +609,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { ...@@ -605,7 +609,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
void SPIFFS_close(spiffs *fs, spiffs_file fh) { void SPIFFS_close(spiffs *fs, spiffs_file fh) {
if (!SPIFFS_CHECK_MOUNT(fs)) { if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->errno = SPIFFS_ERR_NOT_MOUNTED; fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return; return;
} }
SPIFFS_LOCK(fs); SPIFFS_LOCK(fs);
...@@ -661,7 +665,7 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { ...@@ -661,7 +665,7 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) { spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) {
(void)name; (void)name;
if (!SPIFFS_CHECK_MOUNT(fs)) { if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->errno = SPIFFS_ERR_NOT_MOUNTED; fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return 0; return 0;
} }
d->fs = fs; d->fs = fs;
...@@ -707,7 +711,7 @@ static s32_t spiffs_read_dir_v( ...@@ -707,7 +711,7 @@ static s32_t spiffs_read_dir_v(
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
if (!SPIFFS_CHECK_MOUNT(d->fs)) { if (!SPIFFS_CHECK_MOUNT(d->fs)) {
d->fs->errno = SPIFFS_ERR_NOT_MOUNTED; d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return 0; return 0;
} }
SPIFFS_LOCK(fs); SPIFFS_LOCK(fs);
...@@ -732,7 +736,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { ...@@ -732,7 +736,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
d->entry = entry + 1; d->entry = entry + 1;
ret = e; ret = e;
} else { } else {
d->fs->errno = res; d->fs->err_code = res;
} }
SPIFFS_UNLOCK(fs); SPIFFS_UNLOCK(fs);
return ret; return ret;
...@@ -760,6 +764,29 @@ s32_t SPIFFS_check(spiffs *fs) { ...@@ -760,6 +764,29 @@ s32_t SPIFFS_check(spiffs *fs) {
return res; return res;
} }
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);
u32_t blocks = fs->block_count;
u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);
u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);
u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page
if (total) {
*total = total_data_pages * data_page_size;
}
if (used) {
*used = fs->stats_p_allocated * data_page_size;
}
SPIFFS_UNLOCK(fs);
return res;
}
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs); SPIFFS_LOCK(fs);
...@@ -878,11 +905,14 @@ s32_t SPIFFS_vis(spiffs *fs) { ...@@ -878,11 +905,14 @@ s32_t SPIFFS_vis(spiffs *fs) {
} // per block } // per block
spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count); spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count);
spiffs_printf("last_errno: %i\n", fs->errno); spiffs_printf("last_errno: %i\n", fs->err_code);
spiffs_printf("blocks: %i\n", fs->block_count); spiffs_printf("blocks: %i\n", fs->block_count);
spiffs_printf("free_blocks: %i\n", fs->free_blocks); spiffs_printf("free_blocks: %i\n", fs->free_blocks);
spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated); spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated);
spiffs_printf("page_delet: %i\n", fs->stats_p_deleted); spiffs_printf("page_delet: %i\n", fs->stats_p_deleted);
u32_t total, used;
SPIFFS_info(fs, &total, &used);
spiffs_printf("used: %i of %i\n", used, total);
SPIFFS_UNLOCK(fs); SPIFFS_UNLOCK(fs);
return res; return res;
......
...@@ -614,7 +614,7 @@ s32_t spiffs_object_create( ...@@ -614,7 +614,7 @@ s32_t spiffs_object_create(
spiffs_page_object_ix_header oix_hdr; spiffs_page_object_ix_header oix_hdr;
int entry; int entry;
res = spiffs_gc_check(fs, 0); res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
obj_id |= SPIFFS_OBJ_ID_IX_FLAG; obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
...@@ -811,7 +811,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { ...@@ -811,7 +811,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
u32_t written = 0; u32_t written = 0;
res = spiffs_gc_check(fs, len); SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
if (offset > fd->size) {
SPIFFS_DBG("append: offset reversed to size\n");
offset = fd->size;
}
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
if (res != SPIFFS_OK) {
SPIFFS_DBG("append: gc check fail %i\n", res);
}
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
...@@ -912,7 +922,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { ...@@ -912,7 +922,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
} }
SPIFFS_DBG("append: %04x found object index at page %04x\n", fd->obj_id, pix); SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size);
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
...@@ -1003,8 +1013,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { ...@@ -1003,8 +1013,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// update size in object header index page // update size in object header index page
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
, offset+written, new_objix_hdr_page, 0, written); , offset+written, new_objix_hdr_page, 0, written, res2);
SPIFFS_CHECK_RES(res2); SPIFFS_CHECK_RES(res2);
} else { } else {
// wrote within object index header page // wrote within object index header page
...@@ -1042,7 +1052,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { ...@@ -1042,7 +1052,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
u32_t written = 0; u32_t written = 0;
res = spiffs_gc_check(fs, len); res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
...@@ -1308,7 +1318,7 @@ s32_t spiffs_object_truncate( ...@@ -1308,7 +1318,7 @@ s32_t spiffs_object_truncate(
s32_t res = SPIFFS_OK; s32_t res = SPIFFS_OK;
spiffs *fs = fd->fs; spiffs *fs = fd->fs;
res = spiffs_gc_check(fs, 0); res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs));
SPIFFS_CHECK_RES(res); SPIFFS_CHECK_RES(res);
spiffs_page_ix objix_pix = fd->objix_hdr_pix; spiffs_page_ix objix_pix = fd->objix_hdr_pix;
...@@ -1386,13 +1396,26 @@ s32_t spiffs_object_truncate( ...@@ -1386,13 +1396,26 @@ s32_t spiffs_object_truncate(
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
} }
SPIFFS_DBG("truncate: got data pix %04x\n", data_pix);
if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) {
// delete full data page // delete full data page
res = spiffs_page_data_check(fs, fd, data_pix, data_spix); res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
if (res != SPIFFS_OK) break; if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
SPIFFS_DBG("truncate: err validating data pix %i\n", res);
break;
}
if (res == SPIFFS_OK) {
res = spiffs_page_delete(fs, data_pix);
if (res != SPIFFS_OK) {
SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
break;
}
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
res = SPIFFS_OK;
}
res = spiffs_page_delete(fs, data_pix);
if (res != SPIFFS_OK) break;
// update current size // update current size
if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) { if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
cur_size -= SPIFFS_DATA_PAGE_SIZE(fs); cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
......
...@@ -247,19 +247,19 @@ ...@@ -247,19 +247,19 @@
#define SPIFFS_API_CHECK_MOUNT(fs) \ #define SPIFFS_API_CHECK_MOUNT(fs) \
if (!SPIFFS_CHECK_MOUNT((fs))) { \ if (!SPIFFS_CHECK_MOUNT((fs))) { \
(fs)->errno = SPIFFS_ERR_NOT_MOUNTED; \ (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
return -1; \ return -1; \
} }
#define SPIFFS_API_CHECK_RES(fs, res) \ #define SPIFFS_API_CHECK_RES(fs, res) \
if ((res) < SPIFFS_OK) { \ if ((res) < SPIFFS_OK) { \
(fs)->errno = (res); \ (fs)->err_code = (res); \
return -1; \ return -1; \
} }
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ #define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
if ((res) < SPIFFS_OK) { \ if ((res) < SPIFFS_OK) { \
(fs)->errno = (res); \ (fs)->err_code = (res); \
SPIFFS_UNLOCK(fs); \ SPIFFS_UNLOCK(fs); \
return -1; \ return -1; \
} }
......
#include "testrunner.h"
#include <stdlib.h>
int main(int argc, char **args) {
run_tests(argc, args);
exit(EXIT_SUCCESS);
}
/*
* params_test.h
*
* Created on: May 26, 2013
* Author: petera
*/
#ifndef PARAMS_TEST_H_
#define PARAMS_TEST_H_
// total emulated spi flash size
#define PHYS_FLASH_SIZE (16*1024*1024)
// spiffs file system size
#define SPIFFS_FLASH_SIZE (2*1024*1024)
// spiffs file system offset in emulated spi flash
#define SPIFFS_PHYS_ADDR (4*1024*1024)
#define SECTOR_SIZE 65536
#define LOG_BLOCK (SECTOR_SIZE*2)
#define LOG_PAGE (SECTOR_SIZE/256)
#define FD_BUF_SIZE 64*6
#define CACHE_BUF_SIZE (LOG_PAGE + 32)*8
#define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__);
typedef signed int s32_t;
typedef unsigned int u32_t;
typedef signed short s16_t;
typedef unsigned short u16_t;
typedef signed char s8_t;
typedef unsigned char u8_t;
void real_assert(int c, const char *n, const char *file, int l);
#endif /* PARAMS_TEST_H_ */
/*
* test_bugreports.c
*
* Created on: Mar 8, 2015
* Author: petera
*/
#include "testrunner.h"
#include "test_spiffs.h"
#include "spiffs_nucleus.h"
#include "spiffs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
SUITE(bug_tests)
void setup() {
_setup_test_only();
}
void teardown() {
_teardown();
}
TEST(nodemcu_full_fs_1) {
fs_reset_specific(0, 4096*20, 4096, 4096, 256);
int res;
spiffs_file fd;
printf(" fill up system by writing one byte a lot\n");
fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
int i;
spiffs_stat s;
res = SPIFFS_OK;
for (i = 0; i < 100*1000; i++) {
u8_t buf = 'x';
res = SPIFFS_write(FS, fd, &buf, 1);
}
int errno = SPIFFS_errno(FS);
int res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == SPIFFS_OK);
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(errno == SPIFFS_ERR_FULL);
SPIFFS_close(FS, fd);
printf(" remove big file\n");
res = SPIFFS_remove(FS, "test1.txt");
printf("res:%i errno:%i\n",res, SPIFFS_errno(FS));
TEST_CHECK(res == SPIFFS_OK);
res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == -1);
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED);
res2 = SPIFFS_stat(FS, "test1.txt", &s);
TEST_CHECK(res2 == -1);
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND);
printf(" create small file\n");
fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
res = SPIFFS_OK;
for (i = 0; res >= 0 && i < 1000; i++) {
u8_t buf = 'x';
res = SPIFFS_write(FS, fd, &buf, 1);
}
TEST_CHECK(res >= SPIFFS_OK);
res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == SPIFFS_OK);
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(s.size == 1000);
SPIFFS_close(FS, fd);
return TEST_RES_OK;
} TEST_END(nodemcu_full_fs_1)
TEST(nodemcu_full_fs_2) {
fs_reset_specific(0, 4096*22, 4096, 4096, 256);
int res;
spiffs_file fd;
printf(" fill up system by writing one byte a lot\n");
fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
int i;
spiffs_stat s;
res = SPIFFS_OK;
for (i = 0; i < 100*1000; i++) {
u8_t buf = 'x';
res = SPIFFS_write(FS, fd, &buf, 1);
}
int errno = SPIFFS_errno(FS);
int res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == SPIFFS_OK);
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(errno == SPIFFS_ERR_FULL);
SPIFFS_close(FS, fd);
res2 = SPIFFS_stat(FS, "test1.txt", &s);
TEST_CHECK(res2 == SPIFFS_OK);
SPIFFS_clearerr(FS);
printf(" create small file\n");
fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
TEST_CHECK(fd > 0);
for (i = 0; i < 1000; i++) {
u8_t buf = 'x';
res = SPIFFS_write(FS, fd, &buf, 1);
}
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL);
res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == SPIFFS_OK);
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(s.size == 0);
SPIFFS_clearerr(FS);
printf(" remove files\n");
res = SPIFFS_remove(FS, "test1.txt");
TEST_CHECK(res == SPIFFS_OK);
res = SPIFFS_remove(FS, "test2.txt");
TEST_CHECK(res == SPIFFS_OK);
printf(" create medium file\n");
fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
TEST_CHECK(fd > 0);
for (i = 0; i < 20*1000; i++) {
u8_t buf = 'x';
res = SPIFFS_write(FS, fd, &buf, 1);
}
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
res2 = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res2 == SPIFFS_OK);
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(s.size == 20*1000);
return TEST_RES_OK;
} TEST_END(nodemcu_full_fs_2)
SUITE_END(bug_tests)
/*
* test_dev.c
*
* Created on: Jul 14, 2013
* Author: petera
*/
#include "testrunner.h"
#include "test_spiffs.h"
#include "spiffs_nucleus.h"
#include "spiffs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
SUITE(check_tests)
void setup() {
_setup();
}
void teardown() {
_teardown();
}
TEST(evil_write) {
fs_set_validate_flashing(0);
printf("writing corruption to block 1 data range (leaving lu intact)\n");
u32_t data_range = SPIFFS_CFG_LOG_BLOCK_SZ(FS) -
SPIFFS_CFG_LOG_PAGE_SZ(FS) * (SPIFFS_OBJ_LOOKUP_PAGES(FS));
u8_t *corruption = malloc(data_range);
memrand(corruption, data_range);
u32_t addr = 0 * SPIFFS_CFG_LOG_PAGE_SZ(FS) * SPIFFS_OBJ_LOOKUP_PAGES(FS);
area_write(addr, corruption, data_range);
free(corruption);
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
printf("CHECK1-----------------\n");
SPIFFS_check(FS);
printf("CHECK2-----------------\n");
SPIFFS_check(FS);
printf("CHECK3-----------------\n");
SPIFFS_check(FS);
res = test_create_and_write_file("file2", size, size);
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(evil_write)
TEST(lu_check1) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index 1
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix);
TEST_CHECK(res >= 0);
// reset lu entry to being erased, but keep page data
spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED;
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry*sizeof(spiffs_obj_id);
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
return TEST_RES_OK;
} TEST_END(lu_check1)
TEST(page_cons1) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify object index, find object index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
// set object index entry 2 to a bad page
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 0 * sizeof(spiffs_page_ix);
spiffs_page_ix bad_pix_ref = 0x55;
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
area_write(addr+2, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
// delete all cache
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(page_cons1)
TEST(page_cons2) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify object index, find object index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
// find data page span index 0
spiffs_page_ix dpix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &dpix);
TEST_CHECK(res >= 0);
// set object index entry 1+2 to a data page 0
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix);
spiffs_page_ix bad_pix_ref = dpix;
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
// delete all cache
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(page_cons2)
TEST(page_cons3) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify object index, find object index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
// set object index entry 1+2 lookup page
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix);
spiffs_page_ix bad_pix_ref = SPIFFS_PAGES_PER_BLOCK(FS) * (*FS.block_count - 2);
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
// delete all cache
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(page_cons3)
TEST(page_cons_final) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify page header, make unfinalized
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix);
TEST_CHECK(res >= 0);
// set page span ix 1 as unfinalized
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags);
u8_t flags;
area_read(addr, (u8_t*)&flags, 1);
flags |= SPIFFS_PH_FLAG_FINAL;
area_write(addr, (u8_t*)&flags, 1);
// delete all cache
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(page_cons_final)
TEST(index_cons1) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
printf(" deleting lu entry pix %04x\n", pix);
// reset lu entry to being erased, but keep page data
spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED;
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(index_cons1)
TEST(index_cons2) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
printf(" writing lu entry for index page, ix %04x, as data page\n", pix);
spiffs_obj_id obj_id = 0x1234;
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(index_cons2)
TEST(index_cons3) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index header
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
printf(" setting lu entry pix %04x to another index page\n", pix);
// reset lu entry to being erased, but keep page data
spiffs_obj_id obj_id = 1234 | SPIFFS_OBJ_ID_IX_FLAG;
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
return TEST_RES_OK;
} TEST_END(index_cons3)
TEST(index_cons4) {
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
int res = test_create_and_write_file("file", size, size);
TEST_CHECK(res >= 0);
res = read_and_verify("file");
TEST_CHECK(res >= 0);
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
// modify lu entry data page index header, flags
spiffs_page_ix pix;
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
TEST_CHECK(res >= 0);
printf(" cue objix hdr deletion in page %04x\n", pix);
// set flags as deleting ix header
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags);
u8_t flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE);
area_write(addr, (u8_t*)&flags, 1);
#if SPIFFS_CACHE
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
SPIFFS_check(FS);
return TEST_RES_OK;
} TEST_END(index_cons4)
SUITE_END(check_tests)
/*
* test_dev.c
*
* Created on: Jul 14, 2013
* Author: petera
*/
#include "testrunner.h"
#include "test_spiffs.h"
#include "spiffs_nucleus.h"
#include "spiffs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
SUITE(dev_tests)
void setup() {
_setup();
}
void teardown() {
_teardown();
}
TEST(interrupted_write) {
char *name = "interrupt";
char *name2 = "interrupt2";
int res;
spiffs_file fd;
const u32_t sz = SPIFFS_CFG_LOG_PAGE_SZ(FS)*8;
u8_t *buf = malloc(sz);
memrand(buf, sz);
printf(" create reference file\n");
fd = SPIFFS_open(FS, name, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
clear_flash_ops_log();
res = SPIFFS_write(FS, fd, buf, sz);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
u32_t written = get_flash_ops_log_write_bytes();
printf(" written bytes: %i\n", written);
printf(" create error file\n");
fd = SPIFFS_open(FS, name2, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
clear_flash_ops_log();
invoke_error_after_write_bytes(written/2, 0);
res = SPIFFS_write(FS, fd, buf, sz);
SPIFFS_close(FS, fd);
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_TEST);
clear_flash_ops_log();
#if SPIFFS_CACHE
// delete all cache
spiffs_cache *cache = spiffs_get_cache(FS);
cache->cpage_use_map = 0;
#endif
printf(" read error file\n");
fd = SPIFFS_open(FS, name2, SPIFFS_RDONLY, 0);
TEST_CHECK(fd > 0);
spiffs_stat s;
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
printf(" file size: %i\n", s.size);
if (s.size > 0) {
u8_t *buf2 = malloc(s.size);
res = SPIFFS_read(FS, fd, buf2, s.size);
TEST_CHECK(res >= 0);
u32_t ix = 0;
for (ix = 0; ix < s.size; ix += 16) {
int i;
printf(" ");
for (i = 0; i < 16; i++) {
printf("%02x", buf[ix+i]);
}
printf(" ");
for (i = 0; i < 16; i++) {
printf("%02x", buf2[ix+i]);
}
printf("\n");
}
free(buf2);
}
SPIFFS_close(FS, fd);
printf(" FS check\n");
SPIFFS_check(FS);
printf(" read error file again\n");
fd = SPIFFS_open(FS, name2, SPIFFS_APPEND | SPIFFS_RDWR, 0);
TEST_CHECK(fd > 0);
res = SPIFFS_fstat(FS, fd, &s);
TEST_CHECK(res >= 0);
printf(" file size: %i\n", s.size);
printf(" write file\n");
res = SPIFFS_write(FS, fd, buf, sz);
TEST_CHECK(res >= 0);
SPIFFS_close(FS, fd);
free(buf);
return TEST_RES_OK;
} TEST_END(interrupted_write)
SUITE_END(dev_tests)
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment