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