blob: d51146e51c625958f5900639df791ead47d560fe [file] [log] [blame]
/*
FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
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(&param);
param.fVerbose = pdTRUE;
param.ulNops = 10000;
param.ulSeed = 1;
FsstressStart(&param);
/* 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=%d]", pxDirent->d_name, pcAttrib, pxDirent->d_stat.st_size );
}