Browse Source

New version of spiffs (#2172)

Philip Gladstone 6 years ago
parent
commit
11c47fa17a

+ 1 - 1
app/spiffs/LICENSE

@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976<at>gmail.com)
+Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976<at>gmail.com)
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in

+ 1 - 1
app/spiffs/spiffs.c

@@ -14,7 +14,7 @@ spiffs fs;
 static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
 static u8_t spiffs_fds[sizeof(spiffs_fd) * SPIFFS_MAX_OPEN_FILES];
 #if SPIFFS_CACHE
-static u8_t myspiffs_cache[(LOG_PAGE_SIZE+32)*2];
+static u8_t myspiffs_cache[20 + (LOG_PAGE_SIZE+20)*4];
 #endif
 
 static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {

+ 3 - 0
app/spiffs/spiffs.h

@@ -60,6 +60,9 @@ extern "C" {
 #define SPIFFS_ERR_IX_MAP_MAPPED        -10038
 #define SPIFFS_ERR_IX_MAP_BAD_RANGE     -10039
 
+#define SPIFFS_ERR_SEEK_BOUNDS          -10040
+
+
 #define SPIFFS_ERR_INTERNAL             -10050
 
 #define SPIFFS_ERR_TEST                 -10100

+ 15 - 10
app/spiffs/spiffs_cache.c

@@ -20,7 +20,7 @@ static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix)
     if ((cache->cpage_use_map & (1<<i)) &&
         (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
         cp->pix == pix ) {
-      SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix);
+      //SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix);
       cp->last_access = cache->last_access;
       return cp;
     }
@@ -39,17 +39,20 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
         (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
         (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
       u8_t *mem =  spiffs_get_cache_page(fs, cache, ix);
+      SPIFFS_CACHE_DBG("CACHE_FREE: write cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
       res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
     }
 
-    cp->flags = 0;
-    cache->cpage_use_map &= ~(1 << ix);
-
+#if SPIFFS_CACHE_WR
     if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
       SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id);
-    } else {
+    } else
+#endif
+    {
       SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
     }
+    cache->cpage_use_map &= ~(1 << ix);
+    cp->flags = 0;
   }
 
   return res;
@@ -98,7 +101,7 @@ static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
       spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
       cache->cpage_use_map |= (1<<i);
       cp->last_access = cache->last_access;
-      SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i);
+      //SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i);
       return cp;
     }
   }
@@ -136,7 +139,7 @@ s32_t spiffs_phys_rd(
 #endif
     cp->last_access = cache->last_access;
     u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);
-    memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
+    _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
   } else {
     if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
       // for second layer lookup functions, we do not cache in order to prevent shredding
@@ -153,6 +156,7 @@ s32_t spiffs_phys_rd(
     if (cp) {
       cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
       cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
+      SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for pix "_SPIPRIpg "\n", cp->ix, cp->pix);
 
       s32_t res2 = SPIFFS_HAL_READ(fs,
           addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
@@ -163,7 +167,7 @@ s32_t spiffs_phys_rd(
         res = res2;
       }
       u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);
-      memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
+      _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
     } else {
       // this will never happen, last resort for sake of symmetry
       s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
@@ -201,7 +205,7 @@ s32_t spiffs_phys_wr(
     }
 
     u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);
-    memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
+    _SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
 
     cache->last_access++;
     cp->last_access = cache->last_access;
@@ -256,6 +260,7 @@ spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
   cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
   cp->obj_id = fd->obj_id;
   fd->cache_page = cp;
+  SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for fd "_SPIPRIfd ":"_SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id);
   return cp;
 }
 
@@ -299,7 +304,7 @@ void spiffs_cache_init(spiffs *fs) {
 
   cache.cpage_use_map = 0xffffffff;
   cache.cpage_use_mask = cache_mask;
-  memcpy(fs->cache, &cache, sizeof(spiffs_cache));
+  _SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache));
 
   spiffs_cache *c = spiffs_get_cache(fs);
 

+ 18 - 5
app/spiffs/spiffs_check.c

@@ -161,11 +161,17 @@ static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
     return SPIFFS_OK;
   }
   SPIFFS_CHECK_RES(res);
-  u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
+  u8_t flags = 0xff;
+#if SPIFFS_NO_BLIND_WRITES
+  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
+      0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
+      sizeof(flags), &flags);
+  SPIFFS_CHECK_RES(res);
+#endif
+  flags &= ~SPIFFS_PH_FLAG_IXDELE;
   res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
       0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
-      sizeof(u8_t),
-      (u8_t *)&flags);
+      sizeof(flags), &flags);
   return res;
 }
 
@@ -423,10 +429,17 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
           // just finalize
           SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
           CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
-          u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
+          u8_t flags = 0xff;
+#if SPIFFS_NO_BLIND_WRITES
+          res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
+              0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
+              sizeof(flags), &flags);
+          SPIFFS_CHECK_RES(res);
+#endif
+          flags &= ~SPIFFS_PH_FLAG_FINAL;
           res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
               0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
-              sizeof(u8_t), (u8_t*)&flags);
+              sizeof(flags), &flags);
         }
       }
     }

+ 15 - 0
app/spiffs/spiffs_config.h

@@ -34,6 +34,10 @@
 #ifndef SPIFFS_CHECK_DBG
 #define SPIFFS_CHECK_DBG(...) //dbg_printf(__VA_ARGS__)
 #endif
+// Set spiffs debug output call for all api invocations.
+#ifndef SPIFFS_API_DBG
+#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
+#endif
 
 // Defines spiffs debug print formatters
 // some general signed number
@@ -303,6 +307,17 @@
 #define SPIFFS_IX_MAP                         0
 #endif
 
+// By default SPIFFS in some cases relies on the property of NOR flash that bits
+// cannot be set from 0 to 1 by writing and that controllers will ignore such
+// bit changes. This results in fewer reads as SPIFFS can in some cases perform
+// blind writes, with all bits set to 1 and only those it needs reset set to 0.
+// Most of the chips and controllers allow this behavior, so the default is to
+// use this technique. If your controller is one of the rare ones that don't,
+// turn this option on and SPIFFS will perform a read-modify-write instead.
+#ifndef SPIFFS_NO_BLIND_WRITES
+#define SPIFFS_NO_BLIND_WRITES                0
+#endif
+
 // Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
 // in the api. This function will visualize all filesystem using given printf
 // function.

+ 1 - 1
app/spiffs/spiffs_gc.c

@@ -294,7 +294,7 @@ s32_t spiffs_gc_find_candidate(
 
     // calculate score and insert into candidate table
     // stoneage sort, but probably not so many blocks
-    if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
+    if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
       // read erase count
       spiffs_obj_id erase_count;
       res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,

+ 70 - 24
app/spiffs/spiffs_hydrogen.c

@@ -8,14 +8,6 @@
 #include "spiffs.h"
 #include "spiffs_nucleus.h"
 
-#if SPIFFS_FILEHDL_OFFSET
-#define SPIFFS_FH_OFFS(fs, fh)   ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
-#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
-#else
-#define SPIFFS_FH_OFFS(fs, fh)   (fh)
-#define SPIFFS_FH_UNOFFS(fs, fh) (fh)
-#endif
-
 #if SPIFFS_CACHE == 1
 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
 #endif
@@ -69,6 +61,7 @@ s32_t SPIFFS_format(spiffs *fs) {
 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
 
 s32_t SPIFFS_probe_fs(spiffs_config *config) {
+  SPIFFS_API_DBG("%s\n", __func__);
   s32_t res = spiffs_probe(config);
   return res;
 }
@@ -79,11 +72,23 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
     u8_t *fd_space, u32_t fd_space_size,
     void *cache, u32_t cache_size,
     spiffs_check_callback check_cb_f) {
+  SPIFFS_API_DBG("%s "
+                 " sz:"_SPIPRIi " logpgsz:"_SPIPRIi " logblksz:"_SPIPRIi " perasz:"_SPIPRIi
+                 " addr:"_SPIPRIad
+                 " fdsz:"_SPIPRIi " cachesz:"_SPIPRIi
+                 "\n",
+                 __func__,
+                 SPIFFS_CFG_PHYS_SZ(fs),
+                 SPIFFS_CFG_LOG_PAGE_SZ(fs),
+                 SPIFFS_CFG_LOG_BLOCK_SZ(fs),
+                 SPIFFS_CFG_PHYS_ERASE_SZ(fs),
+                 SPIFFS_CFG_PHYS_ADDR(fs),
+                 fd_space_size, cache_size);
   void *user_data;
   SPIFFS_LOCK(fs);
   user_data = fs->user_data;
   memset(fs, 0, sizeof(spiffs));
-  memcpy(&fs->cfg, config, sizeof(spiffs_config));
+  _SPIFFS_MEMCPY(&fs->cfg, config, sizeof(spiffs_config));
   fs->user_data = user_data;
   fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
   fs->work = &work[0];
@@ -148,6 +153,7 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
 }
 
 void SPIFFS_unmount(spiffs *fs) {
+  SPIFFS_API_DBG("%s\n", __func__);
   if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;
   SPIFFS_LOCK(fs);
   u32_t i;
@@ -171,10 +177,12 @@ s32_t SPIFFS_errno(spiffs *fs) {
 }
 
 void SPIFFS_clearerr(spiffs *fs) {
+  SPIFFS_API_DBG("%s\n", __func__);
   fs->err_code = SPIFFS_OK;
 }
 
 s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
+  SPIFFS_API_DBG("%s '%s'\n", __func__, path);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)path; (void)mode;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -199,6 +207,7 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
 }
 
 spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {
+  SPIFFS_API_DBG("%s '%s' "_SPIPRIfl "\n", __func__, path, flags);
   (void)mode;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -279,6 +288,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
 }
 
 spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {
+  SPIFFS_API_DBG("%s '%s':"_SPIPRIid " "_SPIPRIfl "\n", __func__, e->name, e->obj_id, flags);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
   SPIFFS_LOCK(fs);
@@ -311,6 +321,7 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl
 }
 
 spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {
+  SPIFFS_API_DBG("%s "_SPIPRIpg " "_SPIPRIfl "\n", __func__, page_ix, flags);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
   SPIFFS_LOCK(fs);
@@ -411,6 +422,7 @@ static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len)
 }
 
 s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
   s32_t res = spiffs_hydro_read(fs, fh, buf, len);
   if (res == SPIFFS_ERR_END_OF_OBJECT) {
     res = 0;
@@ -444,6 +456,7 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs
 #endif // !SPIFFS_READ_ONLY
 
 s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)fh; (void)buf; (void)len;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -468,7 +481,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
   if ((fd->flags & SPIFFS_O_APPEND)) {
     fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
   }
-
   offset = fd->fdoffset;
 
 #if SPIFFS_CACHE_WR
@@ -502,7 +514,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
             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
-          SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+          SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
               fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
           res = spiffs_hydro_write(fs, fd,
               spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
@@ -520,19 +532,30 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
         if (fd->cache_page) {
           fd->cache_page->offset = offset;
           fd->cache_page->size = 0;
-          SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid"\n",
+          SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid"\n",
               fd->cache_page->ix, fd->file_nbr, fd->obj_id);
         }
       }
 
       if (fd->cache_page) {
         u32_t offset_in_cpage = offset - fd->cache_page->offset;
-        SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n",
+        SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n",
             fd->cache_page->ix, fd->file_nbr, fd->obj_id,
             offset, offset_in_cpage, len);
         spiffs_cache *cache = spiffs_get_cache(fs);
         u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
-        memcpy(&cpage_data[offset_in_cpage], buf, len);
+#ifdef _SPIFFS_TEST
+        {
+          intptr_t __a1 = (u8_t*)&cpage_data[offset_in_cpage]-(u8_t*)cache;
+          intptr_t __a2 = (u8_t*)&cpage_data[offset_in_cpage]+len-(u8_t*)cache;
+          intptr_t __b = sizeof(spiffs_cache) + cache->cpage_count * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
+          if (__a1 > __b || __a2 > __b) {
+            printf("FATAL OOB: CACHE_WR: memcpy to cache buffer ixs:%4ld..%4ld of %4ld\n", __a1, __a2, __b);
+            ERREXIT();
+          }
+        }
+#endif
+        _SPIFFS_MEMCPY(&cpage_data[offset_in_cpage], buf, len);
         fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
         fd->fdoffset += len;
         SPIFFS_UNLOCK(fs);
@@ -548,7 +571,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
       // big write, no need to cache it - but first check if there is a cached write already
       if (fd->cache_page) {
         // write back cache first
-        SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+        SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
             fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
         res = spiffs_hydro_write(fs, fd,
             spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
@@ -572,6 +595,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
 }
 
 s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " %s\n", __func__, fh, offs, (const char* []){"SET","CUR","END","???"}[MIN(whence,3)]);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
   SPIFFS_LOCK(fs);
@@ -586,24 +610,26 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
   spiffs_fflush_cache(fs, fh);
 #endif
 
-  s32_t fileSize = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
+  s32_t file_size = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
 
   switch (whence) {
   case SPIFFS_SEEK_CUR:
     offs = fd->fdoffset+offs;
     break;
   case SPIFFS_SEEK_END:
-    offs = fileSize + offs;
+    offs = file_size + offs;
     break;
   }
-
-  if ((offs > fileSize)) {
-    fd->fdoffset = fileSize;
+  if (offs < 0) {
+    SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_SEEK_BOUNDS);
+  }
+  if (offs > file_size) {
+    fd->fdoffset = file_size;
     res = SPIFFS_ERR_END_OF_OBJECT;
   }
   SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
 
-  spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs);
+  spiffs_span_ix data_spix = (offs > 0 ? (offs-1) : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
   spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
   if (fd->cursor_objix_spix != objix_spix) {
     spiffs_page_ix pix;
@@ -621,6 +647,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
 }
 
 s32_t SPIFFS_remove(spiffs *fs, const char *path) {
+  SPIFFS_API_DBG("%s '%s'\n", __func__, path);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)path;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -663,6 +690,7 @@ s32_t SPIFFS_remove(spiffs *fs, const char *path) {
 }
 
 s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)fh;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -716,13 +744,14 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi
   s->pix = pix;
   strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);
 #if SPIFFS_OBJ_META_LEN
-  memcpy(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
+  _SPIFFS_MEMCPY(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
 #endif
 
   return res;
 }
 
 s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {
+  SPIFFS_API_DBG("%s '%s'\n", __func__, path);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
   if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
@@ -744,6 +773,7 @@ s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {
 }
 
 s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
   SPIFFS_LOCK(fs);
@@ -785,7 +815,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
       fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
     }
     if (fd->cache_page) {
-      SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
+      SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
           fd->cache_page->ix, fd->file_nbr,  fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
       res = spiffs_hydro_write(fs, fd,
           spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
@@ -803,6 +833,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
 #endif
 
 s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   (void)fh;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -819,6 +850,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
 }
 
 s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
 
@@ -839,6 +871,7 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
 }
 
 s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {
+  SPIFFS_API_DBG("%s %s %s\n", __func__, old_path, new_path);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)old_path; (void)new_path;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -965,6 +998,7 @@ s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {
 #endif // SPIFFS_OBJ_META_LEN
 
 spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
+  SPIFFS_API_DBG("%s\n", __func__);
   (void)name;
 
   if (!SPIFFS_CHECK_CFG((fs))) {
@@ -1013,7 +1047,7 @@ static s32_t spiffs_read_dir_v(
     e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
     e->pix = pix;
 #if SPIFFS_OBJ_META_LEN
-  memcpy(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
+    _SPIFFS_MEMCPY(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
 #endif
     return SPIFFS_OK;
   }
@@ -1021,6 +1055,7 @@ static s32_t spiffs_read_dir_v(
 }
 
 struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
+  SPIFFS_API_DBG("%s\n", __func__);
   if (!SPIFFS_CHECK_MOUNT(d->fs)) {
     d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
     return 0;
@@ -1055,12 +1090,14 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
 }
 
 s32_t SPIFFS_closedir(spiffs_DIR *d) {
+  SPIFFS_API_DBG("%s\n", __func__);
   SPIFFS_API_CHECK_CFG(d->fs);
   SPIFFS_API_CHECK_MOUNT(d->fs);
   return 0;
 }
 
 s32_t SPIFFS_check(spiffs *fs) {
+  SPIFFS_API_DBG("%s\n", __func__);
 #if SPIFFS_READ_ONLY
   (void)fs;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -1084,6 +1121,7 @@ s32_t SPIFFS_check(spiffs *fs) {
 }
 
 s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
+  SPIFFS_API_DBG("%s\n", __func__);
   s32_t res = SPIFFS_OK;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -1108,6 +1146,7 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
 }
 
 s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
+  SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, max_free_pages);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)max_free_pages;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -1127,6 +1166,7 @@ s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
 
 
 s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
+  SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, size);
 #if SPIFFS_READ_ONLY
   (void)fs; (void)size;
   return SPIFFS_ERR_RO_NOT_IMPL;
@@ -1145,6 +1185,7 @@ s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
 }
 
 s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   s32_t res;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -1168,6 +1209,7 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
 }
 
 s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   s32_t res;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -1191,6 +1233,7 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
 }
 
 s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {
+  SPIFFS_API_DBG("%s\n", __func__);
   SPIFFS_LOCK(fs);
   fs->file_cb_f = cb_func;
   SPIFFS_UNLOCK(fs);
@@ -1201,6 +1244,7 @@ s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {
 
 s32_t SPIFFS_ix_map(spiffs *fs,  spiffs_file fh, spiffs_ix_map *map,
     u32_t offset, u32_t len, spiffs_page_ix *map_buf) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " "_SPIPRIi "\n", __func__, fh, offset, len);
   s32_t res;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -1233,6 +1277,7 @@ s32_t SPIFFS_ix_map(spiffs *fs,  spiffs_file fh, spiffs_ix_map *map,
 }
 
 s32_t SPIFFS_ix_unmap(spiffs *fs,  spiffs_file fh) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
   s32_t res;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);
@@ -1255,6 +1300,7 @@ s32_t SPIFFS_ix_unmap(spiffs *fs,  spiffs_file fh) {
 }
 
 s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {
+  SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, offset);
   s32_t res = SPIFFS_OK;
   SPIFFS_API_CHECK_CFG(fs);
   SPIFFS_API_CHECK_MOUNT(fs);

+ 59 - 22
app/spiffs/spiffs_nucleus.c

@@ -270,7 +270,7 @@ s32_t spiffs_probe(
   s32_t res;
   u32_t paddr;
   spiffs dummy_fs; // create a dummy fs struct just to be able to use macros
-  memcpy(&dummy_fs.cfg, cfg, sizeof(spiffs_config));
+  _SPIFFS_MEMCPY(&dummy_fs.cfg, cfg, sizeof(spiffs_config));
   dummy_fs.block_count = 0;
 
   // Read three magics, as one block may be in an aborted erase state.
@@ -713,8 +713,8 @@ s32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u
   s32_t res;
   spiffs_ix_map *map = fd->ix_map;
   spiffs_ix_map_populate_state state;
-  vec_entry_start = MIN((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_start);
-  vec_entry_end = MAX((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_end);
+  vec_entry_start = MIN((u32_t)(map->end_spix - map->start_spix), vec_entry_start);
+  vec_entry_end = MAX((u32_t)(map->end_spix - map->start_spix), vec_entry_end);
   if (vec_entry_start > vec_entry_end) {
     return SPIFFS_ERR_IX_MAP_BAD_RANGE;
   }
@@ -877,8 +877,6 @@ s32_t spiffs_page_delete(
     spiffs *fs,
     spiffs_page_ix pix) {
   s32_t res;
-  spiffs_page_header hdr;
-  hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);
   // mark deleted entry in source object lookup
   spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;
   res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,
@@ -892,11 +890,18 @@ s32_t spiffs_page_delete(
   fs->stats_p_allocated--;
 
   // mark deleted in source page
+  u8_t flags = 0xff;
+#if SPIFFS_NO_BLIND_WRITES
+  res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
+      0, SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
+      sizeof(flags), &flags);
+  SPIFFS_CHECK_RES(res);
+#endif
+  flags &= ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);
   res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,
       0,
       SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
-      sizeof(u8_t),
-      (u8_t *)&hdr.flags);
+      sizeof(flags), &flags);
 
   return res;
 }
@@ -942,7 +947,7 @@ s32_t spiffs_object_create(
   strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN);
 #if SPIFFS_OBJ_META_LEN
   if (meta) {
-    memcpy(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);
+    _SPIFFS_MEMCPY(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);
   } else {
     memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN);
   }
@@ -1006,7 +1011,7 @@ s32_t spiffs_object_update_index_hdr(
   }
 #if SPIFFS_OBJ_META_LEN
   if (meta) {
-    memcpy(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);
+    _SPIFFS_MEMCPY(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);
   }
 #else
   (void) meta;
@@ -1048,34 +1053,66 @@ void spiffs_cb_object_event(
   spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG;
   u32_t i;
   spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
+  SPIFFS_DBG("       CALLBACK  %s obj_id:"_SPIPRIid" spix:"_SPIPRIsp" npix:"_SPIPRIpg" nsz:"_SPIPRIi"\n", (const char *[]){"UPD", "NEW", "DEL", "MOV", "HUP","???"}[MIN(ev,5)],
+      obj_id_raw, spix, new_pix, new_size);
   for (i = 0; i < fs->fd_count; i++) {
     spiffs_fd *cur_fd = &fds[i];
-#if SPIFFS_TEMPORAL_FD_CACHE
-    if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
-#else
-    if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
+    if ((cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; // fd not related to updated file
+#if !SPIFFS_TEMPORAL_FD_CACHE
+    if (cur_fd->file_nbr == 0) continue; // fd closed
 #endif
-    if (spix == 0) {
+    if (spix == 0) { // object index header update
       if (ev != SPIFFS_EV_IX_DEL) {
-        SPIFFS_DBG("       callback: setting fd "_SPIPRIfd":"_SPIPRIid" objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
+#if SPIFFS_TEMPORAL_FD_CACHE
+        if (cur_fd->score == 0) continue; // never used fd
+#endif
+        SPIFFS_DBG("       callback: setting fd "_SPIPRIfd":"_SPIPRIid"(fdoffs:"_SPIPRIi" offs:"_SPIPRIi") objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n",
+            SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, cur_fd->fdoffset, cur_fd->offset, new_pix, new_size);
         cur_fd->objix_hdr_pix = new_pix;
         if (new_size != 0) {
+          // update size and offsets for fds to this file
           cur_fd->size = new_size;
+          u32_t act_new_size = new_size == SPIFFS_UNDEFINED_LEN ? 0 : new_size;
+#if SPIFFS_CACHE_WR
+          if (act_new_size > 0 && cur_fd->cache_page) {
+            act_new_size = MAX(act_new_size, cur_fd->cache_page->offset + cur_fd->cache_page->size);
+          }
+#endif
+          if (cur_fd->offset > act_new_size) {
+            cur_fd->offset = act_new_size;
+          }
+          if (cur_fd->fdoffset > act_new_size) {
+            cur_fd->fdoffset = act_new_size;
+          }
+#if SPIFFS_CACHE_WR
+          if (cur_fd->cache_page && cur_fd->cache_page->offset > act_new_size+1) {
+            SPIFFS_CACHE_DBG("CACHE_DROP: file trunced, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix);
+            spiffs_cache_fd_release(fs, cur_fd->cache_page);
+          }
+#endif
         }
       } else {
+        // removing file
+#if SPIFFS_CACHE_WR
+        if (cur_fd->file_nbr && cur_fd->cache_page) {
+          SPIFFS_CACHE_DBG("CACHE_DROP: file deleted, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix);
+          spiffs_cache_fd_release(fs, cur_fd->cache_page);
+        }
+#endif
+        SPIFFS_DBG("       callback: release fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix);
         cur_fd->file_nbr = 0;
         cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;
       }
-    }
+    } // object index header update
     if (cur_fd->cursor_objix_spix == spix) {
       if (ev != SPIFFS_EV_IX_DEL) {
-        SPIFFS_DBG("       callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
+        SPIFFS_DBG("       callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix);
         cur_fd->cursor_objix_pix = new_pix;
       } else {
         cur_fd->cursor_objix_pix = 0;
       }
     }
-  }
+  } // fd update loop
 
 #if SPIFFS_IX_MAP
 
@@ -1087,7 +1124,7 @@ void spiffs_cb_object_event(
       if (cur_fd->file_nbr == 0 ||
           cur_fd->ix_map == 0 ||
           (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
-      SPIFFS_DBG("       callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", cur_fd->file_nbr, cur_fd->obj_id, spix);
+      SPIFFS_DBG("       callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix);
       spiffs_update_ix_map(fs, cur_fd, spix, objix);
     }
   }
@@ -1164,7 +1201,7 @@ s32_t spiffs_object_open_by_page(
 
   SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
 
-  SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", fd->file_nbr, fd->obj_id);
+  SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", SPIFFS_FH_OFFS(fs, fd->file_nbr), fd->obj_id);
 
   return res;
 }
@@ -1275,7 +1312,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
           SPIFFS_CHECK_RES(res);
           // quick "load" of new object index page
           memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
-          memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
+          _SPIFFS_MEMCPY(fs->work, &p_hdr, sizeof(spiffs_page_header));
           spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
               SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
           SPIFFS_DBG("append: "_SPIPRIid" create objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
@@ -2222,7 +2259,7 @@ s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {
     }
   }
 
-  // find the free fd with least score
+  // find the free fd with least score or name match
   for (i = 0; i < fs->fd_count; i++) {
     spiffs_fd *cur_fd = &fds[i];
     if (cur_fd->file_nbr == 0) {

+ 49 - 4
app/spiffs/spiffs_nucleus.h

@@ -141,6 +141,22 @@
 #define SPIFFS_OBJ_ID_DELETED           ((spiffs_obj_id)0)
 #define SPIFFS_OBJ_ID_FREE              ((spiffs_obj_id)-1)
 
+
+
+#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
+    /* For GCC, clang and TI compilers */
+#define SPIFFS_PACKED __attribute__((packed))
+#elif defined(__ICCARM__) || defined(__CC_ARM)
+    /* For IAR ARM and Keil MDK-ARM compilers */
+#define SPIFFS_PACKED 
+
+#else
+    /* Unknown compiler */
+#define SPIFFS_PACKED 
+#endif
+
+
+
 #if SPIFFS_USE_MAGIC
 #if !SPIFFS_USE_MAGIC_LENGTH
 #define SPIFFS_MAGIC(fs, bix)           \
@@ -242,6 +258,15 @@
 #define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
   ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
 
+#if SPIFFS_FILEHDL_OFFSET
+#define SPIFFS_FH_OFFS(fs, fh)   ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
+#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
+#else
+#define SPIFFS_FH_OFFS(fs, fh)   (fh)
+#define SPIFFS_FH_UNOFFS(fs, fh) (fh)
+#endif
+
+
 #define SPIFFS_OP_T_OBJ_LU    (0<<0)
 #define SPIFFS_OP_T_OBJ_LU2   (1<<0)
 #define SPIFFS_OP_T_OBJ_IX    (2<<0)
@@ -430,7 +455,7 @@ typedef struct {
   spiffs_span_ix cursor_objix_spix;
   // current absolute offset
   u32_t offset;
-  // current file descriptor offset
+  // current file descriptor offset (cached)
   u32_t fdoffset;
   // fd flags
   spiffs_flags flags;
@@ -455,7 +480,7 @@ typedef struct {
 // page header, part of each page except object lookup pages
 // NB: this is always aligned when the data page is an object index,
 // as in this case struct spiffs_page_object_ix is used
-typedef struct __attribute(( packed )) {
+typedef struct SPIFFS_PACKED {
   // object id
   spiffs_obj_id obj_id;
   // object span index
@@ -465,7 +490,7 @@ typedef struct __attribute(( packed )) {
 } spiffs_page_header;
 
 // object index header page header
-typedef struct __attribute(( packed ))
+typedef struct SPIFFS_PACKED
 #if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
                 __attribute(( aligned(sizeof(spiffs_page_ix)) ))
 #endif
@@ -487,7 +512,7 @@ typedef struct __attribute(( packed ))
 } spiffs_page_object_ix_header;
 
 // object index page header
-typedef struct __attribute(( packed )) {
+typedef struct SPIFFS_PACKED {
  spiffs_page_header p_hdr;
  u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
 } spiffs_page_object_ix;
@@ -794,4 +819,24 @@ s32_t spiffs_page_consistency_check(
 s32_t spiffs_object_index_consistency_check(
     spiffs *fs);
 
+// memcpy macro,
+// checked in test builds, otherwise plain memcpy (unless already defined)
+#ifdef _SPIFFS_TEST
+#define _SPIFFS_MEMCPY(__d, __s, __l) do { \
+    intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \
+    intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \
+    intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \
+    intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \
+    if (__a1 <= __b2 && __b1 <= __a2) { \
+      printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \
+      ERREXIT(); \
+    } \
+    memcpy((__d),(__s),(__l)); \
+} while (0)
+#else
+#ifndef _SPIFFS_MEMCPY
+#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0)
+#endif
+#endif //_SPIFFS_TEST
+
 #endif /* SPIFFS_NUCLEUS_H_ */