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.

FLASH File System

This file system 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. I wrote a utility called fsbld to create images that can be used with this file system. This GitHub repository contains the sources for that utility.

To get the file system image onto the mbed device, you need to concatenate your binary from the compiler with the file system image binary.

  • On *nix this can be done with the cat command. For example:
    cat Test_LPC1768.bin FileImage.bin >/Volumes/MBED/test.bin
  • On Windows this can be done with the copy command. For example:
    copy Test_LPC1768.bin + FileImage.bin e:\test.bin
Committer:
AdamGreen
Date:
Wed Aug 03 22:29:40 2011 +0000
Revision:
1:a3cb118c4f6e
Parent:
0:5ea6e74c35f7
Child:
2:ca35ecd2fae6
Changed license.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AdamGreen 1:a3cb118c4f6e 1 /* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
AdamGreen 1:a3cb118c4f6e 2
AdamGreen 1:a3cb118c4f6e 3 Licensed under the Apache License, Version 2.0 (the "License");
AdamGreen 1:a3cb118c4f6e 4 you may not use this file except in compliance with the License.
AdamGreen 1:a3cb118c4f6e 5 You may obtain a copy of the License at
AdamGreen 1:a3cb118c4f6e 6
AdamGreen 1:a3cb118c4f6e 7 http://www.apache.org/licenses/LICENSE-2.0
AdamGreen 1:a3cb118c4f6e 8
AdamGreen 1:a3cb118c4f6e 9 Unless required by applicable law or agreed to in writing, software
AdamGreen 1:a3cb118c4f6e 10 distributed under the License is distributed on an "AS IS" BASIS,
AdamGreen 1:a3cb118c4f6e 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
AdamGreen 1:a3cb118c4f6e 12 See the License for the specific language governing permissions and
AdamGreen 1:a3cb118c4f6e 13 limitations under the License.
AdamGreen 0:5ea6e74c35f7 14 */
AdamGreen 0:5ea6e74c35f7 15 /* Specifies the classes used to implement the FlashFileSystem which is a
AdamGreen 0:5ea6e74c35f7 16 read-only file system that exists in the internal FLASH of the mbed
AdamGreen 0:5ea6e74c35f7 17 device.
AdamGreen 0:5ea6e74c35f7 18 */
AdamGreen 0:5ea6e74c35f7 19 #include <mbed.h>
AdamGreen 0:5ea6e74c35f7 20 #include <assert.h>
AdamGreen 0:5ea6e74c35f7 21 #include "FlashFileSystem.h"
AdamGreen 0:5ea6e74c35f7 22 #include "ffsformat.h"
AdamGreen 0:5ea6e74c35f7 23
AdamGreen 0:5ea6e74c35f7 24
AdamGreen 0:5ea6e74c35f7 25 // Set FFS_TRACE to 1 to enable tracing within the FlashFileSystem class.
AdamGreen 0:5ea6e74c35f7 26 #define FFS_TRACE 0
AdamGreen 0:5ea6e74c35f7 27 #if FFS_TRACE
AdamGreen 0:5ea6e74c35f7 28 #define TRACE printf
AdamGreen 0:5ea6e74c35f7 29 #else
AdamGreen 0:5ea6e74c35f7 30 static void __trace(...)
AdamGreen 0:5ea6e74c35f7 31 {
AdamGreen 0:5ea6e74c35f7 32 return;
AdamGreen 0:5ea6e74c35f7 33 }
AdamGreen 0:5ea6e74c35f7 34 #define TRACE __trace
AdamGreen 0:5ea6e74c35f7 35 #endif // FFS_TRACE
AdamGreen 0:5ea6e74c35f7 36
AdamGreen 0:5ea6e74c35f7 37
AdamGreen 0:5ea6e74c35f7 38
AdamGreen 0:5ea6e74c35f7 39 /* Constructor for FlashFileSystemFileHandle which initializes to the specified
AdamGreen 0:5ea6e74c35f7 40 file entry in the image.
AdamGreen 0:5ea6e74c35f7 41
AdamGreen 0:5ea6e74c35f7 42 Parameters:
AdamGreen 0:5ea6e74c35f7 43 pFileStart is the beginning offset of this file in FLASH memory.
AdamGreen 0:5ea6e74c35f7 44 pFileEnd is the ending offset (1 bytes past last valid byte) of this file
AdamGreen 0:5ea6e74c35f7 45 FLASH memory.
AdamGreen 0:5ea6e74c35f7 46 */
AdamGreen 0:5ea6e74c35f7 47 FlashFileSystemFileHandle::FlashFileSystemFileHandle(const char* pFileStart,
AdamGreen 0:5ea6e74c35f7 48 const char* pFileEnd)
AdamGreen 0:5ea6e74c35f7 49 {
AdamGreen 0:5ea6e74c35f7 50 m_pFileStart = pFileStart;
AdamGreen 0:5ea6e74c35f7 51 m_pFileEnd = pFileEnd;
AdamGreen 0:5ea6e74c35f7 52 m_pCurr = pFileStart;
AdamGreen 0:5ea6e74c35f7 53 }
AdamGreen 0:5ea6e74c35f7 54
AdamGreen 0:5ea6e74c35f7 55
AdamGreen 0:5ea6e74c35f7 56 // Constructs a blank FlashFileSystemFileHandle object.
AdamGreen 0:5ea6e74c35f7 57 FlashFileSystemFileHandle::FlashFileSystemFileHandle()
AdamGreen 0:5ea6e74c35f7 58 {
AdamGreen 0:5ea6e74c35f7 59 FlashFileSystemFileHandle(NULL, NULL);
AdamGreen 0:5ea6e74c35f7 60 }
AdamGreen 0:5ea6e74c35f7 61
AdamGreen 0:5ea6e74c35f7 62
AdamGreen 0:5ea6e74c35f7 63 /* Write the contents of a buffer to the file
AdamGreen 0:5ea6e74c35f7 64
AdamGreen 0:5ea6e74c35f7 65 Parameters:
AdamGreen 0:5ea6e74c35f7 66 pBuffer is the buffer from which to write.
AdamGreen 0:5ea6e74c35f7 67 Length is the number of characters to write.
AdamGreen 0:5ea6e74c35f7 68
AdamGreen 0:5ea6e74c35f7 69 Returns
AdamGreen 0:5ea6e74c35f7 70 The number of characters written (possibly 0) on success, -1 on error.
AdamGreen 0:5ea6e74c35f7 71 */
AdamGreen 0:5ea6e74c35f7 72 ssize_t FlashFileSystemFileHandle::write(const void* pBuffer, size_t Length)
AdamGreen 0:5ea6e74c35f7 73 {
AdamGreen 0:5ea6e74c35f7 74 // This file system doesn't support writing.
AdamGreen 0:5ea6e74c35f7 75 return -1;
AdamGreen 0:5ea6e74c35f7 76 }
AdamGreen 0:5ea6e74c35f7 77
AdamGreen 0:5ea6e74c35f7 78
AdamGreen 0:5ea6e74c35f7 79 /* Close the file
AdamGreen 0:5ea6e74c35f7 80
AdamGreen 0:5ea6e74c35f7 81 Returns
AdamGreen 0:5ea6e74c35f7 82 Zero on success, -1 on error.
AdamGreen 0:5ea6e74c35f7 83 */
AdamGreen 0:5ea6e74c35f7 84 int FlashFileSystemFileHandle::close()
AdamGreen 0:5ea6e74c35f7 85 {
AdamGreen 0:5ea6e74c35f7 86 m_pFileStart = NULL;
AdamGreen 0:5ea6e74c35f7 87 m_pFileEnd = NULL;
AdamGreen 0:5ea6e74c35f7 88 m_pCurr = NULL;
AdamGreen 0:5ea6e74c35f7 89
AdamGreen 0:5ea6e74c35f7 90 return 0;
AdamGreen 0:5ea6e74c35f7 91 }
AdamGreen 0:5ea6e74c35f7 92
AdamGreen 0:5ea6e74c35f7 93 /* Reads the contents of the file into a buffer.
AdamGreen 0:5ea6e74c35f7 94
AdamGreen 0:5ea6e74c35f7 95 Parameters
AdamGreen 0:5ea6e74c35f7 96 pBuffer is the buffer into which the read should occur.
AdamGreen 0:5ea6e74c35f7 97 Length is the number of characters to read into pBuffer.
AdamGreen 0:5ea6e74c35f7 98
AdamGreen 0:5ea6e74c35f7 99 Returns
AdamGreen 0:5ea6e74c35f7 100 The number of characters read (zero at end of file) on success, -1 on error.
AdamGreen 0:5ea6e74c35f7 101 */
AdamGreen 0:5ea6e74c35f7 102 ssize_t FlashFileSystemFileHandle::read(void* pBuffer, size_t Length)
AdamGreen 0:5ea6e74c35f7 103 {
AdamGreen 0:5ea6e74c35f7 104 unsigned int BytesLeft;
AdamGreen 0:5ea6e74c35f7 105
AdamGreen 0:5ea6e74c35f7 106 // Don't read more bytes than what are left in the file.
AdamGreen 0:5ea6e74c35f7 107 BytesLeft = m_pFileEnd - m_pCurr;
AdamGreen 0:5ea6e74c35f7 108 if (Length > BytesLeft)
AdamGreen 0:5ea6e74c35f7 109 {
AdamGreen 0:5ea6e74c35f7 110 Length = BytesLeft;
AdamGreen 0:5ea6e74c35f7 111 }
AdamGreen 0:5ea6e74c35f7 112
AdamGreen 0:5ea6e74c35f7 113 // Copy the bytes from FLASH into the caller provided buffer.
AdamGreen 0:5ea6e74c35f7 114 memcpy(pBuffer, m_pCurr, Length);
AdamGreen 0:5ea6e74c35f7 115
AdamGreen 0:5ea6e74c35f7 116 // Update the file pointer.
AdamGreen 0:5ea6e74c35f7 117 m_pCurr += Length;
AdamGreen 0:5ea6e74c35f7 118
AdamGreen 0:5ea6e74c35f7 119 return Length;
AdamGreen 0:5ea6e74c35f7 120 }
AdamGreen 0:5ea6e74c35f7 121
AdamGreen 0:5ea6e74c35f7 122
AdamGreen 0:5ea6e74c35f7 123 /* Check if the handle is for a interactive terminal device .
AdamGreen 0:5ea6e74c35f7 124
AdamGreen 0:5ea6e74c35f7 125 Parameters
AdamGreen 0:5ea6e74c35f7 126 None
AdamGreen 0:5ea6e74c35f7 127 Returns
AdamGreen 0:5ea6e74c35f7 128 1 if it is a terminal, 0 otherwise
AdamGreen 0:5ea6e74c35f7 129 */
AdamGreen 0:5ea6e74c35f7 130 int FlashFileSystemFileHandle::isatty()
AdamGreen 0:5ea6e74c35f7 131 {
AdamGreen 0:5ea6e74c35f7 132 return 0;
AdamGreen 0:5ea6e74c35f7 133 }
AdamGreen 0:5ea6e74c35f7 134
AdamGreen 0:5ea6e74c35f7 135
AdamGreen 0:5ea6e74c35f7 136 /* Move the file position to a given offset from a given location.
AdamGreen 0:5ea6e74c35f7 137
AdamGreen 0:5ea6e74c35f7 138 Parameters
AdamGreen 0:5ea6e74c35f7 139 offset is the offset from whence to move to.
AdamGreen 0:5ea6e74c35f7 140 whence - SEEK_SET for the start of the file,
AdamGreen 0:5ea6e74c35f7 141 SEEK_CUR for the current file position, or
AdamGreen 0:5ea6e74c35f7 142 SEEK_END for the end of the file.
AdamGreen 0:5ea6e74c35f7 143
AdamGreen 0:5ea6e74c35f7 144 Returns
AdamGreen 0:5ea6e74c35f7 145 New file position on success, -1 on failure or unsupported
AdamGreen 0:5ea6e74c35f7 146 */
AdamGreen 0:5ea6e74c35f7 147 off_t FlashFileSystemFileHandle::lseek(off_t offset, int whence)
AdamGreen 0:5ea6e74c35f7 148 {
AdamGreen 0:5ea6e74c35f7 149 switch(whence)
AdamGreen 0:5ea6e74c35f7 150 {
AdamGreen 0:5ea6e74c35f7 151 case SEEK_SET:
AdamGreen 0:5ea6e74c35f7 152 m_pCurr = m_pFileStart + offset;
AdamGreen 0:5ea6e74c35f7 153 break;
AdamGreen 0:5ea6e74c35f7 154 case SEEK_CUR:
AdamGreen 0:5ea6e74c35f7 155 m_pCurr += offset;
AdamGreen 0:5ea6e74c35f7 156 break;
AdamGreen 0:5ea6e74c35f7 157 case SEEK_END:
AdamGreen 0:5ea6e74c35f7 158 m_pCurr = (m_pFileEnd - 1) + offset;
AdamGreen 0:5ea6e74c35f7 159 break;
AdamGreen 0:5ea6e74c35f7 160 default:
AdamGreen 0:5ea6e74c35f7 161 TRACE("FlashFileSytem: Received unknown origin code (%d) for seek.\r\n", whence);
AdamGreen 0:5ea6e74c35f7 162 return -1;
AdamGreen 0:5ea6e74c35f7 163 }
AdamGreen 0:5ea6e74c35f7 164
AdamGreen 0:5ea6e74c35f7 165 return (m_pCurr - m_pFileStart);
AdamGreen 0:5ea6e74c35f7 166 }
AdamGreen 0:5ea6e74c35f7 167
AdamGreen 0:5ea6e74c35f7 168
AdamGreen 0:5ea6e74c35f7 169 /* Flush any buffers associated with the FileHandle, ensuring it
AdamGreen 0:5ea6e74c35f7 170 is up to date on disk. Since the Flash file system is read-only, there
AdamGreen 0:5ea6e74c35f7 171 is nothing to do here.
AdamGreen 0:5ea6e74c35f7 172
AdamGreen 0:5ea6e74c35f7 173 Returns
AdamGreen 0:5ea6e74c35f7 174 0 on success or un-needed, -1 on error
AdamGreen 0:5ea6e74c35f7 175 */
AdamGreen 0:5ea6e74c35f7 176 int FlashFileSystemFileHandle::fsync()
AdamGreen 0:5ea6e74c35f7 177 {
AdamGreen 0:5ea6e74c35f7 178 return 0;
AdamGreen 0:5ea6e74c35f7 179 }
AdamGreen 0:5ea6e74c35f7 180
AdamGreen 0:5ea6e74c35f7 181
AdamGreen 0:5ea6e74c35f7 182 /* Returns the length of the file.
AdamGreen 0:5ea6e74c35f7 183
AdamGreen 0:5ea6e74c35f7 184 Parameters:
AdamGreen 0:5ea6e74c35f7 185 None
AdamGreen 0:5ea6e74c35f7 186 Returns:
AdamGreen 0:5ea6e74c35f7 187 Length of file.
AdamGreen 0:5ea6e74c35f7 188 */
AdamGreen 0:5ea6e74c35f7 189 off_t FlashFileSystemFileHandle::flen()
AdamGreen 0:5ea6e74c35f7 190 {
AdamGreen 0:5ea6e74c35f7 191 return (m_pFileEnd - m_pFileStart);
AdamGreen 0:5ea6e74c35f7 192 }
AdamGreen 0:5ea6e74c35f7 193
AdamGreen 0:5ea6e74c35f7 194
AdamGreen 0:5ea6e74c35f7 195
AdamGreen 0:5ea6e74c35f7 196 /* Construct and initialize a directory handle enumeration object.
AdamGreen 0:5ea6e74c35f7 197
AdamGreen 0:5ea6e74c35f7 198 Parameters:
AdamGreen 0:5ea6e74c35f7 199 pFLASHBase points to the beginning of the file system in FLASH memory.
AdamGreen 0:5ea6e74c35f7 200 pFirstFileEntry is a pointer to the first entry found in this directory.
AdamGreen 0:5ea6e74c35f7 201 DirectoryNameLength is the length of the directory name for which this
AdamGreen 0:5ea6e74c35f7 202 handle is being used to enumerate.
AdamGreen 0:5ea6e74c35f7 203
AdamGreen 0:5ea6e74c35f7 204 Returns:
AdamGreen 0:5ea6e74c35f7 205 Nothing.
AdamGreen 0:5ea6e74c35f7 206 */
AdamGreen 0:5ea6e74c35f7 207 FlashFileSystemDirHandle::FlashFileSystemDirHandle(const char* pFLASHBase,
AdamGreen 0:5ea6e74c35f7 208 const _SFileSystemEntry* pFirstFileEntry,
AdamGreen 0:5ea6e74c35f7 209 unsigned int FileEntriesLeft,
AdamGreen 0:5ea6e74c35f7 210 unsigned int DirectoryNameLength)
AdamGreen 0:5ea6e74c35f7 211 {
AdamGreen 0:5ea6e74c35f7 212 m_pFLASHBase = pFLASHBase;
AdamGreen 0:5ea6e74c35f7 213 m_pFirstFileEntry = pFirstFileEntry;
AdamGreen 0:5ea6e74c35f7 214 m_pCurrentFileEntry = pFirstFileEntry;
AdamGreen 0:5ea6e74c35f7 215 m_FileEntriesLeft = FileEntriesLeft;
AdamGreen 0:5ea6e74c35f7 216 m_DirectoryNameLength = DirectoryNameLength;
AdamGreen 0:5ea6e74c35f7 217 m_DirectoryEntry.d_name[0] = '\0';
AdamGreen 0:5ea6e74c35f7 218 }
AdamGreen 0:5ea6e74c35f7 219
AdamGreen 0:5ea6e74c35f7 220
AdamGreen 0:5ea6e74c35f7 221 // Used to construct a closed directory handle.
AdamGreen 0:5ea6e74c35f7 222 FlashFileSystemDirHandle::FlashFileSystemDirHandle()
AdamGreen 0:5ea6e74c35f7 223 {
AdamGreen 0:5ea6e74c35f7 224 FlashFileSystemDirHandle(NULL, NULL, 0, 0);
AdamGreen 0:5ea6e74c35f7 225 }
AdamGreen 0:5ea6e74c35f7 226
AdamGreen 0:5ea6e74c35f7 227
AdamGreen 0:5ea6e74c35f7 228 /* Closes the directory enumeration object.
AdamGreen 0:5ea6e74c35f7 229
AdamGreen 0:5ea6e74c35f7 230 Parameters:
AdamGreen 0:5ea6e74c35f7 231 None.
AdamGreen 0:5ea6e74c35f7 232
AdamGreen 0:5ea6e74c35f7 233 Returns:
AdamGreen 0:5ea6e74c35f7 234 0 on success, or -1 on error.
AdamGreen 0:5ea6e74c35f7 235 */
AdamGreen 0:5ea6e74c35f7 236 int FlashFileSystemDirHandle::closedir()
AdamGreen 0:5ea6e74c35f7 237 {
AdamGreen 0:5ea6e74c35f7 238 m_pFLASHBase = NULL;
AdamGreen 0:5ea6e74c35f7 239 m_pFirstFileEntry = NULL;
AdamGreen 0:5ea6e74c35f7 240 m_pCurrentFileEntry = NULL;
AdamGreen 0:5ea6e74c35f7 241 m_FileEntriesLeft = 0;
AdamGreen 0:5ea6e74c35f7 242 m_DirectoryNameLength = 0;
AdamGreen 0:5ea6e74c35f7 243 m_DirectoryEntry.d_name[0] = '\0';
AdamGreen 0:5ea6e74c35f7 244
AdamGreen 0:5ea6e74c35f7 245 return 0;
AdamGreen 0:5ea6e74c35f7 246 }
AdamGreen 0:5ea6e74c35f7 247
AdamGreen 0:5ea6e74c35f7 248
AdamGreen 0:5ea6e74c35f7 249 /* Return the directory entry at the current position, and
AdamGreen 0:5ea6e74c35f7 250 advances the position to the next entry.
AdamGreen 0:5ea6e74c35f7 251
AdamGreen 0:5ea6e74c35f7 252 Parameters:
AdamGreen 0:5ea6e74c35f7 253 None.
AdamGreen 0:5ea6e74c35f7 254
AdamGreen 0:5ea6e74c35f7 255 Returns:
AdamGreen 0:5ea6e74c35f7 256 A pointer to a dirent structure representing the
AdamGreen 0:5ea6e74c35f7 257 directory entry at the current position, or NULL on reaching
AdamGreen 0:5ea6e74c35f7 258 end of directory or error.
AdamGreen 0:5ea6e74c35f7 259 */
AdamGreen 0:5ea6e74c35f7 260 struct dirent* FlashFileSystemDirHandle::readdir()
AdamGreen 0:5ea6e74c35f7 261 {
AdamGreen 0:5ea6e74c35f7 262 const char* pPrevEntryName;
AdamGreen 0:5ea6e74c35f7 263 const char* pCurrentEntryName;
AdamGreen 0:5ea6e74c35f7 264 char* pSlash;
AdamGreen 0:5ea6e74c35f7 265 size_t PrefixLength;
AdamGreen 0:5ea6e74c35f7 266 unsigned int FileEntriesUsed;
AdamGreen 0:5ea6e74c35f7 267 unsigned int FileEntriesLeft;
AdamGreen 0:5ea6e74c35f7 268
AdamGreen 0:5ea6e74c35f7 269 // Just return now if we have already finished enumerating the entries in
AdamGreen 0:5ea6e74c35f7 270 // the directory.
AdamGreen 0:5ea6e74c35f7 271 if (!m_pCurrentFileEntry)
AdamGreen 0:5ea6e74c35f7 272 {
AdamGreen 0:5ea6e74c35f7 273 m_DirectoryEntry.d_name[0] = '\0';
AdamGreen 0:5ea6e74c35f7 274 return NULL;
AdamGreen 0:5ea6e74c35f7 275 }
AdamGreen 0:5ea6e74c35f7 276
AdamGreen 0:5ea6e74c35f7 277 // Calculate the number of valid entries are left in the file entry array.
AdamGreen 0:5ea6e74c35f7 278 FileEntriesUsed = m_pCurrentFileEntry - m_pFirstFileEntry;
AdamGreen 0:5ea6e74c35f7 279 FileEntriesLeft = m_FileEntriesLeft - FileEntriesUsed;
AdamGreen 0:5ea6e74c35f7 280
AdamGreen 0:5ea6e74c35f7 281 // Fill in the directory entry structure for the current entry.
AdamGreen 0:5ea6e74c35f7 282 pPrevEntryName = m_pFLASHBase +
AdamGreen 0:5ea6e74c35f7 283 m_pCurrentFileEntry->FilenameOffset;
AdamGreen 0:5ea6e74c35f7 284 strncpy(m_DirectoryEntry.d_name,
AdamGreen 0:5ea6e74c35f7 285 pPrevEntryName + m_DirectoryNameLength,
AdamGreen 0:5ea6e74c35f7 286 sizeof(m_DirectoryEntry.d_name));
AdamGreen 0:5ea6e74c35f7 287 m_DirectoryEntry.d_name[sizeof(m_DirectoryEntry.d_name) - 1] = '\0';
AdamGreen 0:5ea6e74c35f7 288
AdamGreen 0:5ea6e74c35f7 289 // If the entry to be returned contains a slash then this is a directory
AdamGreen 0:5ea6e74c35f7 290 // entry.
AdamGreen 0:5ea6e74c35f7 291 pSlash = strchr(m_DirectoryEntry.d_name, '/');
AdamGreen 0:5ea6e74c35f7 292 if (pSlash)
AdamGreen 0:5ea6e74c35f7 293 {
AdamGreen 0:5ea6e74c35f7 294 // I am truncating everything after the slash but leaving the
AdamGreen 0:5ea6e74c35f7 295 // slash so that I can tell it is a directory and not a file.
AdamGreen 0:5ea6e74c35f7 296 pSlash[1] = '\0';
AdamGreen 0:5ea6e74c35f7 297 }
AdamGreen 0:5ea6e74c35f7 298
AdamGreen 0:5ea6e74c35f7 299 // Skip entries that have the same prefix as the current entry. This
AdamGreen 0:5ea6e74c35f7 300 // will skip the files in the same sub-tree.
AdamGreen 0:5ea6e74c35f7 301 PrefixLength = strlen(m_DirectoryEntry.d_name) + m_DirectoryNameLength;
AdamGreen 0:5ea6e74c35f7 302 do
AdamGreen 0:5ea6e74c35f7 303 {
AdamGreen 0:5ea6e74c35f7 304 m_pCurrentFileEntry++;
AdamGreen 0:5ea6e74c35f7 305 FileEntriesLeft--;
AdamGreen 0:5ea6e74c35f7 306 pCurrentEntryName = m_pFLASHBase + m_pCurrentFileEntry->FilenameOffset;
AdamGreen 0:5ea6e74c35f7 307 } while (FileEntriesLeft &&
AdamGreen 0:5ea6e74c35f7 308 0 == strncmp(pPrevEntryName, pCurrentEntryName, PrefixLength));
AdamGreen 0:5ea6e74c35f7 309
AdamGreen 0:5ea6e74c35f7 310 // If we have walked past the end of all file entries in the file system or
AdamGreen 0:5ea6e74c35f7 311 // the prefix no longer matches this directory, then there are no more files
AdamGreen 0:5ea6e74c35f7 312 // for this directory enumeration.
AdamGreen 0:5ea6e74c35f7 313 if (0 == FileEntriesLeft ||
AdamGreen 0:5ea6e74c35f7 314 0 != strncmp(pPrevEntryName, pCurrentEntryName, m_DirectoryNameLength))
AdamGreen 0:5ea6e74c35f7 315 {
AdamGreen 0:5ea6e74c35f7 316 m_pCurrentFileEntry = NULL;
AdamGreen 0:5ea6e74c35f7 317 }
AdamGreen 0:5ea6e74c35f7 318
AdamGreen 0:5ea6e74c35f7 319 // Return a pointer to the directory entry structure that was previously
AdamGreen 0:5ea6e74c35f7 320 // setup.
AdamGreen 0:5ea6e74c35f7 321 return &m_DirectoryEntry;
AdamGreen 0:5ea6e74c35f7 322 }
AdamGreen 0:5ea6e74c35f7 323
AdamGreen 0:5ea6e74c35f7 324
AdamGreen 0:5ea6e74c35f7 325 //Resets the position to the beginning of the directory.
AdamGreen 0:5ea6e74c35f7 326 void FlashFileSystemDirHandle::rewinddir()
AdamGreen 0:5ea6e74c35f7 327 {
AdamGreen 0:5ea6e74c35f7 328 m_pCurrentFileEntry = m_pFirstFileEntry;
AdamGreen 0:5ea6e74c35f7 329 }
AdamGreen 0:5ea6e74c35f7 330
AdamGreen 0:5ea6e74c35f7 331
AdamGreen 0:5ea6e74c35f7 332 /* Returns the current position of the DirHandle.
AdamGreen 0:5ea6e74c35f7 333
AdamGreen 0:5ea6e74c35f7 334 Parameters:
AdamGreen 0:5ea6e74c35f7 335 None.
AdamGreen 0:5ea6e74c35f7 336
AdamGreen 0:5ea6e74c35f7 337 Returns:
AdamGreen 0:5ea6e74c35f7 338 The current position, or -1 on error.
AdamGreen 0:5ea6e74c35f7 339 */
AdamGreen 0:5ea6e74c35f7 340 off_t FlashFileSystemDirHandle::telldir()
AdamGreen 0:5ea6e74c35f7 341 {
AdamGreen 0:5ea6e74c35f7 342 return (off_t)m_pCurrentFileEntry;
AdamGreen 0:5ea6e74c35f7 343 }
AdamGreen 0:5ea6e74c35f7 344
AdamGreen 0:5ea6e74c35f7 345
AdamGreen 0:5ea6e74c35f7 346 /* Sets the position of the DirHandle.
AdamGreen 0:5ea6e74c35f7 347
AdamGreen 0:5ea6e74c35f7 348 Parameters:
AdamGreen 0:5ea6e74c35f7 349 Location is the location to seek to. Must be a value returned
AdamGreen 0:5ea6e74c35f7 350 by telldir.
AdamGreen 0:5ea6e74c35f7 351
AdamGreen 0:5ea6e74c35f7 352 Returns;
AdamGreen 0:5ea6e74c35f7 353 Nothing.
AdamGreen 0:5ea6e74c35f7 354 */
AdamGreen 0:5ea6e74c35f7 355 void FlashFileSystemDirHandle::seekdir(off_t Location)
AdamGreen 0:5ea6e74c35f7 356 {
AdamGreen 0:5ea6e74c35f7 357 SFileSystemEntry* pLocation = (SFileSystemEntry*)Location;
AdamGreen 0:5ea6e74c35f7 358
AdamGreen 0:5ea6e74c35f7 359 assert ( NULL != pLocation &&
AdamGreen 0:5ea6e74c35f7 360 pLocation > m_pFirstFileEntry &&
AdamGreen 0:5ea6e74c35f7 361 (pLocation - m_pFirstFileEntry) < m_FileEntriesLeft );
AdamGreen 0:5ea6e74c35f7 362
AdamGreen 0:5ea6e74c35f7 363 m_pCurrentFileEntry = pLocation;
AdamGreen 0:5ea6e74c35f7 364 }
AdamGreen 0:5ea6e74c35f7 365
AdamGreen 0:5ea6e74c35f7 366
AdamGreen 0:5ea6e74c35f7 367
AdamGreen 0:5ea6e74c35f7 368 // Structure used to hold context about current filename search.
AdamGreen 0:5ea6e74c35f7 369 struct SSearchContext
AdamGreen 0:5ea6e74c35f7 370 {
AdamGreen 0:5ea6e74c35f7 371 // Name of file to be found in file system image.
AdamGreen 0:5ea6e74c35f7 372 const char* pKey;
AdamGreen 0:5ea6e74c35f7 373 // Base pointer for the file system image.
AdamGreen 0:5ea6e74c35f7 374 const char* pFLASHBase;
AdamGreen 0:5ea6e74c35f7 375 };
AdamGreen 0:5ea6e74c35f7 376
AdamGreen 0:5ea6e74c35f7 377
AdamGreen 0:5ea6e74c35f7 378 /* Internal routine used as callback for bsearch() when searching for a
AdamGreen 0:5ea6e74c35f7 379 requested filename in the FLASH file system image.
AdamGreen 0:5ea6e74c35f7 380
AdamGreen 0:5ea6e74c35f7 381 pvKey is a pointer to the SSearchContext object for this search.
AdamGreen 0:5ea6e74c35f7 382 pvEntry is a pointer to the current file system entry being checked by
AdamGreen 0:5ea6e74c35f7 383 bsearch().
AdamGreen 0:5ea6e74c35f7 384
AdamGreen 0:5ea6e74c35f7 385 Returns <0 if filename to find is lower in sort order than current entry.
AdamGreen 0:5ea6e74c35f7 386 0 if filename to find is the same as the current entry.
AdamGreen 0:5ea6e74c35f7 387 >0 if filename to find is higher in sort order than current entry.
AdamGreen 0:5ea6e74c35f7 388 */
AdamGreen 0:5ea6e74c35f7 389 static int _CompareKeyToFileEntry(const void* pvKey, const void* pvEntry)
AdamGreen 0:5ea6e74c35f7 390 {
AdamGreen 0:5ea6e74c35f7 391 const SSearchContext* pContext = (const SSearchContext*)pvKey;
AdamGreen 0:5ea6e74c35f7 392 const char* pKey = pContext->pKey;
AdamGreen 0:5ea6e74c35f7 393 const SFileSystemEntry* pEntry = (const SFileSystemEntry*)pvEntry;
AdamGreen 0:5ea6e74c35f7 394 const char* pEntryName = pContext->pFLASHBase + pEntry->FilenameOffset;
AdamGreen 0:5ea6e74c35f7 395
AdamGreen 0:5ea6e74c35f7 396 return strcmp(pKey, pEntryName);
AdamGreen 0:5ea6e74c35f7 397 }
AdamGreen 0:5ea6e74c35f7 398
AdamGreen 0:5ea6e74c35f7 399
AdamGreen 0:5ea6e74c35f7 400 /* Constructor for FlashFileSystem
AdamGreen 0:5ea6e74c35f7 401
AdamGreen 0:5ea6e74c35f7 402 Parameters:
AdamGreen 0:5ea6e74c35f7 403 pName is the root name to be used for this file system in fopen()
AdamGreen 0:5ea6e74c35f7 404 pathnames.
AdamGreen 0:5ea6e74c35f7 405 */
AdamGreen 0:5ea6e74c35f7 406 FlashFileSystem::FlashFileSystem(const char* pName) : FileSystemLike(pName)
AdamGreen 0:5ea6e74c35f7 407 {
AdamGreen 0:5ea6e74c35f7 408 static const char FileSystemSignature[] = FILE_SYSTEM_SIGNATURE;
AdamGreen 0:5ea6e74c35f7 409 SFileSystemHeader* pHeader = NULL;
AdamGreen 0:5ea6e74c35f7 410 char* pCurr = (char*)FILE_SYSTEM_FLASH_SIZE - sizeof(pHeader->FileSystemSignature);
AdamGreen 0:5ea6e74c35f7 411
AdamGreen 0:5ea6e74c35f7 412 // Initialize the members
AdamGreen 0:5ea6e74c35f7 413 m_pFLASHBase = NULL;
AdamGreen 0:5ea6e74c35f7 414 m_FileCount = 0;
AdamGreen 0:5ea6e74c35f7 415 m_pFileEntries = NULL;
AdamGreen 0:5ea6e74c35f7 416
AdamGreen 0:5ea6e74c35f7 417 // Scan backwards through 512k FLASH looking for the file system signature
AdamGreen 0:5ea6e74c35f7 418 // NOTE: The file system image should be located after this code itself
AdamGreen 0:5ea6e74c35f7 419 // so stop the search.
AdamGreen 0:5ea6e74c35f7 420 while (pCurr > FileSystemSignature)
AdamGreen 0:5ea6e74c35f7 421 {
AdamGreen 0:5ea6e74c35f7 422 if (0 == memcmp(pCurr, FileSystemSignature, sizeof(pHeader->FileSystemSignature)))
AdamGreen 0:5ea6e74c35f7 423 {
AdamGreen 0:5ea6e74c35f7 424 break;
AdamGreen 0:5ea6e74c35f7 425 }
AdamGreen 0:5ea6e74c35f7 426 pCurr--;
AdamGreen 0:5ea6e74c35f7 427 }
AdamGreen 0:5ea6e74c35f7 428 if (pCurr <= FileSystemSignature)
AdamGreen 0:5ea6e74c35f7 429 {
AdamGreen 0:5ea6e74c35f7 430 TRACE("FlashFileSystem: Failed to find file system image in RAM.\n");
AdamGreen 0:5ea6e74c35f7 431 return;
AdamGreen 0:5ea6e74c35f7 432 }
AdamGreen 0:5ea6e74c35f7 433 if (((unsigned int)pCurr & 0x3) != 0)
AdamGreen 0:5ea6e74c35f7 434 {
AdamGreen 0:5ea6e74c35f7 435 TRACE("FlashFileSystem: File system image at address %08X isn't 4-byte aligned.\n", pCurr);
AdamGreen 0:5ea6e74c35f7 436 return;
AdamGreen 0:5ea6e74c35f7 437 }
AdamGreen 0:5ea6e74c35f7 438
AdamGreen 0:5ea6e74c35f7 439 // Record the location of the file system image in the member fields.
AdamGreen 0:5ea6e74c35f7 440 m_pFLASHBase = pCurr;
AdamGreen 0:5ea6e74c35f7 441 pHeader = (SFileSystemHeader*)m_pFLASHBase;
AdamGreen 0:5ea6e74c35f7 442 m_FileCount = pHeader->FileCount;
AdamGreen 0:5ea6e74c35f7 443 m_pFileEntries = (SFileSystemEntry*)(m_pFLASHBase + sizeof(*pHeader));
AdamGreen 0:5ea6e74c35f7 444 }
AdamGreen 0:5ea6e74c35f7 445
AdamGreen 0:5ea6e74c35f7 446
AdamGreen 0:5ea6e74c35f7 447 /* Opens specified file in FLASH file system when an appropriate call to
AdamGreen 0:5ea6e74c35f7 448 fopen() is made.
AdamGreen 0:5ea6e74c35f7 449
AdamGreen 0:5ea6e74c35f7 450 pFilename is the name of the file to be opened within the file system.
AdamGreen 0:5ea6e74c35f7 451 Flags specify flags to determine open mode of file. This file system only
AdamGreen 0:5ea6e74c35f7 452 support O_RDONLY.
AdamGreen 0:5ea6e74c35f7 453
AdamGreen 0:5ea6e74c35f7 454 Returns NULL if an error was encountered or a pointer to a FileHandle object
AdamGreen 0:5ea6e74c35f7 455 representing the requrested file otherwise.
AdamGreen 0:5ea6e74c35f7 456 */
AdamGreen 0:5ea6e74c35f7 457 FileHandle* FlashFileSystem::open(const char* pFilename, int Flags)
AdamGreen 0:5ea6e74c35f7 458 {
AdamGreen 0:5ea6e74c35f7 459 const SFileSystemEntry* pEntry = NULL;
AdamGreen 0:5ea6e74c35f7 460 FlashFileSystemFileHandle* pFileHandle = NULL;
AdamGreen 0:5ea6e74c35f7 461 SSearchContext SearchContext;
AdamGreen 0:5ea6e74c35f7 462
AdamGreen 0:5ea6e74c35f7 463 TRACE("FlashFileSystem: Attempt to open file /FLASH/%s with flags:%x\r\n", pFilename, Flags);
AdamGreen 0:5ea6e74c35f7 464
AdamGreen 0:5ea6e74c35f7 465 // Can't find the file if file system hasn't been mounted.
AdamGreen 0:5ea6e74c35f7 466 if (!IsMounted())
AdamGreen 0:5ea6e74c35f7 467 {
AdamGreen 0:5ea6e74c35f7 468 return NULL;
AdamGreen 0:5ea6e74c35f7 469 }
AdamGreen 0:5ea6e74c35f7 470
AdamGreen 0:5ea6e74c35f7 471 // Can only open files in FLASH for read.
AdamGreen 0:5ea6e74c35f7 472 if (O_RDONLY != Flags)
AdamGreen 0:5ea6e74c35f7 473 {
AdamGreen 0:5ea6e74c35f7 474 TRACE("FlashFileSystem: Can only open files for reading.\r\n");
AdamGreen 0:5ea6e74c35f7 475 }
AdamGreen 0:5ea6e74c35f7 476
AdamGreen 0:5ea6e74c35f7 477 // Attempt to find the specified file in the file system image.
AdamGreen 0:5ea6e74c35f7 478 SearchContext.pKey = pFilename;
AdamGreen 0:5ea6e74c35f7 479 SearchContext.pFLASHBase = m_pFLASHBase;
AdamGreen 0:5ea6e74c35f7 480 pEntry = (const SFileSystemEntry*) bsearch(&SearchContext,
AdamGreen 0:5ea6e74c35f7 481 m_pFileEntries,
AdamGreen 0:5ea6e74c35f7 482 m_FileCount,
AdamGreen 0:5ea6e74c35f7 483 sizeof(*m_pFileEntries),
AdamGreen 0:5ea6e74c35f7 484 _CompareKeyToFileEntry);
AdamGreen 0:5ea6e74c35f7 485 if(!pEntry)
AdamGreen 0:5ea6e74c35f7 486 {
AdamGreen 0:5ea6e74c35f7 487 // Create failure response.
AdamGreen 0:5ea6e74c35f7 488 TRACE("FlashFileSystem: Failed to find '%s' in file system image.\n", pFilename);
AdamGreen 0:5ea6e74c35f7 489 return NULL;
AdamGreen 0:5ea6e74c35f7 490 }
AdamGreen 0:5ea6e74c35f7 491
AdamGreen 0:5ea6e74c35f7 492 // Attempt to find a free file handle.
AdamGreen 0:5ea6e74c35f7 493 pFileHandle = FindFreeFileHandle();
AdamGreen 0:5ea6e74c35f7 494 if (!pFileHandle)
AdamGreen 0:5ea6e74c35f7 495 {
AdamGreen 0:5ea6e74c35f7 496 TRACE("FlashFileSystem: File handle table is full.\n");
AdamGreen 0:5ea6e74c35f7 497 return NULL;
AdamGreen 0:5ea6e74c35f7 498 }
AdamGreen 0:5ea6e74c35f7 499
AdamGreen 0:5ea6e74c35f7 500 // Initialize the file handle and return it to caller.
AdamGreen 0:5ea6e74c35f7 501 pFileHandle->SetEntry(m_pFLASHBase + pEntry->FileBinaryOffset,
AdamGreen 0:5ea6e74c35f7 502 m_pFLASHBase + pEntry->FileBinaryOffset + pEntry->FileBinarySize);
AdamGreen 0:5ea6e74c35f7 503 return pFileHandle;
AdamGreen 0:5ea6e74c35f7 504 }
AdamGreen 0:5ea6e74c35f7 505
AdamGreen 0:5ea6e74c35f7 506 DirHandle* FlashFileSystem::opendir(const char *pDirectoryName)
AdamGreen 0:5ea6e74c35f7 507 {
AdamGreen 0:5ea6e74c35f7 508 const SFileSystemEntry* pEntry = m_pFileEntries;
AdamGreen 0:5ea6e74c35f7 509 unsigned int DirectoryNameLength;
AdamGreen 0:5ea6e74c35f7 510 unsigned int i;
AdamGreen 0:5ea6e74c35f7 511
AdamGreen 0:5ea6e74c35f7 512 assert ( pDirectoryName);
AdamGreen 0:5ea6e74c35f7 513
AdamGreen 0:5ea6e74c35f7 514 // Removing leading slash since the file system image doesn't contain
AdamGreen 0:5ea6e74c35f7 515 // leading slashes.
AdamGreen 0:5ea6e74c35f7 516 if ('/' == pDirectoryName[0])
AdamGreen 0:5ea6e74c35f7 517 {
AdamGreen 0:5ea6e74c35f7 518 pDirectoryName++;
AdamGreen 0:5ea6e74c35f7 519 }
AdamGreen 0:5ea6e74c35f7 520
AdamGreen 0:5ea6e74c35f7 521 // Make sure that the directory name length would include the trailing
AdamGreen 0:5ea6e74c35f7 522 // slash.
AdamGreen 0:5ea6e74c35f7 523 DirectoryNameLength = strlen(pDirectoryName);
AdamGreen 0:5ea6e74c35f7 524 if (0 != DirectoryNameLength && '/' != pDirectoryName[DirectoryNameLength-1])
AdamGreen 0:5ea6e74c35f7 525 {
AdamGreen 0:5ea6e74c35f7 526 // Add the implicit slash to this count.
AdamGreen 0:5ea6e74c35f7 527 DirectoryNameLength++;
AdamGreen 0:5ea6e74c35f7 528 }
AdamGreen 0:5ea6e74c35f7 529
AdamGreen 0:5ea6e74c35f7 530 // Search through the file entries from the beginning to find the first
AdamGreen 0:5ea6e74c35f7 531 // entry which has pDirectoryName/ as the prefix.
AdamGreen 0:5ea6e74c35f7 532 for (i = 0 ; i < m_FileCount ; i++)
AdamGreen 0:5ea6e74c35f7 533 {
AdamGreen 0:5ea6e74c35f7 534 const char* pEntryFilename = pEntry->FilenameOffset + m_pFLASHBase;
AdamGreen 0:5ea6e74c35f7 535
AdamGreen 0:5ea6e74c35f7 536 if (0 == DirectoryNameLength ||
AdamGreen 0:5ea6e74c35f7 537 (pEntryFilename == strstr(pEntryFilename, pDirectoryName) &&
AdamGreen 0:5ea6e74c35f7 538 '/' == pEntryFilename[DirectoryNameLength-1]) )
AdamGreen 0:5ea6e74c35f7 539 {
AdamGreen 0:5ea6e74c35f7 540 // Found the beginning of the list of files/folders for the
AdamGreen 0:5ea6e74c35f7 541 // requested directory so return it to the caller.
AdamGreen 0:5ea6e74c35f7 542 FlashFileSystemDirHandle* pDirHandle = FindFreeDirHandle();
AdamGreen 0:5ea6e74c35f7 543 if (!pDirHandle)
AdamGreen 0:5ea6e74c35f7 544 {
AdamGreen 0:5ea6e74c35f7 545 TRACE("FlashFileSystem: Dir handle table is full.\n");
AdamGreen 0:5ea6e74c35f7 546 return NULL;
AdamGreen 0:5ea6e74c35f7 547 }
AdamGreen 0:5ea6e74c35f7 548
AdamGreen 0:5ea6e74c35f7 549 pDirHandle->SetEntry(m_pFLASHBase,
AdamGreen 0:5ea6e74c35f7 550 pEntry,
AdamGreen 0:5ea6e74c35f7 551 m_FileCount - (pEntry - m_pFileEntries),
AdamGreen 0:5ea6e74c35f7 552 DirectoryNameLength);
AdamGreen 0:5ea6e74c35f7 553
AdamGreen 0:5ea6e74c35f7 554 return pDirHandle;
AdamGreen 0:5ea6e74c35f7 555 }
AdamGreen 0:5ea6e74c35f7 556
AdamGreen 0:5ea6e74c35f7 557 // Advance to the next file entry
AdamGreen 0:5ea6e74c35f7 558 pEntry++;
AdamGreen 0:5ea6e74c35f7 559 }
AdamGreen 0:5ea6e74c35f7 560
AdamGreen 0:5ea6e74c35f7 561 // Get here when the requested directory wasn't found.
AdamGreen 0:5ea6e74c35f7 562 TRACE("FlashFileSystem: Failed to find '%s' directory in file system image.\n",
AdamGreen 0:5ea6e74c35f7 563 pDirectoryName);
AdamGreen 0:5ea6e74c35f7 564 return NULL;
AdamGreen 0:5ea6e74c35f7 565 }
AdamGreen 0:5ea6e74c35f7 566
AdamGreen 0:5ea6e74c35f7 567
AdamGreen 0:5ea6e74c35f7 568 /* Protected method which attempts to find a free file handle in the object's
AdamGreen 0:5ea6e74c35f7 569 file handle table.
AdamGreen 0:5ea6e74c35f7 570
AdamGreen 0:5ea6e74c35f7 571 Parameters:
AdamGreen 0:5ea6e74c35f7 572 None
AdamGreen 0:5ea6e74c35f7 573
AdamGreen 0:5ea6e74c35f7 574 Returns:
AdamGreen 0:5ea6e74c35f7 575 Pointer to first free file handle entry or NULL if the table is full.
AdamGreen 0:5ea6e74c35f7 576 */
AdamGreen 0:5ea6e74c35f7 577 FlashFileSystemFileHandle* FlashFileSystem::FindFreeFileHandle()
AdamGreen 0:5ea6e74c35f7 578 {
AdamGreen 0:5ea6e74c35f7 579 size_t i;
AdamGreen 0:5ea6e74c35f7 580
AdamGreen 0:5ea6e74c35f7 581 // Iterate through the file handle array, looking for a close file handle.
AdamGreen 0:5ea6e74c35f7 582 for (i = 0 ; i < sizeof(m_FileHandles)/sizeof(m_FileHandles[0]) ; i++)
AdamGreen 0:5ea6e74c35f7 583 {
AdamGreen 0:5ea6e74c35f7 584 if (m_FileHandles[i].IsClosed())
AdamGreen 0:5ea6e74c35f7 585 {
AdamGreen 0:5ea6e74c35f7 586 return &(m_FileHandles[i]);
AdamGreen 0:5ea6e74c35f7 587 }
AdamGreen 0:5ea6e74c35f7 588 }
AdamGreen 0:5ea6e74c35f7 589
AdamGreen 0:5ea6e74c35f7 590 // If we get here, then no free entries were found.
AdamGreen 0:5ea6e74c35f7 591 return NULL;
AdamGreen 0:5ea6e74c35f7 592 }
AdamGreen 0:5ea6e74c35f7 593
AdamGreen 0:5ea6e74c35f7 594
AdamGreen 0:5ea6e74c35f7 595 /* Protected method which attempts to find a free dir handle in the object's
AdamGreen 0:5ea6e74c35f7 596 directory handle table.
AdamGreen 0:5ea6e74c35f7 597
AdamGreen 0:5ea6e74c35f7 598 Parameters:
AdamGreen 0:5ea6e74c35f7 599 None
AdamGreen 0:5ea6e74c35f7 600
AdamGreen 0:5ea6e74c35f7 601 Returns:
AdamGreen 0:5ea6e74c35f7 602 Pointer to first free directory handle entry or NULL if the table is full.
AdamGreen 0:5ea6e74c35f7 603 */
AdamGreen 0:5ea6e74c35f7 604 FlashFileSystemDirHandle* FlashFileSystem::FindFreeDirHandle()
AdamGreen 0:5ea6e74c35f7 605 {
AdamGreen 0:5ea6e74c35f7 606 size_t i;
AdamGreen 0:5ea6e74c35f7 607
AdamGreen 0:5ea6e74c35f7 608 // Iterate through the direcotry handle array, looking for a closed
AdamGreen 0:5ea6e74c35f7 609 // directory handle.
AdamGreen 0:5ea6e74c35f7 610 for (i = 0 ; i < sizeof(m_DirHandles)/sizeof(m_DirHandles[0]) ; i++)
AdamGreen 0:5ea6e74c35f7 611 {
AdamGreen 0:5ea6e74c35f7 612 if (m_DirHandles[i].IsClosed())
AdamGreen 0:5ea6e74c35f7 613 {
AdamGreen 0:5ea6e74c35f7 614 return &(m_DirHandles[i]);
AdamGreen 0:5ea6e74c35f7 615 }
AdamGreen 0:5ea6e74c35f7 616 }
AdamGreen 0:5ea6e74c35f7 617
AdamGreen 0:5ea6e74c35f7 618 // If we get here, then no free entries were found.
AdamGreen 0:5ea6e74c35f7 619 return NULL;
AdamGreen 0:5ea6e74c35f7 620 }