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