Johny Mattsson 526d21dab4 Major cleanup - c_whatever is finally history. (#2838)
The PR removed the bulk of non-newlib headers from the NodeMCU source base.  
app/libc has now been cut down to the bare minimum overrides to shadow the 
corresponding functions in the SDK's libc. The old c_xyz.h headerfiles have been 
nuked in favour of the standard <xyz.h> headers, with a few exceptions over in 
sdk-overrides. Again, shipping a libc.a without headers is a terrible thing to do. We're 
still living on a prayer that libc was configured the same was as a default-configured
xtensa gcc toolchain assumes it is. That part I cannot do anything about, unfortunately, 
but it's no worse than it has been before.

This enables our source files to compile successfully using the standard header files, 
and use the typical malloc()/calloc()/realloc()/free(), the strwhatever()s and 
memwhatever()s. These end up, through macro and linker magic, mapped to the 
appropriate SDK or ROM functions.
2019-07-22 00:58:21 +03:00

476 lines
9.2 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "vfs.h"
#include "vfs_int.h"
#define LDRV_TRAVERSAL 0
// This interferes with our clearerr member in our ops struct
#undef clearerr
// ---------------------------------------------------------------------------
// RTC system interface
//
static int32_t (*rtc_cb)( vfs_time *tm ) = NULL;
// called by operating system
void vfs_register_rtc_cb( int32_t (*cb)( vfs_time *tm ) )
{
// allow NULL pointer to unregister callback function
rtc_cb = cb;
}
// called by file system drivers
int32_t vfs_get_rtc( vfs_time *tm )
{
if (rtc_cb) {
return rtc_cb( tm );
}
return VFS_RES_ERR;
}
static int dir_level = 1;
#if ! LDRV_TRAVERSAL
#define normalize_path(p) (p)
#else
static const char *normalize_path( const char *path )
{
const char *temp = path;
size_t len;
while ((len = strlen( temp )) >= 2) {
if (temp[0] == '.' && temp[1] == '.') {
--dir_level;
if (len >= 4 && dir_level > 0) {
// prepare next step
temp = &(temp[4]);
} else {
// we're at top, the remainder is expected be an absolute path
temp = &(temp[3]);
}
} else {
break;
}
}
if (dir_level > 0) {
// no traversal on root level
return path;
} else {
// path traverses via root
return temp;
}
}
#endif
// ---------------------------------------------------------------------------
// file system functions
//
vfs_vol *vfs_mount( const char *name, int num )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->mount( outname, num );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
vfs_vol *r = fs_fns->mount( outname, num );
free( outname );
return r;
}
#endif
return NULL;
}
int vfs_open( const char *name, const char *mode )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return (int)fs_fns->open( outname, mode );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
int r = (int)fs_fns->open( outname, mode );
free( outname );
return r;
}
#endif
return 0;
}
vfs_dir *vfs_opendir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->opendir( outname );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
vfs_dir *r = fs_fns->opendir( outname );
free( outname );
return r;
}
#endif
return NULL;
}
int32_t vfs_stat( const char *name, struct vfs_stat *buf )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->stat( outname, buf );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
int32_t r = fs_fns->stat( outname, buf );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_remove( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->remove( outname );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
int32_t r = fs_fns->remove( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_rename( const char *oldname, const char *newname )
{
vfs_fs_fns *fs_fns;
const char *normoldname = normalize_path( oldname );
const char *normnewname = normalize_path( newname );
char *oldoutname, *newoutname;
#ifdef BUILD_SPIFFS
if (myspiffs_realm( normoldname, &oldoutname, FALSE )) {
if (fs_fns = myspiffs_realm( normnewname, &newoutname, FALSE )) {
return fs_fns->rename( oldoutname, newoutname );
}
}
#endif
#ifdef BUILD_FATFS
if (myfatfs_realm( normoldname, &oldoutname, FALSE )) {
if (fs_fns = myfatfs_realm( normnewname, &newoutname, FALSE )) {
int32_t r = fs_fns->rename( oldoutname, newoutname );
free( oldoutname );
free( newoutname );
return r;
}
free( oldoutname );
}
#endif
return -1;
}
int32_t vfs_mkdir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef BUILD_SPIFFS
// not supported
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
int32_t r = fs_fns->mkdir( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fsinfo( const char *name, uint32_t *total, uint32_t *used )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->fsinfo( total, used );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
free( outname );
return fs_fns->fsinfo( total, used );
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fscfg( const char *name, uint32_t *phys_addr, uint32_t *phys_size)
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( "/FLASH", &outname, FALSE )) {
return fs_fns->fscfg( phys_addr, phys_size );
}
#endif
#ifdef BUILD_FATFS
// not supported
#endif
// Error
return VFS_RES_ERR;
}
int32_t vfs_format( void )
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( "/FLASH", &outname, FALSE )) {
return fs_fns->format();
}
#endif
#ifdef BUILD_FATFS
// not supported
#endif
// Error
return 0;
}
int32_t vfs_chdir( const char *path )
{
vfs_fs_fns *fs_fns;
const char *normpath = normalize_path( path );
const char *level;
char *outname;
int ok = VFS_RES_ERR;
#if LDRV_TRAVERSAL
// track dir level
if (normpath[0] == '/') {
dir_level = 0;
level = &(normpath[1]);
} else {
level = normpath;
}
while (strlen( level ) > 0) {
dir_level++;
if (level = strchr( level, '/' )) {
level++;
} else {
break;
}
}
#endif
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normpath, &outname, TRUE )) {
// our SPIFFS integration doesn't support directories
if (strlen( outname ) == 0) {
ok = VFS_RES_OK;
}
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normpath, &outname, TRUE )) {
if (strchr( outname, ':' )) {
// need to set FatFS' default drive
fs_fns->chdrive( outname );
// and force chdir to root in case path points only to root
fs_fns->chdir( "/" );
}
if (fs_fns->chdir( outname ) == VFS_RES_OK) {
ok = VFS_RES_OK;
}
free( outname );
}
#endif
return ok == VFS_RES_OK ? VFS_RES_OK : VFS_RES_ERR;
}
int32_t vfs_errno( const char *name )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
return fs_fns->ferrno( );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_ferrno( int fd )
{
vfs_file *f = (vfs_file *)fd;
if (f) {
return f->fns->ferrno ? f->fns->ferrno( f ) : 0;
} else {
vfs_fs_fns *fs_fns;
const char *name = ""; // current drive
char *outname;
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( name, &outname, FALSE )) {
return fs_fns->ferrno( );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( name, &outname, FALSE )) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
}
}
void vfs_clearerr( const char *name )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef BUILD_SPIFFS
if (fs_fns = myspiffs_realm( normname, &outname, FALSE )) {
fs_fns->clearerr ( );
}
#endif
#ifdef BUILD_FATFS
if (fs_fns = myfatfs_realm( normname, &outname, FALSE )) {
fs_fns->clearerr ( );
free( outname );
}
#endif
}
const char *vfs_basename( const char *path )
{
const char *basename;
// deduce basename (incl. extension) for length check
if (basename = strrchr( path, '/' )) {
basename++;
} else if (basename = strrchr( path, ':' )) {
basename++;
} else {
basename = path;
}
return basename;
}
// ---------------------------------------------------------------------------
// supplementary functions
//
int vfs_getc( int fd )
{
unsigned char c = 0xFF;
int32_t res;
if(!vfs_eof( fd )) {
if (1 != vfs_read( fd, &c, 1 )) {
NODE_DBG("getc errno %i\n", vfs_ferrno( fd ));
return VFS_EOF;
} else {
return (int)c;
}
}
return VFS_EOF;
}
int vfs_ungetc( int c, int fd )
{
return vfs_lseek( fd, -1, VFS_SEEK_CUR );
}