1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

Added WOFS + other stuff

This should really be more than one commit, but I wrote everything in one
shot and I don't feel like arranging the changes logically into different
commits. So, these are the changes:

- added WOFS (Write Once File System). This is a writeable file system that
  exists in the MCU's internal Flash memory and allows files to be written,
  but only once, in a single shot. More details to follow.
- the platform interface has a new MCU flash access interface.
- added WOFS "reference implementations" for two CPUs: LM3S8962 and
  STM32F103RE. They are easily extendable to other CPUs in the same platform
  and can be taken as a model for other platforms.
- the ROMFS file layout in memory was slightly changed.
- the simulator (src/platform/sim) got a new function (lseek).
- shell: now each shell command receives its arguments in a C-main-style
  (argc, argv) pair. This was originally Marcelo's idea and it finally
  made it to the master (although this particular implementation is mine),
  after I got fed up with all the argument parsing in the shell functions.
- new shell command: wofmt ("formats" a WOFS, effectively clearing it).
- a couple of small fixes in the shell code
This commit is contained in:
Bogdan Marinescu 2012-06-24 23:07:32 +03:00
parent a378b8943e
commit e9a24cac11
17 changed files with 756 additions and 211 deletions

View File

@ -315,7 +315,16 @@ u32 platform_eth_get_elapsed_time();
void platform_usb_cdc_send( u8 data );
int platform_usb_cdc_recv( s32 timeout );
// *****************************************************************************
// Internal flash erase/write functions
// Currently used by WOFS
u32 platform_flash_get_first_free_block_address( u32 *psect );
u32 platform_flash_get_sector_of_address( u32 addr );
u32 platform_flash_write( const void *from, u32 toaddr, u32 size );
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size );
u32 platform_flash_get_num_sectors();
int platform_flash_erase_sector( u32 sector_id );
// *****************************************************************************
// Allocator support

View File

@ -8,10 +8,20 @@
/*******************************************************************************
The Read-Only "filesystem" resides in a contiguous zone of memory, with the
following structure, repeated for each file:
following structure (repeated for each file):
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH defined here, empty if last file
File size: (4 bytes)
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH, first byte is 0xFF if last file
File size: (4 bytes), aligned to ROMFS_ALIGN bytes
File data: (file size bytes)
The WOFS (Write Once File System) uses much of the ROMFS functions, thuss it is
also implemented in romfs.c. It resides in a contiguous zone of memory, with a
structure that is quite similar with ROMFS' structure (repeated for each file):
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH, first byte is 0xFF if last file.
WOFS filenames always begin at an address which is a multiple of ROMFS_ALIGN.
File deleted flag: (WOFS_DEL_FIELD_SIZE bytes), aligned to ROMFS_ALIGN bytes
File size: (4 bytes), aligned to ROMFS_ALIGN bytes
File data: (file size bytes)
*******************************************************************************/
@ -22,9 +32,9 @@ enum
FS_FILE_OK
};
// This is the function used to read a byte at the given address from the file
// system
typedef u8 ( *p_read_fs_byte )( u32 );
// ROMFS/WOFS functions
typedef u32 ( *p_fs_read )( void *to, u32 fromaddr, u32 size, const void *pdata );
typedef u32 ( *p_fs_write )( const void *from, u32 toaddr, u32 size, const void *pdata );
// File flags
#define ROMFS_FILE_FLAG_READ 0x01
@ -40,19 +50,33 @@ typedef struct
u8 flags;
} FD;
// WOFS constants
// The miminum size we need in order to create another file
// This size will be added to the size of the filename when creating a new file
// to ensure that there's enough space left on the device
// This comes from the size of the file length field (4) + the maximum number of
// bytes needed to align this field (3) + a single 0xFF byte which marks the end
// of the filesystem (1) + the maximum number of bytes needed to align the contents
// of a file (3)
#define WOFS_MIN_NEEDED_SIZE 11
// Filesystem flags
#define ROMFS_FS_FLAG_DIRECT 0x01
#define ROMFS_FS_FLAG_WO 0x02
#define ROMFS_FS_FLAG_DIRECT 0x01 // direct mode (the file is mapped in a memory area directly accesible by the CPU)
#define ROMFS_FS_FLAG_WO 0x02 // this FS is actually a WO (Write-Once) FS
// File system descriptor
typedef struct
{
u8 *pbase;
u8 flags;
u8 *pbase; // pointer to FS base in memory (only for ROMFS_FS_FLAG_DIRECT)
u8 flags; // flags (see above)
p_fs_read readf; // pointer to read function (for non-direct mode FS)
p_fs_write writef; // pointer to write function (only for ROMFS_FS_FLAG_WO)
u32 max_size; // maximum size of the FS (in bytes)
} FSDATA;
// FS functions
int romfs_init();
int wofs_format();
#endif

11
mkfs.py
View File

@ -117,21 +117,20 @@ def mkfs( dirname, outname, flist, mode, compcmd ):
size_lh = ( len( filedata ) >> 8 ) & 0xFF
size_hl = ( len( filedata ) >> 16 ) & 0xFF
size_hh = ( len( filedata ) >> 24 ) & 0xFF
# Round to a multiple of 4
while _bytecnt & ( alignment - 1 ) != 0:
_add_data( 0, outfile )
# Write size
_add_data( size_ll, outfile )
_add_data( size_lh, outfile )
_add_data( size_hl, outfile )
_add_data( size_hh, outfile )
# Round to a multiple of 4
actual = len( filedata )
while _bytecnt & ( alignment - 1 ) != 0:
_add_data( 0, outfile )
actual = actual + 1
# Then write the rest of the file
for c in filedata:
_add_data( ord( c ), outfile )
# Report
print "Encoded file %s (%d bytes real size, %d bytes after rounding, %d bytes total)" % ( fname, len( filedata ), actual, _fcnt )
print "Encoded file %s (%d bytes real size, %d bytes encoded size)" % ( fname, len( filedata ), _fcnt )
# All done, write the final "0xFF" (terminator)
_add_data( 0xFF, outfile, False )

View File

@ -440,6 +440,125 @@ void cmn_int_handler( elua_int_id id, elua_int_resnum resnum )
#endif // #ifdef BUILD_INT_HANDLERS
// ****************************************************************************
// Internal flash support functions (currently used only by WOFS)
#ifdef BUILD_WOFS
// This symbol must be exported by the linker command file and must reflect the
// TOTAL size of flash used by the eLua image (not only the code and constants,
// but also .data and whatever else ends up in the eLua image). WOFS will start
// at the next usable (aligned to a flash sector boundary) address after
// flash_used_size.
extern char flash_used_size[];
// Helper function: find the flash sector in which an address resides
// Return the sector number, as well as the start and end address of the sector
static u32 flashh_find_sector( u32 address, u32 *pstart, u32 *pend )
{
address -= INTERNAL_FLASH_START_ADDRESS;
#ifdef INTERNAL_FLASH_SECTOR_SIZE
// All the sectors in the flash have the same size, so just align the address
u32 sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;
if( pstart )
*pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS;
if( pend )
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS - 1;
return sect_id;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
// The flash has blocks of different size
// Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro
const u16 flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
u32 total = 0, i = 0;
while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( u16 ) ) )
total += flash_sect_size[ i ++ ];
if( pstart )
*pstart = ( total - flash_sect_size[ i - 1 ] ) + INTERNAL_FLASH_START_ADDRESS;
if( pend )
*pend = total + INTERNAL_FLASH_START_ADDRESS - 1;
return i - 1;
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
u32 platform_flash_get_sector_of_address( u32 addr )
{
return flashh_find_sector( addr, NULL, NULL );
}
u32 platform_flash_get_num_sectors()
{
#ifdef INTERNAL_FLASH_SECTOR_SIZE
return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
const u16 flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
return sizeof( flash_sect_size ) / sizeof( u16 );
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
u32 platform_flash_get_first_free_block_address( u32 *psect )
{
// Round the total used flash size to the closest flash block address
u32 temp, sect;
sect = flashh_find_sector( ( u32 )flash_used_size + INTERNAL_FLASH_START_ADDRESS - 1, NULL, &temp );
if( psect )
*psect = sect + 1;
return temp + 1;
}
u32 platform_flash_write( const void *from, u32 toaddr, u32 size )
{
#ifndef INTERNAL_FLASH_WRITE_BLK_SIZE
return platform_s_flash_write( from, toaddr, size );
#else // #ifindef INTERNAL_FLASH_WRITE_BLK_SIZE
u32 temp, rest, ssize = size;
unsigned i;
char tmpdata[ INTERNAL_FLASH_WRITE_BLK_SIZE ];
const u8 *pfrom = ( const u8* )from;
const u32 blksize = INTERNAL_FLASH_WRITE_BLK_SIZE;
const u32 blkmask = INTERNAL_FLASH_WRITE_BLK_SIZE - 1;
// Align the start
if( toaddr & blkmask )
{
rest = toaddr & blkmask;
temp = toaddr & ~blkmask; // this is the actual aligned address
memcpy( tmpdata, ( const void* )temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, temp, blksize );
if( size == 0 )
return ssize;
toaddr = temp + blksize;
}
// The start address is now a multiple of blksize
// Compute how many bytes we can write as multiples of blksize
rest = size & blkmask;
temp = size & ~blkmask;
// Program the blocks now
if( temp )
{
platform_s_flash_write( pfrom, toaddr, temp );
toaddr += temp;
pfrom += temp;
}
// And the final part of a block if needed
if( rest )
{
memcpy( tmpdata, ( const void* )toaddr, blksize );
for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, toaddr, blksize );
}
return ssize;
#endif // #ifndef INTERNAL_FLASH_WRITE_BLK_SIZE
}
#endif // #ifdef BUILD_WOFS
// ****************************************************************************
// Misc support

View File

@ -38,7 +38,7 @@ SECTIONS
. = ALIGN(4);
_edata = .;
} >sram
.ARM.extab :
{
*(.ARM.extab*)
@ -51,6 +51,8 @@ SECTIONS
} >sram
__exidx_end = .;
PROVIDE( flash_used_size = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.extab) + SIZEOF(.ARM.exidx) );
.bss (NOLOAD) : {
_bss = .;
*(.bss .bss.*)

View File

@ -151,6 +151,8 @@ int platform_init()
MAP_IntMasterEnable();
#endif
MAP_FlashUsecSet( SysCtlClockGet() );
// All done
return PLATFORM_OK;
}
@ -1308,6 +1310,19 @@ ControlHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulMsgValue,
#endif // BUILD_USB_CDC
// ****************************************************************************
// Flash access functions
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size )
{
return MAP_FlashProgram( ( unsigned long * )from, toaddr, size );
}
int platform_flash_erase_sector( u32 sector_id )
{
return FlashErase( sector_id * INTERNAL_FLASH_SECTOR_SIZE ) == 0 ? PLATFORM_OK : PLATFORM_ERR;
}
// ****************************************************************************
// Platform specific modules go here

View File

@ -267,6 +267,15 @@
#define SRAM_SIZE ( 0x10000 )
#endif
// Flash data (only for LM3S8962 for now)
#ifdef ELUA_CPU_LM3S8962
#define INTERNAL_FLASH_SIZE ( 256 * 1024 )
#define INTERNAL_FLASH_WRITE_BLK_SIZE 4
#define INTERNAL_FLASH_SECTOR_SIZE 1024
#define INTERNAL_FLASH_START_ADDRESS 0
#define BUILD_WOFS
#endif // #ifdef ELUA_CPU_LM3S8962
// Allocator data: define your free memory zones here in two arrays
// (start address and end address)
#define MEM_START_ADDRESS { ( void* )end }

View File

@ -7,6 +7,7 @@
#define __NR_open 5
#define __NR_close 6
#define __NR_gettimeofday 78
#define __NR_lseek 19
int host_errno = 0;
@ -70,4 +71,5 @@ _syscall6(void *,mmap2, void *,addr, size_t, length, int, prot, int, flags, int,
_syscall1(void, exit, int, status);
_syscall1(int, close, int, status);
_syscall2(int, gettimeofday, struct timeval*, tv, struct timezone*, tz);
_syscall3(long, lseek, int, fd, long, offset, int, whence );

View File

@ -13,6 +13,7 @@ ssize_t host_read( int fd, void * buf, size_t count );
ssize_t host_write( int fd, const void * buf, size_t count );
int host_open( const char *name, int flags, mode_t mode );
int host_close( int fd );
long host_lseek( int fd, long pos, int whence );
#define PROT_READ 0x1 /* Page can be read. */
#define PROT_WRITE 0x2 /* Page can be written. */

View File

@ -32,6 +32,9 @@ int hostif_write( int fd, const void *buf, unsigned count );
// Close
int hostif_close( int fd );
// Seek
long hostif_lseek( int fd, long pos, int whence );
// Get time
s64 hostif_gettime();

View File

@ -65,6 +65,11 @@ int hostif_close( int fd )
return host_close( fd );
}
long hostif_lseek( int fd, long pos, int whence )
{
return host_lseek( fd, pos, whence );
}
s64 hostif_gettime()
{
struct timeval tv;

View File

@ -93,6 +93,9 @@ int platform_init()
/* Capture error */
while (1);
}
// Flash initialization (for WOFS)
FLASH_Unlock();
cmn_platform_init();
@ -1277,6 +1280,33 @@ int platform_adc_start_sequence( )
#endif // ifdef BUILD_ADC
// ****************************************************************************
// Flash access functions
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size )
{
u32 ssize = 0;
const u16 *psrc = ( const u16* )from;
FLASH_Status flstat;
while( ssize < size )
{
if( ( flstat = FLASH_ProgramHalfWord( toaddr, *psrc ++ ) ) != FLASH_COMPLETE )
{
printf( "ERROR in platform_s_flash_write: stat=%d at %08X\n", ( int )flstat, toaddr );
break;
}
toaddr += 2;
ssize += 2;
}
return ssize;
}
int platform_flash_erase_sector( u32 sector_id )
{
return FLASH_ErasePage( sector_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS ) == FLASH_COMPLETE ? PLATFORM_OK : PLATFORM_ERR;
}
// ****************************************************************************
// Platform specific modules go here

View File

@ -172,6 +172,14 @@ u32 platform_s_cpu_get_frequency();
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( SRAM_BASE + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
// Flash data (only for STM32F103RE for now)
#ifdef ELUA_CPU_STM32F103RE
#define INTERNAL_FLASH_SIZE ( 512 * 1024 )
#define INTERNAL_FLASH_SECTOR_SIZE 2048
#define INTERNAL_FLASH_START_ADDRESS 0x08000000
#define BUILD_WOFS
#endif // #ifdef ELUA_CPU_STM32F103RE
// Interrupt queue size
#define PLATFORM_INT_QUEUE_LOG_SIZE 5

View File

@ -51,6 +51,8 @@ SECTIONS
*(.ARM.exidx*)
} >sram
__exidx_end = .;
PROVIDE( flash_used_size = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.extab) + SIZEOF(.ARM.exidx) );
.bss (NOLOAD) : {
. = ALIGN(4);

View File

@ -7,75 +7,129 @@
#include "romfiles.h"
#include <stdio.h>
#include "ioctl.h"
#include <fcntl.h>
#include "platform.h"
#ifdef ELUA_SIMULATOR
#include "hostif.h"
#endif
#include "platform_conf.h"
#ifdef BUILD_ROMFS
#if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
#define ROMFS_MAX_FDS 4
#define TOTAL_MAX_FDS 8
// DO NOT CHANGE THE ROMFS ALIGNMENT.
// UNLESS YOU _LIKE_ TO WATCH THE WORLD BURN.
#define ROMFS_ALIGN 4
#define fsmin( x , y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
static FD romfs_fd_table[ ROMFS_MAX_FDS ];
static FD fd_table[ TOTAL_MAX_FDS ];
static int romfs_num_fd;
#ifdef ELUA_CPU_LINUX
static int wofs_sim_fd;
#define WOFS_FNAME "/tmp/wofs.dat"
#define WOFS_SIZE (256 * 1024)
#endif
#define WOFS_END_MARKER_CHAR 0xFF
#define WOFS_DEL_FIELD_SIZE ( ROMFS_ALIGN )
#define WOFS_FILE_DELETED 0xAA
// Length of the 'file size' field for both ROMFS/WOFS
#define ROMFS_SIZE_LEN 4
static int romfs_find_empty_fd()
{
int i;
for( i = 0; i < ROMFS_MAX_FDS; i ++ )
if( romfs_fd_table[ i ].baseaddr == 0xFFFFFFFF &&
romfs_fd_table[ i ].offset == 0xFFFFFFFF &&
romfs_fd_table[ i ].size == 0xFFFFFFFF )
for( i = 0; i < TOTAL_MAX_FDS; i ++ )
if( fd_table[ i ].baseaddr == 0xFFFFFFFF &&
fd_table[ i ].offset == 0xFFFFFFFF &&
fd_table[ i ].size == 0xFFFFFFFF )
return i;
return -1;
}
static void romfs_close_fd( int fd )
{
memset( romfs_fd_table + fd, 0xFF, sizeof( FD ) );
romfs_fd_table[ fd ].flags = 0;
memset( fd_table + fd, 0xFF, sizeof( FD ) );
fd_table[ fd ].flags = 0;
}
// Helper function: read a byte from the FS
static u8 romfsh_read8( u32 addr, const FSDATA *pfs )
{
u8 temp;
if( pfs->flags & ROMFS_FS_FLAG_DIRECT )
return pfs->pbase[ addr ];
pfs->readf( &temp, addr, 1, pfs );
return temp;
}
// Helper function: return 1 if PFS reffers to a WOFS, 0 otherwise
static int romfsh_is_wofs( const FSDATA* pfs )
{
return ( pfs->flags & ROMFS_FS_FLAG_WO ) != 0;
}
// Open the given file, returning one of FS_FILE_NOT_FOUND, FS_FILE_ALREADY_OPENED
// or FS_FILE_OK
static u8 romfs_open_file( const char* fname, u8 *pbase, FD* pfd )
static u8 romfs_open_file( const char* fname, FD* pfd, FSDATA *pfs, u32 *plast, u32 *pnameaddr )
{
u32 i, j;
u32 i, j, n;
char fsname[ DM_MAX_FNAME_LENGTH + 1 ];
u32 fsize;
int is_deleted;
// Look for the file
i = 0;
while( 1 )
{
if( pbase[ i ] == 0xFF )
if( romfsh_read8( i, pfs ) == WOFS_END_MARKER_CHAR )
{
*plast = i;
return FS_FILE_NOT_FOUND;
}
// Read file name
n = i;
for( j = 0; j < DM_MAX_FNAME_LENGTH; j ++ )
{
fsname[ j ] = pbase[ i + j ];
fsname[ j ] = romfsh_read8( i + j, pfs );
if( fsname[ j ] == 0 )
break;
}
// ' i + j' now points at the '0' byte
j = i + j + 1;
// And read the size
fsize = pbase[ j ] + ( pbase[ j + 1 ] << 8 );
fsize += ( pbase[ j + 2 ] << 16 ) + ( pbase[ j + 3 ] << 24 );
j += 4;
// Round to a multiple of ROMFS_ALIGN
j = ( j + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
if( !strncasecmp( fname, fsname, DM_MAX_FNAME_LENGTH ) )
// WOFS has an additional WOFS_DEL_FIELD_SIZE bytes before the size as an indication for "file deleted"
if( romfsh_is_wofs( pfs ) )
{
is_deleted = romfsh_read8( j, pfs ) == WOFS_FILE_DELETED;
j += WOFS_DEL_FIELD_SIZE;
}
else
is_deleted = 0;
// And read the size
fsize = romfsh_read8( j, pfs ) + ( romfsh_read8( j + 1, pfs ) << 8 );
fsize += ( romfsh_read8( j + 2, pfs ) << 16 ) + ( romfsh_read8( j + 3, pfs ) << 24 );
j += ROMFS_SIZE_LEN;
if( !strncasecmp( fname, fsname, DM_MAX_FNAME_LENGTH ) && !is_deleted )
{
// Found the file
pfd->baseaddr = j;
pfd->offset = 0;
pfd->size = fsize;
if( pnameaddr )
*pnameaddr = n;
return FS_FILE_OK;
}
// Move to next file
i = j + fsize;
// On WOFS, all file names must begin at a multiple of ROMFS_ALIGN
if( romfsh_is_wofs( pfs ) )
i = ( i + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
}
*plast = 0;
return FS_FILE_NOT_FOUND;
}
@ -84,25 +138,115 @@ static int romfs_open_r( struct _reent *r, const char *path, int flags, int mode
FD tempfs;
int i;
FSDATA *pfsdata = ( FSDATA* )pdata;
if( romfs_num_fd == ROMFS_MAX_FDS )
int must_create = 0;
int exists;
u8 lflags = ROMFS_FILE_FLAG_READ;
u32 firstfree, nameaddr;
if( romfs_num_fd == TOTAL_MAX_FDS )
{
r->_errno = ENFILE;
return -1;
}
if( romfs_open_file( path, pfsdata->pbase, &tempfs ) != FS_FILE_OK )
// Does the file exist?
exists = romfs_open_file( path, &tempfs, pfsdata, &firstfree, &nameaddr ) == FS_FILE_OK;
// Now interpret "flags" to set file flags and to check if we should create the file
if( flags & O_CREAT )
{
r->_errno = ENOENT;
// If O_CREAT is specified with O_EXCL and the file already exists, return with error
if( ( flags & O_EXCL ) && exists )
{
r->_errno = EEXIST;
return -1;
}
// Otherwise create the file if it does not exist
must_create = !exists;
}
if( ( flags & O_TRUNC ) && ( flags & ( O_WRONLY | O_RDWR ) ) && exists )
{
// The file exists, but it must be truncated
// In the case of WOFS, this effectively means "create a new file"
must_create = 1;
}
// ROMFS can't create files
if( must_create && ( ( pfsdata->flags & ROMFS_FS_FLAG_WO ) == 0 ) )
{
r->_errno = EROFS;
return -1;
}
// Decode access mode
if( flags & O_WRONLY )
lflags = ROMFS_FILE_FLAG_WRITE;
else if( flags & O_RDWR )
lflags = ROMFS_FILE_FLAG_READ | ROMFS_FILE_FLAG_WRITE;
if( flags & O_APPEND )
lflags |= ROMFS_FILE_FLAG_APPEND;
// If a write access is requested when the file must NOT be created, this
// is an error
if( ( lflags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) ) && !must_create )
{
r->_errno = EACCES;
return -1;
}
// Do we need to create the file ?
if( must_create )
{
if( exists )
{
// Invalidate the file first by changing WOFS_DEL_FIELD_SIZE bytes before
// the file length to WOFS_FILE_DELETED
u8 tempb[] = { WOFS_FILE_DELETED, 0xFF, 0xFF, 0xFF };
pfsdata->writef( tempb, tempfs.baseaddr - ROMFS_SIZE_LEN - WOFS_DEL_FIELD_SIZE, WOFS_DEL_FIELD_SIZE, pfsdata );
}
// Find the last available position by asking romfs_open_file to look for a file
// with an invalid name
romfs_open_file( "\1", &tempfs, pfsdata, &firstfree, NULL );
// Is there enough space on the FS for another file?
if( pfsdata->max_size - firstfree + 1 < strlen( path ) + 1 + WOFS_MIN_NEEDED_SIZE + WOFS_DEL_FIELD_SIZE )
{
r->_errno = ENOSPC;
return -1;
}
// Write the name of the file
pfsdata->writef( path, firstfree, strlen( path ) + 1, pfsdata );
firstfree += strlen( path ) + 1; // skip over the name
// Align to a multiple of ROMFS_ALIGN
firstfree = ( firstfree + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
firstfree += ROMFS_SIZE_LEN + WOFS_DEL_FIELD_SIZE; // skip over the size and the deleted flags area
tempfs.baseaddr = firstfree;
tempfs.offset = tempfs.size = 0;
}
else // File must exist (and was found in the previous 'romfs_open_file' call)
{
if( !exists )
{
r->_errno = ENOENT;
return -1;
}
}
// Find a free FD and copy the descriptor information
tempfs.flags = lflags;
i = romfs_find_empty_fd();
memcpy( romfs_fd_table + i, &tempfs, sizeof( FD ) );
memcpy( fd_table + i, &tempfs, sizeof( FD ) );
romfs_num_fd ++;
return i;
}
static int romfs_close_r( struct _reent *r, int fd, void *pdata )
{
FD* pfd = fd_table + fd;
FSDATA *pfsdata = ( FSDATA* )pdata;
u8 temp[ ROMFS_SIZE_LEN ];
if( pfd->flags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) )
{
// Write back the size
temp[ 0 ] = pfd->size & 0xFF;
temp[ 1 ] = ( pfd->size >> 8 ) & 0xFF;
temp[ 2 ] = ( pfd->size >> 16 ) & 0xFF;
temp[ 3 ] = ( pfd->size >> 24 ) & 0xFF;
pfsdata->writef( temp, pfd->baseaddr - ROMFS_SIZE_LEN, ROMFS_SIZE_LEN, pfsdata );
}
romfs_close_fd( fd );
romfs_num_fd --;
return 0;
@ -110,17 +254,44 @@ static int romfs_close_r( struct _reent *r, int fd, void *pdata )
static _ssize_t romfs_write_r( struct _reent *r, int fd, const void* ptr, size_t len, void *pdata )
{
r->_errno = EINVAL;
return -1;
FD* pfd = fd_table + fd;
FSDATA *pfsdata = ( FSDATA* )pdata;
if( ( pfd->flags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) ) == 0 )
{
r->_errno = EINVAL;
return -1;
}
// Append mode: set the file pointer to the end
if( pfd->flags & ROMFS_FILE_FLAG_APPEND )
pfd->offset = pfd->size;
// Only write at the end of the file!
if( pfd->offset != pfd->size )
return 0;
// Check if we have enough space left on the device. Always keep 1 byte for the final 0xFF
if( pfd->baseaddr + pfd->size + len > pfsdata->max_size - 1 )
len = pfsdata->max_size - ( pfd->baseaddr + pfd->size ) - 1;
pfsdata->writef( ptr, pfd->offset + pfd->baseaddr, len, pfsdata );
pfd->offset += len;
pfd->size += len;
return len;
}
static _ssize_t romfs_read_r( struct _reent *r, int fd, void* ptr, size_t len, void *pdata )
{
FD* pfd = romfs_fd_table + fd;
FD* pfd = fd_table + fd;
long actlen = fsmin( len, pfd->size - pfd->offset );
FSDATA *pfsdata = ( FSDATA* )pdata;
memcpy( ptr, pfsdata->pbase + pfd->offset + pfd->baseaddr, actlen );
if( ( pfd->flags & ROMFS_FILE_FLAG_READ ) == 0 )
{
r->_errno = EBADF;
return -1;
}
if( pfsdata->flags & ROMFS_FS_FLAG_DIRECT )
memcpy( ptr, pfsdata->pbase + pfd->offset + pfd->baseaddr, actlen );
else
actlen = pfsdata->readf( ptr, pfd->offset + pfd->baseaddr, actlen, pfsdata );
pfd->offset += actlen;
return actlen;
}
@ -128,7 +299,7 @@ static _ssize_t romfs_read_r( struct _reent *r, int fd, void* ptr, size_t len, v
// lseek
static off_t romfs_lseek_r( struct _reent *r, int fd, off_t off, int whence, void *pdata )
{
FD* pfd = romfs_fd_table + fd;
FD* pfd = fd_table + fd;
u32 newpos = 0;
switch( whence )
@ -175,20 +346,36 @@ static struct dm_dirent* romfs_readdir_r( struct _reent *r, void *d, void *pdata
{
u32 off = *( u32* )d;
struct dm_dirent *pent = &dm_shared_dirent;
unsigned j = 0;
unsigned j;
FSDATA *pfsdata = ( FSDATA* )pdata;
u8 *pbase = pfsdata->pbase;
int is_deleted;
if( pbase[ off ] == 0xFF )
return NULL;
while( ( dm_shared_fname[ j ++ ] = pbase[ off ++ ] ) != '\0' );
pent->fname = dm_shared_fname;
pent->fsize = pbase[ off ] + ( pbase[ off + 1 ] << 8 );
pent->fsize += ( pbase[ off + 2 ] << 16 ) + ( pbase[ off + 3 ] << 24 );
pent->ftime = 0;
off += 4;
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
*( u32* )d = off + pent->fsize;
while( 1 )
{
if( romfsh_read8( off, pfsdata ) == WOFS_END_MARKER_CHAR )
return NULL;
j = 0;
while( ( dm_shared_fname[ j ++ ] = romfsh_read8( off ++, pfsdata ) ) != '\0' );
pent->fname = dm_shared_fname;
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
if( romfsh_is_wofs( pfsdata ) )
{
is_deleted = romfsh_read8( off, pfsdata ) == WOFS_FILE_DELETED;
off += WOFS_DEL_FIELD_SIZE;
}
else
is_deleted = 0;
pent->fsize = romfsh_read8( off, pfsdata ) + ( romfsh_read8( off + 1, pfsdata ) << 8 );
pent->fsize += ( romfsh_read8( off + 2, pfsdata ) << 16 ) + ( romfsh_read8( off + 3, pfsdata ) << 24 );
pent->ftime = 0;
off += ROMFS_SIZE_LEN;
off += pent->fsize;
if( romfsh_is_wofs( pfsdata ) )
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
if( !is_deleted )
break;
}
*( u32* )d = off;
return pent;
}
@ -202,7 +389,7 @@ static int romfs_closedir_r( struct _reent *r, void *d, void *pdata )
// getaddr
static const char* romfs_getaddr_r( struct _reent *r, int fd, void *pdata )
{
FD* pfd = romfs_fd_table + fd;
FD* pfd = fd_table + fd;
FSDATA *pfsdata = ( FSDATA* )pdata;
if( pfsdata->flags & ROMFS_FS_FLAG_DIRECT )
@ -211,7 +398,10 @@ static const char* romfs_getaddr_r( struct _reent *r, int fd, void *pdata )
return NULL;
}
// ****************************************************************************
// Our ROMFS device descriptor structure
// These functions apply to both ROMFS and WOFS
static const DM_DEVICE romfs_device =
{
romfs_open_r, // open
@ -225,31 +415,130 @@ static const DM_DEVICE romfs_device =
romfs_getaddr_r, // getaddr
};
// ROMFS descriptor
// ****************************************************************************
// ROMFS instance descriptor
static const FSDATA romfs_fsdata =
{
( u8* )romfiles_fs,
ROMFS_FS_FLAG_DIRECT
ROMFS_FS_FLAG_DIRECT,
NULL,
NULL,
sizeof( romfiles_fs )
};
// ****************************************************************************
// WOFS functions and instance descriptor for the simulator (testing)
#if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
static u32 sim_wofs_read( void *to, u32 fromaddr, u32 size, const void *pdata )
{
hostif_lseek( wofs_sim_fd, ( long )fromaddr, SEEK_SET );
return hostif_read( wofs_sim_fd, to, size );
}
static u32 sim_wofs_write( const void *from, u32 toaddr, u32 size, const void *pdata )
{
hostif_lseek( wofs_sim_fd, ( long )toaddr, SEEK_SET );
return hostif_write( wofs_sim_fd, from, size );
}
static const FSDATA wofs_sim_fsdata =
{
NULL,
ROMFS_FS_FLAG_WO,
sim_wofs_read,
sim_wofs_write,
WOFS_SIZE
};
#endif // #ifdef ELUA_CPU_LINUX
// ****************************************************************************
// WOFS functions and instance descriptor for real hardware
#if defined( BUILD_WOFS )
static u32 sim_wofs_write( const void *from, u32 toaddr, u32 size, const void *pdata )
{
const FSDATA *pfsdata = ( const FSDATA* )pdata;
toaddr += ( u32 )pfsdata->pbase;
return platform_flash_write( from, toaddr, size );
}
// This must NOT be a const!
static FSDATA wofs_fsdata =
{
NULL,
ROMFS_FS_FLAG_WO | ROMFS_FS_FLAG_DIRECT,
NULL,
sim_wofs_write,
0
};
// WOFS formatting function
// Returns 1 if OK, 0 for error
int wofs_format()
{
u32 sect_first, sect_last;
FD tempfd;
platform_flash_get_first_free_block_address( &sect_first );
// Get the first free address in WOFS. We use this address to compute the last block that we need to
// erase, instead of simply erasing everything from sect_first to the last Flash page.
romfs_open_file( "\1", &tempfd, &wofs_fsdata, &sect_last, NULL );
sect_last = platform_flash_get_sector_of_address( sect_last + ( u32 )wofs_fsdata.pbase );
while( sect_first <= sect_last )
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
return 0;
return 1;
}
#endif // #ifdef BUILD_WOFS
// Initialize both ROMFS and WOFS as needed
int romfs_init()
{
unsigned i;
for( i = 0; i < ROMFS_MAX_FDS; i ++ )
for( i = 0; i < TOTAL_MAX_FDS; i ++ )
{
memset( romfs_fd_table + i, 0xFF, sizeof( FD ) );
romfs_fd_table[ i ].flags = 0;
memset( fd_table + i, 0xFF, sizeof( FD ) );
fd_table[ i ].flags = 0;
}
return dm_register( "/rom", ( void* )&romfs_fsdata, &romfs_device );
#if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
// Initialize and register WOFS for the simulator
wofs_sim_fd = hostif_open( WOFS_FNAME, 2, 0666 ); // try to open directly first
if( -1 == wofs_sim_fd )
{
wofs_sim_fd = hostif_open( WOFS_FNAME, 66, 0666) ; // 66 == O_RDWR | O_CREAT
u8 temp = WOFS_END_MARKER_CHAR;
for( i = 0; i < WOFS_SIZE; i ++ )
hostif_write( wofs_sim_fd, &temp, 1 );
printf( "SIM_WOFS: creating WOFS file\n" );
hostif_close( wofs_sim_fd );
wofs_sim_fd = hostif_open( WOFS_FNAME, 2, 0666 );
}
dm_register( "/wo", ( void* )&wofs_sim_fsdata, &romfs_device );
#endif // #if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
#ifdef BUILD_WOFS
// Get the start address and size of WOFS and register it
wofs_fsdata.pbase = ( u8* )platform_flash_get_first_free_block_address( NULL );
wofs_fsdata.max_size = INTERNAL_FLASH_SIZE - ( ( u32 )wofs_fsdata.pbase - INTERNAL_FLASH_START_ADDRESS );
dm_register( "/wo", &wofs_fsdata, &romfs_device );
#endif // ifdef BUILD_WOFS
#ifdef BUILD_ROMFS
// Register the ROM filesystem
dm_register( "/rom", ( void* )&romfs_fsdata, &romfs_device );
#endif // #ifdef BUILD_ROMFS
return 0;
}
#else // #ifdef BUILD_ROMFS
#else // #if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
int romfs_init()
{
return dm_register( NULL, NULL, NULL );
}
#endif // #ifdef BUILD_ROMFS
#endif // #if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )

View File

@ -15,6 +15,9 @@
#include "remotefs.h"
#include "eluarpc.h"
#include "linenoise.h"
#include "term.h"
#include "romfs.h"
#include <ctype.h>
#if defined( USE_GIT_REVISION )
#include "git_version.h"
@ -27,6 +30,7 @@
// Shell alternate ' ' char
#define SHELL_ALT_SPACE '\x07'
#define SHELL_MAX_ARGS 10
// EOF is different in UART mode and TCP/IP mode
#ifdef BUILD_CON_GENERIC
@ -36,7 +40,7 @@
#endif
// Shell command handler function
typedef void( *p_shell_handler )( char* args );
typedef void( *p_shell_handler )( int argc, char **argv );
// Command/handler pair structure
typedef struct
@ -52,81 +56,47 @@ static char* shell_prog;
// Shell functions
// 'help' handler
static void shell_help( char* args )
static void shell_help( int argc, char **argv )
{
args = args;
( void )argc;
( void )argv;
printf( "Shell commands:\n" );
printf( " exit - exit from this shell\n" );
printf( " help - print this help\n" );
printf( " ls or dir - lists filesystems files and sizes\n" );
printf( " cat or type - lists file contents\n" );
printf( " lua [args] - run Lua with the given arguments\n" );
printf( " recv [path] - receive a file via XMODEM, if there is a path, save"
" there, otherwise run it.");
printf( " recv [path] - receive a file via XMODEM. If path is given save it there, otherwise run it.\n");
printf( " cp <src> <dst> - copy source file 'src' to 'dst'\n" );
printf( " wofmt - format the internal WOFS\n" );
printf( " ver - print eLua version\n" );
}
// 'lua' handler
static void shell_lua( char* args )
static void shell_lua( int argc, char **argv )
{
int nargs = 0;
char* lua_argv[ SHELL_MAX_LUA_ARGS + 2 ];
char *p, *prev, *temp;
lua_argv[ 0 ] = "lua";
// Process "args" if needed
if( *args )
{
prev = args;
p = strchr( args, ' ' );
while( p )
{
if( nargs == SHELL_MAX_LUA_ARGS )
{
printf( "Too many arguments to 'lua' (maxim %d)\n", SHELL_MAX_LUA_ARGS );
return;
}
*p = 0;
lua_argv[ nargs + 1 ] = temp = prev;
nargs ++;
prev = p + 1;
p = strchr( p + 1, ' ' );
// If the argument is quoted, remove the quotes and transform the 'alternate chars' back to space
if( *temp == '\'' || *temp == '"' )
{
temp ++;
lua_argv[ nargs ] = temp;
while( *temp )
{
if( *temp == SHELL_ALT_SPACE )
*temp = ' ';
temp ++;
}
*( temp - 1 ) = '\0';
}
}
}
lua_argv[ nargs + 1 ] = NULL;
printf( "Press " SHELL_EOF_STRING " to exit Lua\n" );
lua_main( nargs + 1, lua_argv );
lua_main( argc, argv );
clearerr( stdin );
}
// 'recv' handler
static void shell_recv( char* args )
static void shell_recv( int argc, char **argv )
{
args = args;
#ifndef BUILD_XMODEM
printf( "XMODEM support not compiled, unable to recv\n" );
return;
#else // #ifndef BUILD_XMODEM
char *p;
long actsize;
lua_State* L;
if( argc > 2 )
{
printf( "Usage: recv [path]\n" );
return;
}
if( ( shell_prog = malloc( XMODEM_INITIAL_BUFFER_SIZE ) ) == NULL )
{
printf( "Unable to allocate memory\n" );
@ -151,23 +121,21 @@ static void shell_recv( char* args )
printf( "done, got %u bytes\n", ( unsigned )( p - shell_prog ) );
// we've received an argument, try saving it to a file
if( strcmp( args, "") != 0 )
if( argc == 2 )
{
if( strchr( args, ' ' ) )
*strchr( args, ' ' ) = '\0';
FILE *foutput = fopen( args, "w" );
FILE *foutput = fopen( argv[ 1 ], "w" );
size_t file_sz = p - shell_prog;
if( foutput == NULL )
{
printf( "unable to open file %s\n", args);
printf( "unable to open file %s\n", argv[ 1 ] );
free( shell_prog );
shell_prog = NULL;
return;
}
if( fwrite( shell_prog, sizeof( char ), file_sz, foutput ) == file_sz )
printf( "received and saved as %s\n", args );
printf( "received and saved as %s\n", argv[ 1 ] );
else
printf( "disk full, unable to save file %s\n", args );
printf( "unable to save file %s (no space left on target?)\n", argv[ 1 ] );
fclose( foutput );
}
else // no arg, running the file with lua.
@ -193,15 +161,16 @@ static void shell_recv( char* args )
}
// 'ver' handler
static void shell_ver( char* args )
static void shell_ver( int argc, char **argv )
{
args = args;
( void )argc;
( void )argv;
printf( "eLua version %s\n", ELUA_STR_VERSION );
printf( "For more information visit www.eluaproject.net and wiki.eluaproject.net\n" );
}
// 'ls' and 'dir' handler
static void shell_ls( char* args )
static void shell_ls( int argc, char **argv )
{
const DM_INSTANCE_DATA *pinst;
unsigned dev, i;
@ -209,6 +178,8 @@ static void shell_ls( char* args )
struct dm_dirent *ent;
u32 total;
( void )argc;
( void )argv;
// Iterate through all devices, looking for the ones that can do "opendir"
for( dev = 0; dev < dm_get_num_devices(); dev ++ )
{
@ -236,35 +207,32 @@ static void shell_ls( char* args )
}
// 'cat' and 'type' handler
static void shell_cat( char *args )
static void shell_cat( int argc, char **argv )
{
FILE *fp;
int c;
char *p;
unsigned i;
// *args has an appended space. Replace it with the string terminator.
// *(strchr( args, ' ' )) = 0;
if ( *args )
while ( *args )
if( argc < 2 )
{
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
return;
}
for( i = 1; i < argc; i ++ )
{
if( ( fp = fopen( argv[ i ] , "rb" ) ) != NULL )
{
p = strchr( args, ' ' );
*p = 0;
if( ( fp = fopen( args , "rb" ) ) != NULL )
c = fgetc( fp );
while( c != EOF )
{
printf("%c", (char) c );
c = fgetc( fp );
while( c != EOF )
{
printf("%c", (char) c );
c = fgetc( fp );
}
fclose ( fp );
}
else
printf( "File %s not found\n", args );
args = p + 1;
}
else
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
fclose ( fp );
}
else
printf( "Unable to open '%s'\n", argv[ i ] );
}
}
// 'copy' handler
@ -273,60 +241,49 @@ static void shell_cat( char *args )
#else
#define SHELL_COPY_BUFSIZE 256
#endif
static void shell_cp( char *args )
static void shell_cp( int argc, char **argv )
{
char *p1 = NULL, *p2 = NULL;
FILE *fps = NULL, *fpd = NULL;
void *buf = NULL;
size_t datalen, datawrote, total = 0;
if( *args )
if( argc != 3 )
{
p1 = strchr( args, ' ' );
if( p1 )
printf( "Usage: cp <source> <destination>\n" );
return;
}
if( ( fps = fopen( argv[ 1 ], "rb" ) ) == NULL )
printf( "Unable to open %s for reading\n", argv[ 1 ] );
else
{
if( ( fpd = fopen( argv[ 2 ], "wb" ) ) == NULL )
printf( "Unable to open %s for writing\n", argv[ 2 ] );
else
{
*p1 = 0;
p2 = strchr( p1 + 1, ' ' );
if( p2 )
// Alloc memory
if( ( buf = malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
printf( "Not enough memory\n" );
else
{
*p2 = 0;
// First file is at args, second one at p1 + 1
if( ( fps = fopen( args, "rb" ) ) == NULL )
printf( "Unable to open %s for reading\n", args );
else
// Do the actual copy
while( 1 )
{
if( ( fpd = fopen( p1 + 1, "wb" ) ) == NULL )
printf( "Unable to open %s for writing\n", p1 + 1 );
else
datalen = fread( buf, 1, SHELL_COPY_BUFSIZE, fps );
datawrote = fwrite( buf, 1, datalen, fpd );
if( datawrote < datalen )
{
// Alloc memory
if( ( buf = malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
printf( "Not enough memory\n" );
else
{
// Do the actual copy
while( 1 )
{
datalen = fread( buf, 1, SHELL_COPY_BUFSIZE, fps );
datawrote = fwrite( buf, 1, datalen, fpd );
if( datawrote < datalen )
{
printf( "Copy error (no space left on target?)\n" );
break;
}
total += datalen;
if( datalen < SHELL_COPY_BUFSIZE )
break;
}
printf( "%u bytes copied\n", ( unsigned int )total );
}
printf( "Copy error (no space left on target?)\n" );
break;
}
}
total += datalen;
if( datalen < SHELL_COPY_BUFSIZE )
break;
}
fflush( fpd );
printf( "%u bytes copied\n", ( unsigned int )total );
}
}
}
if( !p1 || !p2 )
printf( "Syntax error.\n" );
if( fps )
fclose( fps );
if( fpd )
@ -335,6 +292,37 @@ static void shell_cp( char *args )
free( buf );
}
// 'wofmt' handler
static void shell_wofmt( int argc, char **argv )
{
#ifndef BUILD_WOFS
printf( "WOFS not enabled.\n" );
#else // #ifndef BUILD_WOFS
int c;
printf( "Formatting the internal WOFS will DESTROY ALL THE FILES FROM WOFS.\n" );
while( 1 )
{
printf( "Are you sure you want to continue? [y/n] " );
c = term_getch( TERM_INPUT_WAIT );
printf( "%c\n", isprint( c ) ? c : ' ' );
c = tolower( c );
if( c == 'n' )
return;
else if( c == 'y' )
break;
}
printf( "Formatting ... " );
if( !wofs_format() )
{
printf( "\ni*** ERROR ***: unable to erase the internal flash. WOFS might be compromised.\n" );
printf( "It is advised to re-flash the eLua image.\n" );
}
else
printf( " done.\n" );
#endif // #ifndef BUILD_WOFS
}
// Insert shell commands here
static const SHELL_COMMAND shell_commands[] =
{
@ -348,6 +336,7 @@ static const SHELL_COMMAND shell_commands[] =
{ "cat", shell_cat },
{ "type", shell_cat },
{ "cp", shell_cp },
{ "wofmt", shell_wofmt },
{ NULL, NULL }
};
@ -359,11 +348,13 @@ void shell_start()
const SHELL_COMMAND* pcmd;
int i, inside_quotes;
char quote_char;
int argc;
char *argv[ SHELL_MAX_ARGS ];
printf( SHELL_WELCOMEMSG, ELUA_STR_VERSION );
while( 1 )
{
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE, SHELL_PROMPT ) == -1 )
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE - 1, SHELL_PROMPT ) == -1 )
{
printf( "\n" );
clearerr( stdin );
@ -374,11 +365,11 @@ void shell_start()
if( cmd[ strlen( cmd ) - 1 ] != '\n' )
strcat( cmd, "\n" );
// Change '\r' and '\n' chars to ' ' to ease processing
// Change '\r', '\n' and '\t' chars to ' ' to ease processing
p = cmd;
while( *p )
{
if( *p == '\r' || *p == '\n' )
if( *p == '\r' || *p == '\n' || *p == '\t' )
*p = ' ';
p ++;
}
@ -421,19 +412,57 @@ void shell_start()
memmove( temp, temp + 1, strlen( temp ) );
p = strchr( p + 1, ' ' );
}
if( strlen( cmd ) == 1 )
if( !strcmp( cmd, " " ) )
continue;
// Look for the first ' ' to separate the command from its args
temp = cmd;
if( *temp == ' ' )
temp ++;
if( ( p = strchr( temp, ' ' ) ) == NULL )
// Skip over the initial space char if it exists
p = cmd;
if( *p == ' ' )
p ++;
// Add a final space if it does not exist
if( p[ strlen( p ) - 1 ] != ' ' )
strcat( p, " " );
// Compute argc/argv
for( argc = 0; argc < SHELL_MAX_ARGS; argc ++ )
argv[ argc ] = NULL;
argc = 0;
while( ( temp = strchr( p, ' ' ) ) != NULL )
{
printf( SHELL_ERRMSG );
continue;
*temp = 0;
if( argc == SHELL_MAX_ARGS )
{
printf( "Error: too many arguments\n" );
argc = -1;
break;
}
argv[ argc ++ ] = p;
p = temp + 1;
}
*p = 0;
if( argc == -1 )
continue;
// Additional argument processing happens here
for( i = 0; i < argc; i ++ )
{
p = argv[ i ];
// Put back spaces if needed
for( inside_quotes = 0; inside_quotes < strlen( argv[ i ] ); inside_quotes ++ )
{
if( p[ inside_quotes ] == SHELL_ALT_SPACE )
argv[ i ][ inside_quotes ] = ' ';
}
// Remove quotes
if( ( p[ 0 ] == '\'' || p [ 0 ] == '"' ) && ( p[ 0 ] == p[ strlen( p ) - 1 ] ) )
{
argv[ i ] = p + 1;
p[ strlen( p ) - 1 ] = '\0';
}
}
// Match user command with shell's commands
i = 0;
while( 1 )
{
@ -443,11 +472,11 @@ void shell_start()
printf( SHELL_ERRMSG );
break;
}
if( !strcasecmp( pcmd->cmd, temp ) )
if( !strcasecmp( pcmd->cmd, argv[ 0 ] ) )
{
// Special case: the "exit" command has a NULL handler
if( pcmd->handler_func )
pcmd->handler_func( p + 1 );
pcmd->handler_func( argc, argv );
break;
}
i ++;

View File

@ -123,22 +123,21 @@ function mkfs( dirname, outname, flist, mode, compcmd )
end
_add_data( 0, outfile ) -- ASCIIZ
local plen = string.pack( "<i", #filedata )
-- Round to a multiple of 'alignment'
while _bytecnt % alignment ~= 0 do
_add_data( 0, outfile )
end
-- Write size
_add_data( plen:byte( 1 ), outfile )
_add_data( plen:byte( 2 ), outfile )
_add_data( plen:byte( 3 ), outfile )
_add_data( plen:byte( 4 ), outfile )
-- Round to a multiple of 'alignment'
local actual = #filedata
while _bytecnt % alignment ~= 0 do
_add_data( 0, outfile )
actual = actual + 1
end
-- Then write the rest of the file
-- Then write the rest of the file
for i = 1, #filedata do
_add_data( filedata:byte( i ), outfile )
end
-- Report
print( sf( "Encoded file %s (%d bytes real size, %d bytes after rounding, %d bytes total)", fname, #filedata, actual, _fcnt ) )
print( sf( "Encoded file %s (%d bytes real size, %d bytes encoded size)", fname, #filedata, _fcnt ) )
end
end
end