]> git.sur5r.net Git - freertos/blob
aa4d38f2f420fd2cc80e41bd7384bd0f0e2b3f74
[freertos] /
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* FreeRTOS includes. */\r
30 #include "FreeRTOS.h"\r
31 #include "task.h"\r
32 \r
33 /* Standard includes. */\r
34 #include <stdint.h>\r
35 #include <stdio.h>\r
36 #include <stdlib.h>\r
37 \r
38 /* FreeRTOS+CLI includes. */\r
39 #include "FreeRTOS_CLI.h"\r
40 \r
41 /* File system includes. */\r
42 #include <redposix.h>\r
43 #include <redtests.h>\r
44 \r
45 #ifdef _WINDOWS_\r
46         #define snprintf _snprintf\r
47 #endif\r
48 \r
49 #define cliNEW_LINE             "\r\n"\r
50 \r
51 /*******************************************************************************\r
52  * See the URL in the comments within main.c for the location of the online\r
53  * documentation.\r
54  ******************************************************************************/\r
55 \r
56 /*\r
57  * Print out information on a single file.\r
58  */\r
59 static void prvCreateFileInfoString( char *pcBuffer, REDDIRENT *pxDirent );\r
60 \r
61 /*\r
62  * Copies an existing file into a newly created file.\r
63  */\r
64 static BaseType_t prvPerformCopy( int32_t lSourceFildes,\r
65                                                         int32_t lDestinationFiledes,\r
66                                                         char *pxWriteBuffer,\r
67                                                         size_t xWriteBufferLen );\r
68 \r
69 /*\r
70  * Implements the DIR command.\r
71  */\r
72 static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
73 \r
74 /*\r
75  * Implements the DEL command.\r
76  */\r
77 static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
78 \r
79 /*\r
80  * Implements the TYPE command.\r
81  */\r
82 static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
83 \r
84 /*\r
85  * Implements the APPEND command.\r
86  */\r
87 static BaseType_t prvAPPENDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
88 \r
89 /*\r
90  * Implements the COPY command.\r
91  */\r
92 static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
93 \r
94 /*\r
95  * Implements the CREATE command.\r
96  */\r
97 static BaseType_t prvCREATECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
98 \r
99 /*\r
100  * Implements the MKDIR command.\r
101  */\r
102 static BaseType_t prvMKDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
103 \r
104 /*\r
105  * Implements the RENAME command.\r
106  */\r
107 static BaseType_t prvRENAMECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
108 \r
109 /*\r
110  * Implements the LINK command.\r
111  */\r
112 static BaseType_t prvLINKCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
113 \r
114 /*\r
115  * Implements the STAT command.\r
116  */\r
117 static BaseType_t prvSTATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
118 \r
119 /*\r
120  * Implements the STATFS command.\r
121  */\r
122 static BaseType_t prvSTATFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
123 \r
124 /*\r
125  * Implements the FORMAT command.\r
126  */\r
127 static BaseType_t prvFORMATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
128 \r
129 /*\r
130  * Implements the TRANSACT command.\r
131  */\r
132 static BaseType_t prvTRANSACTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
133 \r
134 /*\r
135  * Implements the TRANSMASKGET command.\r
136  */\r
137 static BaseType_t prvTRANSMASKGETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
138 \r
139 /*\r
140  * Implements the TRANSMASKSET command.\r
141  */\r
142 static BaseType_t prvTRANSMASKSETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
143 \r
144 /*\r
145  * Implements the ABORT command.\r
146  */\r
147 static BaseType_t prvABORTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
148 \r
149 /*\r
150  * Implements the TEST command.\r
151  */\r
152 static BaseType_t prvTESTFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
153 \r
154 \r
155 /* Structure that defines the DIR command line command, which lists all the\r
156 files in the current directory. */\r
157 static const CLI_Command_Definition_t xDIR =\r
158 {\r
159         "dir", /* The command string to type. */\r
160         "\r\ndir <filename>:\r\n Lists the files in the named directory\r\n",\r
161         prvDIRCommand, /* The function to run. */\r
162         1 /* One parameter is expected. */\r
163 };\r
164 \r
165 /* Structure that defines the TYPE command line command, which prints the\r
166 contents of a file to the console. */\r
167 static const CLI_Command_Definition_t xTYPE =\r
168 {\r
169         "type", /* The command string to type. */\r
170         "\r\ntype <filename>:\r\n Prints file contents to the terminal\r\n",\r
171         prvTYPECommand, /* The function to run. */\r
172         1 /* One parameter is expected. */\r
173 };\r
174 \r
175 /* Structure that defines the APPEND command line command, which appends data\r
176 to a file. */\r
177 static const CLI_Command_Definition_t xAPPEND =\r
178 {\r
179         "append", /* The command string to type. */\r
180         "\r\nappend <filename> <character> <length>:\r\n Appends data to a file (created if it does not exist)\r\n",\r
181         prvAPPENDCommand, /* The function to run. */\r
182         3 /* Three parameters are expected. */\r
183 };\r
184 \r
185 /* Structure that defines the DEL command line command, which deletes a file. */\r
186 static const CLI_Command_Definition_t xDEL =\r
187 {\r
188         "del", /* The command string to type. */\r
189         "\r\ndel <filename>:\r\n deletes a file or directory\r\n",\r
190         prvDELCommand, /* The function to run. */\r
191         1 /* One parameter is expected. */\r
192 };\r
193 \r
194 /* Structure that defines the COPY command line command, which copies a file. */\r
195 static const CLI_Command_Definition_t xCOPY =\r
196 {\r
197         "copy", /* The command string to type. */\r
198         "\r\ncopy <source file> <dest file>:\r\n Copies <source file> to <dest file>\r\n",\r
199         prvCOPYCommand, /* The function to run. */\r
200         2 /* Two parameters are expected. */\r
201 };\r
202 \r
203 /* Structure that defines the CREATE command line command, which creates an\r
204 empty file. */\r
205 static const CLI_Command_Definition_t xCREATE =\r
206 {\r
207         "create", /* The command string to type. */\r
208         "\r\ncreate <filename>:\r\n Creates an empty file\r\n",\r
209         prvCREATECommand, /* The function to run. */\r
210         1 /* One parameter is expected. */\r
211 };\r
212 \r
213 /* Structure that defines the MKDIR command line command, which creates an\r
214 empty directory. */\r
215 static const CLI_Command_Definition_t xMKDIR =\r
216 {\r
217         "mkdir", /* The command string to type. */\r
218         "\r\nmkdir <filename>:\r\n Creates an empty directory\r\n",\r
219         prvMKDIRCommand, /* The function to run. */\r
220         1 /* One parameter is expected. */\r
221 };\r
222 \r
223 /* Structure that defines the RENAME command line command, which renames a file. */\r
224 static const CLI_Command_Definition_t xRENAME =\r
225 {\r
226         "rename", /* The command string to type. */\r
227         "\r\nrename <source file> <dest file>:\r\n Rename <source file> to <dest file>\r\n",\r
228         prvRENAMECommand, /* The function to run. */\r
229         2 /* Two parameters are expected. */\r
230 };\r
231 \r
232 /* Structure that defines the LINK command line command, which creates a hard\r
233 link. */\r
234 static const CLI_Command_Definition_t xLINK =\r
235 {\r
236         "link", /* The command string to type. */\r
237         "\r\nlink <source file> <dest file>:\r\n Create hard link <dest file> pointing at <source file>\r\n",\r
238         prvLINKCommand, /* The function to run. */\r
239         2 /* Two parameters are expected. */\r
240 };\r
241 \r
242 /* Structure that defines the STAT command line command, which shows various\r
243 information about a file. */\r
244 static const CLI_Command_Definition_t xSTAT =\r
245 {\r
246         "stat", /* The command string to type. */\r
247         "\r\nstat <filename>:\r\n Show file information\r\n",\r
248         prvSTATCommand, /* The function to run. */\r
249         1 /* One parameter is expected. */\r
250 };\r
251 \r
252 /* Structure that defines the STATFS command line command, which shows various\r
253 file system information. */\r
254 static const CLI_Command_Definition_t xSTATFS =\r
255 {\r
256         "statfs", /* The command string to type. */\r
257         "\r\nstatfs:\r\n Show file system information.\r\n",\r
258         prvSTATFSCommand, /* The function to run. */\r
259         0 /* No parameters are expected. */\r
260 };\r
261 \r
262 /* Structure that defines the FORMAT command line command, which re-formats the\r
263 file system. */\r
264 static const CLI_Command_Definition_t xFORMAT =\r
265 {\r
266         "format", /* The command string to type. */\r
267         "\r\nformat:\r\n Re-formats the file system volume.  ALL FILES WILL BE DELETED!\r\n",\r
268         prvFORMATCommand, /* The function to run. */\r
269         0 /* No parameters are expected. */\r
270 };\r
271 \r
272 /* Structure that defines the TRANSACT command line command, which commits a\r
273 transaction point. */\r
274 static const CLI_Command_Definition_t xTRANSACT =\r
275 {\r
276         "transact", /* The command string to type. */\r
277         "\r\ntransact:\r\n Commit a Reliance Edge transaction point\r\n",\r
278         prvTRANSACTCommand, /* The function to run. */\r
279         0 /* No parameters are expected. */\r
280 };\r
281 \r
282 /* Structure that defines the TRANSMASKGET command line command, which retrieves\r
283 the current automatic transaction event mask. */\r
284 static const CLI_Command_Definition_t xTRANSMASKGET =\r
285 {\r
286         "transmaskget", /* The command string to type. */\r
287         "\r\ntransmaskget:\r\n Retrieve the Reliance Edge automatic transaction mask\r\n",\r
288         prvTRANSMASKGETCommand, /* The function to run. */\r
289         0 /* No parameters are expected. */\r
290 };\r
291 \r
292 /* Structure that defines the TRANSMASKSET command line command, which sets the\r
293 automatic transaction event mask. */\r
294 static const CLI_Command_Definition_t xTRANSMASKSET =\r
295 {\r
296         "transmaskset", /* The command string to type. */\r
297         "\r\ntransmaskset <hex mask>:\r\n Set the Reliance Edge automatic transaction mask\r\n",\r
298         prvTRANSMASKSETCommand, /* The function to run. */\r
299         1 /* One parameter is expected. */\r
300 };\r
301 \r
302 /* Structure that defines the ABORT command line command, which rolls back\r
303 changes which have not been transacted. */\r
304 static const CLI_Command_Definition_t xABORT =\r
305 {\r
306         "abort", /* The command string to type. */\r
307         "\r\nabort:\r\n Roll back all changes not part of the last transaction point\r\n",\r
308         prvABORTCommand, /* The function to run. */\r
309         0 /* No parameters are expected. */\r
310 };\r
311 \r
312 /* Structure that defines the TEST-FS command line command, which executes some\r
313 file system driver tests. */\r
314 static const CLI_Command_Definition_t xTEST_FS =\r
315 {\r
316         "test-fs", /* The command string to type. */\r
317         "\r\ntest-fs:\r\n Executes file system tests.  ALL FILES WILL BE DELETED!\r\n",\r
318         prvTESTFSCommand, /* The function to run. */\r
319         0 /* No parameters are expected. */\r
320 };\r
321 \r
322 /*-----------------------------------------------------------*/\r
323 \r
324 void vRegisterFileSystemCLICommands( void )\r
325 {\r
326         /* Register all the command line commands defined immediately above. */\r
327         FreeRTOS_CLIRegisterCommand( &xDIR );\r
328         FreeRTOS_CLIRegisterCommand( &xTYPE );\r
329         FreeRTOS_CLIRegisterCommand( &xAPPEND );\r
330         FreeRTOS_CLIRegisterCommand( &xDEL );\r
331         FreeRTOS_CLIRegisterCommand( &xCOPY );\r
332         FreeRTOS_CLIRegisterCommand( &xCREATE );\r
333         FreeRTOS_CLIRegisterCommand( &xMKDIR );\r
334         FreeRTOS_CLIRegisterCommand( &xRENAME );\r
335         FreeRTOS_CLIRegisterCommand( &xLINK );\r
336         FreeRTOS_CLIRegisterCommand( &xSTAT );\r
337         FreeRTOS_CLIRegisterCommand( &xSTATFS );\r
338         FreeRTOS_CLIRegisterCommand( &xFORMAT );\r
339         FreeRTOS_CLIRegisterCommand( &xTRANSACT );\r
340         FreeRTOS_CLIRegisterCommand( &xTRANSMASKGET );\r
341         FreeRTOS_CLIRegisterCommand( &xTRANSMASKSET );\r
342         FreeRTOS_CLIRegisterCommand( &xABORT );\r
343         FreeRTOS_CLIRegisterCommand( &xTEST_FS );\r
344 }\r
345 /*-----------------------------------------------------------*/\r
346 \r
347 static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
348 {\r
349 static REDDIR *pxDir = NULL;\r
350 REDDIRENT *pxDirent;\r
351 const char *pcParameter;\r
352 BaseType_t xParameterStringLength, xReturn = pdFALSE;\r
353 \r
354         /* This assumes pcWriteBuffer is long enough. */\r
355         ( void ) pcCommandString;\r
356 \r
357         /* Ensure the buffer leaves space for the \r\n. */\r
358         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
359         xWriteBufferLen -= strlen( cliNEW_LINE );\r
360 \r
361         if( pxDir == NULL )\r
362         {\r
363                 /* Retrieve the directory to DIR. */\r
364                 pcParameter = FreeRTOS_CLIGetParameter\r
365                                                 (\r
366                                                         pcCommandString,                /* The command string itself. */\r
367                                                         1,                                              /* Return the first parameter. */\r
368                                                         &xParameterStringLength /* Store the parameter string length. */\r
369                                                 );\r
370 \r
371                 /* Sanity check something was returned. */\r
372                 configASSERT( pcParameter );\r
373 \r
374                 /* This is the first time this function has been executed since the Dir\r
375                 command was run.  Open the directory. */\r
376                 pxDir = red_opendir( pcParameter );\r
377         }\r
378 \r
379         if( pxDir )\r
380         {\r
381                 /* red_readdir() returns NULL either on error or upon reaching the\r
382                 end of the directory.  Clear errno so these conditions can be\r
383                 distinguished. */\r
384                 red_errno = 0;\r
385                 pxDirent = red_readdir( pxDir );\r
386 \r
387                 if( pxDirent )\r
388                 {\r
389                         prvCreateFileInfoString( pcWriteBuffer, pxDirent );\r
390                         xReturn = pdPASS;\r
391                 }\r
392                 else if( red_errno == 0 )\r
393                 {\r
394                         /* There are no more files.  Close the directory. */\r
395                         red_closedir( pxDir );\r
396                         pxDir = NULL;\r
397 \r
398                         /* No string to return. */\r
399                         pcWriteBuffer[ 0 ] = 0x00;\r
400                 }\r
401                 else\r
402                 {\r
403                         snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d reading directory.", ( int ) red_errno );\r
404                 }\r
405         }\r
406         else\r
407         {\r
408                 /* User-friendly messages for common errors. */\r
409                 switch( red_errno )\r
410                 {\r
411                         case RED_ENOENT :\r
412                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Directory not found." );\r
413                                 break;\r
414 \r
415                         case RED_ENOTDIR :\r
416                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Directory not found or not a directory." );\r
417                                 break;\r
418 \r
419                         default :\r
420                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening directory.", ( int ) red_errno );\r
421                                 break;\r
422                 }\r
423         }\r
424 \r
425         strcat( pcWriteBuffer, cliNEW_LINE );\r
426 \r
427         return xReturn;\r
428 }\r
429 /*-----------------------------------------------------------*/\r
430 \r
431 static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
432 {\r
433 const char *pcParameter;\r
434 BaseType_t xParameterStringLength, xReturn = pdTRUE;\r
435 static int32_t lFildes = -1;\r
436 REDSTAT finfo;\r
437 int32_t lStatus, lBytesRead;\r
438 size_t xColumns = 50U;\r
439 \r
440         /* Ensure there is always a null terminator after each character written. */\r
441         memset( pcWriteBuffer, 0x00, xWriteBufferLen );\r
442 \r
443         /* Ensure the buffer leaves space for the \r\n. */\r
444         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
445         xWriteBufferLen -= strlen( cliNEW_LINE );\r
446 \r
447         if( xWriteBufferLen < xColumns )\r
448         {\r
449                 /* Ensure the loop that uses xColumns as an end condition does not\r
450                 write off the end of the buffer. */\r
451                 xColumns = xWriteBufferLen;\r
452         }\r
453 \r
454         if( lFildes == -1 )\r
455         {\r
456                 /* The file has not been opened yet.  Find the file name. */\r
457                 pcParameter = FreeRTOS_CLIGetParameter\r
458                                                 (\r
459                                                         pcCommandString,                /* The command string itself. */\r
460                                                         1,                                              /* Return the first parameter. */\r
461                                                         &xParameterStringLength /* Store the parameter string length. */\r
462                                                 );\r
463 \r
464                 /* Sanity check something was returned. */\r
465                 configASSERT( pcParameter );\r
466 \r
467                 /* Attempt to open the requested file. */\r
468                 lFildes = red_open( pcParameter, RED_O_RDONLY );\r
469                 if( lFildes == -1 )\r
470                 {\r
471                         /* User-friendly messages for common errors. */\r
472                         switch( red_errno )\r
473                         {\r
474                                 case RED_ENOENT :\r
475                                 case RED_ENOTDIR :\r
476                                         snprintf( pcWriteBuffer, xWriteBufferLen, "File not found." );\r
477                                         break;\r
478 \r
479                                 default :\r
480                                         snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening file.", ( int ) red_errno );\r
481                                         break;\r
482                         }\r
483                 }\r
484                 else\r
485                 {\r
486                         /* Make sure this is a file, not a directory. */\r
487                         lStatus = red_fstat( lFildes, &finfo );\r
488                         if( lStatus == 0 )\r
489                         {\r
490                                 if( RED_S_ISDIR( finfo.st_mode ) )\r
491                                 {\r
492                                         snprintf( pcWriteBuffer, xWriteBufferLen, "Cannot TYPE a directory." );\r
493                                         red_close( lFildes );\r
494                                         lFildes = -1;\r
495                                 }\r
496                         }\r
497                         else\r
498                         {\r
499                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file.", ( int ) red_errno );\r
500                                 red_close( lFildes );\r
501                                 lFildes = -1;\r
502                         }\r
503                 }\r
504         }\r
505 \r
506         if( lFildes != -1 )\r
507         {\r
508                 /* Read the next chunk of data from the file. */\r
509                 lBytesRead = red_read( lFildes, pcWriteBuffer, xColumns );\r
510 \r
511                 if( lBytesRead < ( int32_t ) xColumns )\r
512                 {\r
513                         /* Error or no more characters to return. */\r
514                         red_close( lFildes );\r
515                         lFildes = -1;\r
516                 }\r
517         }\r
518 \r
519         if( lFildes == -1 )\r
520         {\r
521                 /* Either the file was not opened, or all the data from the file has\r
522                 been returned and the file is now closed. */\r
523                 xReturn = pdFALSE;\r
524         }\r
525 \r
526         strcat( pcWriteBuffer, cliNEW_LINE );\r
527 \r
528         return xReturn;\r
529 }\r
530 /*-----------------------------------------------------------*/\r
531 \r
532 static BaseType_t prvAPPENDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
533 {\r
534 char *pcFileName = NULL;\r
535 const char *pcCharacter = NULL, *pcLength;\r
536 BaseType_t xParameterStringLength, xGoodParameters = pdTRUE;\r
537 int32_t lFildes, lAppendLength = -1, lThisWrite, lTotalWritten, lBytesWritten;\r
538 \r
539         /* This function assumes xWriteBufferLen is large enough! */\r
540         ( void ) xWriteBufferLen;\r
541 \r
542         /* Find the length to write. */\r
543         pcLength = FreeRTOS_CLIGetParameter\r
544                                         (\r
545                                                 pcCommandString,                /* The command string itself. */\r
546                                                 3,                                              /* Return the third parameter. */\r
547                                                 &xParameterStringLength /* Store the parameter string length. */\r
548                                         );\r
549         configASSERT( pcLength );\r
550 \r
551         /* Convert the string into a number. */\r
552         lAppendLength = RedAtoI( pcLength );\r
553         if( lAppendLength < 0 )\r
554         {\r
555                 strcpy( pcWriteBuffer, "Third parameter cannot be a negative number." );\r
556                 xGoodParameters = pdFALSE;\r
557         }\r
558 \r
559         if( xGoodParameters )\r
560         {\r
561                 /* Find the character to write. */\r
562                 pcCharacter = FreeRTOS_CLIGetParameter\r
563                                                 (\r
564                                                         pcCommandString,                /* The command string itself. */\r
565                                                         2,                                              /* Return the second parameter. */\r
566                                                         &xParameterStringLength /* Store the parameter string length. */\r
567                                                 );\r
568                 configASSERT( pcCharacter );\r
569 \r
570                 if( xParameterStringLength != 1 )\r
571                 {\r
572                         strcpy( pcWriteBuffer, "Second parameter must be a single character." );\r
573                         xGoodParameters = pdFALSE;\r
574                 }\r
575         }\r
576 \r
577         if( xGoodParameters )\r
578         {\r
579                 /* Find the file name. */\r
580                 pcFileName = ( char * ) FreeRTOS_CLIGetParameter\r
581                                                                 (\r
582                                                                         pcCommandString,                /* The command string itself. */\r
583                                                                         1,                                              /* Return the first parameter. */\r
584                                                                         &xParameterStringLength /* Store the parameter string length. */\r
585                                                                 );\r
586                 configASSERT( pcFileName );\r
587 \r
588                 /* Terminate the string. */\r
589                 pcFileName[ xParameterStringLength ] = 0x00;\r
590         }\r
591 \r
592         if( xGoodParameters )\r
593         {\r
594                 /* Attempt to open the requested file. */\r
595                 lFildes = red_open( pcFileName, RED_O_WRONLY|RED_O_APPEND|RED_O_CREAT );\r
596 \r
597                 if( lFildes == -1 )\r
598                 {\r
599                         /* User-friendly messages for common errors. */\r
600                         switch( red_errno )\r
601                         {\r
602                                 case RED_ENOENT :\r
603                                 case RED_ENOTDIR :\r
604                                         strcpy( pcWriteBuffer, "Bad file path." );\r
605                                         break;\r
606 \r
607                                 case RED_EISDIR :\r
608                                         strcpy( pcWriteBuffer, "Cannot append to a directory." );\r
609                                         break;\r
610 \r
611                                 default :\r
612                                         sprintf( pcWriteBuffer, "Error %d opening file.", ( int ) red_errno );\r
613                                         break;\r
614                         }\r
615                 }\r
616                 else\r
617                 {\r
618                         /* Put the requested character into the buffer. */\r
619                         memset( pcWriteBuffer, pcCharacter[0], xWriteBufferLen );\r
620 \r
621                         /* Append the data. */\r
622                         for( lTotalWritten = 0; lTotalWritten < lAppendLength; lTotalWritten += lThisWrite )\r
623                         {\r
624                                 lThisWrite = lAppendLength - lTotalWritten;\r
625                                 if( lThisWrite > ( int32_t ) xWriteBufferLen )\r
626                                 {\r
627                                         lThisWrite = ( int32_t ) xWriteBufferLen;\r
628                                 }\r
629 \r
630                                 lBytesWritten = red_write( lFildes, pcWriteBuffer, lThisWrite );\r
631                                 if( lBytesWritten == -1 )\r
632                                 {\r
633                                         /* User-friendly messages for common errors. */\r
634                                         switch( red_errno )\r
635                                         {\r
636                                                 case RED_ENOSPC :\r
637                                                         strcpy( pcWriteBuffer, "Out of disk space." );\r
638                                                         break;\r
639 \r
640                                                 default :\r
641                                                         sprintf( pcWriteBuffer, "Error %d writing to file.", ( int ) red_errno );\r
642                                                         break;\r
643                                         }\r
644 \r
645                                         break;\r
646                                 }\r
647                                 else if( lBytesWritten != lThisWrite )\r
648                                 {\r
649                                         /*      Some data was written, but not all of it.  This only\r
650                                         happens when the disk is full or the file reached its\r
651                                         maximum size.  That latter is unlikely in this demo. */\r
652                                         strcpy( pcWriteBuffer, "Out of disk space." );\r
653                                         break;\r
654                                 }\r
655                         }\r
656 \r
657                         if( lTotalWritten == lAppendLength )\r
658                         {\r
659                                 strcpy( pcWriteBuffer, "Append successful." );\r
660                         }\r
661 \r
662                         red_close( lFildes );\r
663                 }\r
664         }\r
665 \r
666         strcat( pcWriteBuffer, cliNEW_LINE );\r
667 \r
668         return pdFALSE;\r
669 }\r
670 /*-----------------------------------------------------------*/\r
671 \r
672 static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
673 {\r
674 const char *pcParameter;\r
675 BaseType_t xParameterStringLength;\r
676 int32_t lStatus;\r
677 \r
678         /* This function assumes xWriteBufferLen is large enough! */\r
679         ( void ) xWriteBufferLen;\r
680 \r
681         /* Obtain the parameter string. */\r
682         pcParameter = FreeRTOS_CLIGetParameter\r
683                                         (\r
684                                                 pcCommandString,                /* The command string itself. */\r
685                                                 1,                                              /* Return the first parameter. */\r
686                                                 &xParameterStringLength /* Store the parameter string length. */\r
687                                         );\r
688 \r
689         /* Sanity check something was returned. */\r
690         configASSERT( pcParameter );\r
691 \r
692         /* Attempt to delete the file or directory. */\r
693         lStatus = red_unlink( pcParameter );\r
694 \r
695         if( lStatus == 0 )\r
696         {\r
697                 sprintf( pcWriteBuffer, "%s was deleted", pcParameter );\r
698         }\r
699         else\r
700         {\r
701                 /* User-friendly messages for common errors. */\r
702                 switch( red_errno )\r
703                 {\r
704                         case RED_ENOTDIR :\r
705                         case RED_ENOENT :\r
706                                 sprintf( pcWriteBuffer, "File not found." );\r
707                                 break;\r
708 \r
709                         case RED_ENOTEMPTY :\r
710                                 sprintf( pcWriteBuffer, "Cannot remove directory: not empty." );\r
711                                 break;\r
712 \r
713                         default :\r
714                                 sprintf( pcWriteBuffer, "Error %d deleting file.", ( int ) red_errno );\r
715                                 break;\r
716                 }\r
717         }\r
718 \r
719         strcat( pcWriteBuffer, cliNEW_LINE );\r
720 \r
721         return pdFALSE;\r
722 }\r
723 /*-----------------------------------------------------------*/\r
724 \r
725 static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
726 {\r
727 char *pcSourceFile;\r
728 const char *pcDestinationFile;\r
729 BaseType_t xParameterStringLength;\r
730 int32_t lSourceFildes, lDestinationFildes;\r
731 \r
732         /* Obtain the name of the destination file. */\r
733         pcDestinationFile = FreeRTOS_CLIGetParameter\r
734                                                 (\r
735                                                         pcCommandString,                /* The command string itself. */\r
736                                                         2,                                              /* Return the second parameter. */\r
737                                                         &xParameterStringLength /* Store the parameter string length. */\r
738                                                 );\r
739 \r
740         /* Sanity check something was returned. */\r
741         configASSERT( pcDestinationFile );\r
742 \r
743         /* Obtain the name of the source file. */\r
744         pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter\r
745                                                                 (\r
746                                                                         pcCommandString,                /* The command string itself. */\r
747                                                                         1,                                              /* Return the first parameter. */\r
748                                                                         &xParameterStringLength /* Store the parameter string length. */\r
749                                                                 );\r
750 \r
751         /* Sanity check something was returned. */\r
752         configASSERT( pcSourceFile );\r
753 \r
754         /* Terminate the string. */\r
755         pcSourceFile[ xParameterStringLength ] = 0x00;\r
756 \r
757         /* See if the source file exists, openm it if it does. */\r
758         lSourceFildes = red_open( pcSourceFile, RED_O_RDONLY );\r
759 \r
760         if( lSourceFildes == -1 )\r
761         {\r
762                 sprintf( pcWriteBuffer, "Source file does not exist" );\r
763         }\r
764         else\r
765         {\r
766                 /* Create the destination file, error if it already exists. */\r
767                 lDestinationFildes = red_open( pcDestinationFile, RED_O_CREAT|RED_O_EXCL|RED_O_WRONLY );\r
768 \r
769                 if( lDestinationFildes == -1 )\r
770                 {\r
771                         sprintf( pcWriteBuffer, "Error: Destination file already exists" );\r
772                 }\r
773                 else\r
774                 {\r
775                         if( prvPerformCopy( lSourceFildes, lDestinationFildes, pcWriteBuffer, xWriteBufferLen ) == pdPASS )\r
776                         {\r
777                                 sprintf( pcWriteBuffer, "Copy made" );\r
778                         }\r
779                         else\r
780                         {\r
781                                 sprintf( pcWriteBuffer, "Error during copy" );\r
782                         }\r
783 \r
784                         red_close( lDestinationFildes );\r
785                 }\r
786 \r
787                 red_close( lSourceFildes );\r
788         }\r
789 \r
790         strcat( pcWriteBuffer, cliNEW_LINE );\r
791 \r
792         return pdFALSE;\r
793 }\r
794 /*-----------------------------------------------------------*/\r
795 \r
796 static BaseType_t prvCREATECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
797 {\r
798 const char *pcParameter;\r
799 BaseType_t xParameterStringLength;\r
800 int32_t lFildes;\r
801 \r
802         /* This function assumes xWriteBufferLen is large enough! */\r
803         ( void ) xWriteBufferLen;\r
804 \r
805         /* Obtain the parameter string. */\r
806         pcParameter = FreeRTOS_CLIGetParameter\r
807                                         (\r
808                                                 pcCommandString,                /* The command string itself. */\r
809                                                 1,                                              /* Return the first parameter. */\r
810                                                 &xParameterStringLength /* Store the parameter string length. */\r
811                                         );\r
812 \r
813         /* Sanity check something was returned. */\r
814         configASSERT( pcParameter );\r
815 \r
816         /* Attempt to create the file. */\r
817         lFildes = red_open( pcParameter, RED_O_CREAT|RED_O_EXCL|RED_O_RDWR );\r
818 \r
819         if( lFildes != -1 )\r
820         {\r
821                 sprintf( pcWriteBuffer, "%s was created", pcParameter );\r
822                 red_close( lFildes );\r
823         }\r
824         else\r
825         {\r
826                 /* User-friendly messages for common errors. */\r
827                 switch( red_errno )\r
828                 {\r
829                         case RED_ENOTDIR :\r
830                         case RED_ENOENT :\r
831                                 sprintf( pcWriteBuffer, "Bad file path." );\r
832                                 break;\r
833 \r
834                         case RED_EEXIST :\r
835                                 sprintf( pcWriteBuffer, "File already exists." );\r
836                                 break;\r
837 \r
838                         default :\r
839                                 sprintf( pcWriteBuffer, "Error %d creating file.", ( int ) red_errno );\r
840                                 break;\r
841                 }\r
842         }\r
843 \r
844         strcat( pcWriteBuffer, cliNEW_LINE );\r
845 \r
846         return pdFALSE;\r
847 }\r
848 /*-----------------------------------------------------------*/\r
849 \r
850 static BaseType_t prvMKDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
851 {\r
852 const char *pcParameter;\r
853 BaseType_t xParameterStringLength;\r
854 int32_t lStatus;\r
855 \r
856         /* This function assumes xWriteBufferLen is large enough! */\r
857         ( void ) xWriteBufferLen;\r
858 \r
859         /* Obtain the parameter string. */\r
860         pcParameter = FreeRTOS_CLIGetParameter\r
861                                         (\r
862                                                 pcCommandString,                /* The command string itself. */\r
863                                                 1,                                              /* Return the first parameter. */\r
864                                                 &xParameterStringLength /* Store the parameter string length. */\r
865                                         );\r
866 \r
867         /* Sanity check something was returned. */\r
868         configASSERT( pcParameter );\r
869 \r
870         /* Attempt to create the file. */\r
871         lStatus = red_mkdir( pcParameter );\r
872 \r
873         if( lStatus == 0 )\r
874         {\r
875                 sprintf( pcWriteBuffer, "%s was created", pcParameter );\r
876         }\r
877         else\r
878         {\r
879                 /* User-friendly messages for common errors. */\r
880                 switch( red_errno )\r
881                 {\r
882                         case RED_ENOTDIR :\r
883                         case RED_ENOENT :\r
884                                 sprintf( pcWriteBuffer, "Bad file path." );\r
885                                 break;\r
886 \r
887                         case RED_EEXIST :\r
888                                 sprintf( pcWriteBuffer, "Directory already exists." );\r
889                                 break;\r
890 \r
891                         default :\r
892                                 sprintf( pcWriteBuffer, "Error %d creating directory.", ( int ) red_errno );\r
893                                 break;\r
894                 }\r
895         }\r
896 \r
897         strcat( pcWriteBuffer, cliNEW_LINE );\r
898 \r
899         return pdFALSE;\r
900 }\r
901 /*-----------------------------------------------------------*/\r
902 \r
903 static BaseType_t prvRENAMECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
904 {\r
905 const char *pcDestinationFile;\r
906 char *pcSourceFile;\r
907 BaseType_t xParameterStringLength;\r
908 int32_t lStatus;\r
909 \r
910         /* This function assumes xWriteBufferLen is large enough! */\r
911         ( void ) xWriteBufferLen;\r
912 \r
913         /* Obtain the name of the destination file. */\r
914         pcDestinationFile = FreeRTOS_CLIGetParameter\r
915                                                 (\r
916                                                         pcCommandString,                /* The command string itself. */\r
917                                                         2,                                              /* Return the second parameter. */\r
918                                                         &xParameterStringLength /* Store the parameter string length. */\r
919                                                 );\r
920 \r
921         /* Sanity check something was returned. */\r
922         configASSERT( pcDestinationFile );\r
923 \r
924         /* Obtain the name of the source file. */\r
925         pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter\r
926                                                                 (\r
927                                                                         pcCommandString,                /* The command string itself. */\r
928                                                                         1,                                              /* Return the first parameter. */\r
929                                                                         &xParameterStringLength /* Store the parameter string length. */\r
930                                                                 );\r
931 \r
932         /* Sanity check something was returned. */\r
933         configASSERT( pcSourceFile );\r
934 \r
935         /* Terminate the string. */\r
936         pcSourceFile[ xParameterStringLength ] = 0x00;\r
937 \r
938         /* Attempt to rename the file. */\r
939         lStatus = red_rename( pcSourceFile, pcDestinationFile );\r
940 \r
941         if( lStatus == 0 )\r
942         {\r
943                 sprintf( pcWriteBuffer, "%s was renamed to %s", pcSourceFile, pcDestinationFile );\r
944         }\r
945         else\r
946         {\r
947                 /* User-friendly messages for common errors. */\r
948                 switch( red_errno )\r
949                 {\r
950                         case RED_ENOTDIR :\r
951                         case RED_ENOENT :\r
952                         case RED_EISDIR :\r
953                                 sprintf( pcWriteBuffer, "Bad file path." );\r
954                                 break;\r
955 \r
956                         /* This will only be seen if POSIX rename is disabled. */\r
957                         case RED_EEXIST :\r
958                                 sprintf( pcWriteBuffer, "Destination already exists." );\r
959                                 break;\r
960 \r
961                         default :\r
962                                 sprintf( pcWriteBuffer, "Error %d renaming file.", ( int ) red_errno );\r
963                                 break;\r
964                 }\r
965         }\r
966 \r
967         strcat( pcWriteBuffer, cliNEW_LINE );\r
968 \r
969         return pdFALSE;\r
970 }\r
971 /*-----------------------------------------------------------*/\r
972 \r
973 static BaseType_t prvLINKCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
974 {\r
975 const char *pcDestinationFile;\r
976 char *pcSourceFile;\r
977 BaseType_t xParameterStringLength;\r
978 int32_t lStatus;\r
979 \r
980         /* This function assumes xWriteBufferLen is large enough! */\r
981         ( void ) xWriteBufferLen;\r
982 \r
983         /* Obtain the name of the destination file. */\r
984         pcDestinationFile = FreeRTOS_CLIGetParameter\r
985                                                 (\r
986                                                         pcCommandString,                /* The command string itself. */\r
987                                                         2,                                              /* Return the second parameter. */\r
988                                                         &xParameterStringLength /* Store the parameter string length. */\r
989                                                 );\r
990 \r
991         /* Sanity check something was returned. */\r
992         configASSERT( pcDestinationFile );\r
993 \r
994         /* Obtain the name of the source file. */\r
995         pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter\r
996                                                                 (\r
997                                                                         pcCommandString,                /* The command string itself. */\r
998                                                                         1,                                              /* Return the first parameter. */\r
999                                                                         &xParameterStringLength /* Store the parameter string length. */\r
1000                                                                 );\r
1001 \r
1002         /* Sanity check something was returned. */\r
1003         configASSERT( pcSourceFile );\r
1004 \r
1005         /* Terminate the string. */\r
1006         pcSourceFile[ xParameterStringLength ] = 0x00;\r
1007 \r
1008         /* Attempt to create the hard link. */\r
1009         lStatus = red_link( pcSourceFile, pcDestinationFile );\r
1010 \r
1011         if( lStatus == 0 )\r
1012         {\r
1013                 sprintf( pcWriteBuffer, "%s was linked to %s", pcDestinationFile, pcSourceFile );\r
1014         }\r
1015         else\r
1016         {\r
1017                 /* User-friendly messages for common errors. */\r
1018                 switch( red_errno )\r
1019                 {\r
1020                         case RED_ENOTDIR :\r
1021                         case RED_ENOENT :\r
1022                                 sprintf( pcWriteBuffer, "Bad file path." );\r
1023                                 break;\r
1024 \r
1025                         case RED_EPERM :\r
1026                                 sprintf( pcWriteBuffer, "Cannot link a directory." );\r
1027                                 break;\r
1028 \r
1029                         case RED_EMLINK :\r
1030                                 sprintf( pcWriteBuffer, "Too many hard links." );\r
1031                                 break;\r
1032 \r
1033                         default :\r
1034                                 sprintf( pcWriteBuffer, "Error %d linking file.", ( int ) red_errno );\r
1035                                 break;\r
1036                 }\r
1037         }\r
1038 \r
1039         strcat( pcWriteBuffer, cliNEW_LINE );\r
1040 \r
1041         return pdFALSE;\r
1042 }\r
1043 /*-----------------------------------------------------------*/\r
1044 \r
1045 static BaseType_t prvSTATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1046 {\r
1047 const char *pcParameter, *pcModeString;\r
1048 BaseType_t xParameterStringLength;\r
1049 REDSTAT finfo;\r
1050 int32_t lFildes, lStatus;\r
1051 \r
1052         /* Ensure the buffer leaves space for the \r\n. */\r
1053         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
1054         xWriteBufferLen -= strlen( cliNEW_LINE );\r
1055 \r
1056         /* Find the file name. */\r
1057         pcParameter = FreeRTOS_CLIGetParameter\r
1058                                         (\r
1059                                                 pcCommandString,                /* The command string itself. */\r
1060                                                 1,                                              /* Return the first parameter. */\r
1061                                                 &xParameterStringLength /* Store the parameter string length. */\r
1062                                         );\r
1063 \r
1064         /* Sanity check something was returned. */\r
1065         configASSERT( pcParameter );\r
1066 \r
1067         /* Attempt to open the requested file. */\r
1068         lFildes = red_open( pcParameter, RED_O_RDONLY );\r
1069         if( lFildes == -1 )\r
1070         {\r
1071                 /* User-friendly messages for common errors. */\r
1072                 switch( red_errno )\r
1073                 {\r
1074                         case RED_ENOENT :\r
1075                         case RED_ENOTDIR :\r
1076                                 snprintf( pcWriteBuffer, xWriteBufferLen, "File not found." );\r
1077                                 break;\r
1078 \r
1079                         default :\r
1080                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d opening file.", ( int ) red_errno );\r
1081                                 break;\r
1082                 }\r
1083         }\r
1084         else\r
1085         {\r
1086                 lStatus = red_fstat( lFildes, &finfo );\r
1087                 if( lStatus == 0 )\r
1088                 {\r
1089                         if( RED_S_ISDIR( finfo.st_mode ) )\r
1090                         {\r
1091                                 pcModeString = "dir";\r
1092                         }\r
1093                         else\r
1094                         {\r
1095                                 pcModeString = "file";\r
1096                         }\r
1097 \r
1098                         snprintf( pcWriteBuffer, xWriteBufferLen, "ino=%lu mode=0x%04x(%s) nlink=%x size=%lu blocks=%lu",\r
1099                                 ( unsigned long ) finfo.st_ino, ( unsigned ) finfo.st_mode, pcModeString,\r
1100                                 ( unsigned ) finfo.st_nlink, (unsigned long) finfo.st_size, (unsigned long) finfo.st_blocks );\r
1101                 }\r
1102                 else\r
1103                 {\r
1104                         snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file.", ( int ) red_errno );\r
1105                 }\r
1106 \r
1107                 red_close( lFildes );\r
1108         }\r
1109 \r
1110         strcat( pcWriteBuffer, cliNEW_LINE );\r
1111 \r
1112         return pdFALSE;\r
1113 }\r
1114 /*-----------------------------------------------------------*/\r
1115 \r
1116 static BaseType_t prvSTATFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1117 {\r
1118 REDSTATFS fsinfo;\r
1119 int32_t lStatus;\r
1120 \r
1121         /* Avoid compiler warnings. */\r
1122         ( void ) pcCommandString;\r
1123 \r
1124         /* Ensure the buffer leaves space for the \r\n. */\r
1125         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
1126         xWriteBufferLen -= strlen( cliNEW_LINE );\r
1127 \r
1128         lStatus = red_statvfs( "", &fsinfo );\r
1129 \r
1130         if( lStatus == -1 )\r
1131         {\r
1132                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d querying file system.", ( int ) red_errno );\r
1133         }\r
1134         else\r
1135         {\r
1136                 snprintf( pcWriteBuffer, xWriteBufferLen,\r
1137                         "Block size: %lu\r\n"\r
1138                         "Block count: %lu\r\n"\r
1139                         "Free blocks: %lu\r\n"\r
1140                         "Inode count: %lu\r\n"\r
1141                         "Free inodes: %lu\r\n",\r
1142                         ( unsigned long ) fsinfo.f_bsize, ( unsigned long ) fsinfo.f_blocks,\r
1143                         ( unsigned long ) fsinfo.f_bfree, ( unsigned long ) fsinfo.f_files,\r
1144                         ( unsigned long ) fsinfo.f_ffree );\r
1145         }\r
1146 \r
1147         strcat( pcWriteBuffer, cliNEW_LINE );\r
1148 \r
1149         return pdFALSE;\r
1150 }\r
1151 /*-----------------------------------------------------------*/\r
1152 \r
1153 static BaseType_t prvFORMATCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1154 {\r
1155 int32_t lStatus;\r
1156 \r
1157         /* Avoid compiler warnings. */\r
1158         ( void ) pcCommandString;\r
1159 \r
1160         /* This function assumes xWriteBufferLen is large enough! */\r
1161         ( void ) xWriteBufferLen;\r
1162 \r
1163         /* File system volumes cannot be formatted while mounted. */\r
1164         lStatus = red_umount( "" );\r
1165         if( lStatus == -1 )\r
1166         {\r
1167                 sprintf( pcWriteBuffer, "Error %d during unmount.",  ( int ) red_errno );\r
1168         }\r
1169         else\r
1170         {\r
1171                 /* Re-format the file system volume. */\r
1172                 lStatus = red_format( "" );\r
1173 \r
1174                 if( lStatus == -1 )\r
1175                 {\r
1176                         sprintf( pcWriteBuffer, "Error %d during format.",  ( int ) red_errno );\r
1177                 }\r
1178                 else\r
1179                 {\r
1180                         /* Mount again so that other commands will work properly. */\r
1181                         lStatus = red_mount( "" );\r
1182 \r
1183                         if( lStatus == -1 )\r
1184                         {\r
1185                                 sprintf( pcWriteBuffer, "Error %d during mount.",  ( int ) red_errno );\r
1186                         }\r
1187                         else\r
1188                         {\r
1189                                 strcpy( pcWriteBuffer, "Format successful." );\r
1190                         }\r
1191                 }\r
1192         }\r
1193 \r
1194         strcat( pcWriteBuffer, cliNEW_LINE );\r
1195 \r
1196         return pdFALSE;\r
1197 }\r
1198 /*-----------------------------------------------------------*/\r
1199 \r
1200 static BaseType_t prvTRANSACTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1201 {\r
1202 int32_t lStatus;\r
1203 \r
1204         /* Avoid compiler warnings. */\r
1205         ( void ) pcCommandString;\r
1206 \r
1207         /* This function assumes xWriteBufferLen is large enough! */\r
1208         ( void ) xWriteBufferLen;\r
1209 \r
1210         /* Save the original transaction mask settings. */\r
1211         lStatus = red_transact( "" );\r
1212 \r
1213         if( lStatus == -1 )\r
1214         {\r
1215                 sprintf( pcWriteBuffer, "Error %d during transaction point.",  ( int ) red_errno );\r
1216         }\r
1217         else\r
1218         {\r
1219                 strcpy( pcWriteBuffer, "Transaction point successful." );\r
1220         }\r
1221 \r
1222         strcat( pcWriteBuffer, cliNEW_LINE );\r
1223 \r
1224         return pdFALSE;\r
1225 }\r
1226 /*-----------------------------------------------------------*/\r
1227 \r
1228 static BaseType_t prvTRANSMASKGETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1229 {\r
1230 uint32_t ulEventMask;\r
1231 int32_t lStatus;\r
1232 \r
1233         /* Avoid compiler warnings. */\r
1234         ( void ) pcCommandString;\r
1235 \r
1236         /* Ensure the buffer leaves space for the \r\n. */\r
1237         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
1238         xWriteBufferLen -= strlen( cliNEW_LINE );\r
1239 \r
1240         lStatus = red_gettransmask( "", &ulEventMask );\r
1241         if( lStatus == -1 )\r
1242         {\r
1243                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d retrieving automatic transaction event mask.",  ( int ) red_errno );\r
1244         }\r
1245         else\r
1246         {\r
1247                 snprintf( pcWriteBuffer, xWriteBufferLen,\r
1248                         "Current automatic transaction event mask: 0x%04lx\r\n"\r
1249                         "RED_TRANSACT_UMOUNT   (0x0001): %s\r\n"\r
1250                         "RED_TRANSACT_CREAT    (0x0002): %s\r\n"\r
1251                         "RED_TRANSACT_UNLINK   (0x0004): %s\r\n"\r
1252                         "RED_TRANSACT_MKDIR    (0x0008): %s\r\n"\r
1253                         "RED_TRANSACT_RENAME   (0x0010): %s\r\n"\r
1254                         "RED_TRANSACT_LINK     (0x0020): %s\r\n"\r
1255                         "RED_TRANSACT_CLOSE    (0x0040): %s\r\n"\r
1256                         "RED_TRANSACT_WRITE    (0x0080): %s\r\n"\r
1257                         "RED_TRANSACT_FSYNC    (0x0100): %s\r\n"\r
1258                         "RED_TRANSACT_TRUNCATE (0x0200): %s\r\n"\r
1259                         "RED_TRANSACT_VOLFULL  (0x0400): %s\r\n",\r
1260                         ( unsigned long ) ulEventMask,\r
1261                         ( ulEventMask & RED_TRANSACT_UMOUNT )   ? "Enabled" : "Disabled",\r
1262                         ( ulEventMask & RED_TRANSACT_CREAT )    ? "Enabled" : "Disabled",\r
1263                         ( ulEventMask & RED_TRANSACT_UNLINK )   ? "Enabled" : "Disabled",\r
1264                         ( ulEventMask & RED_TRANSACT_MKDIR )    ? "Enabled" : "Disabled",\r
1265                         ( ulEventMask & RED_TRANSACT_RENAME )   ? "Enabled" : "Disabled",\r
1266                         ( ulEventMask & RED_TRANSACT_LINK )     ? "Enabled" : "Disabled",\r
1267                         ( ulEventMask & RED_TRANSACT_CLOSE )    ? "Enabled" : "Disabled",\r
1268                         ( ulEventMask & RED_TRANSACT_WRITE )    ? "Enabled" : "Disabled",\r
1269                         ( ulEventMask & RED_TRANSACT_FSYNC )    ? "Enabled" : "Disabled",\r
1270                         ( ulEventMask & RED_TRANSACT_TRUNCATE ) ? "Enabled" : "Disabled",\r
1271                         ( ulEventMask & RED_TRANSACT_VOLFULL )  ? "Enabled" : "Disabled" );\r
1272         }\r
1273 \r
1274         strcat( pcWriteBuffer, cliNEW_LINE );\r
1275 \r
1276         return pdFALSE;\r
1277 }\r
1278 /*-----------------------------------------------------------*/\r
1279 \r
1280 static BaseType_t prvTRANSMASKSETCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1281 {\r
1282 const char *pcParameter;\r
1283 BaseType_t xParameterStringLength;\r
1284 uint32_t ulEventMask;\r
1285 int32_t lStatus;\r
1286 \r
1287         /* Ensure the buffer leaves space for the \r\n. */\r
1288         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
1289         xWriteBufferLen -= strlen( cliNEW_LINE );\r
1290 \r
1291         /* Obtain the parameter string. */\r
1292         pcParameter = FreeRTOS_CLIGetParameter\r
1293                                         (\r
1294                                                 pcCommandString,                /* The command string itself. */\r
1295                                                 1,                                              /* Return the first parameter. */\r
1296                                                 &xParameterStringLength /* Store the parameter string length. */\r
1297                                         );\r
1298 \r
1299         /* Sanity check something was returned. */\r
1300         configASSERT( pcParameter );\r
1301 \r
1302         if( ( pcParameter[0] == '0' ) && ( ( pcParameter[1] == 'x' ) || ( pcParameter[1] == 'X' ) ) )\r
1303         {\r
1304                 pcParameter += 2;\r
1305         }\r
1306 \r
1307         /* Convert the argument into a value. */\r
1308         RedHtoUL( pcParameter, &ulEventMask );\r
1309 \r
1310         /* Set the new transaction mask. */\r
1311         lStatus = red_settransmask( "", ulEventMask );\r
1312         if( lStatus == -1 )\r
1313         {\r
1314                 /* User-friendly messages for common errors. */\r
1315                 switch( red_errno )\r
1316                 {\r
1317                         case RED_EINVAL:\r
1318                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Invalid bits in transaction mask." );\r
1319                                 break;\r
1320 \r
1321                         default :\r
1322                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error %d setting transaction mask.", ( int ) red_errno );\r
1323                                 break;\r
1324                 }\r
1325         }\r
1326         else\r
1327         {\r
1328                 snprintf( pcWriteBuffer, xWriteBufferLen,\r
1329                         "Successfully set automatic transaction mask.  Enabled events:\r\n"\r
1330                         "RED_TRANSACT_UMOUNT   (0x0001): %s\r\n"\r
1331                         "RED_TRANSACT_CREAT    (0x0002): %s\r\n"\r
1332                         "RED_TRANSACT_UNLINK   (0x0004): %s\r\n"\r
1333                         "RED_TRANSACT_MKDIR    (0x0008): %s\r\n"\r
1334                         "RED_TRANSACT_RENAME   (0x0010): %s\r\n"\r
1335                         "RED_TRANSACT_LINK     (0x0020): %s\r\n"\r
1336                         "RED_TRANSACT_CLOSE    (0x0040): %s\r\n"\r
1337                         "RED_TRANSACT_WRITE    (0x0080): %s\r\n"\r
1338                         "RED_TRANSACT_FSYNC    (0x0100): %s\r\n"\r
1339                         "RED_TRANSACT_TRUNCATE (0x0200): %s\r\n"\r
1340                         "RED_TRANSACT_VOLFULL  (0x0400): %s\r\n",\r
1341                         ( ulEventMask & RED_TRANSACT_UMOUNT )   ? "Enabled" : "Disabled",\r
1342                         ( ulEventMask & RED_TRANSACT_CREAT )    ? "Enabled" : "Disabled",\r
1343                         ( ulEventMask & RED_TRANSACT_UNLINK )   ? "Enabled" : "Disabled",\r
1344                         ( ulEventMask & RED_TRANSACT_MKDIR )    ? "Enabled" : "Disabled",\r
1345                         ( ulEventMask & RED_TRANSACT_RENAME )   ? "Enabled" : "Disabled",\r
1346                         ( ulEventMask & RED_TRANSACT_LINK )     ? "Enabled" : "Disabled",\r
1347                         ( ulEventMask & RED_TRANSACT_CLOSE )    ? "Enabled" : "Disabled",\r
1348                         ( ulEventMask & RED_TRANSACT_WRITE )    ? "Enabled" : "Disabled",\r
1349                         ( ulEventMask & RED_TRANSACT_FSYNC )    ? "Enabled" : "Disabled",\r
1350                         ( ulEventMask & RED_TRANSACT_TRUNCATE ) ? "Enabled" : "Disabled",\r
1351                         ( ulEventMask & RED_TRANSACT_VOLFULL )  ? "Enabled" : "Disabled" );\r
1352         }\r
1353 \r
1354         strcat( pcWriteBuffer, cliNEW_LINE );\r
1355 \r
1356         return pdFALSE;\r
1357 }\r
1358 /*-----------------------------------------------------------*/\r
1359 \r
1360 static BaseType_t prvABORTCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1361 {\r
1362 uint32_t ulEventMask;\r
1363 int32_t lStatus;\r
1364 \r
1365         /* Avoid compiler warnings. */\r
1366         ( void ) pcCommandString;\r
1367 \r
1368         /* This function assumes xWriteBufferLen is large enough! */\r
1369         ( void ) xWriteBufferLen;\r
1370 \r
1371         /* Save the original transaction mask settings. */\r
1372         lStatus = red_gettransmask( "", &ulEventMask );\r
1373 \r
1374         if( lStatus == -1 )\r
1375         {\r
1376                 sprintf( pcWriteBuffer, "Error %d querying transaction mask.",  ( int ) red_errno );\r
1377         }\r
1378         else\r
1379         {\r
1380                 /* Make it so that red_umount() will not automatically commit a new\r
1381                 transaction point. */\r
1382                 lStatus = red_settransmask( "", ulEventMask & ~( ( uint32_t ) RED_TRANSACT_UMOUNT ) );\r
1383 \r
1384                 if( lStatus == -1 )\r
1385                 {\r
1386                         sprintf( pcWriteBuffer, "Error %d setting transaction mask.",  ( int ) red_errno );\r
1387                 }\r
1388                 else\r
1389                 {\r
1390                         /* Unmount.  Since red_umount() will not transact, all changes which\r
1391                         were not already transacted are rolled back. */\r
1392                         lStatus = red_umount( "" );\r
1393 \r
1394                         if( lStatus == -1 )\r
1395                         {\r
1396                                 sprintf( pcWriteBuffer, "Error %d during unmount.",  ( int ) red_errno );\r
1397                         }\r
1398                         else\r
1399                         {\r
1400                                 /* Mount.  Mount always starts from the last transaction point. */\r
1401                                 lStatus = red_mount( "" );\r
1402 \r
1403                                 if( lStatus == -1 )\r
1404                                 {\r
1405                                         sprintf( pcWriteBuffer, "Error %d during mount.",  ( int ) red_errno );\r
1406                                 }\r
1407                                 else\r
1408                                 {\r
1409                                         strcpy( pcWriteBuffer, "Working state changes succesfully aborted." );\r
1410                                 }\r
1411                         }\r
1412 \r
1413                         /* Restore the original transaction mask settings. */\r
1414                         red_settransmask( "", ulEventMask );\r
1415                 }\r
1416         }\r
1417 \r
1418         strcat( pcWriteBuffer, cliNEW_LINE );\r
1419 \r
1420         return pdFALSE;\r
1421 }\r
1422 /*-----------------------------------------------------------*/\r
1423 \r
1424 static BaseType_t prvTESTFSCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
1425 {\r
1426 UBaseType_t uxOriginalPriority;\r
1427 FSSTRESSPARAM param;\r
1428 \r
1429         /* Avoid compiler warnings. */\r
1430         ( void ) xWriteBufferLen;\r
1431         ( void ) pcCommandString;\r
1432 \r
1433         /* Limitations in the interaction with the Windows TCP/IP stack require\r
1434         the command console to run at the idle priority.  Raise the priority for\r
1435         the duration of the tests to ensure there are not multiple switches to the\r
1436         idle task as in the simulated environment the idle task hook function may\r
1437         include a (relatively) long delay. */\r
1438         uxOriginalPriority = uxTaskPriorityGet( NULL );\r
1439         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
1440 \r
1441         /* Delete all files to avoid inteferring with the test. */\r
1442         red_umount( "" );\r
1443         red_format( "" );\r
1444         red_mount( "" );\r
1445 \r
1446         FsstressDefaultParams(&param);\r
1447         param.fVerbose = pdTRUE;\r
1448         param.ulNops = 10000;\r
1449         param.ulSeed = 1;\r
1450         FsstressStart(&param);\r
1451 \r
1452         /* Clean up after the test. */\r
1453         red_umount( "" );\r
1454         red_format( "" );\r
1455         red_mount( "" );\r
1456 \r
1457         /* Reset back to the original priority. */\r
1458         vTaskPrioritySet( NULL, uxOriginalPriority );\r
1459 \r
1460         sprintf( pcWriteBuffer, "%s", "Test results were sent to Windows console" );\r
1461         strcat( pcWriteBuffer, cliNEW_LINE );\r
1462 \r
1463         return pdFALSE;\r
1464 }\r
1465 /*-----------------------------------------------------------*/\r
1466 \r
1467 static BaseType_t prvPerformCopy( int32_t lSourceFildes,\r
1468                                                                         int32_t lDestinationFiledes,\r
1469                                                                         char *pxWriteBuffer,\r
1470                                                                         size_t xWriteBufferLen )\r
1471 {\r
1472 int32_t lBytesRead;\r
1473 BaseType_t xReturn = pdPASS;\r
1474 \r
1475         /* Assuming both files are at offset zero. */\r
1476 \r
1477         for( ;; )\r
1478         {\r
1479                 /* Read the next block of data. */\r
1480                 lBytesRead = red_read( lSourceFildes, pxWriteBuffer, xWriteBufferLen );\r
1481                 if( lBytesRead <= 0 )\r
1482                 {\r
1483                         if( lBytesRead == -1)\r
1484                         {\r
1485                                 /* Error reading from file. */\r
1486                                 xReturn = pdFAIL;\r
1487                         }\r
1488                         else\r
1489                         {\r
1490                                 /* No error: reached end of file, time to stop. */\r
1491                         }\r
1492 \r
1493                         break;\r
1494                 }\r
1495 \r
1496                 /* Write the block of data to the end of the file. */\r
1497                 if( red_write( lDestinationFiledes, pxWriteBuffer, lBytesRead ) != lBytesRead )\r
1498                 {\r
1499                         xReturn = pdFAIL;\r
1500                         break;\r
1501                 }\r
1502         }\r
1503 \r
1504         return xReturn;\r
1505 }\r
1506 /*-----------------------------------------------------------*/\r
1507 \r
1508 static void prvCreateFileInfoString( char *pcBuffer, REDDIRENT *pxDirent )\r
1509 {\r
1510 const char *pcFile = "file", *pcDirectory = "directory";\r
1511 const char *pcAttrib;\r
1512 \r
1513         /* Point pcAttrib to a string that describes the file. */\r
1514         if( RED_S_ISDIR(pxDirent->d_stat.st_mode) )\r
1515         {\r
1516                 pcAttrib = pcDirectory;\r
1517         }\r
1518         else\r
1519         {\r
1520                 pcAttrib = pcFile;\r
1521         }\r
1522 \r
1523         /* Create a string that includes the file name, the file size and the\r
1524         attributes string. */\r
1525         sprintf( pcBuffer, "%s [%s] [size=%lld]", pxDirent->d_name, pcAttrib, pxDirent->d_stat.st_size );\r
1526 }\r