A file system which can mount, read, and enumerate a file system image which has been appended to the compiled .bin code file before being uploaded to the mbed device.
FlashFileSystem.cpp
00001 /* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/) 00002 00003 Licensed under the Apache License, Version 2.0 (the "License"); 00004 you may not use this file except in compliance with the License. 00005 You may obtain a copy of the License at 00006 00007 http://www.apache.org/licenses/LICENSE-2.0 00008 00009 Unless required by applicable law or agreed to in writing, software 00010 distributed under the License is distributed on an "AS IS" BASIS, 00011 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 See the License for the specific language governing permissions and 00013 limitations under the License. 00014 */ 00015 /* Specifies the classes used to implement the FlashFileSystem which is a 00016 read-only file system that exists in the internal FLASH of the mbed 00017 device. 00018 */ 00019 #include <mbed.h> 00020 #include <assert.h> 00021 #include "FlashFileSystem.h" 00022 #include "ffsformat.h" 00023 00024 00025 // Set FFS_TRACE to 1 to enable tracing within the FlashFileSystem class. 00026 #define FFS_TRACE 0 00027 #if FFS_TRACE 00028 #define TRACE printf 00029 #else 00030 static void __trace(...) 00031 { 00032 return; 00033 } 00034 #define TRACE __trace 00035 #endif // FFS_TRACE 00036 00037 00038 00039 /* Constructor for FlashFileSystemFileHandle which initializes to the specified 00040 file entry in the image. 00041 00042 Parameters: 00043 pFileStart is the beginning offset of this file in FLASH memory. 00044 pFileEnd is the ending offset (1 bytes past last valid byte) of this file 00045 FLASH memory. 00046 */ 00047 FlashFileSystemFileHandle::FlashFileSystemFileHandle(const char* pFileStart, 00048 const char* pFileEnd) 00049 { 00050 m_pFileStart = pFileStart; 00051 m_pFileEnd = pFileEnd; 00052 m_pCurr = pFileStart; 00053 } 00054 00055 00056 // Constructs a blank FlashFileSystemFileHandle object. 00057 FlashFileSystemFileHandle::FlashFileSystemFileHandle() 00058 { 00059 FlashFileSystemFileHandle(NULL, NULL); 00060 } 00061 00062 00063 /* Write the contents of a buffer to the file 00064 00065 Parameters: 00066 pBuffer is the buffer from which to write. 00067 Length is the number of characters to write. 00068 00069 Returns 00070 The number of characters written (possibly 0) on success, -1 on error. 00071 */ 00072 ssize_t FlashFileSystemFileHandle::write(const void* pBuffer, size_t Length) 00073 { 00074 // This file system doesn't support writing. 00075 return -1; 00076 } 00077 00078 00079 /* Close the file 00080 00081 Returns 00082 Zero on success, -1 on error. 00083 */ 00084 int FlashFileSystemFileHandle::close() 00085 { 00086 m_pFileStart = NULL; 00087 m_pFileEnd = NULL; 00088 m_pCurr = NULL; 00089 00090 return 0; 00091 } 00092 00093 /* Reads the contents of the file into a buffer. 00094 00095 Parameters 00096 pBuffer is the buffer into which the read should occur. 00097 Length is the number of characters to read into pBuffer. 00098 00099 Returns 00100 The number of characters read (zero at end of file) on success, -1 on error. 00101 */ 00102 ssize_t FlashFileSystemFileHandle::read(void* pBuffer, size_t Length) 00103 { 00104 unsigned int BytesLeft; 00105 00106 // Don't read more bytes than what are left in the file. 00107 BytesLeft = m_pFileEnd - m_pCurr; 00108 if (Length > BytesLeft) 00109 { 00110 Length = BytesLeft; 00111 } 00112 00113 // Copy the bytes from FLASH into the caller provided buffer. 00114 memcpy(pBuffer, m_pCurr, Length); 00115 00116 // Update the file pointer. 00117 m_pCurr += Length; 00118 00119 return Length; 00120 } 00121 00122 00123 /* Check if the handle is for a interactive terminal device . 00124 00125 Parameters 00126 None 00127 Returns 00128 1 if it is a terminal, 0 otherwise 00129 */ 00130 int FlashFileSystemFileHandle::isatty() 00131 { 00132 return 0; 00133 } 00134 00135 00136 /* Move the file position to a given offset from a given location. 00137 00138 Parameters 00139 offset is the offset from whence to move to. 00140 whence - SEEK_SET for the start of the file, 00141 SEEK_CUR for the current file position, or 00142 SEEK_END for the end of the file. 00143 00144 Returns 00145 New file position on success, -1 on failure or unsupported 00146 */ 00147 off_t FlashFileSystemFileHandle::lseek(off_t offset, int whence) 00148 { 00149 switch(whence) 00150 { 00151 case SEEK_SET: 00152 m_pCurr = m_pFileStart + offset; 00153 break; 00154 case SEEK_CUR: 00155 m_pCurr += offset; 00156 break; 00157 case SEEK_END: 00158 m_pCurr = (m_pFileEnd - 1) + offset; 00159 break; 00160 default: 00161 TRACE("FlashFileSytem: Received unknown origin code (%d) for seek.\r\n", whence); 00162 return -1; 00163 } 00164 00165 return (m_pCurr - m_pFileStart); 00166 } 00167 00168 00169 /* Flush any buffers associated with the FileHandle, ensuring it 00170 is up to date on disk. Since the Flash file system is read-only, there 00171 is nothing to do here. 00172 00173 Returns 00174 0 on success or un-needed, -1 on error 00175 */ 00176 int FlashFileSystemFileHandle::fsync() 00177 { 00178 return 0; 00179 } 00180 00181 00182 /* Returns the length of the file. 00183 00184 Parameters: 00185 None 00186 Returns: 00187 Length of file. 00188 */ 00189 off_t FlashFileSystemFileHandle::flen() 00190 { 00191 return (m_pFileEnd - m_pFileStart); 00192 } 00193 00194 00195 00196 /* Construct and initialize a directory handle enumeration object. 00197 00198 Parameters: 00199 pFLASHBase points to the beginning of the file system in FLASH memory. 00200 pFirstFileEntry is a pointer to the first entry found in this directory. 00201 DirectoryNameLength is the length of the directory name for which this 00202 handle is being used to enumerate. 00203 00204 Returns: 00205 Nothing. 00206 */ 00207 FlashFileSystemDirHandle::FlashFileSystemDirHandle(const char* pFLASHBase, 00208 const _SFileSystemEntry* pFirstFileEntry, 00209 unsigned int FileEntriesLeft, 00210 unsigned int DirectoryNameLength) 00211 { 00212 m_pFLASHBase = pFLASHBase; 00213 m_pFirstFileEntry = pFirstFileEntry; 00214 m_pCurrentFileEntry = pFirstFileEntry; 00215 m_FileEntriesLeft = FileEntriesLeft; 00216 m_DirectoryNameLength = DirectoryNameLength; 00217 m_DirectoryEntry.d_name[0] = '\0'; 00218 } 00219 00220 00221 // Used to construct a closed directory handle. 00222 FlashFileSystemDirHandle::FlashFileSystemDirHandle() 00223 { 00224 FlashFileSystemDirHandle(NULL, NULL, 0, 0); 00225 } 00226 00227 00228 /* Closes the directory enumeration object. 00229 00230 Parameters: 00231 None. 00232 00233 Returns: 00234 0 on success, or -1 on error. 00235 */ 00236 int FlashFileSystemDirHandle::closedir() 00237 { 00238 m_pFLASHBase = NULL; 00239 m_pFirstFileEntry = NULL; 00240 m_pCurrentFileEntry = NULL; 00241 m_FileEntriesLeft = 0; 00242 m_DirectoryNameLength = 0; 00243 m_DirectoryEntry.d_name[0] = '\0'; 00244 00245 return 0; 00246 } 00247 00248 00249 /* Return the directory entry at the current position, and 00250 advances the position to the next entry. 00251 00252 Parameters: 00253 None. 00254 00255 Returns: 00256 A pointer to a dirent structure representing the 00257 directory entry at the current position, or NULL on reaching 00258 end of directory or error. 00259 */ 00260 struct dirent* FlashFileSystemDirHandle::readdir() 00261 { 00262 const char* pPrevEntryName; 00263 const char* pCurrentEntryName; 00264 char* pSlash; 00265 size_t PrefixLength; 00266 unsigned int FileEntriesUsed; 00267 unsigned int FileEntriesLeft; 00268 00269 // Just return now if we have already finished enumerating the entries in 00270 // the directory. 00271 if (!m_pCurrentFileEntry) 00272 { 00273 m_DirectoryEntry.d_name[0] = '\0'; 00274 return NULL; 00275 } 00276 00277 // Calculate the number of valid entries are left in the file entry array. 00278 FileEntriesUsed = m_pCurrentFileEntry - m_pFirstFileEntry; 00279 FileEntriesLeft = m_FileEntriesLeft - FileEntriesUsed; 00280 00281 // Fill in the directory entry structure for the current entry. 00282 pPrevEntryName = m_pFLASHBase + 00283 m_pCurrentFileEntry->FilenameOffset; 00284 strncpy(m_DirectoryEntry.d_name, 00285 pPrevEntryName + m_DirectoryNameLength, 00286 sizeof(m_DirectoryEntry.d_name)); 00287 m_DirectoryEntry.d_name[sizeof(m_DirectoryEntry.d_name) - 1] = '\0'; 00288 00289 // If the entry to be returned contains a slash then this is a directory 00290 // entry. 00291 pSlash = strchr(m_DirectoryEntry.d_name, '/'); 00292 if (pSlash) 00293 { 00294 // I am truncating everything after the slash but leaving the 00295 // slash so that I can tell it is a directory and not a file. 00296 pSlash[1] = '\0'; 00297 } 00298 00299 // Skip entries that have the same prefix as the current entry. This 00300 // will skip the files in the same sub-tree. 00301 PrefixLength = strlen(m_DirectoryEntry.d_name) + m_DirectoryNameLength; 00302 do 00303 { 00304 m_pCurrentFileEntry++; 00305 FileEntriesLeft--; 00306 pCurrentEntryName = m_pFLASHBase + m_pCurrentFileEntry->FilenameOffset; 00307 } while (FileEntriesLeft && 00308 0 == strncmp(pPrevEntryName, pCurrentEntryName, PrefixLength)); 00309 00310 // If we have walked past the end of all file entries in the file system or 00311 // the prefix no longer matches this directory, then there are no more files 00312 // for this directory enumeration. 00313 if (0 == FileEntriesLeft || 00314 0 != strncmp(pPrevEntryName, pCurrentEntryName, m_DirectoryNameLength)) 00315 { 00316 m_pCurrentFileEntry = NULL; 00317 } 00318 00319 // Return a pointer to the directory entry structure that was previously 00320 // setup. 00321 return &m_DirectoryEntry; 00322 } 00323 00324 00325 //Resets the position to the beginning of the directory. 00326 void FlashFileSystemDirHandle::rewinddir() 00327 { 00328 m_pCurrentFileEntry = m_pFirstFileEntry; 00329 } 00330 00331 00332 /* Returns the current position of the DirHandle. 00333 00334 Parameters: 00335 None. 00336 00337 Returns: 00338 The current position, or -1 on error. 00339 */ 00340 off_t FlashFileSystemDirHandle::telldir() 00341 { 00342 return (off_t)m_pCurrentFileEntry; 00343 } 00344 00345 00346 /* Sets the position of the DirHandle. 00347 00348 Parameters: 00349 Location is the location to seek to. Must be a value returned 00350 by telldir. 00351 00352 Returns; 00353 Nothing. 00354 */ 00355 void FlashFileSystemDirHandle::seekdir(off_t Location) 00356 { 00357 SFileSystemEntry* pLocation = (SFileSystemEntry*)Location; 00358 00359 assert ( NULL != pLocation && 00360 pLocation > m_pFirstFileEntry && 00361 (pLocation - m_pFirstFileEntry) < m_FileEntriesLeft ); 00362 00363 m_pCurrentFileEntry = pLocation; 00364 } 00365 00366 00367 00368 // Structure used to hold context about current filename search. 00369 struct SSearchContext 00370 { 00371 // Name of file to be found in file system image. 00372 const char* pKey; 00373 // Base pointer for the file system image. 00374 const char* pFLASHBase; 00375 }; 00376 00377 00378 /* Internal routine used as callback for bsearch() when searching for a 00379 requested filename in the FLASH file system image. 00380 00381 pvKey is a pointer to the SSearchContext object for this search. 00382 pvEntry is a pointer to the current file system entry being checked by 00383 bsearch(). 00384 00385 Returns <0 if filename to find is lower in sort order than current entry. 00386 0 if filename to find is the same as the current entry. 00387 >0 if filename to find is higher in sort order than current entry. 00388 */ 00389 static int _CompareKeyToFileEntry(const void* pvKey, const void* pvEntry) 00390 { 00391 const SSearchContext* pContext = (const SSearchContext*)pvKey; 00392 const char* pKey = pContext->pKey; 00393 const SFileSystemEntry* pEntry = (const SFileSystemEntry*)pvEntry; 00394 const char* pEntryName = pContext->pFLASHBase + pEntry->FilenameOffset; 00395 00396 return strcmp(pKey, pEntryName); 00397 } 00398 00399 00400 /* Constructor for FlashFileSystem 00401 00402 Parameters: 00403 pName is the root name to be used for this file system in fopen() 00404 pathnames. 00405 pFlashDrive (optional) is a pointer to the read-only file system (const char array). 00406 When pFlashDrive is not specified, it is up to the user to append the 00407 read-only file system file to the compiled binary. 00408 FlashSize (optional) is the size of the FLASH (KB) on the device to 00409 search through for the file system signature (default = 512). 00410 */ 00411 FlashFileSystem::FlashFileSystem(const char* pName, const uint8_t *pFlashDrive, const uint32_t FlashSize) : FileSystemLike(pName) 00412 { 00413 static const char FileSystemSignature[] = FILE_SYSTEM_SIGNATURE; 00414 SFileSystemHeader* pHeader = NULL; 00415 char* pCurr = (char*)(FlashSize * 1024) - sizeof(pHeader->FileSystemSignature); 00416 00417 // Initialize the members 00418 m_pFLASHBase = NULL; 00419 m_FileCount = 0; 00420 m_pFileEntries = NULL; 00421 00422 // Scan backwards through 512k FLASH looking for the file system signature 00423 // NOTE: The file system image should be located after this code itself 00424 // so stop the search. 00425 if(pFlashDrive == NULL) 00426 { 00427 while (pCurr > FileSystemSignature) 00428 { 00429 if (0 == memcmp(pCurr, FileSystemSignature, sizeof(pHeader->FileSystemSignature))) 00430 { 00431 break; 00432 } 00433 pCurr--; 00434 } 00435 if (pCurr <= FileSystemSignature) 00436 { 00437 TRACE("FlashFileSystem: Failed to find file system image in ROM.\n"); 00438 return; 00439 } 00440 } 00441 else 00442 { 00443 pCurr = (char *)pFlashDrive; 00444 } 00445 if (((unsigned int)pCurr & 0x3) != 0) 00446 { 00447 TRACE("FlashFileSystem: File system image at address %08X isn't 4-byte aligned.\n", pCurr); 00448 return; 00449 } 00450 00451 // Record the location of the file system image in the member fields. 00452 m_pFLASHBase = pCurr; 00453 pHeader = (SFileSystemHeader*)m_pFLASHBase; 00454 m_FileCount = pHeader->FileCount; 00455 m_pFileEntries = (SFileSystemEntry*)(m_pFLASHBase + sizeof(*pHeader)); 00456 } 00457 00458 00459 /* Opens specified file in FLASH file system when an appropriate call to 00460 fopen() is made. 00461 00462 pFilename is the name of the file to be opened within the file system. 00463 Flags specify flags to determine open mode of file. This file system only 00464 support O_RDONLY. 00465 00466 Returns NULL if an error was encountered or a pointer to a FileHandle object 00467 representing the requrested file otherwise. 00468 */ 00469 FileHandle* FlashFileSystem::open(const char* pFilename, int Flags) 00470 { 00471 const SFileSystemEntry* pEntry = NULL; 00472 FlashFileSystemFileHandle* pFileHandle = NULL; 00473 SSearchContext SearchContext; 00474 00475 TRACE("FlashFileSystem: Attempt to open file /FLASH/%s with flags:%x\r\n", pFilename, Flags); 00476 00477 // Can't find the file if file system hasn't been mounted. 00478 if (!IsMounted()) 00479 { 00480 return NULL; 00481 } 00482 00483 // Can only open files in FLASH for read. 00484 if (O_RDONLY != Flags) 00485 { 00486 TRACE("FlashFileSystem: Can only open files for reading.\r\n"); 00487 } 00488 00489 // Attempt to find the specified file in the file system image. 00490 SearchContext.pKey = pFilename; 00491 SearchContext.pFLASHBase = m_pFLASHBase; 00492 pEntry = (const SFileSystemEntry*) bsearch(&SearchContext, 00493 m_pFileEntries, 00494 m_FileCount, 00495 sizeof(*m_pFileEntries), 00496 _CompareKeyToFileEntry); 00497 if(!pEntry) 00498 { 00499 // Create failure response. 00500 TRACE("FlashFileSystem: Failed to find '%s' in file system image.\n", pFilename); 00501 return NULL; 00502 } 00503 00504 // Attempt to find a free file handle. 00505 pFileHandle = FindFreeFileHandle(); 00506 if (!pFileHandle) 00507 { 00508 TRACE("FlashFileSystem: File handle table is full.\n"); 00509 return NULL; 00510 } 00511 00512 // Initialize the file handle and return it to caller. 00513 pFileHandle->SetEntry(m_pFLASHBase + pEntry->FileBinaryOffset, 00514 m_pFLASHBase + pEntry->FileBinaryOffset + pEntry->FileBinarySize); 00515 return pFileHandle; 00516 } 00517 00518 DirHandle* FlashFileSystem::opendir(const char *pDirectoryName) 00519 { 00520 const SFileSystemEntry* pEntry = m_pFileEntries; 00521 unsigned int DirectoryNameLength; 00522 unsigned int i; 00523 00524 assert ( pDirectoryName); 00525 00526 // Removing leading slash since the file system image doesn't contain 00527 // leading slashes. 00528 if ('/' == pDirectoryName[0]) 00529 { 00530 pDirectoryName++; 00531 } 00532 00533 // Make sure that the directory name length would include the trailing 00534 // slash. 00535 DirectoryNameLength = strlen(pDirectoryName); 00536 if (0 != DirectoryNameLength && '/' != pDirectoryName[DirectoryNameLength-1]) 00537 { 00538 // Add the implicit slash to this count. 00539 DirectoryNameLength++; 00540 } 00541 00542 // Search through the file entries from the beginning to find the first 00543 // entry which has pDirectoryName/ as the prefix. 00544 for (i = 0 ; i < m_FileCount ; i++) 00545 { 00546 const char* pEntryFilename = pEntry->FilenameOffset + m_pFLASHBase; 00547 00548 if (0 == DirectoryNameLength || 00549 (pEntryFilename == strstr(pEntryFilename, pDirectoryName) && 00550 '/' == pEntryFilename[DirectoryNameLength-1]) ) 00551 { 00552 // Found the beginning of the list of files/folders for the 00553 // requested directory so return it to the caller. 00554 FlashFileSystemDirHandle* pDirHandle = FindFreeDirHandle(); 00555 if (!pDirHandle) 00556 { 00557 TRACE("FlashFileSystem: Dir handle table is full.\n"); 00558 return NULL; 00559 } 00560 00561 pDirHandle->SetEntry(m_pFLASHBase, 00562 pEntry, 00563 m_FileCount - (pEntry - m_pFileEntries), 00564 DirectoryNameLength); 00565 00566 return pDirHandle; 00567 } 00568 00569 // Advance to the next file entry 00570 pEntry++; 00571 } 00572 00573 // Get here when the requested directory wasn't found. 00574 TRACE("FlashFileSystem: Failed to find '%s' directory in file system image.\n", 00575 pDirectoryName); 00576 return NULL; 00577 } 00578 00579 00580 /* Protected method which attempts to find a free file handle in the object's 00581 file handle table. 00582 00583 Parameters: 00584 None 00585 00586 Returns: 00587 Pointer to first free file handle entry or NULL if the table is full. 00588 */ 00589 FlashFileSystemFileHandle* FlashFileSystem::FindFreeFileHandle() 00590 { 00591 size_t i; 00592 00593 // Iterate through the file handle array, looking for a close file handle. 00594 for (i = 0 ; i < sizeof(m_FileHandles)/sizeof(m_FileHandles[0]) ; i++) 00595 { 00596 if (m_FileHandles[i].IsClosed()) 00597 { 00598 return &(m_FileHandles[i]); 00599 } 00600 } 00601 00602 // If we get here, then no free entries were found. 00603 return NULL; 00604 } 00605 00606 00607 /* Protected method which attempts to find a free dir handle in the object's 00608 directory handle table. 00609 00610 Parameters: 00611 None 00612 00613 Returns: 00614 Pointer to first free directory handle entry or NULL if the table is full. 00615 */ 00616 FlashFileSystemDirHandle* FlashFileSystem::FindFreeDirHandle() 00617 { 00618 size_t i; 00619 00620 // Iterate through the direcotry handle array, looking for a closed 00621 // directory handle. 00622 for (i = 0 ; i < sizeof(m_DirHandles)/sizeof(m_DirHandles[0]) ; i++) 00623 { 00624 if (m_DirHandles[i].IsClosed()) 00625 { 00626 return &(m_DirHandles[i]); 00627 } 00628 } 00629 00630 // If we get here, then no free entries were found. 00631 return NULL; 00632 }
Generated on Tue Jul 12 2022 18:57:29 by 1.7.2