]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/Common/FreeRTOS_Plus_CLI_Demos/File-Related-CLI-commands.c
20eaf720661ecf8bd6bbcebb7662a7d2ddfbb029
[freertos] / FreeRTOS-Plus / Demo / Common / FreeRTOS_Plus_CLI_Demos / File-Related-CLI-commands.c
1 /*\r
2  * FreeRTOS Kernel V10.0.1\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 \r
29 /* FreeRTOS includes. */\r
30 #include "FreeRTOS.h"\r
31 #include "task.h"\r
32 \r
33 /* Standard includes. */\r
34 #include <stdint.h>\r
35 #include <stdio.h>\r
36 #include <stdlib.h>\r
37 #include <string.h>\r
38 \r
39 /* FreeRTOS+CLI includes. */\r
40 #include "FreeRTOS_CLI.h"\r
41 \r
42 /* File system includes. */\r
43 #include "fat_sl.h"\r
44 #include "api_mdriver_ram.h"\r
45 \r
46 #ifdef _WINDOWS_\r
47         #define snprintf _snprintf\r
48 #endif\r
49 \r
50 #define cliNEW_LINE             "\r\n"\r
51 \r
52 /*******************************************************************************\r
53  * See the URL in the comments within main.c for the location of the online\r
54  * documentation.\r
55  ******************************************************************************/\r
56 \r
57 /*\r
58  * Print out information on a single file.\r
59  */\r
60 static void prvCreateFileInfoString( char *pcBuffer, F_FIND *pxFindStruct );\r
61 \r
62 /*\r
63  * Copies an existing file into a newly created file.\r
64  */\r
65 static BaseType_t prvPerformCopy( const char *pcSourceFile,\r
66                                                                         int32_t lSourceFileLength,\r
67                                                                         const char *pcDestinationFile,\r
68                                                                         char *pxWriteBuffer,\r
69                                                                         size_t xWriteBufferLen );\r
70 \r
71 /*\r
72  * Implements the DIR command.\r
73  */\r
74 static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
75 \r
76 /*\r
77  * Implements the CD command.\r
78  */\r
79 static BaseType_t prvCDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
80 \r
81 /*\r
82  * Implements the DEL command.\r
83  */\r
84 static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
85 \r
86 /*\r
87  * Implements the TYPE command.\r
88  */\r
89 static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
90 \r
91 /*\r
92  * Implements the COPY command.\r
93  */\r
94 static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );\r
95 \r
96 /* Structure that defines the DIR command line command, which lists all the\r
97 files in the current directory. */\r
98 static const CLI_Command_Definition_t xDIR =\r
99 {\r
100         "dir", /* The command string to type. */\r
101         "\r\ndir:\r\n Lists the files in the current directory\r\n",\r
102         prvDIRCommand, /* The function to run. */\r
103         0 /* No parameters are expected. */\r
104 };\r
105 \r
106 /* Structure that defines the CD command line command, which changes the\r
107 working directory. */\r
108 static const CLI_Command_Definition_t xCD =\r
109 {\r
110         "cd", /* The command string to type. */\r
111         "\r\ncd <dir name>:\r\n Changes the working directory\r\n",\r
112         prvCDCommand, /* The function to run. */\r
113         1 /* One parameter is expected. */\r
114 };\r
115 \r
116 /* Structure that defines the TYPE command line command, which prints the\r
117 contents of a file to the console. */\r
118 static const CLI_Command_Definition_t xTYPE =\r
119 {\r
120         "type", /* The command string to type. */\r
121         "\r\ntype <filename>:\r\n Prints file contents to the terminal\r\n",\r
122         prvTYPECommand, /* The function to run. */\r
123         1 /* One parameter is expected. */\r
124 };\r
125 \r
126 /* Structure that defines the DEL command line command, which deletes a file. */\r
127 static const CLI_Command_Definition_t xDEL =\r
128 {\r
129         "del", /* The command string to type. */\r
130         "\r\ndel <filename>:\r\n deletes a file or directory\r\n",\r
131         prvDELCommand, /* The function to run. */\r
132         1 /* One parameter is expected. */\r
133 };\r
134 \r
135 /* Structure that defines the COPY command line command, which deletes a file. */\r
136 static const CLI_Command_Definition_t xCOPY =\r
137 {\r
138         "copy", /* The command string to type. */\r
139         "\r\ncopy <source file> <dest file>:\r\n Copies <source file> to <dest file>\r\n",\r
140         prvCOPYCommand, /* The function to run. */\r
141         2 /* Two parameters are expected. */\r
142 };\r
143 \r
144 \r
145 /*-----------------------------------------------------------*/\r
146 \r
147 void vRegisterFileSystemCLICommands( void )\r
148 {\r
149         /* Register all the command line commands defined immediately above. */\r
150         FreeRTOS_CLIRegisterCommand( &xDIR );\r
151         FreeRTOS_CLIRegisterCommand( &xCD );\r
152         FreeRTOS_CLIRegisterCommand( &xTYPE );\r
153         FreeRTOS_CLIRegisterCommand( &xDEL );\r
154         FreeRTOS_CLIRegisterCommand( &xCOPY );\r
155 }\r
156 /*-----------------------------------------------------------*/\r
157 \r
158 static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
159 {\r
160 const char *pcParameter;\r
161 BaseType_t xParameterStringLength, xReturn = pdTRUE;\r
162 static F_FILE *pxFile = NULL;\r
163 int iChar;\r
164 size_t xByte;\r
165 size_t xColumns = 50U;\r
166 \r
167         /* Ensure there is always a null terminator after each character written. */\r
168         memset( pcWriteBuffer, 0x00, xWriteBufferLen );\r
169 \r
170         /* Ensure the buffer leaves space for the \r\n. */\r
171         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
172         xWriteBufferLen -= strlen( cliNEW_LINE );\r
173 \r
174         if( xWriteBufferLen < xColumns )\r
175         {\r
176                 /* Ensure the loop that uses xColumns as an end condition does not\r
177                 write off the end of the buffer. */\r
178                 xColumns = xWriteBufferLen;\r
179         }\r
180 \r
181         if( pxFile == NULL )\r
182         {\r
183                 /* The file has not been opened yet.  Find the file name. */\r
184                 pcParameter = FreeRTOS_CLIGetParameter\r
185                                                 (\r
186                                                         pcCommandString,                /* The command string itself. */\r
187                                                         1,                                              /* Return the first parameter. */\r
188                                                         &xParameterStringLength /* Store the parameter string length. */\r
189                                                 );\r
190 \r
191                 /* Sanity check something was returned. */\r
192                 configASSERT( pcParameter );\r
193 \r
194                 /* Attempt to open the requested file. */\r
195                 pxFile = f_open( pcParameter, "r" );\r
196         }\r
197 \r
198         if( pxFile != NULL )\r
199         {\r
200                 /* Read the next chunk of data from the file. */\r
201                 for( xByte = 0; xByte < xColumns; xByte++ )\r
202                 {\r
203                         iChar = f_getc( pxFile );\r
204 \r
205                         if( iChar == -1 )\r
206                         {\r
207                                 /* No more characters to return. */\r
208                                 f_close( pxFile );\r
209                                 pxFile = NULL;\r
210                                 break;\r
211                         }\r
212                         else\r
213                         {\r
214                                 pcWriteBuffer[ xByte ] = ( char ) iChar;\r
215                         }\r
216                 }\r
217         }\r
218 \r
219         if( pxFile == NULL )\r
220         {\r
221                 /* Either the file was not opened, or all the data from the file has\r
222                 been returned and the file is now closed. */\r
223                 xReturn = pdFALSE;\r
224         }\r
225 \r
226         strcat( pcWriteBuffer, cliNEW_LINE );\r
227 \r
228         return xReturn;\r
229 }\r
230 /*-----------------------------------------------------------*/\r
231 \r
232 static BaseType_t prvCDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
233 {\r
234 const char *pcParameter;\r
235 BaseType_t xParameterStringLength;\r
236 unsigned char ucReturned;\r
237 size_t xStringLength;\r
238 \r
239         /* Obtain the parameter string. */\r
240         pcParameter = FreeRTOS_CLIGetParameter\r
241                                         (\r
242                                                 pcCommandString,                /* The command string itself. */\r
243                                                 1,                                              /* Return the first parameter. */\r
244                                                 &xParameterStringLength /* Store the parameter string length. */\r
245                                         );\r
246 \r
247         /* Sanity check something was returned. */\r
248         configASSERT( pcParameter );\r
249 \r
250         /* Attempt to move to the requested directory. */\r
251         ucReturned = f_chdir( pcParameter );\r
252 \r
253         if( ucReturned == F_NO_ERROR )\r
254         {\r
255                 sprintf( pcWriteBuffer, "In: " );\r
256                 xStringLength = strlen( pcWriteBuffer );\r
257                 f_getcwd( &( pcWriteBuffer[ xStringLength ] ), ( unsigned char ) ( xWriteBufferLen - xStringLength ) );\r
258         }\r
259         else\r
260         {\r
261                 sprintf( pcWriteBuffer, "Error" );\r
262         }\r
263 \r
264         strcat( pcWriteBuffer, cliNEW_LINE );\r
265 \r
266         return pdFALSE;\r
267 }\r
268 /*-----------------------------------------------------------*/\r
269 \r
270 static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
271 {\r
272 static F_FIND *pxFindStruct = NULL;\r
273 unsigned char ucReturned;\r
274 BaseType_t xReturn = pdFALSE;\r
275 \r
276         /* This assumes pcWriteBuffer is long enough. */\r
277         ( void ) pcCommandString;\r
278 \r
279         /* Ensure the buffer leaves space for the \r\n. */\r
280         configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
281         xWriteBufferLen -= strlen( cliNEW_LINE );\r
282 \r
283         if( pxFindStruct == NULL )\r
284         {\r
285                 /* This is the first time this function has been executed since the Dir\r
286                 command was run.  Create the find structure. */\r
287                 pxFindStruct = ( F_FIND * ) pvPortMalloc( sizeof( F_FIND ) );\r
288 \r
289                 if( pxFindStruct != NULL )\r
290                 {\r
291                         ucReturned = f_findfirst( "*.*", pxFindStruct );\r
292 \r
293                         if( ucReturned == F_NO_ERROR )\r
294                         {\r
295                                 prvCreateFileInfoString( pcWriteBuffer, pxFindStruct );\r
296                                 xReturn = pdPASS;\r
297                         }\r
298                         else\r
299                         {\r
300                                 snprintf( pcWriteBuffer, xWriteBufferLen, "Error: f_findfirst() failed." );\r
301                         }\r
302                 }\r
303                 else\r
304                 {\r
305                         snprintf( pcWriteBuffer, xWriteBufferLen, "Failed to allocate RAM (using heap_4.c will prevent fragmentation)." );\r
306                 }\r
307         }\r
308         else\r
309         {\r
310                 /* The find struct has already been created.  Find the next file in\r
311                 the directory. */\r
312                 ucReturned = f_findnext( pxFindStruct );\r
313 \r
314                 if( ucReturned == F_NO_ERROR )\r
315                 {\r
316                         prvCreateFileInfoString( pcWriteBuffer, pxFindStruct );\r
317                         xReturn = pdPASS;\r
318                 }\r
319                 else\r
320                 {\r
321                         /* There are no more files.  Free the find structure. */\r
322                         vPortFree( pxFindStruct );\r
323                         pxFindStruct = NULL;\r
324 \r
325                         /* No string to return. */\r
326                         pcWriteBuffer[ 0 ] = 0x00;\r
327                 }\r
328         }\r
329 \r
330         strcat( pcWriteBuffer, cliNEW_LINE );\r
331 \r
332         return xReturn;\r
333 }\r
334 /*-----------------------------------------------------------*/\r
335 \r
336 static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
337 {\r
338 const char *pcParameter;\r
339 BaseType_t xParameterStringLength;\r
340 unsigned char ucReturned;\r
341 \r
342         /* This function assumes xWriteBufferLen is large enough! */\r
343         ( void ) xWriteBufferLen;\r
344 \r
345         /* Obtain the parameter string. */\r
346         pcParameter = FreeRTOS_CLIGetParameter\r
347                                         (\r
348                                                 pcCommandString,                /* The command string itself. */\r
349                                                 1,                                              /* Return the first parameter. */\r
350                                                 &xParameterStringLength /* Store the parameter string length. */\r
351                                         );\r
352 \r
353         /* Sanity check something was returned. */\r
354         configASSERT( pcParameter );\r
355 \r
356         /* Attempt to delete the file. */\r
357         ucReturned = f_delete( pcParameter );\r
358 \r
359         if( ucReturned == F_NO_ERROR )\r
360         {\r
361                 sprintf( pcWriteBuffer, "%s was deleted", pcParameter );\r
362         }\r
363         else\r
364         {\r
365                 sprintf( pcWriteBuffer, "Error" );\r
366         }\r
367 \r
368         strcat( pcWriteBuffer, cliNEW_LINE );\r
369 \r
370         return pdFALSE;\r
371 }\r
372 /*-----------------------------------------------------------*/\r
373 \r
374 static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )\r
375 {\r
376 char *pcSourceFile, *pcDestinationFile;\r
377 BaseType_t xParameterStringLength;\r
378 long lSourceLength, lDestinationLength = 0;\r
379 \r
380         /* Obtain the name of the destination file. */\r
381         pcDestinationFile = ( char * ) FreeRTOS_CLIGetParameter\r
382                                                                         (\r
383                                                                                 pcCommandString,                /* The command string itself. */\r
384                                                                                 2,                                              /* Return the second parameter. */\r
385                                                                                 &xParameterStringLength /* Store the parameter string length. */\r
386                                                                         );\r
387 \r
388         /* Sanity check something was returned. */\r
389         configASSERT( pcDestinationFile );\r
390 \r
391         /* Obtain the name of the source file. */\r
392         pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter\r
393                                                                 (\r
394                                                                         pcCommandString,                /* The command string itself. */\r
395                                                                         1,                                              /* Return the first parameter. */\r
396                                                                         &xParameterStringLength /* Store the parameter string length. */\r
397                                                                 );\r
398 \r
399         /* Sanity check something was returned. */\r
400         configASSERT( pcSourceFile );\r
401 \r
402         /* Terminate the string. */\r
403         pcSourceFile[ xParameterStringLength ] = 0x00;\r
404 \r
405         /* See if the source file exists, obtain its length if it does. */\r
406         lSourceLength = f_filelength( pcSourceFile );\r
407 \r
408         if( lSourceLength == 0 )\r
409         {\r
410                 sprintf( pcWriteBuffer, "Source file does not exist" );\r
411         }\r
412         else\r
413         {\r
414                 /* See if the destination file exists. */\r
415                 lDestinationLength = f_filelength( pcDestinationFile );\r
416 \r
417                 if( lDestinationLength != 0 )\r
418                 {\r
419                         sprintf( pcWriteBuffer, "Error: Destination file already exists" );\r
420                 }\r
421         }\r
422 \r
423         /* Continue only if the source file exists and the destination file does\r
424         not exist. */\r
425         if( ( lSourceLength != 0 ) && ( lDestinationLength == 0 ) )\r
426         {\r
427                 if( prvPerformCopy( pcSourceFile, lSourceLength, pcDestinationFile, pcWriteBuffer, xWriteBufferLen ) == pdPASS )\r
428                 {\r
429                         sprintf( pcWriteBuffer, "Copy made" );\r
430                 }\r
431                 else\r
432                 {\r
433                         sprintf( pcWriteBuffer, "Error during copy" );\r
434                 }\r
435         }\r
436 \r
437         strcat( pcWriteBuffer, cliNEW_LINE );\r
438 \r
439         return pdFALSE;\r
440 }\r
441 /*-----------------------------------------------------------*/\r
442 \r
443 static BaseType_t prvPerformCopy( const char *pcSourceFile,\r
444                                                                         int32_t lSourceFileLength,\r
445                                                                         const char *pcDestinationFile,\r
446                                                                         char *pxWriteBuffer,\r
447                                                                         size_t xWriteBufferLen )\r
448 {\r
449 int32_t lBytesRead = 0, lBytesToRead, lBytesRemaining;\r
450 F_FILE *pxFile;\r
451 BaseType_t xReturn = pdPASS;\r
452 \r
453         /* NOTE:  Error handling has been omitted for clarity. */\r
454 \r
455         while( lBytesRead < lSourceFileLength )\r
456         {\r
457                 /* How many bytes are left? */\r
458                 lBytesRemaining = lSourceFileLength - lBytesRead;\r
459 \r
460                 /* How many bytes should be read this time around the loop.  Can't\r
461                 read more bytes than will fit into the buffer. */\r
462                 if( lBytesRemaining > ( long ) xWriteBufferLen )\r
463                 {\r
464                         lBytesToRead = ( long ) xWriteBufferLen;\r
465                 }\r
466                 else\r
467                 {\r
468                         lBytesToRead = lBytesRemaining;\r
469                 }\r
470 \r
471                 /* Open the source file, seek past the data that has already been\r
472                 read from the file, read the next block of data, then close the\r
473                 file again so the destination file can be opened. */\r
474                 pxFile = f_open( pcSourceFile, "r" );\r
475                 if( pxFile != NULL )\r
476                 {\r
477                         f_seek( pxFile, lBytesRead, F_SEEK_SET );\r
478                         f_read( pxWriteBuffer, lBytesToRead, 1, pxFile );\r
479                         f_close( pxFile );\r
480                 }\r
481                 else\r
482                 {\r
483                         xReturn = pdFAIL;\r
484                         break;\r
485                 }\r
486 \r
487                 /* Open the destination file and write the block of data to the end of\r
488                 the file. */\r
489                 pxFile = f_open( pcDestinationFile, "a" );\r
490                 if( pxFile != NULL )\r
491                 {\r
492                         f_write( pxWriteBuffer, lBytesToRead, 1, pxFile );\r
493                         f_close( pxFile );\r
494                 }\r
495                 else\r
496                 {\r
497                         xReturn = pdFAIL;\r
498                         break;\r
499                 }\r
500 \r
501                 lBytesRead += lBytesToRead;\r
502         }\r
503 \r
504         return xReturn;\r
505 }\r
506 /*-----------------------------------------------------------*/\r
507 \r
508 static void prvCreateFileInfoString( char *pcBuffer, F_FIND *pxFindStruct )\r
509 {\r
510 const char *pcWritableFile = "writable file", *pcReadOnlyFile = "read only file", *pcDirectory = "directory";\r
511 const char * pcAttrib;\r
512 \r
513         /* Point pcAttrib to a string that describes the file. */\r
514         if( ( pxFindStruct->attr & F_ATTR_DIR ) != 0 )\r
515         {\r
516                 pcAttrib = pcDirectory;\r
517         }\r
518         else if( pxFindStruct->attr & F_ATTR_READONLY )\r
519         {\r
520                 pcAttrib = pcReadOnlyFile;\r
521         }\r
522         else\r
523         {\r
524                 pcAttrib = pcWritableFile;\r
525         }\r
526 \r
527         /* Create a string that includes the file name, the file size and the\r
528         attributes string. */\r
529         sprintf( pcBuffer, "%s [%s] [size=%d]", pxFindStruct->filename, pcAttrib, ( int ) pxFindStruct->filesize );\r
530 }\r