1526 lines
45 KiB
C
1526 lines
45 KiB
C
/*
|
|
* FreeRTOS Kernel V10.2.1
|
|
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* 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
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* http://www.FreeRTOS.org
|
|
* http://aws.amazon.com/freertos
|
|
*
|
|
* 1 tab == 4 spaces!
|
|
*/
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
/* Standard includes. */
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/* FreeRTOS+CLI includes. */
|
|
#include "FreeRTOS_CLI.h"
|
|
|
|
/* File system includes. */
|
|
#include <redposix.h>
|
|
#include <redtests.h>
|
|
|
|
#ifdef _WINDOWS_
|
|
#define snprintf _snprintf
|
|
#endif
|
|
|
|
#define cliNEW_LINE "\r\n"
|
|
|
|
/*******************************************************************************
|
|
* See the URL in the comments within main.c for the location of the online
|
|
* documentation.
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* Print out information on a single file.
|
|
*/
|
|
static void prvCreateFileInfoString( char *pcBuffer, REDDIRENT *pxDirent );
|
|
|
|
/*
|
|
* Copies an existing file into a newly created file.
|
|
*/
|
|
static BaseType_t prvPerformCopy( int32_t lSourceFildes,
|
|
int32_t lDestinationFiledes,
|
|
char *pxWriteBuffer,
|
|
size_t xWriteBufferLen );
|
|
|
|
/*
|
|
* Implements the DIR command.
|
|
*/
|
|
static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the DEL command.
|
|
*/
|
|
static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the TYPE command.
|
|
*/
|
|
static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the APPEND command.
|
|
*/
|
|
static BaseType_t prvAPPENDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the COPY command.
|
|
*/
|
|
static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the CREATE command.
|
|
*/
|
|
static BaseType_t prvCREATECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the MKDIR command.
|
|
*/
|
|
static BaseType_t prvMKDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the RENAME command.
|
|
*/
|
|
static BaseType_t prvRENAMECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the LINK command.
|
|
*/
|
|
static BaseType_t prvLINKCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the STAT command.
|
|
*/
|
|
static BaseType_t prvSTATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the STATFS command.
|
|
*/
|
|
static BaseType_t prvSTATFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the FORMAT command.
|
|
*/
|
|
static BaseType_t prvFORMATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the TRANSACT command.
|
|
*/
|
|
static BaseType_t prvTRANSACTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the TRANSMASKGET command.
|
|
*/
|
|
static BaseType_t prvTRANSMASKGETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the TRANSMASKSET command.
|
|
*/
|
|
static BaseType_t prvTRANSMASKSETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the ABORT command.
|
|
*/
|
|
static BaseType_t prvABORTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
/*
|
|
* Implements the TEST command.
|
|
*/
|
|
static BaseType_t prvTESTFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
|
|
|
|
|
|
/* Structure that defines the DIR command line command, which lists all the
|
|
files in the current directory. */
|
|
static const CLI_Command_Definition_t xDIR =
|
|
{
|
|
"dir", /* The command string to type. */
|
|
"\r\ndir <filename>:\r\n Lists the files in the named directory\r\n",
|
|
prvDIRCommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the TYPE command line command, which prints the
|
|
contents of a file to the console. */
|
|
static const CLI_Command_Definition_t xTYPE =
|
|
{
|
|
"type", /* The command string to type. */
|
|
"\r\ntype <filename>:\r\n Prints file contents to the terminal\r\n",
|
|
prvTYPECommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the APPEND command line command, which appends data
|
|
to a file. */
|
|
static const CLI_Command_Definition_t xAPPEND =
|
|
{
|
|
"append", /* The command string to type. */
|
|
"\r\nappend <filename> <character> <length>:\r\n Appends data to a file (created if it does not exist)\r\n",
|
|
prvAPPENDCommand, /* The function to run. */
|
|
3 /* Three parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the DEL command line command, which deletes a file. */
|
|
static const CLI_Command_Definition_t xDEL =
|
|
{
|
|
"del", /* The command string to type. */
|
|
"\r\ndel <filename>:\r\n deletes a file or directory\r\n",
|
|
prvDELCommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the COPY command line command, which copies a file. */
|
|
static const CLI_Command_Definition_t xCOPY =
|
|
{
|
|
"copy", /* The command string to type. */
|
|
"\r\ncopy <source file> <dest file>:\r\n Copies <source file> to <dest file>\r\n",
|
|
prvCOPYCommand, /* The function to run. */
|
|
2 /* Two parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the CREATE command line command, which creates an
|
|
empty file. */
|
|
static const CLI_Command_Definition_t xCREATE =
|
|
{
|
|
"create", /* The command string to type. */
|
|
"\r\ncreate <filename>:\r\n Creates an empty file\r\n",
|
|
prvCREATECommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the MKDIR command line command, which creates an
|
|
empty directory. */
|
|
static const CLI_Command_Definition_t xMKDIR =
|
|
{
|
|
"mkdir", /* The command string to type. */
|
|
"\r\nmkdir <filename>:\r\n Creates an empty directory\r\n",
|
|
prvMKDIRCommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the RENAME command line command, which renames a file. */
|
|
static const CLI_Command_Definition_t xRENAME =
|
|
{
|
|
"rename", /* The command string to type. */
|
|
"\r\nrename <source file> <dest file>:\r\n Rename <source file> to <dest file>\r\n",
|
|
prvRENAMECommand, /* The function to run. */
|
|
2 /* Two parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the LINK command line command, which creates a hard
|
|
link. */
|
|
static const CLI_Command_Definition_t xLINK =
|
|
{
|
|
"link", /* The command string to type. */
|
|
"\r\nlink <source file> <dest file>:\r\n Create hard link <dest file> pointing at <source file>\r\n",
|
|
prvLINKCommand, /* The function to run. */
|
|
2 /* Two parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the STAT command line command, which shows various
|
|
information about a file. */
|
|
static const CLI_Command_Definition_t xSTAT =
|
|
{
|
|
"stat", /* The command string to type. */
|
|
"\r\nstat <filename>:\r\n Show file information\r\n",
|
|
prvSTATCommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the STATFS command line command, which shows various
|
|
file system information. */
|
|
static const CLI_Command_Definition_t xSTATFS =
|
|
{
|
|
"statfs", /* The command string to type. */
|
|
"\r\nstatfs:\r\n Show file system information.\r\n",
|
|
prvSTATFSCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the FORMAT command line command, which re-formats the
|
|
file system. */
|
|
static const CLI_Command_Definition_t xFORMAT =
|
|
{
|
|
"format", /* The command string to type. */
|
|
"\r\nformat:\r\n Re-formats the file system volume. ALL FILES WILL BE DELETED!\r\n",
|
|
prvFORMATCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the TRANSACT command line command, which commits a
|
|
transaction point. */
|
|
static const CLI_Command_Definition_t xTRANSACT =
|
|
{
|
|
"transact", /* The command string to type. */
|
|
"\r\ntransact:\r\n Commit a Reliance Edge transaction point\r\n",
|
|
prvTRANSACTCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the TRANSMASKGET command line command, which retrieves
|
|
the current automatic transaction event mask. */
|
|
static const CLI_Command_Definition_t xTRANSMASKGET =
|
|
{
|
|
"transmaskget", /* The command string to type. */
|
|
"\r\ntransmaskget:\r\n Retrieve the Reliance Edge automatic transaction mask\r\n",
|
|
prvTRANSMASKGETCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the TRANSMASKSET command line command, which sets the
|
|
automatic transaction event mask. */
|
|
static const CLI_Command_Definition_t xTRANSMASKSET =
|
|
{
|
|
"transmaskset", /* The command string to type. */
|
|
"\r\ntransmaskset <hex mask>:\r\n Set the Reliance Edge automatic transaction mask\r\n",
|
|
prvTRANSMASKSETCommand, /* The function to run. */
|
|
1 /* One parameter is expected. */
|
|
};
|
|
|
|
/* Structure that defines the ABORT command line command, which rolls back
|
|
changes which have not been transacted. */
|
|
static const CLI_Command_Definition_t xABORT =
|
|
{
|
|
"abort", /* The command string to type. */
|
|
"\r\nabort:\r\n Roll back all changes not part of the last transaction point\r\n",
|
|
prvABORTCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/* Structure that defines the TEST-FS command line command, which executes some
|
|
file system driver tests. */
|
|
static const CLI_Command_Definition_t xTEST_FS =
|
|
{
|
|
"test-fs", /* The command string to type. */
|
|
"\r\ntest-fs:\r\n Executes file system tests. ALL FILES WILL BE DELETED!\r\n",
|
|
prvTESTFSCommand, /* The function to run. */
|
|
0 /* No parameters are expected. */
|
|
};
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void vRegisterFileSystemCLICommands( void )
|
|
{
|
|
/* Register all the command line commands defined immediately above. */
|
|
FreeRTOS_CLIRegisterCommand( &xDIR );
|
|
FreeRTOS_CLIRegisterCommand( &xTYPE );
|
|
FreeRTOS_CLIRegisterCommand( &xAPPEND );
|
|
FreeRTOS_CLIRegisterCommand( &xDEL );
|
|
FreeRTOS_CLIRegisterCommand( &xCOPY );
|
|
FreeRTOS_CLIRegisterCommand( &xCREATE );
|
|
FreeRTOS_CLIRegisterCommand( &xMKDIR );
|
|
FreeRTOS_CLIRegisterCommand( &xRENAME );
|
|
FreeRTOS_CLIRegisterCommand( &xLINK );
|
|
FreeRTOS_CLIRegisterCommand( &xSTAT );
|
|
FreeRTOS_CLIRegisterCommand( &xSTATFS );
|
|
FreeRTOS_CLIRegisterCommand( &xFORMAT );
|
|
FreeRTOS_CLIRegisterCommand( &xTRANSACT );
|
|
FreeRTOS_CLIRegisterCommand( &xTRANSMASKGET );
|
|
FreeRTOS_CLIRegisterCommand( &xTRANSMASKSET );
|
|
FreeRTOS_CLIRegisterCommand( &xABORT );
|
|
FreeRTOS_CLIRegisterCommand( &xTEST_FS );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
static REDDIR *pxDir = NULL;
|
|
REDDIRENT *pxDirent;
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength, xReturn = pdFALSE;
|
|
|
|
/* This assumes pcWriteBuffer is long enough. */
|
|
( void ) pcCommandString;
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
if( pxDir == NULL )
|
|
{
|
|
/* Retrieve the directory to DIR. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* This is the first time this function has been executed since the Dir
|
|
command was run. Open the directory. */
|
|
pxDir = red_opendir( pcParameter );
|
|
}
|
|
|
|
if( pxDir )
|
|
{
|
|
/* red_readdir() returns NULL either on error or upon reaching the
|
|
end of the directory. Clear errno so these conditions can be
|
|
distinguished. */
|
|
red_errno = 0;
|
|
pxDirent = red_readdir( pxDir );
|
|
|
|
if( pxDirent )
|
|
{
|
|
prvCreateFileInfoString( pcWriteBuffer, pxDirent );
|
|
xReturn = pdPASS;
|
|
}
|
|
else if( red_errno == 0 )
|
|
{
|
|
/* There are no more files. Close the directory. */
|
|
red_closedir( pxDir );
|
|
pxDir = NULL;
|
|
|
|
/* No string to return. */
|
|
pcWriteBuffer[ 0 ] = 0x00;
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d reading directory.", ( int ) red_errno );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOENT :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Directory not found." );
|
|
break;
|
|
|
|
case RED_ENOTDIR :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Directory not found or not a directory." );
|
|
break;
|
|
|
|
default :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening directory.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength, xReturn = pdTRUE;
|
|
static int32_t lFildes = -1;
|
|
REDSTAT finfo;
|
|
int32_t lStatus, lBytesRead;
|
|
size_t xColumns = 50U;
|
|
|
|
/* Ensure there is always a null terminator after each character written. */
|
|
memset( pcWriteBuffer, 0x00, xWriteBufferLen );
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
if( xWriteBufferLen < xColumns )
|
|
{
|
|
/* Ensure the loop that uses xColumns as an end condition does not
|
|
write off the end of the buffer. */
|
|
xColumns = xWriteBufferLen;
|
|
}
|
|
|
|
if( lFildes == -1 )
|
|
{
|
|
/* The file has not been opened yet. Find the file name. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* Attempt to open the requested file. */
|
|
lFildes = red_open( pcParameter, RED_O_RDONLY );
|
|
if( lFildes == -1 )
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOENT :
|
|
case RED_ENOTDIR :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "File not found." );
|
|
break;
|
|
|
|
default :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Make sure this is a file, not a directory. */
|
|
lStatus = red_fstat( lFildes, &finfo );
|
|
if( lStatus == 0 )
|
|
{
|
|
if( RED_S_ISDIR( finfo.st_mode ) )
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Cannot TYPE a directory." );
|
|
red_close( lFildes );
|
|
lFildes = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file.", ( int ) red_errno );
|
|
red_close( lFildes );
|
|
lFildes = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( lFildes != -1 )
|
|
{
|
|
/* Read the next chunk of data from the file. */
|
|
lBytesRead = red_read( lFildes, pcWriteBuffer, xColumns );
|
|
|
|
if( lBytesRead < ( int32_t ) xColumns )
|
|
{
|
|
/* Error or no more characters to return. */
|
|
red_close( lFildes );
|
|
lFildes = -1;
|
|
}
|
|
}
|
|
|
|
if( lFildes == -1 )
|
|
{
|
|
/* Either the file was not opened, or all the data from the file has
|
|
been returned and the file is now closed. */
|
|
xReturn = pdFALSE;
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvAPPENDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
char *pcFileName = NULL;
|
|
const char *pcCharacter = NULL, *pcLength;
|
|
BaseType_t xParameterStringLength, xGoodParameters = pdTRUE;
|
|
int32_t lFildes, lAppendLength = -1, lThisWrite, lTotalWritten, lBytesWritten;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Find the length to write. */
|
|
pcLength = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
3, /* Return the third parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
configASSERT( pcLength );
|
|
|
|
/* Convert the string into a number. */
|
|
lAppendLength = RedAtoI( pcLength );
|
|
if( lAppendLength < 0 )
|
|
{
|
|
strcpy( pcWriteBuffer, "Third parameter cannot be a negative number." );
|
|
xGoodParameters = pdFALSE;
|
|
}
|
|
|
|
if( xGoodParameters )
|
|
{
|
|
/* Find the character to write. */
|
|
pcCharacter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
2, /* Return the second parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
configASSERT( pcCharacter );
|
|
|
|
if( xParameterStringLength != 1 )
|
|
{
|
|
strcpy( pcWriteBuffer, "Second parameter must be a single character." );
|
|
xGoodParameters = pdFALSE;
|
|
}
|
|
}
|
|
|
|
if( xGoodParameters )
|
|
{
|
|
/* Find the file name. */
|
|
pcFileName = ( char * ) FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
configASSERT( pcFileName );
|
|
|
|
/* Terminate the string. */
|
|
pcFileName[ xParameterStringLength ] = 0x00;
|
|
}
|
|
|
|
if( xGoodParameters )
|
|
{
|
|
/* Attempt to open the requested file. */
|
|
lFildes = red_open( pcFileName, RED_O_WRONLY|RED_O_APPEND|RED_O_CREAT );
|
|
|
|
if( lFildes == -1 )
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOENT :
|
|
case RED_ENOTDIR :
|
|
strcpy( pcWriteBuffer, "Bad file path." );
|
|
break;
|
|
|
|
case RED_EISDIR :
|
|
strcpy( pcWriteBuffer, "Cannot append to a directory." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d opening file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Put the requested character into the buffer. */
|
|
memset( pcWriteBuffer, pcCharacter[0], xWriteBufferLen );
|
|
|
|
/* Append the data. */
|
|
for( lTotalWritten = 0; lTotalWritten < lAppendLength; lTotalWritten += lThisWrite )
|
|
{
|
|
lThisWrite = lAppendLength - lTotalWritten;
|
|
if( lThisWrite > ( int32_t ) xWriteBufferLen )
|
|
{
|
|
lThisWrite = ( int32_t ) xWriteBufferLen;
|
|
}
|
|
|
|
lBytesWritten = red_write( lFildes, pcWriteBuffer, lThisWrite );
|
|
if( lBytesWritten == -1 )
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOSPC :
|
|
strcpy( pcWriteBuffer, "Out of disk space." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d writing to file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
else if( lBytesWritten != lThisWrite )
|
|
{
|
|
/* Some data was written, but not all of it. This only
|
|
happens when the disk is full or the file reached its
|
|
maximum size. That latter is unlikely in this demo. */
|
|
strcpy( pcWriteBuffer, "Out of disk space." );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( lTotalWritten == lAppendLength )
|
|
{
|
|
strcpy( pcWriteBuffer, "Append successful." );
|
|
}
|
|
|
|
red_close( lFildes );
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lStatus;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Obtain the parameter string. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* Attempt to delete the file or directory. */
|
|
lStatus = red_unlink( pcParameter );
|
|
|
|
if( lStatus == 0 )
|
|
{
|
|
sprintf( pcWriteBuffer, "%s was deleted", pcParameter );
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOTDIR :
|
|
case RED_ENOENT :
|
|
sprintf( pcWriteBuffer, "File not found." );
|
|
break;
|
|
|
|
case RED_ENOTEMPTY :
|
|
sprintf( pcWriteBuffer, "Cannot remove directory: not empty." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d deleting file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
char *pcSourceFile;
|
|
const char *pcDestinationFile;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lSourceFildes, lDestinationFildes;
|
|
|
|
/* Obtain the name of the destination file. */
|
|
pcDestinationFile = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
2, /* Return the second parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcDestinationFile );
|
|
|
|
/* Obtain the name of the source file. */
|
|
pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcSourceFile );
|
|
|
|
/* Terminate the string. */
|
|
pcSourceFile[ xParameterStringLength ] = 0x00;
|
|
|
|
/* See if the source file exists, openm it if it does. */
|
|
lSourceFildes = red_open( pcSourceFile, RED_O_RDONLY );
|
|
|
|
if( lSourceFildes == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Source file does not exist" );
|
|
}
|
|
else
|
|
{
|
|
/* Create the destination file, error if it already exists. */
|
|
lDestinationFildes = red_open( pcDestinationFile, RED_O_CREAT|RED_O_EXCL|RED_O_WRONLY );
|
|
|
|
if( lDestinationFildes == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error: Destination file already exists" );
|
|
}
|
|
else
|
|
{
|
|
if( prvPerformCopy( lSourceFildes, lDestinationFildes, pcWriteBuffer, xWriteBufferLen ) == pdPASS )
|
|
{
|
|
sprintf( pcWriteBuffer, "Copy made" );
|
|
}
|
|
else
|
|
{
|
|
sprintf( pcWriteBuffer, "Error during copy" );
|
|
}
|
|
|
|
red_close( lDestinationFildes );
|
|
}
|
|
|
|
red_close( lSourceFildes );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvCREATECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lFildes;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Obtain the parameter string. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* Attempt to create the file. */
|
|
lFildes = red_open( pcParameter, RED_O_CREAT|RED_O_EXCL|RED_O_RDWR );
|
|
|
|
if( lFildes != -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "%s was created", pcParameter );
|
|
red_close( lFildes );
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOTDIR :
|
|
case RED_ENOENT :
|
|
sprintf( pcWriteBuffer, "Bad file path." );
|
|
break;
|
|
|
|
case RED_EEXIST :
|
|
sprintf( pcWriteBuffer, "File already exists." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d creating file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvMKDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lStatus;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Obtain the parameter string. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* Attempt to create the file. */
|
|
lStatus = red_mkdir( pcParameter );
|
|
|
|
if( lStatus == 0 )
|
|
{
|
|
sprintf( pcWriteBuffer, "%s was created", pcParameter );
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOTDIR :
|
|
case RED_ENOENT :
|
|
sprintf( pcWriteBuffer, "Bad file path." );
|
|
break;
|
|
|
|
case RED_EEXIST :
|
|
sprintf( pcWriteBuffer, "Directory already exists." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d creating directory.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvRENAMECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcDestinationFile;
|
|
char *pcSourceFile;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lStatus;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Obtain the name of the destination file. */
|
|
pcDestinationFile = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
2, /* Return the second parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcDestinationFile );
|
|
|
|
/* Obtain the name of the source file. */
|
|
pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcSourceFile );
|
|
|
|
/* Terminate the string. */
|
|
pcSourceFile[ xParameterStringLength ] = 0x00;
|
|
|
|
/* Attempt to rename the file. */
|
|
lStatus = red_rename( pcSourceFile, pcDestinationFile );
|
|
|
|
if( lStatus == 0 )
|
|
{
|
|
sprintf( pcWriteBuffer, "%s was renamed to %s", pcSourceFile, pcDestinationFile );
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOTDIR :
|
|
case RED_ENOENT :
|
|
case RED_EISDIR :
|
|
sprintf( pcWriteBuffer, "Bad file path." );
|
|
break;
|
|
|
|
/* This will only be seen if POSIX rename is disabled. */
|
|
case RED_EEXIST :
|
|
sprintf( pcWriteBuffer, "Destination already exists." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d renaming file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvLINKCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcDestinationFile;
|
|
char *pcSourceFile;
|
|
BaseType_t xParameterStringLength;
|
|
int32_t lStatus;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Obtain the name of the destination file. */
|
|
pcDestinationFile = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
2, /* Return the second parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcDestinationFile );
|
|
|
|
/* Obtain the name of the source file. */
|
|
pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcSourceFile );
|
|
|
|
/* Terminate the string. */
|
|
pcSourceFile[ xParameterStringLength ] = 0x00;
|
|
|
|
/* Attempt to create the hard link. */
|
|
lStatus = red_link( pcSourceFile, pcDestinationFile );
|
|
|
|
if( lStatus == 0 )
|
|
{
|
|
sprintf( pcWriteBuffer, "%s was linked to %s", pcDestinationFile, pcSourceFile );
|
|
}
|
|
else
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOTDIR :
|
|
case RED_ENOENT :
|
|
sprintf( pcWriteBuffer, "Bad file path." );
|
|
break;
|
|
|
|
case RED_EPERM :
|
|
sprintf( pcWriteBuffer, "Cannot link a directory." );
|
|
break;
|
|
|
|
case RED_EMLINK :
|
|
sprintf( pcWriteBuffer, "Too many hard links." );
|
|
break;
|
|
|
|
default :
|
|
sprintf( pcWriteBuffer, "Error %d linking file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvSTATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter, *pcModeString;
|
|
BaseType_t xParameterStringLength;
|
|
REDSTAT finfo;
|
|
int32_t lFildes, lStatus;
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
/* Find the file name. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
/* Attempt to open the requested file. */
|
|
lFildes = red_open( pcParameter, RED_O_RDONLY );
|
|
if( lFildes == -1 )
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_ENOENT :
|
|
case RED_ENOTDIR :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "File not found." );
|
|
break;
|
|
|
|
default :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening file.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lStatus = red_fstat( lFildes, &finfo );
|
|
if( lStatus == 0 )
|
|
{
|
|
if( RED_S_ISDIR( finfo.st_mode ) )
|
|
{
|
|
pcModeString = "dir";
|
|
}
|
|
else
|
|
{
|
|
pcModeString = "file";
|
|
}
|
|
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "ino=%lu mode=0x%04x(%s) nlink=%x size=%lu blocks=%lu",
|
|
( unsigned long ) finfo.st_ino, ( unsigned ) finfo.st_mode, pcModeString,
|
|
( unsigned ) finfo.st_nlink, (unsigned long) finfo.st_size, (unsigned long) finfo.st_blocks );
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file.", ( int ) red_errno );
|
|
}
|
|
|
|
red_close( lFildes );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvSTATFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
REDSTATFS fsinfo;
|
|
int32_t lStatus;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) pcCommandString;
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
lStatus = red_statvfs( "", &fsinfo );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file system.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen,
|
|
"Block size: %lu\r\n"
|
|
"Block count: %lu\r\n"
|
|
"Free blocks: %lu\r\n"
|
|
"Inode count: %lu\r\n"
|
|
"Free inodes: %lu\r\n",
|
|
( unsigned long ) fsinfo.f_bsize, ( unsigned long ) fsinfo.f_blocks,
|
|
( unsigned long ) fsinfo.f_bfree, ( unsigned long ) fsinfo.f_files,
|
|
( unsigned long ) fsinfo.f_ffree );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvFORMATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
int32_t lStatus;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) pcCommandString;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* File system volumes cannot be formatted while mounted. */
|
|
lStatus = red_umount( "" );
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during unmount.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
/* Re-format the file system volume. */
|
|
lStatus = red_format( "" );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during format.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
/* Mount again so that other commands will work properly. */
|
|
lStatus = red_mount( "" );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during mount.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
strcpy( pcWriteBuffer, "Format successful." );
|
|
}
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvTRANSACTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
int32_t lStatus;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) pcCommandString;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Save the original transaction mask settings. */
|
|
lStatus = red_transact( "" );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during transaction point.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
strcpy( pcWriteBuffer, "Transaction point successful." );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvTRANSMASKGETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
uint32_t ulEventMask;
|
|
int32_t lStatus;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) pcCommandString;
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
lStatus = red_gettransmask( "", &ulEventMask );
|
|
if( lStatus == -1 )
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d retrieving automatic transaction event mask.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen,
|
|
"Current automatic transaction event mask: 0x%04lx\r\n"
|
|
"RED_TRANSACT_UMOUNT (0x0001): %s\r\n"
|
|
"RED_TRANSACT_CREAT (0x0002): %s\r\n"
|
|
"RED_TRANSACT_UNLINK (0x0004): %s\r\n"
|
|
"RED_TRANSACT_MKDIR (0x0008): %s\r\n"
|
|
"RED_TRANSACT_RENAME (0x0010): %s\r\n"
|
|
"RED_TRANSACT_LINK (0x0020): %s\r\n"
|
|
"RED_TRANSACT_CLOSE (0x0040): %s\r\n"
|
|
"RED_TRANSACT_WRITE (0x0080): %s\r\n"
|
|
"RED_TRANSACT_FSYNC (0x0100): %s\r\n"
|
|
"RED_TRANSACT_TRUNCATE (0x0200): %s\r\n"
|
|
"RED_TRANSACT_VOLFULL (0x0400): %s\r\n",
|
|
( unsigned long ) ulEventMask,
|
|
( ulEventMask & RED_TRANSACT_UMOUNT ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_CREAT ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_UNLINK ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_MKDIR ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_RENAME ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_LINK ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_CLOSE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_WRITE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_FSYNC ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_TRUNCATE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_VOLFULL ) ? "Enabled" : "Disabled" );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvTRANSMASKSETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
const char *pcParameter;
|
|
BaseType_t xParameterStringLength;
|
|
uint32_t ulEventMask;
|
|
int32_t lStatus;
|
|
|
|
/* Ensure the buffer leaves space for the \r\n. */
|
|
configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );
|
|
xWriteBufferLen -= strlen( cliNEW_LINE );
|
|
|
|
/* Obtain the parameter string. */
|
|
pcParameter = FreeRTOS_CLIGetParameter
|
|
(
|
|
pcCommandString, /* The command string itself. */
|
|
1, /* Return the first parameter. */
|
|
&xParameterStringLength /* Store the parameter string length. */
|
|
);
|
|
|
|
/* Sanity check something was returned. */
|
|
configASSERT( pcParameter );
|
|
|
|
if( ( pcParameter[0] == '0' ) && ( ( pcParameter[1] == 'x' ) || ( pcParameter[1] == 'X' ) ) )
|
|
{
|
|
pcParameter += 2;
|
|
}
|
|
|
|
/* Convert the argument into a value. */
|
|
RedHtoUL( pcParameter, &ulEventMask );
|
|
|
|
/* Set the new transaction mask. */
|
|
lStatus = red_settransmask( "", ulEventMask );
|
|
if( lStatus == -1 )
|
|
{
|
|
/* User-friendly messages for common errors. */
|
|
switch( red_errno )
|
|
{
|
|
case RED_EINVAL:
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Invalid bits in transaction mask." );
|
|
break;
|
|
|
|
default :
|
|
snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d setting transaction mask.", ( int ) red_errno );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snprintf( pcWriteBuffer, xWriteBufferLen,
|
|
"Successfully set automatic transaction mask. Enabled events:\r\n"
|
|
"RED_TRANSACT_UMOUNT (0x0001): %s\r\n"
|
|
"RED_TRANSACT_CREAT (0x0002): %s\r\n"
|
|
"RED_TRANSACT_UNLINK (0x0004): %s\r\n"
|
|
"RED_TRANSACT_MKDIR (0x0008): %s\r\n"
|
|
"RED_TRANSACT_RENAME (0x0010): %s\r\n"
|
|
"RED_TRANSACT_LINK (0x0020): %s\r\n"
|
|
"RED_TRANSACT_CLOSE (0x0040): %s\r\n"
|
|
"RED_TRANSACT_WRITE (0x0080): %s\r\n"
|
|
"RED_TRANSACT_FSYNC (0x0100): %s\r\n"
|
|
"RED_TRANSACT_TRUNCATE (0x0200): %s\r\n"
|
|
"RED_TRANSACT_VOLFULL (0x0400): %s\r\n",
|
|
( ulEventMask & RED_TRANSACT_UMOUNT ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_CREAT ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_UNLINK ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_MKDIR ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_RENAME ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_LINK ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_CLOSE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_WRITE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_FSYNC ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_TRUNCATE ) ? "Enabled" : "Disabled",
|
|
( ulEventMask & RED_TRANSACT_VOLFULL ) ? "Enabled" : "Disabled" );
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvABORTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
uint32_t ulEventMask;
|
|
int32_t lStatus;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) pcCommandString;
|
|
|
|
/* This function assumes xWriteBufferLen is large enough! */
|
|
( void ) xWriteBufferLen;
|
|
|
|
/* Save the original transaction mask settings. */
|
|
lStatus = red_gettransmask( "", &ulEventMask );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d querying transaction mask.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
/* Make it so that red_umount() will not automatically commit a new
|
|
transaction point. */
|
|
lStatus = red_settransmask( "", ulEventMask & ~( ( uint32_t ) RED_TRANSACT_UMOUNT ) );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d setting transaction mask.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
/* Unmount. Since red_umount() will not transact, all changes which
|
|
were not already transacted are rolled back. */
|
|
lStatus = red_umount( "" );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during unmount.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
/* Mount. Mount always starts from the last transaction point. */
|
|
lStatus = red_mount( "" );
|
|
|
|
if( lStatus == -1 )
|
|
{
|
|
sprintf( pcWriteBuffer, "Error %d during mount.", ( int ) red_errno );
|
|
}
|
|
else
|
|
{
|
|
strcpy( pcWriteBuffer, "Working state changes succesfully aborted." );
|
|
}
|
|
}
|
|
|
|
/* Restore the original transaction mask settings. */
|
|
red_settransmask( "", ulEventMask );
|
|
}
|
|
}
|
|
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvTESTFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
|
|
{
|
|
UBaseType_t uxOriginalPriority;
|
|
FSSTRESSPARAM param;
|
|
|
|
/* Avoid compiler warnings. */
|
|
( void ) xWriteBufferLen;
|
|
( void ) pcCommandString;
|
|
|
|
/* Limitations in the interaction with the Windows TCP/IP stack require
|
|
the command console to run at the idle priority. Raise the priority for
|
|
the duration of the tests to ensure there are not multiple switches to the
|
|
idle task as in the simulated environment the idle task hook function may
|
|
include a (relatively) long delay. */
|
|
uxOriginalPriority = uxTaskPriorityGet( NULL );
|
|
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
|
|
|
/* Delete all files to avoid inteferring with the test. */
|
|
red_umount( "" );
|
|
red_format( "" );
|
|
red_mount( "" );
|
|
|
|
FsstressDefaultParams(¶m);
|
|
param.fVerbose = pdTRUE;
|
|
param.ulNops = 10000;
|
|
param.ulSeed = 1;
|
|
FsstressStart(¶m);
|
|
|
|
/* Clean up after the test. */
|
|
red_umount( "" );
|
|
red_format( "" );
|
|
red_mount( "" );
|
|
|
|
/* Reset back to the original priority. */
|
|
vTaskPrioritySet( NULL, uxOriginalPriority );
|
|
|
|
sprintf( pcWriteBuffer, "%s", "Test results were sent to Windows console" );
|
|
strcat( pcWriteBuffer, cliNEW_LINE );
|
|
|
|
return pdFALSE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvPerformCopy( int32_t lSourceFildes,
|
|
int32_t lDestinationFiledes,
|
|
char *pxWriteBuffer,
|
|
size_t xWriteBufferLen )
|
|
{
|
|
int32_t lBytesRead;
|
|
BaseType_t xReturn = pdPASS;
|
|
|
|
/* Assuming both files are at offset zero. */
|
|
|
|
for( ;; )
|
|
{
|
|
/* Read the next block of data. */
|
|
lBytesRead = red_read( lSourceFildes, pxWriteBuffer, xWriteBufferLen );
|
|
if( lBytesRead <= 0 )
|
|
{
|
|
if( lBytesRead == -1)
|
|
{
|
|
/* Error reading from file. */
|
|
xReturn = pdFAIL;
|
|
}
|
|
else
|
|
{
|
|
/* No error: reached end of file, time to stop. */
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Write the block of data to the end of the file. */
|
|
if( red_write( lDestinationFiledes, pxWriteBuffer, lBytesRead ) != lBytesRead )
|
|
{
|
|
xReturn = pdFAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvCreateFileInfoString( char *pcBuffer, REDDIRENT *pxDirent )
|
|
{
|
|
const char *pcFile = "file", *pcDirectory = "directory";
|
|
const char *pcAttrib;
|
|
|
|
/* Point pcAttrib to a string that describes the file. */
|
|
if( RED_S_ISDIR(pxDirent->d_stat.st_mode) )
|
|
{
|
|
pcAttrib = pcDirectory;
|
|
}
|
|
else
|
|
{
|
|
pcAttrib = pcFile;
|
|
}
|
|
|
|
/* Create a string that includes the file name, the file size and the
|
|
attributes string. */
|
|
sprintf( pcBuffer, "%s [%s] [size=%lld]", pxDirent->d_name, pcAttrib, pxDirent->d_stat.st_size );
|
|
}
|