소스 검색

Fix memory leak in file_stat(). (#1871)

* Change vfs_stat() api to pre-allocated buffer for stat info.
* Change vfs_readdir() api to stat buffer as well. vfs_item api removed.
Arnim Läuger 7 년 전
부모
커밋
fc887e9f9f
6개의 변경된 파일106개의 추가작업 그리고 309개의 파일을 삭제
  1. 34 125
      app/fatfs/myfatfs.c
  2. 21 29
      app/modules/file.c
  3. 4 4
      app/platform/vfs.c
  4. 6 53
      app/platform/vfs.h
  5. 15 23
      app/platform/vfs_int.h
  6. 26 75
      app/spiffs/spiffs.c

+ 34 - 125
app/fatfs/myfatfs.c

@@ -29,22 +29,12 @@ static uint32_t myfatfs_fsize( const struct vfs_file *fd );
 static sint32_t myfatfs_ferrno( const struct vfs_file *fd );
 
 static sint32_t  myfatfs_closedir( const struct vfs_dir *dd );
-static vfs_item *myfatfs_readdir( const struct vfs_dir *dd );
-
-static void        myfatfs_iclose( const struct vfs_item *di );
-static uint32_t    myfatfs_isize( const struct vfs_item *di );
-static sint32_t    myfatfs_time( const struct vfs_item *di, struct vfs_time *tm );
-static const char *myfatfs_name( const struct vfs_item *di );
-static sint32_t    myfatfs_is_dir( const struct vfs_item *di );
-static sint32_t    myfatfs_is_rdonly( const struct vfs_item *di );
-static sint32_t    myfatfs_is_hidden( const struct vfs_item *di );
-static sint32_t    myfatfs_is_sys( const struct vfs_item *di );
-static sint32_t    myfatfs_is_arch( const struct vfs_item *di );
+static sint32_t  myfatfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf );
 
 static vfs_vol  *myfatfs_mount( const char *name, int num );
 static vfs_file *myfatfs_open( const char *name, const char *mode );
 static vfs_dir  *myfatfs_opendir( const char *name );
-static vfs_item *myfatfs_stat( const char *name );
+static sint32_t  myfatfs_stat( const char *name, struct vfs_stat *buf );
 static sint32_t  myfatfs_remove( const char *name );
 static sint32_t  myfatfs_rename( const char *oldname, const char *newname );
 static sint32_t  myfatfs_mkdir( const char *name );
@@ -89,18 +79,6 @@ static vfs_file_fns myfatfs_file_fns = {
   .ferrno    = myfatfs_ferrno
 };
 
-static vfs_item_fns myfatfs_item_fns = {
-  .close     = myfatfs_iclose,
-  .size      = myfatfs_isize,
-  .time      = myfatfs_time,
-  .name      = myfatfs_name,
-  .is_dir    = myfatfs_is_dir,
-  .is_rdonly = myfatfs_is_rdonly,
-  .is_hidden = myfatfs_is_hidden,
-  .is_sys    = myfatfs_is_sys,
-  .is_arch   = myfatfs_is_arch
-};
-
 static vfs_dir_fns myfatfs_dir_fns = {
   .close     = myfatfs_closedir,
   .readdir   = myfatfs_readdir
@@ -130,11 +108,6 @@ struct myvfs_dir {
   DIR dp;
 };
 
-struct myvfs_item {
-  struct vfs_item vfs_item;
-  FILINFO fno;
-};
-
 
 // ---------------------------------------------------------------------------
 // exported helper functions for FatFS
@@ -321,105 +294,45 @@ static sint32_t myfatfs_closedir( const struct vfs_dir *dd )
   return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
 }
 
-static vfs_item *myfatfs_readdir( const struct vfs_dir *dd )
+static void myfatfs_fill_stat( const FILINFO *fno, struct vfs_stat *buf )
 {
-  GET_DIR_DP(dd);
-  struct myvfs_item *di;
+  c_memset( buf, 0, sizeof( struct vfs_stat ) );
 
-  if (di = c_malloc( sizeof( struct myvfs_item ) )) {
-    FILINFO *fno = &(di->fno);
-
-    if (FR_OK == (last_result = f_readdir( dp, fno ))) {
-      // condition "no further item" is signalled with empty name
-      if (fno->fname[0] != '\0') {
-        di->vfs_item.fs_type = VFS_FS_FATFS;
-        di->vfs_item.fns     = &myfatfs_item_fns;
-        return (vfs_item *)di;
-      }
-    }
-    c_free( di );
-  }
-
-  return NULL;
-}
-
-
-// ---------------------------------------------------------------------------
-// dir info functions
-//
-#define GET_FILINFO_FNO(descr) \
-  const struct myvfs_item *mydi = (const struct myvfs_item *)descr; \
-  FILINFO *fno = (FILINFO *)&(mydi->fno);
-
-static void myfatfs_iclose( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
-
-  // free descriptor memory
-  c_free( (void *)di );
-}
-
-static uint32_t myfatfs_isize( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
-
-  return fno->fsize;
-}
-
-static sint32_t myfatfs_time( const struct vfs_item *di, struct vfs_time *tm )
-{
-  GET_FILINFO_FNO(di);
+  // fill in supported stat entries
+  c_strncpy( buf->name, fno->fname, FS_OBJ_NAME_LEN+1 );
+  buf->name[FS_OBJ_NAME_LEN] = '\0';
+  buf->size = fno->fsize;
+  buf->is_dir = fno->fattrib & AM_DIR ? 1 : 0;
+  buf->is_rdonly = fno->fattrib & AM_RDO ? 1 : 0;
+  buf->is_hidden = fno->fattrib & AM_HID ? 1 : 0;
+  buf->is_sys = fno->fattrib & AM_SYS ? 1 : 0;
+  buf->is_arch = fno->fattrib & AM_ARC ? 1 : 0;
 
+  struct vfs_time *tm = &(buf->tm);
   tm->year = (fno->fdate >>  9) + 1980;
   tm->mon  = (fno->fdate >>  5) & 0x0f;
   tm->day  =  fno->fdate        & 0x1f;
   tm->hour = (fno->ftime >> 11);
   tm->min  = (fno->ftime >>  5) & 0x3f;
   tm->sec  =  fno->ftime        & 0x3f;
-
-  return VFS_RES_OK;
+  buf->tm_valid = 1;
 }
 
-static const char *myfatfs_name( const struct vfs_item *di )
+static sint32_t myfatfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf )
 {
-  GET_FILINFO_FNO(di);
-
-  return fno->fname;
-}
-
-static sint32_t myfatfs_is_dir( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
-
-  return fno->fattrib & AM_DIR ? 1 : 0;
-}
-
-static sint32_t myfatfs_is_rdonly( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
-
-  return fno->fattrib & AM_RDO ? 1 : 0;
-}
-
-static sint32_t myfatfs_is_hidden( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
-
-  return fno->fattrib & AM_HID ? 1 : 0;
-}
-
-static sint32_t myfatfs_is_sys( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
+  GET_DIR_DP(dd);
+  FILINFO fno;
 
-  return fno->fattrib & AM_SYS ? 1 : 0;
-}
+  if (FR_OK == (last_result = f_readdir( dp, &fno ))) {
+    // condition "no further item" is signalled with empty name
+    if (fno.fname[0] != '\0') {
+      myfatfs_fill_stat( &fno, buf );
 
-static sint32_t myfatfs_is_arch( const struct vfs_item *di )
-{
-  GET_FILINFO_FNO(di);
+      return VFS_RES_OK;
+    }
+  }
 
-  return fno->fattrib & AM_ARC ? 1 : 0;
+  return VFS_RES_ERR;
 }
 
 
@@ -521,21 +434,17 @@ static vfs_dir *myfatfs_opendir( const char *name )
   return NULL;
 }
 
-static vfs_item *myfatfs_stat( const char *name )
+static sint32_t myfatfs_stat( const char *name, struct vfs_stat *buf )
 {
-  struct myvfs_item *di;
+  FILINFO fno;
 
-  if (di = c_malloc( sizeof( struct myvfs_item ) )) {
-    if (FR_OK == (last_result = f_stat( name, &(di->fno) ))) {
-      di->vfs_item.fs_type = VFS_FS_FATFS;
-      di->vfs_item.fns     = &myfatfs_item_fns;
-      return (vfs_item *)di;
-    } else {
-      c_free( di );
-    }
-  }
+  if (FR_OK == (last_result = f_stat( name, &fno ))) {
+    myfatfs_fill_stat( &fno, buf );
 
-  return NULL;
+    return VFS_RES_OK;
+  } else {
+    return VFS_RES_ERR;
+  }
 }
 
 static sint32_t myfatfs_remove( const char *name )

+ 21 - 29
app/modules/file.c

@@ -214,14 +214,13 @@ static int file_open( lua_State* L )
 static int file_list( lua_State* L )
 {
   vfs_dir  *dir;
-  vfs_item *item;
 
   if (dir = vfs_opendir("")) {
     lua_newtable( L );
-    while (item = vfs_readdir(dir)) {
-      lua_pushinteger(L, vfs_item_size(item));
-      lua_setfield(L, -2, vfs_item_name(item));
-      vfs_closeitem(item);
+    struct vfs_stat stat;
+    while (vfs_readdir(dir, &stat) == VFS_RES_OK) {
+      lua_pushinteger(L, stat.size);
+      lua_setfield(L, -2, stat.name);
     }
     vfs_closedir(dir);
     return 1;
@@ -270,11 +269,8 @@ static int file_exists( lua_State* L )
   const char *basename = vfs_basename( fname );
   luaL_argcheck(L, c_strlen(basename) <= FS_OBJ_NAME_LEN && c_strlen(fname) == len, 1, "filename invalid");
 
-  vfs_item *stat = vfs_stat((char *)fname);
-
-  lua_pushboolean(L, stat ? 1 : 0);
-
-  if (stat) vfs_closeitem(stat);
+  struct vfs_stat stat;
+  lua_pushboolean(L, vfs_stat((char *)fname, &stat) == VFS_RES_OK ? 1 : 0);
 
   return 1;
 }
@@ -332,58 +328,54 @@ static int file_stat( lua_State* L )
   const char *fname = luaL_checklstring( L, 1, &len );    
   luaL_argcheck( L, c_strlen(fname) <= FS_OBJ_NAME_LEN && c_strlen(fname) == len, 1, "filename invalid" );
 
-  vfs_item *stat = vfs_stat( (char *)fname );
-
-  if (!stat) {
+  struct vfs_stat stat;
+  if (vfs_stat( (char *)fname, &stat ) != VFS_RES_OK) {
     lua_pushnil( L );
     return 1;
   }
 
   lua_createtable( L, 0, 7 );
 
-  lua_pushinteger( L, vfs_item_size( stat ) );
+  lua_pushinteger( L, stat.size );
   lua_setfield( L, -2, "size" );
 
-  lua_pushstring( L, vfs_item_name( stat ) );
+  lua_pushstring( L, stat.name );
   lua_setfield( L, -2, "name" );
 
-  lua_pushboolean( L, vfs_item_is_dir( stat ) );
+  lua_pushboolean( L, stat.is_dir );
   lua_setfield( L, -2, "is_dir" );
 
-  lua_pushboolean( L, vfs_item_is_rdonly( stat ) );
+  lua_pushboolean( L, stat.is_rdonly );
   lua_setfield( L, -2, "is_rdonly" );
 
-  lua_pushboolean( L, vfs_item_is_hidden( stat ) );
+  lua_pushboolean( L, stat.is_hidden );
   lua_setfield( L, -2, "is_hidden" );
 
-  lua_pushboolean( L, vfs_item_is_sys( stat ) );
+  lua_pushboolean( L, stat.is_sys );
   lua_setfield( L, -2, "is_sys" );
 
-  lua_pushboolean( L, vfs_item_is_arch( stat ) );
+  lua_pushboolean( L, stat.is_arch );
   lua_setfield( L, -2, "is_arch" );
 
   // time stamp as sub-table
-  vfs_time tm;
-  int got_time = VFS_RES_OK == vfs_item_time( stat, &tm ) ? TRUE : FALSE;
-  
   lua_createtable( L, 0, 6 );
 
-  lua_pushinteger( L, got_time ? tm.year : FILE_TIMEDEF_YEAR );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.year : FILE_TIMEDEF_YEAR );
   lua_setfield( L, -2, "year" );
 
-  lua_pushinteger( L, got_time ? tm.mon : FILE_TIMEDEF_MON );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.mon : FILE_TIMEDEF_MON );
   lua_setfield( L, -2, "mon" );
 
-  lua_pushinteger( L, got_time ? tm.day : FILE_TIMEDEF_DAY );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.day : FILE_TIMEDEF_DAY );
   lua_setfield( L, -2, "day" );
 
-  lua_pushinteger( L, got_time ? tm.hour : FILE_TIMEDEF_HOUR );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.hour : FILE_TIMEDEF_HOUR );
   lua_setfield( L, -2, "hour" );
 
-  lua_pushinteger( L, got_time ? tm.min : FILE_TIMEDEF_MIN );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.min : FILE_TIMEDEF_MIN );
   lua_setfield( L, -2, "min" );
 
-  lua_pushinteger( L, got_time ? tm.sec : FILE_TIMEDEF_SEC );
+  lua_pushinteger( L, stat.tm_valid ? stat.tm.sec : FILE_TIMEDEF_SEC );
   lua_setfield( L, -2, "sec" );
 
   lua_setfield( L, -2, "time" );

+ 4 - 4
app/platform/vfs.c

@@ -139,7 +139,7 @@ vfs_dir *vfs_opendir( const char *name )
   return NULL;
 }
 
-vfs_item *vfs_stat( const char *name )
+sint32_t vfs_stat( const char *name, struct vfs_stat *buf )
 {
   vfs_fs_fns *fs_fns;
   const char *normname = normalize_path( name );
@@ -147,19 +147,19 @@ vfs_item *vfs_stat( const char *name )
 
 #ifdef BUILD_SPIFFS
   if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
-    return fs_fns->stat( outname );
+    return fs_fns->stat( outname, buf );
   }
 #endif
 
 #ifdef BUILD_FATFS
   if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
-    vfs_item *r = fs_fns->stat( outname );
+    sint32_t r = fs_fns->stat( outname, buf );
     c_free( outname );
     return r;
   }
 #endif
 
-  return NULL;
+  return VFS_RES_ERR;
 }
 
 sint32_t vfs_remove( const char *name )

+ 6 - 53
app/platform/vfs.h

@@ -104,57 +104,9 @@ inline sint32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); }
 
 // vfs_readdir - read next directory item
 //   dd: dir descriptor
-//   Returns: item object, or NULL in case of error
-inline vfs_item  *vfs_readdir( vfs_dir *dd ) { return dd->fns->readdir( dd ); }
-
-// ---------------------------------------------------------------------------
-// dir item functions
-//
-
-// vfs_closeitem - close directory item and free memory
-//   di: item descriptor
-//   Returns: nothing
-inline void vfs_closeitem( vfs_item *di ) { return di->fns->close( di ); }
-
-// vfs_item_size - get item's size
-//   di: item descriptor
-//   Returns: Item size
-inline uint32_t vfs_item_size( vfs_item *di ) { return di->fns->size( di ); }
-
-// vfs_item_time - get item's modification time
-//   di: item descriptor
-//   Returns: Item modification time
-inline sint32_t vfs_item_time( vfs_item *di, struct vfs_time *tm ) { return di->fns->time ? di->fns->time( di, tm ) : VFS_RES_ERR; }
-
-// vfs_item_name - get item's name
-//   di: item descriptor
-//   Returns: Item name
-inline const char *vfs_item_name( vfs_item *di ) { return di->fns->name( di ); }
-
-// vfs_item_is_dir - check for directory
-//   di: item descriptor
-//   Returns: >0 if item is a directory, 0 if not
-inline sint32_t vfs_item_is_dir( vfs_item *di ) { return di->fns->is_dir ? di->fns->is_dir( di ) : 0; }
-
-// vfs_item_is_rdonly - check for read-only
-//   di: item descriptor
-//   Returns: >0 if item is read only, 0 if not
-inline sint32_t vfs_item_is_rdonly( vfs_item *di ) { return di->fns->is_rdonly ? di->fns->is_rdonly( di ) : 0; }
-
-// vfs_item_is_hidden - check for hidden attribute
-//   di: item descriptor
-//   Returns: >0 if item is hidden, 0 if not
-inline sint32_t vfs_item_is_hidden( vfs_item *di ) { return di->fns->is_hidden ? di->fns->is_hidden( di ) : 0; }
-
-// vfs_item_is_sys - check for sys attribute
-//   di: item descriptor
-//   Returns: >0 if item is sys, 0 if not
-inline sint32_t vfs_item_is_sys( vfs_item *di ) { return di->fns->is_sys ? di->fns->is_sys( di ) : 0; }
-
-// vfs_item_is_arch - check for archive attribute
-//   di: item descriptor
-//   Returns: >0 if item is archive, 0 if not
-inline sint32_t vfs_item_is_arch( vfs_item *di ) { return di->fns->is_arch ? di->fns->is_arch( di ) : 0; }
+//   buf:  pre-allocated stat structure to be filled in
+//   Returns: VFS_RES_OK if next item found, otherwise VFS_RES_ERR
+inline sint32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns->readdir( dd, buf ); }
 
 // ---------------------------------------------------------------------------
 // volume functions
@@ -188,8 +140,9 @@ vfs_dir  *vfs_opendir( const char *name );
 
 // vfs_stat - stat file or directory
 //   name: file or directory name
-//   Returns: Item object, or NULL in case of error
-vfs_item *vfs_stat( const char *name );
+//   buf:  pre-allocated structure to be filled in
+//   Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
+sint32_t  vfs_stat( const char *name, struct vfs_stat *buf );
 
 // vfs_remove - remove file or directory
 //   name: file or directory name

+ 15 - 23
app/platform/vfs_int.h

@@ -47,6 +47,19 @@ struct vfs_file {
 };
 typedef const struct vfs_file vfs_file;
 
+// stat data
+struct vfs_stat {
+  uint32_t size;
+  char name[FS_OBJ_NAME_LEN+1];
+  struct vfs_time tm;
+  uint8_t tm_valid;
+  uint8_t is_dir;
+  uint8_t is_rdonly;
+  uint8_t is_hidden;
+  uint8_t is_sys;
+  uint8_t is_arch;
+};
+
 // file descriptor functions
 struct vfs_file_fns {
   sint32_t (*close)( const struct vfs_file *fd );
@@ -61,27 +74,6 @@ struct vfs_file_fns {
 };
 typedef const struct vfs_file_fns vfs_file_fns;
 
-// generic dir item descriptor
-struct vfs_item {
-  int fs_type;
-  const struct vfs_item_fns *fns;
-};
-typedef const struct vfs_item vfs_item;
-
-// directory item functions
-struct vfs_item_fns {
-  void (*close)( const struct vfs_item *di );
-  uint32_t (*size)( const struct vfs_item *di );
-  sint32_t (*time)( const struct vfs_item *di, struct vfs_time *tm );
-  const char *(*name)( const struct vfs_item *di );
-  sint32_t (*is_dir)( const struct vfs_item *di );
-  sint32_t (*is_rdonly)( const struct vfs_item *di );
-  sint32_t (*is_hidden)( const struct vfs_item *di );
-  sint32_t (*is_sys)( const struct vfs_item *di );
-  sint32_t (*is_arch)( const struct vfs_item *di );
-};
-typedef const struct vfs_item_fns vfs_item_fns;
-
 // generic dir descriptor
 struct vfs_dir {
   int fs_type;
@@ -92,7 +84,7 @@ typedef const struct vfs_dir vfs_dir;
 // dir descriptor functions
 struct vfs_dir_fns {
   sint32_t (*close)( const struct vfs_dir *dd );
-  vfs_item *(*readdir)( const struct vfs_dir *dd );
+  sint32_t (*readdir)( const struct vfs_dir *dd, struct vfs_stat *buf );
 };
 typedef const struct vfs_dir_fns vfs_dir_fns;
 
@@ -113,7 +105,7 @@ struct vfs_fs_fns {
   vfs_vol  *(*mount)( const char *name, int num );
   vfs_file *(*open)( const char *name, const char *mode );
   vfs_dir  *(*opendir)( const char *name );
-  vfs_item *(*stat)( const char *name );
+  sint32_t  (*stat)( const char *name, struct vfs_stat *buf );
   sint32_t  (*remove)( const char *name );
   sint32_t  (*rename)( const char *oldname, const char *newname );
   sint32_t  (*mkdir)( const char *name );

+ 26 - 75
app/spiffs/spiffs.c

@@ -255,17 +255,12 @@ static uint32_t myspiffs_vfs_size( const struct vfs_file *fd );
 static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd );
 
 static sint32_t  myspiffs_vfs_closedir( const struct vfs_dir *dd );
-static vfs_item *myspiffs_vfs_readdir( const struct vfs_dir *dd );
-
-static void       myspiffs_vfs_iclose( const struct vfs_item *di );
-static uint32_t   myspiffs_vfs_isize( const struct vfs_item *di );
-//static const struct tm *myspiffs_vfs_time( const struct vfs_item *di );
-static const char *myspiffs_vfs_name( const struct vfs_item *di );
+static sint32_t  myspiffs_vfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf );
 
 static vfs_vol  *myspiffs_vfs_mount( const char *name, int num );
 static vfs_file *myspiffs_vfs_open( const char *name, const char *mode );
 static vfs_dir  *myspiffs_vfs_opendir( const char *name );
-static vfs_item *myspiffs_vfs_stat( const char *name );
+static sint32_t  myspiffs_vfs_stat( const char *name, struct vfs_stat *buf );
 static sint32_t  myspiffs_vfs_remove( const char *name );
 static sint32_t  myspiffs_vfs_rename( const char *oldname, const char *newname );
 static sint32_t  myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used );
@@ -308,18 +303,6 @@ static vfs_file_fns myspiffs_file_fns = {
   .ferrno    = myspiffs_vfs_ferrno
 };
 
-static vfs_item_fns myspiffs_item_fns = {
-  .close     = myspiffs_vfs_iclose,
-  .size      = myspiffs_vfs_isize,
-  .time      = NULL,
-  .name      = myspiffs_vfs_name,
-  .is_dir    = NULL,
-  .is_rdonly = NULL,
-  .is_hidden = NULL,
-  .is_sys    = NULL,
-  .is_arch   = NULL
-};
-
 static vfs_dir_fns myspiffs_dd_fns = {
   .close     = myspiffs_vfs_closedir,
   .readdir   = myspiffs_vfs_readdir
@@ -339,36 +322,6 @@ struct myvfs_dir {
   spiffs_DIR d;
 };
 
-struct myvfs_stat {
-  struct vfs_item vfs_item;
-  spiffs_stat s;
-};
-
-
-// ---------------------------------------------------------------------------
-// stat functions
-//
-#define GET_STAT_S(descr) \
-  const struct myvfs_stat *mystat = (const struct myvfs_stat *)descr; \
-  spiffs_stat *s = (spiffs_stat *)&(mystat->s);
-
-static void myspiffs_vfs_iclose( const struct vfs_item *di ) {
-  // free descriptor memory
-  c_free( (void *)di );
-}
-
-static uint32_t myspiffs_vfs_isize( const struct vfs_item *di ) {
-  GET_STAT_S(di);
-
-  return s->size;
-}
-
-static const char *myspiffs_vfs_name( const struct vfs_item *di ) {
-  GET_STAT_S(di);
-
-  return s->name;
-}
-
 
 // ---------------------------------------------------------------------------
 // volume functions
@@ -396,25 +349,22 @@ static sint32_t myspiffs_vfs_closedir( const struct vfs_dir *dd ) {
   c_free( (void *)dd );
 }
 
-static vfs_item *myspiffs_vfs_readdir( const struct vfs_dir *dd ) {
+static sint32_t myspiffs_vfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf ) {
   GET_DIR_D(dd);
-  struct myvfs_stat *stat;
   struct spiffs_dirent dirent;
 
-  if (stat = c_malloc( sizeof( struct myvfs_stat ) )) {
-    if (SPIFFS_readdir( d, &dirent )) {
-      stat->vfs_item.fs_type = VFS_FS_FATFS;
-      stat->vfs_item.fns     = &myspiffs_item_fns;
-      // copy entries to vfs' directory item
-      stat->s.size = dirent.size;
-      c_strncpy( stat->s.name, dirent.name, SPIFFS_OBJ_NAME_LEN );
-      return (vfs_item *)stat;
-    } else {
-      c_free( stat );
-    }
+  if (SPIFFS_readdir( d, &dirent )) {
+    c_memset( buf, 0, sizeof( struct vfs_stat ) );
+
+    // copy entries to  item
+    // fill in supported stat entries
+    c_strncpy( buf->name, dirent.name, FS_OBJ_NAME_LEN+1 );
+    buf->name[FS_OBJ_NAME_LEN] = '\0';
+    buf->size = dirent.size;
+    return VFS_RES_OK;
   }
 
-  return NULL;
+  return VFS_RES_ERR;
 }
 
 
@@ -566,20 +516,21 @@ static vfs_dir *myspiffs_vfs_opendir( const char *name ){
   return NULL;
 }
 
-static vfs_item *myspiffs_vfs_stat( const char *name ) {
-  struct myvfs_stat *s;
+static sint32_t myspiffs_vfs_stat( const char *name, struct vfs_stat *buf ) {
+  spiffs_stat stat;
 
-  if (s = (struct myvfs_stat *)c_malloc( sizeof( struct myvfs_stat ) )) {
-    if (0 <= SPIFFS_stat( &fs, name, &(s->s) )) {
-      s->vfs_item.fs_type = VFS_FS_SPIFFS;
-      s->vfs_item.fns     = &myspiffs_item_fns;
-      return (vfs_item *)s;
-    } else {
-      c_free( s );
-    }
-  }
+  if (0 <= SPIFFS_stat( &fs, name, &stat )) {
+    c_memset( buf, 0, sizeof( struct vfs_stat ) );
 
-  return NULL;
+    // fill in supported stat entries
+    c_strncpy( buf->name, stat.name, FS_OBJ_NAME_LEN+1 );
+    buf->name[FS_OBJ_NAME_LEN] = '\0';
+    buf->size = stat.size;
+
+    return VFS_RES_OK;
+  } else {
+    return VFS_RES_ERR;
+  }
 }
 
 static sint32_t myspiffs_vfs_remove( const char *name ) {