]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_file.c
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal...
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / ff_file.c
1 /*\r
2  * FreeRTOS+FAT build 191128 - Note:  FreeRTOS+FAT is still in the lab!\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
5  *\r
6  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
7  * this software and associated documentation files (the "Software"), to deal in\r
8  * the Software without restriction, including without limitation the rights to\r
9  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
10  * the Software, and to permit persons to whom the Software is furnished to do so,\r
11  * subject to the following conditions:\r
12  *\r
13  * The above copyright notice and this permission notice shall be included in all\r
14  * copies or substantial portions of the Software.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * https://www.FreeRTOS.org\r
24  *\r
25  */\r
26 \r
27 /**\r
28  *      @file           ff_file.c\r
29  *      @ingroup        FILEIO\r
30  *\r
31  *      @defgroup       FILEIO FILE I/O Access\r
32  *      @brief          Provides an interface to allow File I/O on a mounted IOMAN.\r
33  *\r
34  *      Provides file-system interfaces for the FAT file-system.\r
35  **/\r
36 \r
37 #include "ff_headers.h"\r
38 \r
39 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
40 #include <wchar.h>\r
41 #endif\r
42 \r
43 static FF_Error_t FF_Truncate( FF_FILE *pxFile, BaseType_t bClosing );\r
44 \r
45 static int32_t FF_ReadPartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount,\r
46         uint8_t *pucBuffer, FF_Error_t *pxError );\r
47 \r
48 static int32_t FF_WritePartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount,\r
49         const uint8_t *pucBuffer, FF_Error_t *pxError );\r
50 \r
51 static uint32_t FF_SetCluster( FF_FILE *pxFile, FF_Error_t *pxError );\r
52 static uint32_t FF_FileLBA( FF_FILE *pxFile );\r
53 \r
54 /*-----------------------------------------------------------*/\r
55 \r
56 /**\r
57  *      @public\r
58  *      @brief  Converts STDIO mode strings into the equivalent FreeRTOS+FAT mode.\r
59  *\r
60  *      @param  Mode    The mode string e.g. "rb" "rb+" "w" "a" "r" "w+" "a+" etc\r
61  *\r
62  *      @return Returns the mode bits that should be passed to the FF_Open function.\r
63  **/\r
64 uint8_t FF_GetModeBits( const char *pcMode )\r
65 {\r
66 uint8_t ucModeBits = 0x00;\r
67 \r
68         while( *pcMode != '\0' )\r
69         {\r
70                 switch( *pcMode )\r
71                 {\r
72                         case 'r':                                               /* Allow Read. */\r
73                         case 'R':\r
74                                 ucModeBits |= FF_MODE_READ;\r
75                                 break;\r
76 \r
77                         case 'w':                                               /* Allow Write. */\r
78                         case 'W':\r
79                                 ucModeBits |= FF_MODE_WRITE;\r
80                                 ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */\r
81                                 ucModeBits |= FF_MODE_TRUNCATE;\r
82                                 break;\r
83 \r
84                         case 'a':                                               /* Append new writes to the end of the file. */\r
85                         case 'A':\r
86                                 ucModeBits |= FF_MODE_WRITE;\r
87                                 ucModeBits |= FF_MODE_APPEND;\r
88                                 ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */\r
89                                 break;\r
90 \r
91                         case '+':                                               /* Update the file, don't Append! */\r
92                                 ucModeBits |= FF_MODE_READ;\r
93                                 ucModeBits |= FF_MODE_WRITE;    /* RW Mode. */\r
94                                 break;\r
95 \r
96                         case 'D':\r
97                                 /* Internal use only! */\r
98                                 ucModeBits |= FF_MODE_DIR;\r
99                                 break;\r
100 \r
101                         case 'b':\r
102                         case 'B':\r
103                                 /* b|B flags not supported (Binary mode is native anyway). */\r
104                                 break;\r
105 \r
106                         default:\r
107                                 break;\r
108                 }\r
109 \r
110                 pcMode++;\r
111         }\r
112 \r
113         return ucModeBits;\r
114 }       /* FF_GetModeBits() */\r
115 /*-----------------------------------------------------------*/\r
116 \r
117 static FF_FILE *prvAllocFileHandle( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )\r
118 {\r
119 FF_FILE *pxFile;\r
120 \r
121         pxFile = ffconfigMALLOC( sizeof( FF_FILE ) );\r
122         if( pxFile == NULL )\r
123         {\r
124                 *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );\r
125         }\r
126         else\r
127         {\r
128                 memset( pxFile, 0, sizeof( *pxFile ) );\r
129 \r
130                 #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
131                 {\r
132                         pxFile->pucBuffer = ( uint8_t * ) ffconfigMALLOC( pxIOManager->usSectorSize );\r
133                         if( pxFile->pucBuffer != NULL )\r
134                         {\r
135                                 memset( pxFile->pucBuffer, 0, pxIOManager->usSectorSize );\r
136                         }\r
137                         else\r
138                         {\r
139                                 *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN );\r
140                                 ffconfigFREE( pxFile );\r
141                                 /* Make sure that NULL will be returned. */\r
142                                 pxFile = NULL;\r
143                         }\r
144                 }\r
145                 #else\r
146                 {\r
147                         /* Remove compiler warnings. */\r
148                         ( void ) pxIOManager;\r
149                 }\r
150                 #endif\r
151         }\r
152 \r
153         return pxFile;\r
154 }       /* prvAllocFileHandle() */\r
155 /*-----------------------------------------------------------*/\r
156 \r
157 /**\r
158  * FF_Open() Mode Information\r
159  * - FF_MODE_WRITE\r
160  *   - Allows WRITE access to the file.\r
161  *   .\r
162  * - FF_MODE_READ\r
163  *   - Allows READ access to the file.\r
164  *   .\r
165  * - FF_MODE_CREATE\r
166  *   - Create file if it doesn't exist.\r
167  *   .\r
168  * - FF_MODE_TRUNCATE\r
169  *   - Erase the file if it already exists and overwrite.\r
170  *   *\r
171  * - FF_MODE_APPEND\r
172  *   - Causes all writes to occur at the end of the file. (Its impossible to overwrite other data in a file with this flag set).\r
173  *   .\r
174  * .\r
175  *\r
176  * Some sample modes:\r
177  * - (FF_MODE_WRITE | FF_MODE_CREATE | FF_MODE_TRUNCATE)\r
178  *   - Write access to the file. (Equivalent to "w").\r
179  *   .\r
180  * - (FF_MODE_WRITE | FF_MODE_READ)\r
181  *   - Read and Write access to the file. (Equivalent to "rb+").\r
182  *   .\r
183  * - (FF_MODE_WRITE | FF_MODE_READ | FF_MODE_APPEND | FF_MODE_CREATE)\r
184  *   - Read and Write append mode access to the file. (Equivalent to "a+").\r
185  *   .\r
186  * .\r
187  * Be careful when choosing modes. For those using FF_Open() at the application layer\r
188  * its best to use the provided FF_GetModeBits() function, as this complies to the same\r
189  * behaviour as the stdio.h fopen() function.\r
190  *\r
191  **/\r
192 \r
193 /**\r
194  *      @public\r
195  *      @brief  Opens a File for Access\r
196  *\r
197  *      @param  pxIOManager     FF_IOManager_t object that was created by FF_CreateIOManger().\r
198  *      @param  pcPath          Path to the File or object.\r
199  *      @param  ucMode          Access Mode required. Modes are a little complicated, the function FF_GetModeBits()\r
200  *      @param  ucMode          will convert a stdio Mode string into the equivalent Mode bits for this parameter.\r
201  *      @param  pxError         Pointer to a signed byte for error checking. Can be NULL if not required.\r
202  *      @param  pxError         To be checked when a NULL pointer is returned.\r
203  *\r
204  *      @return NULL pointer on error, in which case pxError should be checked for more information.\r
205  *      @return pxError can be:\r
206  **/\r
207 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
208 FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath, uint8_t ucMode, FF_Error_t *pxError )\r
209 #else\r
210 FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const char *pcPath, uint8_t ucMode, FF_Error_t *pxError )\r
211 #endif\r
212 {\r
213 FF_FILE *pxFile = NULL;\r
214 FF_FILE *pxFileChain;\r
215 FF_DirEnt_t xDirEntry;\r
216 uint32_t ulFileCluster;\r
217 FF_Error_t xError;\r
218 BaseType_t xIndex;\r
219 FF_FindParams_t xFindParams;\r
220 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
221         FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];\r
222 #else\r
223         char pcFileName[ ffconfigMAX_FILENAME ];\r
224 #endif\r
225 \r
226         memset( &xFindParams, '\0', sizeof( xFindParams ) );\r
227 \r
228         /* Inform the functions that the entry will be created if not found. */\r
229         if( ( ucMode & FF_MODE_CREATE ) != 0 )\r
230         {\r
231                 xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG;\r
232         }\r
233 \r
234         if( pxIOManager == NULL )\r
235         {\r
236                 /* Use the error function code 'FF_OPEN' as this static\r
237                 function is only called from that function. */\r
238                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_OPEN );\r
239         }\r
240 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
241         else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
242         {\r
243                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_OPEN );\r
244         }\r
245 #endif /* ffconfigREMOVABLE_MEDIA */\r
246         else\r
247         {\r
248                 xError = FF_ERR_NONE;\r
249 \r
250                 /* Let xIndex point to the last occurrence of '/' or '\',\r
251                 to separate the path from the file name. */\r
252                 xIndex = ( BaseType_t ) STRLEN( pcPath );\r
253                 while( xIndex != 0 )\r
254                 {\r
255                         if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) )\r
256                         {\r
257                                 break;\r
258                         }\r
259                         xIndex--;\r
260                 }\r
261 \r
262                 /* Copy the file name, i.e. the string that comes after the last separator. */\r
263                 STRNCPY( pcFileName, pcPath + xIndex + 1, ffconfigMAX_FILENAME );\r
264 \r
265                 if( xIndex == 0 )\r
266                 {\r
267                         /* Only for the root, the slash is part of the directory name.\r
268                         'xIndex' now equals to the length of the path name. */\r
269                         xIndex = 1;\r
270                 }\r
271 \r
272                 /* FF_CreateShortName() might set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK. */\r
273                 FF_CreateShortName( &xFindParams, pcFileName );\r
274 \r
275                 /* Lookup the path and find the cluster pointing to the directory: */\r
276                 xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, xIndex, &xError );\r
277                 if( xFindParams.ulDirCluster == 0ul )\r
278                 {\r
279                         if( ( ucMode & FF_MODE_WRITE ) != 0 )\r
280                         {\r
281                                 FF_PRINTF( "FF_Open[%s]: Path not found\n", pcPath );\r
282                         }\r
283                         /* The user tries to open a file but the path leading to the file does not exist. */\r
284                 }\r
285                 else if( FF_isERR( xError ) == pdFALSE )\r
286                 {\r
287                         /* Allocate an empty file handle and buffer space for 'unaligned access'. */\r
288                         pxFile = prvAllocFileHandle( pxIOManager, &xError );\r
289                 }\r
290         }\r
291 \r
292         if( FF_isERR( xError ) == pdFALSE )\r
293         {\r
294                 /* Copy the Mode Bits. */\r
295                 pxFile->ucMode = ucMode;\r
296 \r
297                 /* See if the file does exist within the given directory. */\r
298                 ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0x00, &xDirEntry, &xError );\r
299 \r
300                 if( ulFileCluster == 0ul )\r
301                 {\r
302                         /* If cluster 0 was returned, it might be because the file has no allocated cluster,\r
303                         i.e. only a directory entry and no stored data. */\r
304                         if( STRLEN( pcFileName ) == STRLEN( xDirEntry.pcFileName ) )\r
305                         {\r
306                                 if( ( xDirEntry.ulFileSize == 0 ) && ( FF_strmatch( pcFileName, xDirEntry.pcFileName, ( BaseType_t ) STRLEN( pcFileName ) ) == pdTRUE ) )\r
307                                 {\r
308                                         /* It is the file, give it a pseudo cluster number '1'. */\r
309                                         ulFileCluster = 1;\r
310                                         /* And reset any error. */\r
311                                         xError = FF_ERR_NONE;\r
312                                 }\r
313                         }\r
314                 }\r
315 \r
316                 /* Test 'ulFileCluster' again, it might have been changed. */\r
317                 if( ulFileCluster == 0ul )\r
318                 {\r
319                         /* The path is found, but it does not contain the file name yet.\r
320                         Maybe the user wants to create it? */\r
321                         if( ( ucMode & FF_MODE_CREATE ) == 0 )\r
322                         {\r
323                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_OPEN );\r
324                         }\r
325                         else\r
326                         {\r
327                                 ulFileCluster = FF_CreateFile( pxIOManager, &xFindParams, pcFileName, &xDirEntry, &xError );\r
328                                 if( FF_isERR( xError ) == pdFALSE )\r
329                                 {\r
330                                         xDirEntry.usCurrentItem += 1;\r
331                                 }\r
332                         }\r
333                 }\r
334         }\r
335 \r
336         if( FF_isERR( xError ) == pdFALSE )\r
337         {\r
338                 /* Now the file exists, or it has been created.\r
339                 Check if the Mode flags are allowed: */\r
340                 if( ( xDirEntry.ucAttrib == FF_FAT_ATTR_DIR ) && ( ( ucMode & FF_MODE_DIR ) == 0 ) )\r
341                 {\r
342                         /* Not the object, File Not Found! */\r
343                         xError = ( FF_Error_t ) ( FF_ERR_FILE_OBJECT_IS_A_DIR | FF_OPEN );\r
344                 }\r
345                 /*---------- Ensure Read-Only files don't get opened for Writing. */\r
346                 else if( ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) && ( ( xDirEntry.ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) )\r
347                 {\r
348                         xError = ( FF_Error_t ) ( FF_ERR_FILE_IS_READ_ONLY | FF_OPEN );\r
349                 }\r
350         }\r
351 \r
352         if( FF_isERR( xError ) == pdFALSE )\r
353         {\r
354                 pxFile->pxIOManager = pxIOManager;\r
355                 pxFile->ulFilePointer = 0;\r
356                 /* Despite the warning output by MSVC - it is not possible to get here\r
357                 if xDirEntry has not been initialised. */\r
358                 pxFile->ulObjectCluster = xDirEntry.ulObjectCluster;\r
359                 pxFile->ulFileSize = xDirEntry.ulFileSize;\r
360                 pxFile->ulCurrentCluster = 0;\r
361                 pxFile->ulAddrCurrentCluster = pxFile->ulObjectCluster;\r
362 \r
363                 pxFile->pxNext = NULL;\r
364                 pxFile->ulDirCluster = xFindParams.ulDirCluster;\r
365                 pxFile->usDirEntry = xDirEntry.usCurrentItem - 1;\r
366                 pxFile->ulChainLength = 0;\r
367                 pxFile->ulEndOfChain = 0;\r
368                 pxFile->ulValidFlags &= ~( FF_VALID_FLAG_DELETED );\r
369 \r
370                 /* Add pxFile onto the end of our linked list of FF_FILE objects.\r
371                 But first make sure that there are not 2 handles with write access\r
372                 to the same object. */\r
373                 FF_PendSemaphore( pxIOManager->pvSemaphore );\r
374                 {\r
375                         pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;\r
376                         if( pxFileChain == NULL )\r
377                         {\r
378                                 pxIOManager->FirstFile = pxFile;\r
379                         }\r
380                         else\r
381                         {\r
382                                 for( ; ; )\r
383                                 {\r
384                                         /* See if two file handles point to the same object. */\r
385                                         if( ( pxFileChain->ulObjectCluster == pxFile->ulObjectCluster ) &&\r
386                                                 ( pxFileChain->ulDirCluster == pxFile->ulDirCluster ) &&\r
387                                                 ( pxFileChain->usDirEntry == pxFile->usDirEntry ) )\r
388                                         {\r
389                                                 /* Fail if any of the two has write access to the object. */\r
390                                                 if( ( ( pxFileChain->ucMode | pxFile->ucMode ) & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 )\r
391                                                 {\r
392                                                         /* File is already open! DON'T ALLOW IT! */\r
393                                                         xError = ( FF_Error_t ) ( FF_ERR_FILE_ALREADY_OPEN | FF_OPEN );\r
394                                                         break;\r
395                                                 }\r
396                                         }\r
397 \r
398                                         if( pxFileChain->pxNext == NULL )\r
399                                         {\r
400                                                 pxFileChain->pxNext = pxFile;\r
401                                                 break;\r
402                                         }\r
403 \r
404                                         pxFileChain = ( FF_FILE * ) pxFileChain->pxNext;\r
405                                 }\r
406                         }\r
407                 }\r
408 \r
409                 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );\r
410         }\r
411 \r
412         if( FF_isERR( xError ) == pdFALSE )\r
413         {\r
414                 /* If the file is opened with the truncate flag, truncate its contents. */\r
415                 if( ( ucMode & FF_MODE_TRUNCATE ) != 0 )\r
416                 {\r
417                         /* Set the current size and position to zero. */\r
418                         pxFile->ulFileSize = 0;\r
419                         pxFile->ulFilePointer = 0;\r
420                 }\r
421         }\r
422 \r
423         if( FF_isERR( xError ) != pdFALSE )\r
424         {\r
425                 if( pxFile != NULL )\r
426                 {\r
427                         #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
428                         {\r
429                                 ffconfigFREE( pxFile->pucBuffer );\r
430                         }\r
431                         #endif\r
432                         ffconfigFREE( pxFile );\r
433                 }\r
434                 pxFile = NULL;\r
435         }\r
436 \r
437         if( pxError != NULL )\r
438         {\r
439                 *pxError = xError;\r
440         }\r
441 \r
442         return pxFile;\r
443 }  /* FF_Open() */\r
444 /*-----------------------------------------------------------*/\r
445 \r
446 /**\r
447  *      @public\r
448  *      @brief  Tests if a Directory contains any other files or folders.\r
449  *\r
450  *      @param  pxIOManager     FF_IOManager_t object returned from the FF_CreateIOManger() function.\r
451  *\r
452  **/\r
453 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
454 BaseType_t FF_isDirEmpty ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR *pcPath )\r
455 #else\r
456 BaseType_t FF_isDirEmpty ( FF_IOManager_t * pxIOManager, const char *pcPath )\r
457 #endif\r
458 {\r
459 FF_DirEnt_t     xDirEntry;\r
460 FF_Error_t      xError = FF_ERR_NONE;\r
461 BaseType_t xReturn;\r
462 \r
463         if( pxIOManager == NULL )\r
464         {\r
465                 xReturn = pdFALSE;\r
466         }\r
467         else\r
468         {\r
469                 xError = FF_FindFirst( pxIOManager, &xDirEntry, pcPath );\r
470 \r
471                 /* Assume the directory is empty until a file is\r
472                 encountered with a name other than ".." or "." */\r
473                 xReturn = pdTRUE;\r
474 \r
475                 while( xError == 0 )\r
476                 {\r
477                         /* As we can't be sure the first 2 entries contain\r
478                          * "." and "..", check it, not just count them\r
479                          */\r
480                 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
481                         if( ( wcscmp( xDirEntry.pcFileName, L".." ) != 0 ) && ( wcscmp( xDirEntry.pcFileName, L"." ) != 0 ) )\r
482                 #else\r
483                         if( ( strcmp( xDirEntry.pcFileName, ".." ) != 0 ) && ( strcmp( xDirEntry.pcFileName, "." ) != 0 ) )\r
484                 #endif\r
485                         {\r
486                                 xReturn = pdFALSE;\r
487                                 break;\r
488                         }\r
489                         xError = FF_FindNext( pxIOManager, &xDirEntry );\r
490                 }\r
491         }\r
492 \r
493         return xReturn;\r
494 }       /* FF_isDirEmpty() */\r
495 /*-----------------------------------------------------------*/\r
496 \r
497 #if( ffconfigPATH_CACHE != 0 )\r
498         /* _HT_ After a directory has been renamed, the path cache becomes out-of-date */\r
499         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
500         static void FF_RmPathCache ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath )\r
501         #else\r
502         static void FF_RmPathCache ( FF_IOManager_t * pxIOManager, const char *pcPath )\r
503         #endif\r
504         {\r
505                 /*\r
506         * The directory 'path' will be removed or renamed\r
507         * now clear all entries starting with 'path' in the path cache\r
508         */\r
509                 BaseType_t      xIndex;\r
510                 BaseType_t      pathLen = STRLEN( pcPath );\r
511 \r
512                 FF_PendSemaphore( pxIOManager->pvSemaphore );\r
513                 {\r
514                         for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ )\r
515                         {\r
516                                 BaseType_t      len2 = STRLEN( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath );\r
517 \r
518                                 if( len2 >= pathLen && FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) )\r
519                                 {\r
520                                         pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath[ 0 ] = '\0';\r
521                                         pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster = 0;\r
522                                 }\r
523                         }\r
524                 }\r
525 \r
526                 FF_ReleaseSemaphore( pxIOManager->pvSemaphore );\r
527         }\r
528 #endif /* ffconfigPATH_CACHE */\r
529 /*-----------------------------------------------------------*/\r
530 \r
531 \r
532 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
533 FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath )\r
534 #else\r
535 FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const char *pcPath )\r
536 #endif\r
537 {\r
538 FF_FILE                         *pxFile;\r
539 uint8_t                         ucEntryBuffer[32];\r
540 FF_FetchContext_t       xFetchContext;\r
541 FF_Error_t                      xError = FF_ERR_NONE;\r
542 \r
543         if( pxIOManager == NULL )\r
544         {\r
545                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_RMDIR );\r
546         }\r
547 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
548         else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
549         {\r
550                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_RMDIR );\r
551         }\r
552 #endif /* ffconfigREMOVABLE_MEDIA */\r
553         else\r
554         {\r
555                 pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_DIR, &xError );\r
556 \r
557                 if( pxFile != NULL )\r
558                 {\r
559                         pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;\r
560 \r
561                         /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any\r
562                         state. */\r
563                         memset( &xFetchContext, '\0', sizeof( xFetchContext ) );\r
564 \r
565                         /* This task will get the unique right to change directories. */\r
566                         FF_LockDirectory( pxIOManager );\r
567                         do /* while( pdFALSE ) */\r
568                         {\r
569                                 /* This while loop is only introduced to be able to use break\r
570                                 statements. */\r
571                                 if( FF_isDirEmpty( pxIOManager, pcPath ) == pdFALSE )\r
572                                 {\r
573                                         xError = ( FF_ERR_DIR_NOT_EMPTY | FF_RMDIR );\r
574                                         break;\r
575                                 }\r
576                                 FF_LockFAT( pxIOManager );\r
577                                 #if( ffconfigHASH_CACHE != 0 )\r
578                                 {\r
579                                         /* A directory is removed so invalidate any hash table\r
580                                         referring to this directory. */\r
581                                         FF_UnHashDir( pxIOManager, pxFile->ulObjectCluster );\r
582                                 }\r
583                                 #endif  /* ffconfigHASH_CACHE */\r
584                                 {\r
585                                         /* Add parameter 0 to delete the entire chain!\r
586                                         The actual directory entries on disk will be freed. */\r
587                                         xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );\r
588                                 }\r
589                                 FF_UnlockFAT( pxIOManager );\r
590                                 if( FF_isERR( xError ) )\r
591                                 {\r
592                                         break;\r
593                                 }\r
594 \r
595                                 /* Now remove this directory from its parent directory.\r
596                                 Initialise the dirent Fetch Context object for faster removal of\r
597                                 dirents. */\r
598                                 xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );\r
599                                 if( FF_isERR( xError ) )\r
600                                 {\r
601                                         break;\r
602                                 }\r
603 \r
604                                 #if( ffconfigHASH_CACHE != 0 )\r
605                                 {\r
606                                         /* Invalidate any hash table of the parent directory\r
607                                         as well. */\r
608                                         FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );\r
609                                 }\r
610                                 #endif  /* ffconfigHASH_CACHE */\r
611 \r
612                                 /* Edit the Directory Entry, so it will show as deleted.\r
613                                 First remove the LFN entries: */\r
614                                 xError = FF_RmLFNs( pxIOManager, pxFile->usDirEntry, &xFetchContext );\r
615                                 if( FF_isERR( xError ) )\r
616                                 {\r
617                                         break;\r
618                                 }\r
619 \r
620                                 /* And remove the Short file name entry: */\r
621                                 xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
622                                 if( FF_isERR( xError ) == pdFALSE )\r
623                                 {\r
624                                         ucEntryBuffer[0] = FF_FAT_DELETED;\r
625                                         FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );\r
626                                         FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW,  ( uint32_t ) 0ul );\r
627 \r
628                                         xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
629                                 }\r
630                                 if( FF_isERR( xError ) )\r
631                                 {\r
632                                         break;\r
633                                 }\r
634 \r
635                                 #if( ffconfigPATH_CACHE != 0 )\r
636                                 {\r
637                                         /* We're removing a directory which might contain\r
638                                         subdirectories.  Instead of iterating through all\r
639                                         subdirectories, just clear the path cache. */\r
640                                         FF_RmPathCache( pxIOManager, pcPath );\r
641                                 }\r
642                                 #endif\r
643                         } while( pdFALSE );\r
644                         {\r
645                         FF_Error_t xTempError;\r
646                                 xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
647                                 if( FF_isERR( xError ) == pdFALSE )\r
648                                 {\r
649                                         xError = xTempError;\r
650                                 }\r
651                                 FF_UnlockDirectory( pxIOManager );\r
652 \r
653                                 /* Free the file pointer resources. */\r
654                                 xTempError = FF_Close( pxFile );\r
655                                 if( FF_isERR( xError ) == pdFALSE )\r
656                                 {\r
657                                         xError = xTempError;\r
658                                 }\r
659 \r
660                                 xTempError = FF_FlushCache( pxIOManager );\r
661                                 if( FF_isERR( xError ) == pdFALSE )\r
662                                 {\r
663                                         xError = xTempError;\r
664                                 }\r
665                         }\r
666                 }       /* if( pxFile != NULL ) */\r
667         }       /* else if( pxIOManager != NULL ) */\r
668 \r
669         return xError;\r
670 }       /* FF_RmDir() */\r
671 /*-----------------------------------------------------------*/\r
672 \r
673 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
674 FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath )\r
675 #else\r
676 FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const char *pcPath )\r
677 #endif\r
678 {\r
679 FF_FILE *pxFile;\r
680 FF_Error_t xError = FF_ERR_NONE;\r
681 uint8_t ucEntryBuffer[32];\r
682 FF_FetchContext_t xFetchContext;\r
683 \r
684         /* Opening the file-to-be-deleted in WR mode has two advantages:\r
685         1. The file handle gives all necessary information to delete it such\r
686            as the data clusters and directory entries.\r
687         2. The file is now locked, it can not be opened by another task. */\r
688         pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_WRITE, &xError );\r
689 \r
690         if( pxFile != NULL )\r
691         {\r
692                 /* FF_Close() will see this flag and won't do any disc access. */\r
693                 pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED;\r
694 \r
695                 /* Ensure there is actually a cluster chain to delete! */\r
696                 if( pxFile->ulObjectCluster != 0 )\r
697                 {\r
698                         /* Lock the FAT so its thread-safe. */\r
699                         FF_LockFAT( pxIOManager );\r
700                         {\r
701                                 /* 0 to delete the entire chain! */\r
702                                 xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );\r
703                         }\r
704                         FF_UnlockFAT( pxIOManager );\r
705                 }\r
706 \r
707                 if( FF_isERR( xError ) == pdFALSE )\r
708                 {\r
709                         /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any\r
710                         state. */\r
711                         memset( &xFetchContext, '\0', sizeof( xFetchContext ) );\r
712 \r
713                         /* Get sole access to "directory changes" */\r
714                         FF_LockDirectory( pxIOManager );\r
715 \r
716                         /* Edit the Directory Entry! (So it appears as deleted); */\r
717                         do {\r
718                                 xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext );\r
719                                 if( FF_isERR( xError ) )\r
720                                 {\r
721                                         break;\r
722                                 }\r
723 \r
724                                 #if( ffconfigHASH_CACHE != 0 )\r
725                                 {\r
726                                         FF_UnHashDir( pxIOManager, pxFile->ulDirCluster );\r
727                                 }\r
728                                 #endif  /* ffconfigHASH_CACHE */\r
729                                 /* Remove LFN entries, if any. */\r
730                                 xError = FF_RmLFNs( pxIOManager, ( uint16_t ) pxFile->usDirEntry, &xFetchContext );\r
731                                 if( FF_isERR( xError ) )\r
732                                 {\r
733                                         break;\r
734                                 }\r
735 \r
736                                 /* Remove the Short file name entry. */\r
737                                 xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
738                                 if( FF_isERR( xError ) == pdFALSE )\r
739                                 {\r
740                                         ucEntryBuffer[0] = FF_FAT_DELETED;\r
741                                         FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );\r
742                                         FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW,  ( uint32_t ) 0ul );\r
743 \r
744                                         xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
745                                 }\r
746                         } while( pdFALSE );\r
747                         {\r
748                         FF_Error_t xTempError;\r
749                                 xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
750                                 if( FF_isERR( xError ) == pdFALSE )\r
751                                 {\r
752                                         xError = xTempError;\r
753                                 }\r
754                                 FF_UnlockDirectory( pxIOManager );\r
755 \r
756                                 /* Free the file pointer resources. */\r
757                                 xTempError = FF_Close( pxFile );\r
758                                 if( FF_isERR( xError ) == pdFALSE )\r
759                                 {\r
760                                         xError = xTempError;\r
761                                 }\r
762 \r
763                                 xTempError = FF_FlushCache( pxIOManager );\r
764                                 if( FF_isERR( xError ) == pdFALSE )\r
765                                 {\r
766                                         xError = xTempError;\r
767                                 }\r
768                         }\r
769                 }\r
770         }       /* if( pxFile != NULL ) */\r
771 \r
772         return xError;\r
773 }       /* FF_RmFile() */\r
774 /*-----------------------------------------------------------*/\r
775 \r
776 /**\r
777  *      @public\r
778  *      @brief  Moves a file or directory from source to destination.\r
779  *\r
780  *      @param  pxIOManager                             The FF_IOManager_t object pointer.\r
781  *      @param  szSourceFile            String of the source file to be moved or renamed.\r
782  *      @param  szDestinationFile       String of the destination file to where the source should be moved or renamed.\r
783  *\r
784  *      @return FF_ERR_NONE on success.\r
785  *      @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists.\r
786  *      @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!).\r
787  *      @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found.\r
788  *      @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found.\r
789  *\r
790  **/\r
791 \r
792 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
793 FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const FF_T_WCHAR*szSourceFile,\r
794         const FF_T_WCHAR *szDestinationFile, BaseType_t xDeleteIfExists )\r
795 #else\r
796 FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const char     *szSourceFile,\r
797         const char      *szDestinationFile, BaseType_t  xDeleteIfExists )\r
798 #endif\r
799 {\r
800 FF_Error_t xError;\r
801 FF_FILE *pSrcFile, *pxDestFile;\r
802 FF_DirEnt_t xMyFile;\r
803 uint8_t ucEntryBuffer[32];\r
804 BaseType_t xIndex;\r
805 uint32_t ulDirCluster = 0ul;\r
806 FF_FetchContext_t xFetchContext;\r
807 #if( ffconfigPATH_CACHE != 0 )\r
808         BaseType_t xIsDirectory = pdFALSE;\r
809 #endif\r
810 \r
811         memset( &xFetchContext, '\0', sizeof( xFetchContext ) );\r
812 \r
813         if( pxIOManager == NULL )\r
814         {\r
815                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MOVE );\r
816         }\r
817 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
818         else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 )\r
819         {\r
820                 xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MOVE );\r
821         }\r
822 #endif /* ffconfigREMOVABLE_MEDIA */\r
823         else\r
824         {\r
825                 /* Check destination file doesn't exist! */\r
826                 pxDestFile = FF_Open( pxIOManager, szDestinationFile, FF_MODE_READ, &xError );\r
827 \r
828                 if( ( pxDestFile != NULL) || ( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR ) )\r
829                 {\r
830                         xError = ( FF_Error_t ) ( FF_ERR_FILE_DESTINATION_EXISTS | FF_MOVE );\r
831                         if( pxDestFile != NULL )\r
832                         {\r
833                                 FF_Close( pxDestFile );\r
834                                 if( xDeleteIfExists != pdFALSE )\r
835                                 {\r
836                                         xError = FF_RmFile( pxIOManager, szDestinationFile );\r
837                                 }\r
838                         }\r
839                 }\r
840                 else\r
841                 {\r
842                         /* Discard the error set by FF_Open().\r
843                         The target file (or directory) is not found: continue renaming. */\r
844                         xError = FF_ERR_NONE;\r
845                 }\r
846         }\r
847 \r
848         if( FF_isERR( xError ) == pdFALSE )\r
849         {\r
850                 /* About to move/rename 'szSourceFile'.  When opening it with 'FF_MODE_WRITE'\r
851                 only succeeds if it has no other open handle to it. */\r
852                 pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_WRITE, &xError );\r
853 \r
854                 if( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR )\r
855                 {\r
856                         /* Open a directory for moving! */\r
857                         pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_DIR, &xError );\r
858         #if( ffconfigPATH_CACHE != 0 )\r
859                         xIsDirectory = pdTRUE;\r
860         #endif\r
861                 }\r
862 \r
863                 if( pSrcFile != NULL )\r
864                 {\r
865                         /* Collect information about the current directory entry. */\r
866                         xError = FF_InitEntryFetch( pxIOManager, pSrcFile->ulDirCluster, &xFetchContext );\r
867                         if( FF_isERR( xError ) == pdFALSE )\r
868                         {\r
869                                 xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
870                                 if( FF_isERR( xError ) == pdFALSE )\r
871                                 {\r
872                                         xMyFile.ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) );\r
873                                         xMyFile.ulFileSize = pSrcFile->ulFileSize;\r
874                                         xMyFile.ulObjectCluster = pSrcFile->ulObjectCluster;\r
875                                         xMyFile.usCurrentItem = 0;\r
876 \r
877                                         xIndex = ( BaseType_t ) STRLEN( szDestinationFile );\r
878 \r
879                                         while( xIndex != 0 )\r
880                                         {\r
881                                                 if( ( szDestinationFile[ xIndex ] == '\\' ) || ( szDestinationFile[ xIndex ] == '/' ) )\r
882                                                 {\r
883                                                         break;\r
884                                                 }\r
885 \r
886                                                 xIndex--;\r
887                                         }\r
888 \r
889                                         /* Copy the base name of the destination file. */\r
890                                         STRNCPY( xMyFile.pcFileName, ( szDestinationFile + xIndex + 1 ), ffconfigMAX_FILENAME );\r
891 \r
892                                         if( xIndex == 0 )\r
893                                         {\r
894                                                 xIndex = 1;\r
895                                         }\r
896 \r
897                                         /* Find the (cluster of the) directory in which the target file will be located.\r
898                                         It must exist before calling FF_Move(). */\r
899                                         ulDirCluster = FF_FindDir( pxIOManager, szDestinationFile, xIndex, &xError );\r
900                                 }\r
901                         }\r
902                 }\r
903 \r
904                 if( FF_isERR( xError ) == pdFALSE )\r
905                 {\r
906                         if( ulDirCluster != 0ul )\r
907                         {\r
908                                 FF_FindParams_t xFindParams;\r
909                                 memset( &xFindParams, '\0', sizeof( xFindParams ) );\r
910 \r
911                                 /* Clean up because FF_CreateDirent might want to write to the same sector. */\r
912                                 xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
913 \r
914                                 if( FF_isERR( xError ) == pdFALSE )\r
915                                 {\r
916                                         /* Destination directory was found, we can now create the new entry. */\r
917                                         xFindParams.ulDirCluster = ulDirCluster;\r
918                                         xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyFile );\r
919                                 }\r
920 \r
921                                 if( FF_isERR( xError ) == pdFALSE )\r
922                                 {\r
923                                         /* Edit the Directory Entry! (So it appears as deleted); */\r
924                                         FF_LockDirectory( pxIOManager );\r
925                                         {\r
926                                                 xError = FF_RmLFNs( pxIOManager, pSrcFile->usDirEntry, &xFetchContext );\r
927 \r
928                                                 if( FF_isERR( xError ) == pdFALSE )\r
929                                                 {\r
930                                                         xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
931 \r
932                                                         if( FF_isERR( xError ) == pdFALSE )\r
933                                                         {\r
934                                                         FF_Error_t xTempError;\r
935                                                                 ucEntryBuffer[0] = FF_FAT_DELETED;\r
936                                                                 FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul );\r
937                                                                 FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW,  ( uint32_t ) 0ul );\r
938 \r
939                                                                 xError = FF_PushEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer );\r
940                                                                 /* The contents of 'xFetchContext' has changed, flush it to disk now. */\r
941                                                                 xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
942                                                                 if( FF_isERR( xError ) == pdFALSE )\r
943                                                                 {\r
944                                                                         xError = xTempError;\r
945                                                                 }\r
946                                                         }\r
947                                                 }\r
948                                         }\r
949                                         FF_UnlockDirectory( pxIOManager );\r
950                                 }\r
951 \r
952                                 #if( ffconfigPATH_CACHE != 0 )\r
953                                 {\r
954                                         if( xIsDirectory != 0 )\r
955                                         {\r
956                                                 /* We've renamed a directory which might contain\r
957                                                 subdirectories.  To avoid having false entries, clear\r
958                                                 the path cache. */\r
959                                                 FF_RmPathCache( pxIOManager, szSourceFile );\r
960                                         }\r
961                                 }\r
962                                 #endif\r
963                         }\r
964                         else    /* ulDirCluster == 0ul */\r
965                         {\r
966                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_DIR_NOT_FOUND | FF_MOVE );\r
967                         }\r
968                 }\r
969 \r
970                 if( pSrcFile != NULL )\r
971                 {\r
972                         /* The source file was opened in WRITE mode just to lock it.\r
973                         Now clear the write flags to avoid writing back any changes. */\r
974                         pSrcFile->ucMode &= ~( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE );\r
975                         FF_Close( pSrcFile );\r
976                 }\r
977         }\r
978 \r
979         {\r
980         FF_Error_t xTempError;\r
981 \r
982                 xTempError = FF_FlushCache( pxIOManager );\r
983                 if( FF_isERR( xError ) == pdFALSE )\r
984                 {\r
985                         xError = xTempError;\r
986                 }\r
987                 xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );\r
988                 if( FF_isERR( xError ) == pdFALSE )\r
989                 {\r
990                         xError = xTempError;\r
991                 }\r
992         }\r
993 \r
994         return xError;\r
995 }       /* FF_Move() */\r
996 /*-----------------------------------------------------------*/\r
997 \r
998                                         /**\r
999  *      @public\r
1000  *      @brief  Get's the next Entry based on the data recorded in the FF_DirEnt_t object.\r
1001  *\r
1002  *      @param  pxFile  FF_FILE object that was created by FF_Open().\r
1003  *\r
1004  *      @return pdTRUE if End of File was reached. pdFALSE if not.\r
1005  *      @return pdFALSE if a null pointer was provided.\r
1006  *\r
1007  **/\r
1008 BaseType_t FF_isEOF( FF_FILE *pxFile )\r
1009 {\r
1010 BaseType_t xReturn;\r
1011 \r
1012         if( ( pxFile != NULL ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )\r
1013         {\r
1014                 xReturn = pdTRUE;\r
1015         }\r
1016         else\r
1017         {\r
1018                 xReturn = pdFALSE;\r
1019         }\r
1020 \r
1021         return xReturn;\r
1022 }       /* FF_isEOF() */\r
1023 /*-----------------------------------------------------------*/\r
1024 \r
1025 /**\r
1026  *      @public\r
1027  *      @brief  Checks the number of bytes left on a read handle\r
1028  *\r
1029  *      @param  pxFile          An open file handle\r
1030  *\r
1031  *      @return Less than zero: an error code\r
1032  *      @return Number of bytes left to read from handle\r
1033  **/\r
1034 int32_t FF_BytesLeft( FF_FILE *pxFile )\r
1035 {\r
1036 BaseType_t xReturn;\r
1037 \r
1038         if( pxFile == NULL )\r
1039         {\r
1040                 xReturn = FF_ERR_NULL_POINTER | FF_BYTESLEFT;\r
1041         }\r
1042         else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )\r
1043         {\r
1044                 xReturn = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_BYTESLEFT;\r
1045         }\r
1046         else if( pxFile->ulFilePointer >= pxFile->ulFileSize )\r
1047         {\r
1048                 xReturn = 0;\r
1049         }\r
1050         else\r
1051         {\r
1052                 xReturn = pxFile->ulFileSize - pxFile->ulFilePointer;\r
1053         }\r
1054 \r
1055         return xReturn;\r
1056 }       /* FF_BytesLeft() */\r
1057 /*-----------------------------------------------------------*/\r
1058 \r
1059 /**\r
1060  *      @public\r
1061  *      @brief  Returns the file size of a read handle\r
1062  *\r
1063  *      @param  pxFile          An open file handle\r
1064  *\r
1065  *      @return Less than zero: an error code\r
1066  *      @return Number of bytes left to read from handle\r
1067  **/\r
1068 FF_Error_t FF_GetFileSize( FF_FILE *pxFile, uint32_t *pulSize ) /* Writes # of bytes in a file to the parameter. */\r
1069 {\r
1070 BaseType_t xReturn;\r
1071 \r
1072         if( pxFile == NULL )\r
1073         {\r
1074                 xReturn = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_BYTESLEFT );\r
1075                 *( pulSize ) = ( uint32_t ) 0u;\r
1076         }\r
1077         else if( FF_isERR( FF_CheckValid( pxFile ) ) )\r
1078         {\r
1079                 xReturn = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_BYTESLEFT );\r
1080                 *( pulSize ) = ( uint32_t ) 0u;\r
1081         }\r
1082         else\r
1083         {\r
1084                 xReturn = 0;\r
1085                 *( pulSize ) = pxFile->ulFileSize;\r
1086         }\r
1087 \r
1088         return xReturn;\r
1089 }       /* FF_GetFileSize */\r
1090 \r
1091 int32_t FF_FileSize( FF_FILE *pxFile )\r
1092 {\r
1093 uint32_t ulLength;\r
1094 FF_Error_t xResult;\r
1095 \r
1096         /* Function is deprecated. Please use FF_GetFileSize(). */\r
1097         xResult = FF_GetFileSize( pxFile, &( ulLength ) );\r
1098 \r
1099         if( FF_isERR( xResult ) == 0 )\r
1100         {\r
1101                 xResult = ( int32_t ) ulLength;\r
1102         }\r
1103 \r
1104         return ( int32_t ) xResult;\r
1105 }       /* FF_FileSize() */\r
1106 /*-----------------------------------------------------------*/\r
1107 \r
1108 static uint32_t FF_GetSequentialClusters( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t ulLimit, FF_Error_t *pxError )\r
1109 {\r
1110 uint32_t ulCurrentCluster;\r
1111 uint32_t ulNextCluster = ulStartCluster;\r
1112 uint32_t ulIndex = 0;\r
1113 \r
1114         FF_FATBuffers_t xFATBuffers;\r
1115         FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ );\r
1116 \r
1117         *pxError = FF_ERR_NONE;\r
1118 \r
1119         FF_LockFAT( pxIOManager );\r
1120         do\r
1121         {\r
1122                 ulCurrentCluster = ulNextCluster;\r
1123                 ulNextCluster = FF_getFATEntry( pxIOManager, ulCurrentCluster, pxError, &xFATBuffers );\r
1124                 if( FF_isERR( *pxError ) )\r
1125                 {\r
1126                         ulIndex = 0;\r
1127                         break;\r
1128                 }\r
1129 \r
1130                 if( ulNextCluster == ( ulCurrentCluster + 1 ) )\r
1131                 {\r
1132                         ulIndex++;\r
1133                 }\r
1134                 else\r
1135                 {\r
1136                         break;\r
1137                 }\r
1138 \r
1139                 if( ( ulLimit != 0 ) && ( ulIndex == ulLimit ) )\r
1140                 {\r
1141                         break;\r
1142                 }\r
1143         }\r
1144         while( ulNextCluster == ( ulCurrentCluster + 1 ) );\r
1145 \r
1146         FF_UnlockFAT( pxIOManager );\r
1147 \r
1148         *pxError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
1149 \r
1150         return ulIndex;\r
1151 }       /* FF_GetSequentialClusters() */\r
1152 /*-----------------------------------------------------------*/\r
1153 \r
1154 static FF_Error_t FF_ReadClusters( FF_FILE *pxFile, uint32_t ulCount, uint8_t *buffer )\r
1155 {\r
1156 uint32_t ulSectors;\r
1157 uint32_t ulSequentialClusters = 0;\r
1158 uint32_t ulItemLBA;\r
1159 FF_Error_t xError = FF_ERR_NONE;\r
1160 \r
1161         while( ulCount != 0 )\r
1162         {\r
1163                 if( ( ulCount - 1 ) > 0 )\r
1164                 {\r
1165                         ulSequentialClusters =\r
1166                                 FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );\r
1167                         if( FF_isERR( xError ) )\r
1168                         {\r
1169                                 break;\r
1170                         }\r
1171                 }\r
1172 \r
1173                 ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;\r
1174                 ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );\r
1175                 ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );\r
1176 \r
1177                 xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );\r
1178                 if( FF_isERR( xError ) )\r
1179                 {\r
1180                         break;\r
1181                 }\r
1182 \r
1183                 ulCount -= ( ulSequentialClusters + 1 );\r
1184 \r
1185                 FF_LockFAT( pxFile->pxIOManager );\r
1186                 {\r
1187                         pxFile->ulAddrCurrentCluster =\r
1188                                 FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );\r
1189                 }\r
1190                 FF_UnlockFAT( pxFile->pxIOManager );\r
1191                 if( FF_isERR( xError ) )\r
1192                 {\r
1193                         break;\r
1194                 }\r
1195 \r
1196                 pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );\r
1197                 buffer += ulSectors * pxFile->pxIOManager->usSectorSize;\r
1198                 ulSequentialClusters = 0;\r
1199         }\r
1200 \r
1201         return xError;\r
1202 }       /* FF_ReadClusters ()*/\r
1203 /*-----------------------------------------------------------*/\r
1204 \r
1205 static FF_Error_t FF_ExtendFile( FF_FILE *pxFile, uint32_t ulSize )\r
1206 {\r
1207 FF_IOManager_t *pxIOManager = pxFile->pxIOManager;\r
1208 uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
1209 uint32_t ulTotalClustersNeeded = ( ulSize + ulBytesPerCluster - 1 ) / ulBytesPerCluster;\r
1210 uint32_t ulClusterToExtend;\r
1211 /* Initialise xIndex just for the compiler. */\r
1212 BaseType_t xIndex = 0;\r
1213 FF_DirEnt_t xOriginalEntry;\r
1214 FF_Error_t xError = FF_ERR_NONE;\r
1215 FF_FATBuffers_t xFATBuffers;\r
1216 \r
1217         if( ( pxFile->ucMode & FF_MODE_WRITE ) != FF_MODE_WRITE )\r
1218         {\r
1219                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_EXTENDFILE );\r
1220         }\r
1221         else\r
1222         {\r
1223                 if( ( pxFile->ulFileSize == 0 ) && ( pxFile->ulObjectCluster == 0 ) )\r
1224                 {\r
1225                         /* If there is no object cluster yet, create it.*/\r
1226                         pxFile->ulAddrCurrentCluster = FF_CreateClusterChain( pxFile->pxIOManager, &xError );\r
1227 \r
1228                         if( FF_isERR( xError ) == pdFALSE )\r
1229                         {\r
1230                                 /* The directory denotes the address of the first data cluster of every file.\r
1231                                 Now change it to 'ulAddrCurrentCluster': */\r
1232                                 xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );\r
1233 \r
1234                                 if( FF_isERR( xError ) == pdFALSE )\r
1235                                 {\r
1236                                         xOriginalEntry.ulObjectCluster = pxFile->ulAddrCurrentCluster;\r
1237                                         xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );\r
1238 \r
1239                                         if( FF_isERR( xError ) == pdFALSE )\r
1240                                         {\r
1241                                                 pxFile->ulObjectCluster = pxFile->ulAddrCurrentCluster;\r
1242                                                 pxFile->ulChainLength = 1;\r
1243                                                 pxFile->ulCurrentCluster = 0;\r
1244                                                 pxFile->ulEndOfChain = pxFile->ulAddrCurrentCluster;\r
1245                                         }\r
1246                                 }\r
1247                         }\r
1248                 }\r
1249                 else\r
1250                 {\r
1251                         /* This file already has at least one cluster. */\r
1252                 }\r
1253         }\r
1254 \r
1255         if( FF_isERR( xError ) == pdFALSE )\r
1256         {\r
1257                 if( pxFile->ulChainLength == 0 )\r
1258                 {\r
1259                         /* This is the first extension requiring the chain length.\r
1260                         Calculate it now: */\r
1261                         pxFile->ulChainLength = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, &pxFile->ulEndOfChain, &xError );\r
1262                 }\r
1263         }\r
1264 \r
1265         if( ( FF_isERR( xError ) == pdFALSE ) && ( ulTotalClustersNeeded > pxFile->ulChainLength ) )\r
1266         {\r
1267         uint32_t ulCurrentCluster, ulNextCluster;\r
1268 \r
1269                 ulClusterToExtend = ( ulTotalClustersNeeded - pxFile->ulChainLength );\r
1270                 /* Now the file has at least 1 cluster, but it needs more clusters. */\r
1271                 ulNextCluster = pxFile->ulAddrCurrentCluster;\r
1272                 FF_LockFAT( pxIOManager );\r
1273 \r
1274                 ulCurrentCluster = FF_FindEndOfChain( pxIOManager, ulNextCluster, &xError );\r
1275 \r
1276                 if( FF_isERR( xError ) == pdFALSE )\r
1277                 {\r
1278                         for( xIndex = 0; xIndex < ( BaseType_t ) ulClusterToExtend; xIndex++ )\r
1279                         {\r
1280                                 /* In FF_ExtendFile() */\r
1281                                 ulNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE );\r
1282                                 if( ( FF_isERR( xError ) == pdFALSE ) && ( ulNextCluster == 0UL ) )\r
1283                                 {\r
1284                                         xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDFILE );\r
1285                                 }\r
1286 \r
1287                                 if( FF_isERR( xError ) )\r
1288                                 {\r
1289                                         break;\r
1290                                 }\r
1291 \r
1292                                 /* Can not use this buffer earlier because of FF_FindEndOfChain/FF_FindFreeCluster */\r
1293                                 FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE );\r
1294                                 xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, ulNextCluster, &xFATBuffers );\r
1295                                 if( FF_isERR( xError ) )\r
1296                                 {\r
1297                                         break;\r
1298                                 }\r
1299                                 xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers );\r
1300                                 if( FF_isERR( xError ) )\r
1301                                 {\r
1302                                         break;\r
1303                                 }\r
1304                                 ulCurrentCluster = ulNextCluster;\r
1305                         }\r
1306 \r
1307                         if( FF_isERR( xError ) == pdFALSE )\r
1308                         {\r
1309                                 pxFile->ulEndOfChain = ulCurrentCluster;\r
1310                         }\r
1311                         pxFile->ulChainLength += xIndex;\r
1312                 }\r
1313                 FF_UnlockFAT( pxIOManager );\r
1314 \r
1315                 {\r
1316                 FF_Error_t xTempError;\r
1317                         xTempError = FF_DecreaseFreeClusters( pxIOManager, ( uint32_t ) xIndex );       /* Keep Tab of Numbers for fast FreeSize() */\r
1318                         if( FF_isERR( xError ) == pdFALSE )\r
1319                         {\r
1320                                 xError = xTempError;\r
1321                         }\r
1322                 }\r
1323 \r
1324                 /* We must ensure that the ulAddrCurrentCluster is not out-of-sync with the CurrentCluster number.\r
1325                 This could have occurred in append mode, where the file was opened with a filesize % clustersize == 0\r
1326                 because of a seek, where the ulAddrCurrentCluster was not updated after extending. This caused the data to\r
1327                 be written to the previous cluster(s). */\r
1328                 if( ( pxFile->ulCurrentCluster == pxFile->ulChainLength - 1 ) &&\r
1329                         ( pxFile->ulAddrCurrentCluster != pxFile->ulEndOfChain ) )\r
1330                 {\r
1331                         pxFile->ulAddrCurrentCluster = pxFile->ulEndOfChain;\r
1332                 }\r
1333 \r
1334                 /* By default, 'ffconfigFILE_EXTEND_FLUSHES_BUFFERS' is\r
1335                 defined as 1.\r
1336                 Users may set it to zero in order to increase the\r
1337                 speed of writing to disk. */\r
1338 \r
1339                 #if( ffconfigFILE_EXTEND_FLUSHES_BUFFERS != 0 )\r
1340                 {\r
1341                 FF_Error_t xTempError;\r
1342 \r
1343                         xTempError = FF_FlushCache( pxIOManager );\r
1344                         if( FF_isERR( xError ) == pdFALSE )\r
1345                         {\r
1346                                 xError = xTempError;\r
1347                         }\r
1348                 }\r
1349                 #endif  /* ffconfigFILE_EXTEND_FLUSHES_BUFFERS */\r
1350         } /* if( ulTotalClustersNeeded > pxFile->ulChainLength ) */\r
1351 \r
1352         return xError;\r
1353 }       /* FF_ExtendFile() */\r
1354 /*-----------------------------------------------------------*/\r
1355 \r
1356 static FF_Error_t FF_WriteClusters( FF_FILE *pxFile, uint32_t ulCount, uint8_t *buffer )\r
1357 {\r
1358 uint32_t ulSectors;\r
1359 uint32_t ulSequentialClusters = 0;\r
1360 uint32_t ulItemLBA;\r
1361 FF_Error_t xError = FF_ERR_NONE;\r
1362 \r
1363         while( ulCount != 0 )\r
1364         {\r
1365                 if( ( ulCount - 1 ) > 0 )\r
1366                 {\r
1367                         ulSequentialClusters =\r
1368                                 FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError );\r
1369                         if( FF_isERR( xError ) )\r
1370                         {\r
1371                                 break;\r
1372                         }\r
1373                 }\r
1374 \r
1375                 ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;\r
1376                 ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );\r
1377                 ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );\r
1378 \r
1379                 xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE );\r
1380 \r
1381                 if( FF_isERR( xError ) )\r
1382                 {\r
1383                         break;\r
1384                 }\r
1385 \r
1386                 ulCount -= ulSequentialClusters + 1;\r
1387 \r
1388                 FF_LockFAT( pxFile->pxIOManager );\r
1389                 {\r
1390                         pxFile->ulAddrCurrentCluster =\r
1391                                 FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError );\r
1392                 }\r
1393                 FF_UnlockFAT( pxFile->pxIOManager );\r
1394                 if( FF_isERR( xError ) )\r
1395                 {\r
1396                         break;\r
1397                 }\r
1398 \r
1399                 pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 );\r
1400                 buffer += ulSectors * pxFile->pxIOManager->usSectorSize;\r
1401                 ulSequentialClusters = 0;\r
1402         }\r
1403 \r
1404         return xError;\r
1405 }       /* FF_WriteClusters */\r
1406 /*-----------------------------------------------------------*/\r
1407 \r
1408 /**\r
1409  *      @private\r
1410  *      @brief  Calculate the Logical Block Address (LBA)\r
1411  *\r
1412  *      @param  pxFile       The file handle\r
1413  *\r
1414  *      @return LBA\r
1415  *\r
1416  *  Must be set:\r
1417  *    - pxFile->ulFilePointer        : byte offset in file\r
1418  *    - pxFile->ulAddrCurrentCluster : physical cluster on the partition\r
1419  **/\r
1420 static uint32_t FF_FileLBA( FF_FILE *pxFile )\r
1421 {\r
1422         uint32_t        ulItemLBA;\r
1423         ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster );\r
1424         ulItemLBA += FF_getMajorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );\r
1425         ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA );\r
1426         ulItemLBA += FF_getMinorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );\r
1427 \r
1428         return ulItemLBA;\r
1429 }       /* FF_FileLBA() */\r
1430 /*-----------------------------------------------------------*/\r
1431 \r
1432 /**\r
1433  *      @private\r
1434  *      @brief  Depending on FilePointer, calculate CurrentCluster\r
1435  *  @brief      and traverse the FAT to find the right ulAddrCurrentCluster\r
1436  *\r
1437  *      @param  pxFile       The file handle\r
1438  *\r
1439  *      @return FF_ERR_NONE on success\r
1440  *      @return Possible error returned by FF_TraverseFAT() or END_OF_DIR\r
1441  *\r
1442  *  Side effects:\r
1443  *    - pxFile->ulCurrentCluster     : relative cluster number (0 <= Num < ulChainLength)\r
1444  *    - pxFile->ulAddrCurrentCluster : fysical cluster on the partition\r
1445  **/\r
1446 static uint32_t FF_SetCluster( FF_FILE *pxFile, FF_Error_t *pxError )\r
1447 {\r
1448 FF_IOManager_t *pxIOManager = pxFile->pxIOManager;\r
1449 uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 );\r
1450 FF_Error_t xResult = FF_ERR_NONE;\r
1451 uint32_t ulReturn;\r
1452 \r
1453         if( ulNewCluster > pxFile->ulCurrentCluster )\r
1454         {\r
1455                 FF_LockFAT( pxIOManager );\r
1456                 {\r
1457                         pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulAddrCurrentCluster,\r
1458                                 ulNewCluster - pxFile->ulCurrentCluster, &xResult );\r
1459                 }\r
1460                 FF_UnlockFAT( pxIOManager );\r
1461         }\r
1462         else if( ulNewCluster < pxFile->ulCurrentCluster )\r
1463         {\r
1464                 FF_LockFAT( pxIOManager );\r
1465                 {\r
1466                         pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &xResult );\r
1467                 }\r
1468                 FF_UnlockFAT( pxIOManager );\r
1469         }\r
1470         else\r
1471         {\r
1472                 /* Well positioned. */\r
1473         }\r
1474 \r
1475         if( FF_isERR( xResult ) == pdFALSE )\r
1476         {\r
1477                 pxFile->ulCurrentCluster = ulNewCluster;\r
1478                 ulReturn = FF_FileLBA( pxFile );\r
1479         }\r
1480         else\r
1481         {\r
1482                 ulReturn = 0;\r
1483         }\r
1484         *pxError = xResult;\r
1485 \r
1486         return ulReturn;\r
1487 }       /* FF_SetCluster() */\r
1488 /*-----------------------------------------------------------*/\r
1489 \r
1490 static int32_t FF_ReadPartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount,\r
1491         uint8_t *pucBuffer, FF_Error_t *pxError )\r
1492 {\r
1493 FF_Error_t xError = FF_ERR_NONE;\r
1494 uint32_t ulBytesRead;\r
1495 \r
1496         /* Bytes to read are within a block and less than a block size. */\r
1497         #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
1498         {\r
1499         BaseType_t xLastRead;\r
1500 \r
1501                 /* Optimised method: each file handle holds one data block\r
1502                 in cache: 'pxFile->pucBuffer'. */\r
1503                 /* See if the current block will be accessed after this read: */\r
1504                 if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )\r
1505                 {\r
1506                         /* After this read, ulFilePointer will point to the next block/sector. */\r
1507                         xLastRead = pdTRUE;\r
1508                 }\r
1509                 else\r
1510                 {\r
1511                         /* It is not the last read within this block/sector. */\r
1512                         xLastRead = pdFALSE;\r
1513                 }\r
1514 \r
1515                 if( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 )\r
1516                 {\r
1517                         xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );\r
1518                         if( FF_isERR( xError ) == pdFALSE )\r
1519                         {\r
1520                                 pxFile->ucState = FF_BUFSTATE_VALID;\r
1521                         }\r
1522                 }\r
1523 \r
1524                 if( ( pxFile->ucState & FF_BUFSTATE_VALID ) != 0 )\r
1525                 {\r
1526                         memcpy( pucBuffer, pxFile->pucBuffer + ulRelBlockPos, ulCount );\r
1527                         pxFile->ulFilePointer += ulCount;\r
1528                         ulBytesRead = ulCount;\r
1529                         if( ( xLastRead == pdTRUE ) && ( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 ) )\r
1530                         {\r
1531                                 /* If the data was changed (file in 'update' mode), store the changes: */\r
1532                                 xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );\r
1533                         }\r
1534                 }\r
1535                 else\r
1536                 {\r
1537                         ulBytesRead = 0ul;\r
1538                 }\r
1539                 if( xLastRead == pdTRUE )\r
1540                 {\r
1541                         /* As the next FF_Read() will go passed the current block, invalidate the buffer now. */\r
1542                         pxFile->ucState = FF_BUFSTATE_INVALID;\r
1543                 }\r
1544         }\r
1545         #else\r
1546         {\r
1547         FF_Buffer_t *pxBuffer;\r
1548                 /* Reading in the standard way, using FF_Buffer_t. */\r
1549                 pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_READ );\r
1550                 if( pxBuffer == NULL )\r
1551                 {\r
1552                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_READ );\r
1553                         ulBytesRead = 0ul;\r
1554                 }\r
1555                 else\r
1556                 {\r
1557                         memcpy( pucBuffer, pxBuffer->pucBuffer + ulRelBlockPos, ulCount );\r
1558                         /* Releasing a buffer in FF_MODE_READ mode will not lead to an error,\r
1559                         because no disk access is needed. */\r
1560                         xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );\r
1561                         pxFile->ulFilePointer += ulCount;\r
1562                         ulBytesRead = ulCount;\r
1563                 }\r
1564         }\r
1565         #endif\r
1566 \r
1567         *pxError = xError;\r
1568 \r
1569         return ulBytesRead;\r
1570 }       /* FF_ReadPartial() */\r
1571 /*-----------------------------------------------------------*/\r
1572 \r
1573 /**\r
1574  *      @public\r
1575  *      @brief  Equivalent to fread()\r
1576  *\r
1577  *      @param  pxFile                  FF_FILE object that was created by FF_Open().\r
1578  *      @param  ulElementSize   The size of an element to read.\r
1579  *      @param  ulCount                 The number of elements to read.\r
1580  *      @param  buffer                  A pointer to a buffer of adequate size to be filled with the requested data.\r
1581  *\r
1582  *      @return Number of bytes read.\r
1583  *\r
1584  * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:\r
1585  *      1. Read bytes up to a sector border:  FF_ReadPartial()\r
1586  *      2. Read sectors up to cluster border: FF_BlockRead()\r
1587  *      3. Read complete clusters:            FF_ReadClusters()\r
1588  *      4. Read remaining sectors:            FF_BlockRead()\r
1589  *      5. Read remaining bytes:              FF_ReadPartial()\r
1590  **/\r
1591 int32_t FF_Read( FF_FILE *pxFile, uint32_t ulElementSize, uint32_t ulCount, uint8_t *pucBuffer )\r
1592 {\r
1593 uint32_t ulBytesLeft = ulElementSize * ulCount;\r
1594 uint32_t ulBytesRead = 0;\r
1595 uint32_t ulBytesToRead;\r
1596 FF_IOManager_t *pxIOManager;\r
1597 uint32_t ulRelBlockPos;\r
1598 uint32_t ulItemLBA;\r
1599 int32_t lResult;\r
1600 uint32_t ulSectors;\r
1601 uint32_t ulRelClusterPos;\r
1602 uint32_t ulBytesPerCluster;\r
1603 FF_Error_t xError;\r
1604 \r
1605         if( pxFile == NULL )\r
1606         {\r
1607                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ );\r
1608         }\r
1609         else\r
1610         {\r
1611                 /* Check validity of the handle and the current position within the file. */\r
1612                 xError = FF_CheckValid( pxFile );\r
1613                 if( FF_isERR( xError ) == pdFALSE )\r
1614                 {\r
1615                         if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )\r
1616                         {\r
1617                                 /* File was not opened with READ mode access. */\r
1618                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_READ );\r
1619                         }\r
1620                         else if( pxFile->ulFilePointer >= pxFile->ulFileSize )\r
1621                         {\r
1622                                 /* The end-of-file is reached.  The error READ_ZERO will not be\r
1623                                 returned, it is just used to avoid further processing. */\r
1624                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_READ_ZERO | FF_READ );\r
1625                         }\r
1626                         else if( ( pxFile->ulFilePointer + ulBytesLeft ) > pxFile->ulFileSize )\r
1627                         {\r
1628                                 /* Note that many bytes can be read. */\r
1629                                 ulBytesLeft = pxFile->ulFileSize - pxFile->ulFilePointer;\r
1630                         }\r
1631                 }\r
1632                 else\r
1633                 {\r
1634                         /* The file handle is not valid. */\r
1635                 }\r
1636         }       /* else pxFile != NULL */\r
1637 \r
1638         if( FF_isERR( xError ) == pdFALSE )\r
1639         {\r
1640                 pxIOManager = pxFile->pxIOManager;\r
1641 \r
1642                 /* And calculate the Logical Block Address. */\r
1643                 ulItemLBA = FF_SetCluster( pxFile, &xError );\r
1644 \r
1645                 /* Get the position within a block. */\r
1646                 ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 );\r
1647                 /* Open a do {} while( 0 ) loop to allow easy breaks: */\r
1648                 do\r
1649                 {\r
1650                         if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )\r
1651                         {\r
1652                                 /*---------- A small read within the current block only. */\r
1653                                 ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );\r
1654                                 break;\r
1655                         }\r
1656                         /*---------- Read (memcpy) to a Sector Boundary. */\r
1657                         if( ulRelBlockPos != 0 )\r
1658                         {\r
1659                                 /* Not on a sector boundary, at this point the LBA is known. */\r
1660                                 ulBytesToRead = pxIOManager->usSectorSize - ulRelBlockPos;\r
1661                                 ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesToRead, pucBuffer, &xError );\r
1662                                 if( FF_isERR( xError ) )\r
1663                                 {\r
1664                                         break;\r
1665                                 }\r
1666                                 ulBytesLeft -= ulBytesRead;\r
1667                                 pucBuffer += ulBytesRead;\r
1668                         }\r
1669 \r
1670                         /*---------- Read sectors, up to a Cluster Boundary. */\r
1671                         ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );\r
1672                         ulRelClusterPos = pxFile->ulFilePointer % ( ulBytesPerCluster * pxIOManager->xPartition.ucBlkFactor );\r
1673 \r
1674                         if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) )\r
1675                         {\r
1676                                 /* Need to get to cluster boundary. */\r
1677                                 ulItemLBA = FF_SetCluster( pxFile, &xError );\r
1678                                 if( FF_isERR( xError ) )\r
1679                                 {\r
1680                                         break;\r
1681                                 }\r
1682                                 ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize );\r
1683                                 xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );\r
1684                                 if( FF_isERR( xError ) )\r
1685                                 {\r
1686                                         break;\r
1687                                 }\r
1688                                 ulBytesToRead = ulSectors * pxIOManager->usSectorSize;\r
1689                                 ulBytesLeft -= ulBytesToRead;\r
1690                                 pucBuffer += ulBytesToRead;\r
1691                                 ulBytesRead += ulBytesToRead;\r
1692                                 pxFile->ulFilePointer += ulBytesToRead;\r
1693                         }\r
1694 \r
1695                         /*---------- Read entire clusters. */\r
1696                         if( ulBytesLeft >= ulBytesPerCluster )\r
1697                         {\r
1698                         uint32_t ulClusters;\r
1699 \r
1700                         FF_SetCluster( pxFile, &xError );\r
1701                                 if( FF_isERR( xError ) )\r
1702                                 {\r
1703                                         break;\r
1704                                 }\r
1705 \r
1706                                 ulClusters = ulBytesLeft / ulBytesPerCluster;\r
1707 \r
1708                                 xError = FF_ReadClusters( pxFile, ulClusters, pucBuffer );\r
1709                                 if( FF_isERR( xError ) )\r
1710                                 {\r
1711                                         break;\r
1712                                 }\r
1713                                 ulBytesToRead = ulBytesPerCluster * ulClusters;\r
1714                                 pxFile->ulFilePointer += ulBytesToRead;\r
1715                                 ulBytesLeft -= ulBytesToRead;\r
1716                                 pucBuffer += ulBytesToRead;\r
1717                                 ulBytesRead += ulBytesToRead;\r
1718                         }\r
1719 \r
1720                         /*---------- Read Remaining Blocks. */\r
1721                         while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )\r
1722                         {\r
1723                                 ulSectors = ulBytesLeft / pxIOManager->usSectorSize;\r
1724                                 {\r
1725                                         /* HT: I'd leave these pPart/ulOffset for readability */\r
1726                                         /* and shorter code lines */\r
1727                                         FF_Partition_t *pPart = &( pxIOManager->xPartition );\r
1728                                         uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;\r
1729                                         uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;\r
1730                                         if( ulSectors > ulRemain )\r
1731                                         {\r
1732                                                 ulSectors = ulRemain;\r
1733                                         }\r
1734                                 }\r
1735 \r
1736                                 ulItemLBA = FF_SetCluster( pxFile, &xError );\r
1737                                 if( FF_isERR( xError ) )\r
1738                                 {\r
1739                                         break;\r
1740                                 }\r
1741                                 xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );\r
1742 \r
1743                                 if( FF_isERR( xError ) )\r
1744                                 {\r
1745                                         break;\r
1746                                 }\r
1747                                 ulBytesToRead = ulSectors * pxIOManager->usSectorSize;\r
1748                                 pxFile->ulFilePointer += ulBytesToRead;\r
1749                                 ulBytesLeft -= ulBytesToRead;\r
1750                                 pucBuffer += ulBytesToRead;\r
1751                                 ulBytesRead += ulBytesToRead;\r
1752                         }\r
1753 \r
1754                         /*---------- Read (memcpy) Remaining Bytes */\r
1755                         if( ulBytesLeft == 0 )\r
1756                         {\r
1757                                 break;\r
1758                         }\r
1759                         ulItemLBA = FF_SetCluster( pxFile, &xError );\r
1760                         if( FF_isERR( xError ) )\r
1761                         {\r
1762                                 break;\r
1763                         }\r
1764                         /* Bytes to read are within a block and less than a block size. */\r
1765                         FF_ReadPartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );\r
1766                         if( FF_isERR( xError ) == pdFALSE )\r
1767                         {\r
1768                                 ulBytesRead += ulBytesLeft;\r
1769                         }\r
1770                 }\r
1771                 while( pdFALSE );\r
1772         } /* if( FF_isERR( xError ) == pdFALSE ) */\r
1773 \r
1774         if( FF_GETERROR( xError ) == FF_ERR_FILE_READ_ZERO )\r
1775         {\r
1776                 lResult = 0;\r
1777         }\r
1778         else if( FF_isERR( xError ) )\r
1779         {\r
1780                 lResult = xError;\r
1781         }\r
1782         else\r
1783         {\r
1784                 lResult = ( int32_t )( ulBytesRead / ulElementSize );\r
1785         }\r
1786 \r
1787         return lResult;\r
1788 }       /* FF_Read() */\r
1789 /*-----------------------------------------------------------*/\r
1790 \r
1791 /**\r
1792 *       @public\r
1793 *       @brief  Equivalent to fgetc()\r
1794 *\r
1795 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
1796 *\r
1797 *       @return The character that was read (cast as a 32-bit interger). -1 on EOF.\r
1798 *       @return FF_Error_t code. (Check with if(FF_isERR(xRetVal)) {}).\r
1799 *       @return -1 EOF (end of file).\r
1800 *\r
1801 **/\r
1802 int32_t FF_GetC( FF_FILE *pxFile )\r
1803 {\r
1804 uint32_t ulItemLBA;\r
1805 uint8_t ucReturnedChar;\r
1806 uint32_t ulRelBlockPos;\r
1807 FF_Error_t xResult;\r
1808 \r
1809         if( pxFile == NULL )\r
1810         {\r
1811                 xResult = FF_ERR_NULL_POINTER | FF_GETC;        /* Ensure this is a signed error. */\r
1812         }\r
1813         else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 )\r
1814         {\r
1815                 xResult = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_GETC;\r
1816         }\r
1817         else if( pxFile->ulFilePointer >= pxFile->ulFileSize )\r
1818         {\r
1819                 /* The end-of-file is reached.  The error READ_ZERO will not be\r
1820                 returned, it is just used to avoid further processing. */\r
1821                 xResult = FF_ERR_FILE_READ_ZERO | FF_READ;\r
1822         }\r
1823         else\r
1824         {\r
1825                 ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );\r
1826 \r
1827                 ulItemLBA = FF_SetCluster( pxFile, &xResult );\r
1828                 if( FF_isERR( xResult ) == pdFALSE )\r
1829                 {\r
1830                         FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucReturnedChar, &xResult );\r
1831                         if( FF_isERR( xResult ) == pdFALSE )\r
1832                         {\r
1833                                 xResult = ( int32_t ) ( ( uint32_t ) ucReturnedChar );\r
1834                         }\r
1835                 }\r
1836         }\r
1837 \r
1838         return ( int32_t ) xResult;\r
1839 }       /* FF_GetC() */\r
1840 /*-----------------------------------------------------------*/\r
1841 \r
1842 /**\r
1843 * @public\r
1844 * @brief        Gets a Line from a Text File, but no more than ulLimit characters. The line will be NULL terminated.\r
1845 *\r
1846 *                       The behaviour of this function is undefined when called on a binary file.\r
1847 *                       It should just read in ulLimit bytes of binary, and ZERO terminate the line.\r
1848 *\r
1849 *                       This function works for both UNIX line feeds, and Windows CRLF type files.\r
1850 *\r
1851 * @param        pxFile  The FF_FILE object pointer.\r
1852 * @param        szLine  The character buffer where the line should be stored.\r
1853 * @param        ulLimit This should be the max number of characters that szLine can hold.\r
1854 *\r
1855 * @return       The number of characters read from the line, on success.\r
1856 * @return       0 when no more lines are available, or when ulLimit is 0.\r
1857 * @return       FF_ERR_NULL_POINTER if pxFile or szLine are NULL;\r
1858 *\r
1859 **/\r
1860 int32_t FF_GetLine( FF_FILE *pxFile, char *pcLine, uint32_t ulLimit )\r
1861 {\r
1862 int32_t iChar = 0;\r
1863 BaseType_t xIndex;\r
1864 FF_Error_t xResult = FF_ERR_NONE;\r
1865 \r
1866         if( ( pxFile == NULL ) || ( pcLine == NULL ) )\r
1867         {\r
1868                 xResult = FF_ERR_NULL_POINTER | FF_GETLINE;\r
1869         }\r
1870         else\r
1871         {\r
1872                 for( xIndex = 0; xIndex < ( BaseType_t ) ( ulLimit - 1 ); ++xIndex )\r
1873                 {\r
1874                         iChar = FF_GetC( pxFile );\r
1875 \r
1876                         if( FF_isERR( iChar ) == pdFALSE )\r
1877                         {\r
1878                                 pcLine[ xIndex ] = ( char ) iChar;\r
1879 \r
1880                                 if( iChar == '\n' )\r
1881                                 {\r
1882                                         /* Read until the first linefeed.  Move xIndex forward so the\r
1883                                         null terminator does not overwrite the \n.  xIndex must be less\r
1884                                         thank ( ulLimit - 1 ), so incrementing it here cannot make it\r
1885                                         greater than ulLimit - 1, so the NULL can be inserted without\r
1886                                         overflowing the buffer. */\r
1887                                         xIndex++;\r
1888                                         break;\r
1889                                 }\r
1890                         }\r
1891                         else\r
1892                         {\r
1893                                 if( ( FF_GETERROR( iChar ) == FF_ERR_FILE_READ_ZERO ) && ( xIndex > 0 ) )\r
1894                                 {\r
1895                                         /* Although FF_GetC() returns an End Of File,\r
1896                                         the last few characters will be returned first. */\r
1897                                         iChar = xIndex;\r
1898                                 }\r
1899                                 break;\r
1900                         }\r
1901                 }\r
1902 \r
1903                 /* Make sure that the resulting string always ends with a zero: */\r
1904                 pcLine[ xIndex ] = '\0';\r
1905 \r
1906                 /*_RB_ In some paths this will be the second time FF_isERR() is called\r
1907                 on the same value. */\r
1908                 if( FF_isERR( iChar ) == pdFALSE )\r
1909                 {\r
1910                         /* Return the number of bytes read. */\r
1911                         xResult = xIndex;\r
1912                 }\r
1913                 else\r
1914                 {\r
1915                         /* Return iChar as an error code (see FF_GetC()). */\r
1916                         xResult = iChar;\r
1917                 }\r
1918         }\r
1919 \r
1920         return xResult;\r
1921 }       /* FF_GetLine() */\r
1922 /*-----------------------------------------------------------*/\r
1923 \r
1924 static int32_t FF_WritePartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount,\r
1925         const uint8_t *pucBuffer, FF_Error_t *pxError )\r
1926 {\r
1927 FF_Error_t xError;\r
1928 uint32_t ulBytesWritten;\r
1929 \r
1930         #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
1931         {\r
1932                 BaseType_t xLastRead;\r
1933                 if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize )\r
1934                 {\r
1935                         /* After this read, ulFilePointer will point to the next block/sector. */\r
1936                         xLastRead = pdTRUE;\r
1937                 }\r
1938                 else\r
1939                 {\r
1940                         /* It is not the last read within this block/sector. */\r
1941                         xLastRead = pdFALSE;\r
1942                 }\r
1943 \r
1944                 if( ( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 ) &&\r
1945                         ( ( ulRelBlockPos != 0 ) || ( pxFile->ulFilePointer < pxFile->ulFileSize ) ) )\r
1946                 {\r
1947                         xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );\r
1948                         /* pxFile->ucState will be set later on. */\r
1949                 }\r
1950                 else\r
1951                 {\r
1952                         xError = FF_ERR_NONE;\r
1953                         /* the buffer is valid or a whole block/sector will be written, so it is\r
1954                         not necessary to read the contents first. */\r
1955                 }\r
1956                 if( FF_isERR( xError ) == pdFALSE )\r
1957                 {\r
1958                         memcpy( pxFile->pucBuffer + ulRelBlockPos, pucBuffer, ulCount );\r
1959                         if( xLastRead == pdTRUE )\r
1960                         {\r
1961                                 xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE );\r
1962                                 pxFile->ucState = FF_BUFSTATE_INVALID;\r
1963                         }\r
1964                         else\r
1965                         {\r
1966                                 pxFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID;\r
1967                         }\r
1968                 }\r
1969                 else\r
1970                 {\r
1971                         pxFile->ucState = FF_BUFSTATE_INVALID;\r
1972                 }\r
1973         }\r
1974         #else\r
1975         {\r
1976         FF_Buffer_t *pxBuffer;\r
1977                 if( ( ulRelBlockPos == 0 ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) )\r
1978                 {\r
1979                         /* An entire sector will be written. */\r
1980                         pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WR_ONLY );\r
1981                 }\r
1982                 else\r
1983                 {\r
1984                         /* A partial write will be done, make sure to read the contents before\r
1985                         changing anything. */\r
1986                         pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WRITE );\r
1987                 }\r
1988 \r
1989                 if( pxBuffer == NULL )\r
1990                 {\r
1991                         xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE );\r
1992                 }\r
1993                 else\r
1994                 {\r
1995                         /* Here we copy to the sector boundary. */\r
1996                         memcpy( ( pxBuffer->pucBuffer + ulRelBlockPos ), pucBuffer, ulCount );\r
1997 \r
1998                         xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer );\r
1999                 }\r
2000         }\r
2001         #endif\r
2002         if( FF_isERR( xError ) == pdFALSE )\r
2003         {\r
2004                 pxFile->ulFilePointer += ulCount;\r
2005                 ulBytesWritten = ulCount;\r
2006 \r
2007                 if( pxFile->ulFilePointer > pxFile->ulFileSize )\r
2008                 {\r
2009                         pxFile->ulFileSize = pxFile->ulFilePointer;\r
2010                 }\r
2011         }\r
2012         else\r
2013         {\r
2014                 ulBytesWritten = 0ul;\r
2015         }\r
2016         *pxError = xError;\r
2017 \r
2018         return ulBytesWritten;\r
2019 }       /* FF_WritePartial() */\r
2020 /*-----------------------------------------------------------*/\r
2021 \r
2022 /**\r
2023  *      @public\r
2024  *      @brief  Writes data to a File.\r
2025  *\r
2026  *      @param  pxFile                  FILE Pointer.\r
2027  *      @param  ulElementSize           Size of an Element of Data to be copied. (in bytes).\r
2028  *      @param  ulCount                 Number of Elements of Data to be copied. (ulElementSize * ulCount must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best.\r
2029  *      @param  pucBuffer                       Byte-wise pucBuffer containing the data to be written.\r
2030  *\r
2031  * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps:\r
2032  *      1. Write bytes up to a sector border:  FF_WritePartial()\r
2033  *      2. Write sectors up to cluster border: FF_BlockWrite()\r
2034  *      3. Write complete clusters:            FF_WriteClusters()\r
2035  *      4. Write remaining sectors:            FF_BlockWrite()\r
2036  *      5. Write remaining bytes:              FF_WritePartial()\r
2037  *      @return\r
2038 **/\r
2039 int32_t FF_Write( FF_FILE *pxFile, uint32_t ulElementSize, uint32_t ulCount, uint8_t *pucBuffer )\r
2040 {\r
2041 uint32_t ulBytesLeft = ulElementSize * ulCount;\r
2042 uint32_t nBytesWritten = 0;\r
2043 uint32_t nBytesToWrite;\r
2044 FF_IOManager_t *pxIOManager;\r
2045 uint32_t ulRelBlockPos;\r
2046 uint32_t ulItemLBA;\r
2047 int32_t lResult;\r
2048 uint32_t ulSectors;\r
2049 uint32_t ulRelClusterPos;\r
2050 uint32_t ulBytesPerCluster;\r
2051 FF_Error_t xError;\r
2052 \r
2053         if( pxFile == NULL )\r
2054         {\r
2055                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ );\r
2056         }\r
2057         else\r
2058         {\r
2059                 /* Check validity of the handle and the current position within the file. */\r
2060                 xError = FF_CheckValid( pxFile );\r
2061                 if( FF_isERR( xError ) == pdFALSE )\r
2062                 {\r
2063                         if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )\r
2064                         {\r
2065                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_WRITE );\r
2066                         }\r
2067                         /* Make sure a write is after the append point. */\r
2068                         else if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )\r
2069                         {\r
2070                                 if( pxFile->ulFilePointer < pxFile->ulFileSize )\r
2071                                 {\r
2072                                         xError = FF_Seek( pxFile, 0, FF_SEEK_END );\r
2073                                 }\r
2074                         }\r
2075                 }\r
2076         }\r
2077 \r
2078         if( FF_isERR( xError ) == pdFALSE )\r
2079         {\r
2080                 pxIOManager = pxFile->pxIOManager;\r
2081 \r
2082                 /* Open a do{} while( 0 ) loop to allow the use of breaks */\r
2083                 do\r
2084                 {\r
2085                         /* Extend File for at least ulBytesLeft!\r
2086                         Handle file-space allocation\r
2087                         + 1 byte because the code assumes there is always a next cluster */\r
2088                         xError = FF_ExtendFile( pxFile, pxFile->ulFilePointer + ulBytesLeft + 1 );\r
2089                         if( FF_isERR( xError ) )\r
2090                         {\r
2091                                 /* On every error, break from the while( 0 ) loop. */\r
2092                                 break;\r
2093                         }\r
2094 \r
2095                         ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 ); /* Get the position within a block. */\r
2096                         ulItemLBA = FF_SetCluster( pxFile, &xError );\r
2097                         if( FF_isERR( xError ) )\r
2098                         {\r
2099                                 break;\r
2100                         }\r
2101 \r
2102                         if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize )\r
2103                         {\r
2104                                 /* Bytes to write are within a block and and do not go passed the current block. */\r
2105                                 nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError );\r
2106                                 break;\r
2107                         }\r
2108 \r
2109                         /*---------- Write (memcpy) to a Sector Boundary. */\r
2110                         if( ulRelBlockPos != 0 )\r
2111                         {\r
2112                                 /* Not writing on a sector boundary, at this point the LBA is known. */\r
2113                                 nBytesToWrite = pxIOManager->usSectorSize - ulRelBlockPos;\r
2114                                 nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, nBytesToWrite, pucBuffer, &xError );\r
2115                                 if( FF_isERR( xError ) )\r
2116                                 {\r
2117                                         break;\r
2118                                 }\r
2119 \r
2120                                 ulBytesLeft -= nBytesWritten;\r
2121                                 pucBuffer += nBytesWritten;\r
2122                         }\r
2123 \r
2124                         /*---------- Write sectors, up to a Cluster Boundary. */\r
2125                         ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize );\r
2126                         ulRelClusterPos = FF_getClusterPosition( pxIOManager, pxFile->ulFilePointer, 1 );\r
2127 \r
2128                         if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) )\r
2129                         {\r
2130                                 /* Need to get to cluster boundary */\r
2131                                 ulItemLBA = FF_SetCluster( pxFile, &xError );\r
2132                                 if( FF_isERR( xError ) )\r
2133                                 {\r
2134                                         break;\r
2135                                 }\r
2136 \r
2137                                 ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize );\r
2138                                 xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );\r
2139                                 if( FF_isERR( xError ) )\r
2140                                 {\r
2141                                         break;\r
2142                                 }\r
2143 \r
2144                                 nBytesToWrite = ulSectors * pxIOManager->usSectorSize;\r
2145                                 ulBytesLeft -= nBytesToWrite;\r
2146                                 pucBuffer += nBytesToWrite;\r
2147                                 nBytesWritten += nBytesToWrite;\r
2148                                 pxFile->ulFilePointer += nBytesToWrite;\r
2149                                 if( pxFile->ulFilePointer > pxFile->ulFileSize )\r
2150                                 {\r
2151                                         pxFile->ulFileSize = pxFile->ulFilePointer;\r
2152                                 }\r
2153                         }\r
2154 \r
2155                         /*---------- Write entire Clusters. */\r
2156                         if( ulBytesLeft >= ulBytesPerCluster )\r
2157                         {\r
2158                         uint32_t ulClusters;\r
2159 \r
2160                                 FF_SetCluster( pxFile, &xError );\r
2161                                 if( FF_isERR( xError ) )\r
2162                                 {\r
2163                                         break;\r
2164                                 }\r
2165 \r
2166                                 ulClusters = ( ulBytesLeft / ulBytesPerCluster );\r
2167 \r
2168                                 xError = FF_WriteClusters( pxFile, ulClusters, pucBuffer );\r
2169                                 if( FF_isERR( xError ) )\r
2170                                 {\r
2171                                         break;\r
2172                                 }\r
2173 \r
2174                                 nBytesToWrite = ulBytesPerCluster * ulClusters;\r
2175                                 ulBytesLeft -= nBytesToWrite;\r
2176                                 pucBuffer += nBytesToWrite;\r
2177                                 nBytesWritten += nBytesToWrite;\r
2178                                 pxFile->ulFilePointer += nBytesToWrite;\r
2179                                 if( pxFile->ulFilePointer > pxFile->ulFileSize )\r
2180                                 {\r
2181                                         pxFile->ulFileSize = pxFile->ulFilePointer;\r
2182                                 }\r
2183                         }\r
2184 \r
2185                         /*---------- Write Remaining Blocks */\r
2186                         while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )\r
2187                         {\r
2188                                 ulSectors = ulBytesLeft / pxIOManager->usSectorSize;\r
2189                                 {\r
2190                                         /* HT: I'd leave these pPart/ulOffset for readability... */\r
2191                                         FF_Partition_t  *pPart = &( pxIOManager->xPartition );\r
2192                                         uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;\r
2193                                         uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;\r
2194                                         if( ulSectors > ulRemain )\r
2195                                         {\r
2196                                                 ulSectors = ulRemain;\r
2197                                         }\r
2198                                 }\r
2199 \r
2200                                 ulItemLBA = FF_SetCluster( pxFile, &xError );\r
2201                                 if( FF_isERR( xError ) )\r
2202                                 {\r
2203                                         break;\r
2204                                 }\r
2205 \r
2206                                 xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );\r
2207                                 if( FF_isERR( xError ) )\r
2208                                 {\r
2209                                         break;\r
2210                                 }\r
2211 \r
2212                                 nBytesToWrite = ulSectors * pxIOManager->usSectorSize;\r
2213                                 ulBytesLeft -= nBytesToWrite;\r
2214                                 pucBuffer += nBytesToWrite;\r
2215                                 nBytesWritten += nBytesToWrite;\r
2216                                 pxFile->ulFilePointer += nBytesToWrite;\r
2217                                 if( pxFile->ulFilePointer > pxFile->ulFileSize )\r
2218                                 {\r
2219                                         pxFile->ulFileSize = pxFile->ulFilePointer;\r
2220                                 }\r
2221                         }\r
2222 \r
2223                         /*---------- Write (memcpy) Remaining Bytes */\r
2224                         if( ulBytesLeft == 0 )\r
2225                         {\r
2226                                 break;\r
2227                         }\r
2228 \r
2229                         ulItemLBA = FF_SetCluster( pxFile, &xError );\r
2230                         if( FF_isERR( xError ) )\r
2231                         {\r
2232                                 break;\r
2233                         }\r
2234                         FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );\r
2235                         nBytesWritten += ulBytesLeft;\r
2236                 }\r
2237                 while( pdFALSE );\r
2238         }\r
2239 \r
2240         if( FF_isERR( xError ) )\r
2241         {\r
2242                 lResult = xError;\r
2243         }\r
2244         else\r
2245         {\r
2246                 lResult = ( int32_t )( nBytesWritten / ulElementSize );\r
2247         }\r
2248 \r
2249         return lResult;\r
2250 }       /* FF_Write() */\r
2251 /*-----------------------------------------------------------*/\r
2252 \r
2253 /**\r
2254 *       @public\r
2255 *       @brief  Writes a char to a FILE.\r
2256 *\r
2257 *       @param  pxFile          FILE Pointer.\r
2258 *       @param  ucValue Char to be placed in the file.\r
2259 *\r
2260 *       @return Returns the value written to the file, or a value less than 0.\r
2261 *\r
2262 **/\r
2263 int32_t FF_PutC( FF_FILE *pxFile, uint8_t ucValue )\r
2264 {\r
2265 uint32_t ulItemLBA;\r
2266 uint32_t ulRelBlockPos;\r
2267 FF_Error_t xResult;\r
2268 \r
2269         if( pxFile == NULL )\r
2270         {       /* Ensure we don't have a Null file pointer on a Public interface. */\r
2271                 xResult = FF_ERR_NULL_POINTER | FF_PUTC;\r
2272         }\r
2273         else if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 )\r
2274         {\r
2275                 xResult = FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_PUTC;\r
2276         }\r
2277         else\r
2278         {\r
2279                 xResult = FF_ERR_NONE;\r
2280                 do\r
2281                 {\r
2282                         /* Make sure a write is after the append point. */\r
2283                         if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 )\r
2284                         {\r
2285                                 if( pxFile->ulFilePointer < pxFile->ulFileSize )\r
2286                                 {\r
2287                                         xResult = FF_Seek( pxFile, 0, FF_SEEK_END );\r
2288                                         if( FF_isERR( xResult ) )\r
2289                                         {\r
2290                                                 break;\r
2291                                         }\r
2292                                 }\r
2293                         }\r
2294 \r
2295                         ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 );\r
2296 \r
2297                         /* Handle File Space Allocation. */\r
2298                         /* We'll write 1 byte and always have a next cluster reserved. */\r
2299                         xResult = FF_ExtendFile( pxFile, pxFile->ulFilePointer + 2 );\r
2300                         if( FF_isERR( xResult ) )\r
2301                         {\r
2302                                 break;\r
2303                         }\r
2304 \r
2305                         ulItemLBA = FF_SetCluster( pxFile, &xResult );\r
2306                         if( FF_isERR( xResult ) )\r
2307                         {\r
2308                                 break;\r
2309                         }\r
2310                         FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucValue, &xResult );\r
2311 \r
2312                         if( FF_isERR( xResult ) == pdFALSE )\r
2313                         {\r
2314                                 xResult = ( FF_Error_t ) ucValue;\r
2315                         }\r
2316 \r
2317                 } while( pdFALSE );\r
2318         }\r
2319 \r
2320         return xResult;\r
2321 }       /* FF_PutC() */\r
2322 /*-----------------------------------------------------------*/\r
2323 \r
2324 /**\r
2325 *       @public\r
2326 *       @brief  Equivalent to fseek()\r
2327 *\r
2328 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2329 *       @param  ulOffset        An integer (+/-) to seek to, from the specified origin.\r
2330 *       @param  xOrigin         Where to seek from. (FF_SEEK_SET seek from start, FF_SEEK_CUR seek from current position, or FF_SEEK_END seek from end of file).\r
2331 *\r
2332 *       @return 0 on Sucess,\r
2333 *       @return -2 if offset results in an invalid position in the file.\r
2334 *       @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not received.\r
2335 *       @return -3 if an invalid origin was provided.\r
2336 *\r
2337 **/\r
2338 FF_Error_t FF_Seek( FF_FILE *pxFile, int32_t lOffset, BaseType_t xOrigin )\r
2339 {\r
2340 FF_Error_t xError;\r
2341 uint32_t ulPosition = 0ul;\r
2342 \r
2343         xError = FF_CheckValid( pxFile );\r
2344 \r
2345         if( FF_isERR( xError ) == pdFALSE )\r
2346         {\r
2347                 xError = FF_FlushCache( pxFile->pxIOManager );\r
2348 \r
2349                 #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
2350                 {\r
2351                         if( FF_isERR( xError ) == pdFALSE )\r
2352                         {\r
2353                                 /* Here we must ensure that if the user tries to seek, and we had data in the file's\r
2354                                 write buffer that this is written to disk. */\r
2355                                 if( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 )\r
2356                                 {\r
2357                                         xError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );\r
2358                                 }\r
2359                                 pxFile->ucState = FF_BUFSTATE_INVALID;\r
2360                         }\r
2361                 }\r
2362                 #endif  /* ffconfigOPTIMISE_UNALIGNED_ACCESS */\r
2363 \r
2364                 if( FF_isERR( xError ) == pdFALSE )\r
2365                 {\r
2366                         if( xOrigin == FF_SEEK_SET )\r
2367                         {\r
2368                                 ulPosition = ( uint32_t )lOffset;\r
2369                         }\r
2370                         else if( xOrigin == FF_SEEK_CUR )\r
2371                         {\r
2372                                 if( lOffset >= ( int32_t ) 0 )\r
2373                                 {\r
2374                                         ulPosition = pxFile->ulFilePointer + ( ( uint32_t ) lOffset );\r
2375                                 }\r
2376                                 else\r
2377                                 {\r
2378                                         ulPosition = pxFile->ulFilePointer - ( ( uint32_t ) ( -lOffset ) );\r
2379                                 }\r
2380                         }\r
2381                         else if( xOrigin == FF_SEEK_END )\r
2382                         {\r
2383                                 /* 'FF_SEEK_END' only allows zero or negative values. */\r
2384                                 if( lOffset <= ( int32_t ) 0 )\r
2385                                 {\r
2386                                         ulPosition = pxFile->ulFileSize - ( ( uint32_t ) ( -lOffset ) );\r
2387                                 }\r
2388                         }\r
2389                         else\r
2390                         {\r
2391                                 xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_ORIGIN );\r
2392                                 /* To supress a compiler warning. */\r
2393                                 ulPosition = ( uint32_t ) 0u;\r
2394                         }\r
2395 \r
2396                         if( FF_isERR( xError ) == pdFALSE )\r
2397                         {\r
2398                                 if( ulPosition <= ( uint32_t ) pxFile->ulFileSize )\r
2399                                 {\r
2400                                         if( ulPosition != ( uint32_t ) pxFile->ulFilePointer )\r
2401                                         {\r
2402                                                 pxFile->ulFilePointer = ulPosition;\r
2403                                                 FF_SetCluster( pxFile, &xError );\r
2404                                         }\r
2405                                 }\r
2406                                 else\r
2407                                 {\r
2408                                         xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_POSITION );\r
2409                                 }\r
2410                         }\r
2411                 }\r
2412         }\r
2413 \r
2414         return xError;\r
2415 }       /* FF_Seek() */\r
2416 /*-----------------------------------------------------------*/\r
2417 \r
2418 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
2419         /**\r
2420         *       @public\r
2421         *       @brief  Invalidate all file handles belonging to pxIOManager\r
2422         *\r
2423         *       @param  pIoMan          FF_IOManager_t object that was created by FF_CreateIOManger().\r
2424         *\r
2425         *       @return 0 if no handles were open\r
2426         *       @return >0 the amount of handles that were invalidated\r
2427         *       @return <0 probably an invalid FF_IOManager_t pointer\r
2428         *\r
2429         **/\r
2430         int32_t FF_Invalidate( FF_IOManager_t *pxIOManager )\r
2431         {\r
2432         int32_t xResult;\r
2433         FF_FILE *pxFileChain;\r
2434 \r
2435                 if( pxIOManager == NULL )\r
2436                 {\r
2437                         xResult = FF_ERR_NULL_POINTER | FF_INVALIDATE;\r
2438                 }\r
2439                 else\r
2440                 {\r
2441                         xResult = 0;\r
2442                         FF_PendSemaphore( pxIOManager->pvSemaphore );\r
2443                         {\r
2444                                 pxIOManager->ucFlags |= FF_IOMAN_DEVICE_IS_EXTRACTED;\r
2445                                 /* Semaphore is required, or linked list might change */\r
2446                                 pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile;\r
2447                                 if( pxFileChain != NULL )\r
2448                                 {\r
2449                                         /* Count elements in FirstFile */\r
2450                                         do\r
2451                                         {\r
2452                                                 pxFileChain->ulValidFlags |= FF_VALID_FLAG_INVALID;\r
2453                                                 xResult++;\r
2454                                                 pxFileChain = pxFileChain->pxNext;\r
2455                                         }\r
2456                                         while( pxFileChain != NULL );\r
2457                                 }\r
2458                         }\r
2459 \r
2460                         FF_ReleaseSemaphore( pxIOManager->pvSemaphore );\r
2461                 }\r
2462 \r
2463                 return xResult;\r
2464         }       /* FF_Invalidate() */\r
2465 #endif /* ffconfigREMOVABLE_MEDIA */\r
2466 /*-----------------------------------------------------------*/\r
2467 \r
2468 /**\r
2469 *       @public\r
2470 *       @brief  Check validity of file handle\r
2471 *\r
2472 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2473 *\r
2474 *       @return 0 on sucess.\r
2475 *       @return FF_ERR_NULL_POINTER       if a null pointer was provided.\r
2476 *       @return FF_ERR_FILE_BAD_HANDLE    if handle is not recognized\r
2477 *       @return FF_ERR_FILE_MEDIA_REMOVED please call FF_Close\r
2478 *\r
2479 **/\r
2480 FF_Error_t FF_CheckValid( FF_FILE *pxFile )\r
2481 {\r
2482         FF_FILE         *pxFileChain;\r
2483         FF_Error_t      xError;\r
2484 \r
2485         if( ( pxFile == NULL ) || ( pxFile->pxIOManager == NULL ) )\r
2486         {\r
2487                 xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CHECKVALID );\r
2488         }\r
2489         else\r
2490         {\r
2491                 FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2492                 {\r
2493                         pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;\r
2494                         xError = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_CHECKVALID );\r
2495                         while( pxFileChain != NULL )\r
2496                         {\r
2497                                 if( pxFileChain == pxFile )\r
2498                                 {\r
2499                                 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
2500                                         if( ( pxFileChain->ulValidFlags & FF_VALID_FLAG_INVALID ) != 0 )\r
2501                                         {\r
2502                                                 /* The medium has been removed while this file handle was open. */\r
2503                                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_MEDIA_REMOVED | FF_CHECKVALID );\r
2504                                         }\r
2505                                         else\r
2506                                 #endif\r
2507                                         {\r
2508                                                 /* Found the handle, so it is a valid / existing handle. */\r
2509                                                 xError = FF_ERR_NONE;\r
2510                                         }\r
2511 \r
2512                                         break;\r
2513                                 }\r
2514 \r
2515                                 pxFileChain = pxFileChain->pxNext;\r
2516                         }\r
2517                 }\r
2518                 FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2519         }\r
2520 \r
2521         return xError;\r
2522 }       /* FF_CheckValid() */\r
2523 /*-----------------------------------------------------------*/\r
2524 \r
2525 #if( ffconfigTIME_SUPPORT != 0 )\r
2526         /**\r
2527         *       @public\r
2528         *       @brief  Set the time-stamp(s) of a file entry\r
2529         *\r
2530         *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2531         *       @param  pxTime      FF_SystemTime_t the time stamp\r
2532         *       @param  uxWhat       UBaseType_t a combination of enum ETimeMask\r
2533         *\r
2534         *       @return 0 or FF_Error_t\r
2535         *\r
2536         **/\r
2537         FF_Error_t FF_SetFileTime( FF_FILE *pxFile, FF_SystemTime_t *pxTime, UBaseType_t uxWhat )\r
2538         {\r
2539         FF_DirEnt_t     xOriginalEntry;\r
2540         FF_Error_t      xError;\r
2541 \r
2542                 xError = FF_CheckValid( pxFile );\r
2543                 if( FF_isERR( xError ) == pdFALSE )\r
2544                 {\r
2545                         if( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED )\r
2546                         {       /*if (pxFile->FileDeleted) */\r
2547                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETFILETIME );\r
2548                         }\r
2549                         else if( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) == 0 )\r
2550                         {\r
2551                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETFILETIME );\r
2552                         }\r
2553                         else\r
2554                         {\r
2555                                 /* Update the Dirent! */\r
2556                                 xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );\r
2557                                 if( FF_isERR( xError ) == pdFALSE )\r
2558                                 {\r
2559                                         if( uxWhat & ETimeCreate )\r
2560                                         {\r
2561                                                 xOriginalEntry.xCreateTime = *pxTime;           /*/< Date and Time Created. */\r
2562                                         }\r
2563 \r
2564                                         if( uxWhat & ETimeMod )\r
2565                                         {\r
2566                                                 xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */\r
2567                                         }\r
2568 \r
2569                                         if( uxWhat & ETimeAccess )\r
2570                                         {\r
2571                                                 xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */\r
2572                                         }\r
2573 \r
2574                                         xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );\r
2575                                 }\r
2576 \r
2577                                 if( FF_isERR( xError ) == pdFALSE )\r
2578                                 {\r
2579                                         xError = FF_FlushCache( pxFile->pxIOManager );          /* Ensure all modfied blocks are flushed to disk! */\r
2580                                 }\r
2581                         }\r
2582                 }\r
2583 \r
2584                 return xError;\r
2585         }       /* FF_SetFileTime() */\r
2586 #endif /* ffconfigTIME_SUPPORT */\r
2587 /*-----------------------------------------------------------*/\r
2588 \r
2589 #if( ffconfigTIME_SUPPORT != 0 )\r
2590         /**\r
2591         *       @public\r
2592         *       @brief  Set the time-stamp(s) of a file entry (by name)\r
2593         *\r
2594         *       @param  pxIOManager             FF_IOManager_t device handle\r
2595         *       @param  pcPath          int8_t/FF_T_WCHAR name of the file\r
2596         *       @param  pxTime       FF_SystemTime_t the time stamp\r
2597         *       @param  uxWhat       UBaseType_t a combination of enum ETimeMask\r
2598         *\r
2599         *       @return 0 or FF_Error_t\r
2600         *\r
2601         **/\r
2602         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2603         FF_Error_t FF_SetTime ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath, FF_SystemTime_t *pxTime, UBaseType_t uxWhat )\r
2604         #else\r
2605         FF_Error_t FF_SetTime ( FF_IOManager_t * pxIOManager, const char *pcPath, FF_SystemTime_t *pxTime, UBaseType_t uxWhat )\r
2606         #endif  /* ffconfigUNICODE_UTF16_SUPPORT */\r
2607         {\r
2608         FF_DirEnt_t xOriginalEntry;\r
2609         FF_Error_t xError;\r
2610         uint32_t ulFileCluster;\r
2611         BaseType_t xIndex;\r
2612         FF_FindParams_t xFindParams;\r
2613         #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2614                 FF_T_WCHAR pcFileName[ffconfigMAX_FILENAME];\r
2615         #else\r
2616                 char pcFileName[ffconfigMAX_FILENAME];\r
2617         #endif  /* ffconfigUNICODE_UTF16_SUPPORT */\r
2618 \r
2619                 xIndex = ( BaseType_t ) STRLEN( pcPath );\r
2620 \r
2621                 memset( &xFindParams, '\0', sizeof( xFindParams ) );\r
2622 \r
2623                 while( xIndex != 0 )\r
2624                 {\r
2625                         if( pcPath[ xIndex ] == '\\' || pcPath[ xIndex ] == '/' )\r
2626                         {\r
2627                                 break;\r
2628                         }\r
2629 \r
2630                         xIndex--;\r
2631                 }\r
2632 \r
2633                 STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );\r
2634 \r
2635                 if( xIndex == 0 )\r
2636                 {\r
2637                         xIndex = 1;\r
2638                 }\r
2639 \r
2640                 xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );\r
2641                 if( FF_isERR( xError ) == pdFALSE )\r
2642                 {\r
2643                         if( xFindParams.ulDirCluster == 0 )\r
2644                         {\r
2645                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );\r
2646                         }\r
2647                         else\r
2648                         {\r
2649                                 ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );\r
2650                                 if( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) )\r
2651                                 {\r
2652                                         if( ulFileCluster == 0ul )\r
2653                                         {\r
2654                                                 /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */\r
2655                                                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );\r
2656                                         }\r
2657                                 }\r
2658                         }\r
2659                 }\r
2660 \r
2661                 if( FF_isERR( xError ) == pdFALSE )\r
2662                 {\r
2663                         /* Update the Dirent! */\r
2664                         if( uxWhat & ETimeCreate )\r
2665                         {\r
2666                                 xOriginalEntry.xCreateTime = *pxTime;                   /*/< Date and Time Created. */\r
2667                         }\r
2668 \r
2669                         if( uxWhat & ETimeMod )\r
2670                         {\r
2671                                 xOriginalEntry.xModifiedTime = *pxTime;         /*/< Date and Time Modified. */\r
2672                         }\r
2673 \r
2674                         if( uxWhat & ETimeAccess )\r
2675                         {\r
2676                                 xOriginalEntry.xAccessedTime = *pxTime;         /*/< Date of Last Access. */\r
2677                         }\r
2678 \r
2679                         xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );\r
2680 \r
2681                         if( FF_isERR( xError ) == pdFALSE )\r
2682                         {\r
2683                                 xError = FF_FlushCache( pxIOManager );                  /* Ensure all modified blocks are flushed to disk! */\r
2684                         }\r
2685                 }\r
2686 \r
2687                 return xError;\r
2688         }       /* FF_SetTime() */\r
2689 #endif /* ffconfigTIME_SUPPORT */\r
2690 /*-----------------------------------------------------------*/\r
2691 \r
2692 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2693 FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath, UBaseType_t aPerm )\r
2694 #else\r
2695 FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager, const char *pcPath, UBaseType_t aPerm )\r
2696 #endif\r
2697 {\r
2698 FF_DirEnt_t xOriginalEntry;\r
2699 FF_Error_t xError;\r
2700 uint32_t ulFileCluster;\r
2701 BaseType_t xIndex;\r
2702 #if( ffconfigUNICODE_UTF16_SUPPORT != 0 )\r
2703         FF_T_WCHAR pcFileName[ffconfigMAX_FILENAME];\r
2704 #else\r
2705         char pcFileName[ffconfigMAX_FILENAME];\r
2706 #endif\r
2707 FF_FindParams_t xFindParams;\r
2708 \r
2709         xIndex = ( BaseType_t ) STRLEN( pcPath );\r
2710 \r
2711         memset( &xFindParams, '\0', sizeof( xFindParams ) );\r
2712 \r
2713         while( xIndex != 0 )\r
2714         {\r
2715                 if( pcPath[ xIndex ] == '\\' || pcPath[ xIndex ] == '/' )\r
2716                 {\r
2717                         break;\r
2718                 }\r
2719 \r
2720                 xIndex--;\r
2721         }\r
2722 \r
2723         STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME );\r
2724 \r
2725         if( xIndex == 0 )\r
2726         {\r
2727                 xIndex = 1;\r
2728         }\r
2729 \r
2730         /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */\r
2731         do\r
2732         {\r
2733                 xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError );\r
2734                 if( xError )\r
2735                 {\r
2736                         break;\r
2737                 }\r
2738 \r
2739                 if( !xFindParams.ulDirCluster )\r
2740                 {\r
2741                         xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );\r
2742                         break;\r
2743                 }\r
2744 \r
2745                 ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError );\r
2746                 if( FF_isERR( xError ) )\r
2747                 {\r
2748                         break;\r
2749                 }\r
2750 \r
2751                 if( ulFileCluster == 0ul )\r
2752                 {\r
2753                         /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */\r
2754                         xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME );\r
2755                         break;\r
2756                 }\r
2757 \r
2758                 /*      #define FF_FAT_ATTR_READONLY            0x01 */\r
2759                 /*      #define FF_FAT_ATTR_HIDDEN                      0x02 */\r
2760                 /*      #define FF_FAT_ATTR_SYSTEM                      0x04 */\r
2761                 /*      #define FF_FAT_ATTR_VOLID                       0x08 */\r
2762                 /*      #define FF_FAT_ATTR_DIR                         0x10 */\r
2763                 /*      #define FF_FAT_ATTR_ARCHIVE                     0x20 */\r
2764                 /*      #define FF_FAT_ATTR_LFN                         0x0F */\r
2765         #define FF_FAT_ATTR_USER        ( ( uint8_t ) FF_FAT_ATTR_READONLY | FF_FAT_ATTR_HIDDEN | FF_FAT_ATTR_SYSTEM | FF_FAT_ATTR_ARCHIVE )\r
2766                 /* Update the Dirent! */\r
2767                 xOriginalEntry.ucAttrib &= ~FF_FAT_ATTR_USER;\r
2768                 xOriginalEntry.ucAttrib |= ( aPerm & FF_FAT_ATTR_USER );\r
2769                 xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL );\r
2770 \r
2771                 if( FF_isERR( xError ) == pdFALSE )\r
2772                 {\r
2773                         xError = FF_FlushCache( pxIOManager );                  /* Ensure all modfied blocks are flushed to disk! */\r
2774                 }\r
2775         }\r
2776         while( pdFALSE );\r
2777 \r
2778         return xError;\r
2779 }       /* FF_SetPerm() */\r
2780 /*-----------------------------------------------------------*/\r
2781 \r
2782 /**\r
2783 *       @public\r
2784 *       @brief  Equivalent to fclose()\r
2785 *\r
2786 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2787 *\r
2788 *       @return 0 on sucess.\r
2789 *       @return -1 if a null pointer was provided.\r
2790 *\r
2791 **/\r
2792 FF_Error_t FF_Close( FF_FILE *pxFile )\r
2793 {\r
2794 FF_FILE *pxFileChain;\r
2795 FF_DirEnt_t xOriginalEntry;\r
2796 FF_Error_t xError;\r
2797 \r
2798         /* Opening a do {} while( 0 )  loop to allow the use of the break statement. */\r
2799         do\r
2800         {\r
2801                 if( pxFile == NULL )\r
2802                 {\r
2803                         xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CLOSE );\r
2804                         break;\r
2805                 }\r
2806 \r
2807                 /* It is important to check that user doesn't supply invalid\r
2808                 handle or a handle invalid because of "media removed" */\r
2809                 xError = FF_CheckValid( pxFile );\r
2810 \r
2811                 #if( ffconfigREMOVABLE_MEDIA != 0 )\r
2812                 {\r
2813                         if( FF_GETERROR( xError ) == FF_ERR_FILE_MEDIA_REMOVED )\r
2814                         {\r
2815                                 FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2816                                 {\r
2817                                         pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;\r
2818                                         if( pxFileChain == pxFile )\r
2819                                         {\r
2820                                                 pxFile->pxIOManager->FirstFile = pxFile->pxNext;\r
2821                                         }\r
2822                                         else\r
2823                                         {\r
2824                                                 while( pxFileChain )\r
2825                                                 {\r
2826                                                         if( pxFileChain->pxNext == pxFile )\r
2827                                                         {\r
2828                                                                 pxFileChain->pxNext = pxFile->pxNext;\r
2829                                                                 break;\r
2830                                                         }\r
2831 \r
2832                                                         pxFileChain = pxFileChain->pxNext;      /* Forgot this one */\r
2833                                                 }\r
2834                                         }\r
2835                                 }                                       /* Semaphore released, linked list was shortened! */\r
2836 \r
2837                                 FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2838                                 #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
2839                                 {\r
2840                                         ffconfigFREE( pxFile->pucBuffer );\r
2841                                 }\r
2842                                 #endif  /* ffconfigOPTIMISE_UNALIGNED_ACCESS */\r
2843                                 ffconfigFREE( pxFile ); /* So at least we have freed the pointer. */\r
2844                                 xError = FF_ERR_NONE;\r
2845                                 break;\r
2846                         }\r
2847                 }\r
2848                 #endif  /* ffconfigREMOVABLE_MEDIA */\r
2849 \r
2850                 if( FF_isERR( xError ) )\r
2851                 {\r
2852                         /* FF_ERR_FILE_BAD_HANDLE or FF_ERR_NULL_POINTER */\r
2853                         break;\r
2854                 }\r
2855 \r
2856                 /* So here we have a normal valid file handle. */\r
2857 \r
2858                 /* Sometimes FreeRTOS+FAT will leave a trailing cluster on the end of a cluster chain.\r
2859                 To ensure we're compliant we shall now check for this condition and truncate it. */\r
2860                 if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&\r
2861                         ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )\r
2862                 {\r
2863                 uint32_t ulClusterSize;\r
2864 \r
2865                         /* File is not deleted and it was opened for writing or updating */\r
2866                         ulClusterSize = pxFile->pxIOManager->xPartition.usBlkSize * pxFile->pxIOManager->xPartition.ulSectorsPerCluster;\r
2867 \r
2868                         if( ( ( pxFile->ulFileSize % ulClusterSize ) == 0 ) && ( pxFile->ulObjectCluster != 0ul ) )\r
2869                         {\r
2870                                 /* The file's length is a multiple of cluster size.  This means\r
2871                                 that an extra cluster has been reserved, which wasn't necessary. */\r
2872                                 xError = FF_Truncate( pxFile, pdTRUE );\r
2873                         }\r
2874 \r
2875                         /* Get the directory entry and update it to show the new file size */\r
2876                         if( FF_isERR( xError ) == pdFALSE )\r
2877                         {\r
2878                                 xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );\r
2879 \r
2880                                 /* Now update the directory entry */\r
2881                                 if( ( FF_isERR( xError ) == pdFALSE ) &&\r
2882                                         ( ( pxFile->ulFileSize != xOriginalEntry.ulFileSize ) || ( pxFile->ulFileSize == 0UL ) ) )\r
2883                                 {\r
2884                                         if( pxFile->ulFileSize == 0UL )\r
2885                                         {\r
2886                                                 xOriginalEntry.ulObjectCluster = 0;\r
2887                                         }\r
2888 \r
2889                                         xOriginalEntry.ulFileSize = pxFile->ulFileSize;\r
2890                                         xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );\r
2891                                 }\r
2892                         }\r
2893                 }\r
2894 \r
2895                 /* Handle Linked list! */\r
2896                 FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2897                 {       /* Semaphore is required, or linked list could become corrupted. */\r
2898                         pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile;\r
2899                         if( pxFileChain == pxFile )\r
2900                         {\r
2901                                 pxFile->pxIOManager->FirstFile = pxFile->pxNext;\r
2902                         }\r
2903                         else\r
2904                         {\r
2905                                 while( pxFileChain )\r
2906                                 {\r
2907                                         if( pxFileChain->pxNext == pxFile )\r
2908                                         {\r
2909                                                 /* Found it, remove it from the list. */\r
2910                                                 pxFileChain->pxNext = pxFile->pxNext;\r
2911                                                 break;\r
2912                                         }\r
2913                                         pxFileChain = pxFileChain->pxNext;\r
2914                                 }\r
2915                         }\r
2916                 }       /* Semaphore released, linked list was shortened! */\r
2917                 FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore );\r
2918 \r
2919                 #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )\r
2920                 {\r
2921                         if( pxFile->pucBuffer != NULL )\r
2922                         {\r
2923                                 /* Ensure any unaligned points are pushed to the disk! */\r
2924                                 if( pxFile->ucState & FF_BUFSTATE_WRITTEN )\r
2925                                 {\r
2926                                 FF_Error_t xTempError;\r
2927 \r
2928                                         xTempError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE );\r
2929                                         if( FF_isERR( xError ) == pdFALSE )\r
2930                                         {\r
2931                                                 xError = xTempError;\r
2932                                         }\r
2933                                 }\r
2934 \r
2935                                 ffconfigFREE( pxFile->pucBuffer );\r
2936                         }\r
2937                 }\r
2938                 #endif\r
2939                 if( FF_isERR( xError ) == pdFALSE )\r
2940                 {\r
2941                         xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modified blocks are flushed to disk! */\r
2942                 }\r
2943                 ffconfigFREE( pxFile );\r
2944         }\r
2945         while( pdFALSE );\r
2946 \r
2947         return xError;\r
2948 }       /* FF_Close() */\r
2949 /*-----------------------------------------------------------*/\r
2950 \r
2951 /**\r
2952 *       @public\r
2953 *       @brief  Make Filesize equal to the FilePointer and truncates the file to this position\r
2954 *\r
2955 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2956 *\r
2957 *       @return 0 on sucess.\r
2958 *       @return negative if some error occurred\r
2959 *\r
2960 **/\r
2961 FF_Error_t FF_SetEof( FF_FILE *pxFile )\r
2962 {\r
2963         FF_Error_t xError;\r
2964 \r
2965         /* Check if the file was not deleted and if it was opened with write permissions: */\r
2966         if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) &&\r
2967                 ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) )\r
2968         {\r
2969                 pxFile->ulFileSize = pxFile->ulFilePointer;\r
2970                 if( pxFile->ulObjectCluster != 0ul )\r
2971                 {\r
2972                         xError = FF_Truncate( pxFile, pdFALSE );\r
2973                 }\r
2974                 else\r
2975                 {\r
2976                         xError = FF_ERR_NONE;\r
2977                 }\r
2978         }\r
2979         else\r
2980         {\r
2981                 xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETEOF );\r
2982         }\r
2983 \r
2984         return xError;\r
2985 }       /* FF_SetEof() */\r
2986 /*-----------------------------------------------------------*/\r
2987 \r
2988 /**\r
2989 *       @public\r
2990 *       @brief  Truncate a file to 'pxFile->ulFileSize'\r
2991 *\r
2992 *       @param  pxFile          FF_FILE object that was created by FF_Open().\r
2993 *\r
2994 *       @return 0 on sucess.\r
2995 *       @return negative if some error occurred\r
2996 *\r
2997 **/\r
2998 static FF_Error_t FF_Truncate( FF_FILE *pxFile, BaseType_t bClosing )\r
2999 {\r
3000 FF_Error_t xError;\r
3001 FF_IOManager_t *pxIOManager = pxFile->pxIOManager;\r
3002 \r
3003 uint32_t ulClusterSize;\r
3004 uint32_t ulClusterCount;\r
3005 uint32_t ulClustersNeeded;\r
3006 \r
3007         /* The number of bytes contained in a cluster. */\r
3008         ulClusterSize = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster;\r
3009 \r
3010         /* See how many clusters have been allocated. */\r
3011         ulClusterCount = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, NULL, &xError );\r
3012 \r
3013         /* Calculate the actual number of clusters needed, rounding up */\r
3014         ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize - 1 ) / ulClusterSize;\r
3015         if( bClosing != pdFALSE )\r
3016         {\r
3017                 /* The handle will be closed after truncating.  This function is called\r
3018                 because Filesize is an exact multiple of ulClusterSize. */\r
3019                 ulClustersNeeded = pxFile->ulFileSize / ulClusterSize;\r
3020         }\r
3021         else\r
3022         {\r
3023                 /* This function is called to make the file size equal to the current\r
3024                 position within the file. Always keep an extra cluster to write to. */\r
3025                 ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize ) / ulClusterSize;\r
3026         }\r
3027 \r
3028         /* First change the FAT chain. */\r
3029         if( ( FF_isERR( xError ) == pdFALSE ) && ( ulClusterCount > ulClustersNeeded ) )\r
3030         {\r
3031                 if( ulClustersNeeded == 0ul )\r
3032                 {\r
3033                         FF_LockFAT( pxIOManager );\r
3034                         {\r
3035                                 /* In FF_Truncate() */\r
3036                                 xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 );\r
3037                         }\r
3038                         FF_UnlockFAT( pxIOManager );\r
3039 \r
3040                         if( FF_isERR( xError ) == pdFALSE )\r
3041                         {\r
3042                         FF_DirEnt_t xOriginalEntry;\r
3043 \r
3044                                 /* The directory denotes the address of the first data cluster of every file.\r
3045                                 Now change it to 'ulAddrCurrentCluster': */\r
3046                                 xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry );\r
3047 \r
3048                                 if( FF_isERR( xError ) == pdFALSE )\r
3049                                 {\r
3050                                         xOriginalEntry.ulObjectCluster = 0ul;\r
3051                                         xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL );\r
3052 \r
3053                                         if( FF_isERR( xError ) == pdFALSE )\r
3054                                         {\r
3055                                                 pxFile->ulObjectCluster = 0ul;\r
3056                                                 pxFile->ulChainLength = 0ul;\r
3057                                                 pxFile->ulCurrentCluster = 0ul;\r
3058                                                 pxFile->ulEndOfChain = 0ul;\r
3059                                         }\r
3060                                 }\r
3061                         }\r
3062                 }\r
3063                 else\r
3064                 {\r
3065                         FF_LockFAT( pxIOManager );\r
3066                         {\r
3067                                 uint32_t ulTruncateCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulClustersNeeded - 1, &xError );\r
3068 \r
3069                                 if( FF_isERR( xError ) == pdFALSE )\r
3070                                 {\r
3071                                         xError = FF_UnlinkClusterChain( pxIOManager, ulTruncateCluster, 1 );\r
3072                                 }\r
3073                         }\r
3074                         FF_UnlockFAT( pxIOManager );\r
3075                 }\r
3076         }\r
3077 \r
3078         return xError;\r
3079 }       /* FF_Truncate() */\r
3080 /*-----------------------------------------------------------*/\r