summaryrefslogtreecommitdiff
path: root/utils/fswrapper.c
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
committerYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
commit990090a4cc9070837d31e66b58d40f0c3d038741 (patch)
treecf1b905082c364e9b223e0c5058566103138dae5 /utils/fswrapper.c
parent7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff)
Add usblib and utils
Diffstat (limited to 'utils/fswrapper.c')
-rw-r--r--utils/fswrapper.c860
1 files changed, 860 insertions, 0 deletions
diff --git a/utils/fswrapper.c b/utils/fswrapper.c
new file mode 100644
index 0000000..74e80af
--- /dev/null
+++ b/utils/fswrapper.c
@@ -0,0 +1,860 @@
+//*****************************************************************************
+//
+// fswrapper.c - File System Processing for lwIP Web Server Apps.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "httpserver_raw/fs.h"
+#include "httpserver_raw/fsdata.h"
+#include "fatfs/src/ff.h"
+#include "fatfs/src/diskio.h"
+#include "utils/fswrapper.h"
+#include "utils/lwiplib.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup fswrapper_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Static file system images for use with this module may be created using
+// the makefsfile.exe utility. Both position-independent (built using the -b
+// command line option to makefsfile) and position dependent file system images
+// may be used.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The index of the file system containing this file.
+ //
+ uint32_t ui32MountIndex;
+
+ //
+ // The FatFs file structure allocated if the target file is in the FAT
+ // file system.
+ //
+ FIL *psFATFile;
+}
+fs_wrapper_data;
+
+//*****************************************************************************
+//
+// A marker used to indicate that a passed filename cannot be mapped to any of
+// the configured mount points.
+//
+//*****************************************************************************
+#define BAD_MOUNT_INDEX 0xFFFFFFFF
+
+//*****************************************************************************
+//
+// This macro is used to extract pointers from the file descriptors. We
+// support files systems linked into the image as well as external, position
+// independent file system images and this macro allows us to use the same code
+// to extract pointers from file descriptors in each case.
+//
+//*****************************************************************************
+#define FS_POINTER(ptTree, ptValue, bPosInd) \
+ ((char *)((bPosInd) ? ((int8_t *)(ptTree) + (uint32_t)(ptValue)) : \
+ (int8_t *)(ptValue)))
+
+//*****************************************************************************
+//
+// The pointer to the mount point table and the number of entries in the
+// table.
+//
+//*****************************************************************************
+static fs_mount_data *g_psMountPoints = NULL;
+static uint32_t g_ui32NumMountPoints = 0;
+static uint32_t g_ui32DefaultMountIndex = BAD_MOUNT_INDEX;
+static bool g_bFatFsEnabled = false;
+
+//*****************************************************************************
+//
+// Given a filename, this function determine which of the configured mount
+// points it resides under. It returns the index of the mount point in the
+// g_psMountPoints array and also a pointer to the first character of the
+// filename with the mount point name (directory) stripped from it.
+//
+//*****************************************************************************
+static uint32_t
+fs_find_mount_index(const char *pcName, char **ppcFSFilename)
+{
+ uint32_t ui32Loop;
+ int iLenDirName;
+ int iLenMountName;
+ char *pcSlash;
+
+ //
+ // First extract the top level directory name which we need to match
+ // with the mount point name. For this to exist, the pcName string
+ // must start with a '/' character and must contain at least one more
+ // '/'.
+ //
+ if(pcName[0] == '/')
+ {
+ //
+ // The string starts with a '/'. Does it contain a second one?
+ //
+ pcSlash = strchr(pcName + 1, '/');
+
+ //
+ // Did we find another forward slash character?
+ //
+ if(pcSlash)
+ {
+ //
+ // Yes - the mount point name is between the start of the
+ // string and the slash we just found. How long is this string?
+ //
+ iLenDirName = (int)(pcSlash - (pcName + 1));
+ }
+ else
+ {
+ //
+ // The mount point name is the whole string.
+ //
+ iLenDirName = ustrlen(pcName + 1);
+ pcSlash = (char *)pcName + 1 + iLenDirName;
+ }
+
+ //
+ // Now figure out which, if any, of the mount points this matches.
+ //
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // Skip the default mount point if found.
+ //
+ if(!g_psMountPoints[ui32Loop].pcNamePrefix)
+ {
+ continue;
+ }
+
+ //
+ // How long is the name of this mount point?
+ //
+ iLenMountName = ustrlen(g_psMountPoints[ui32Loop].pcNamePrefix);
+
+ //
+ // Does the mount point name match the directory name extracted
+ // from the passed pcName?
+ //
+ if(iLenMountName == iLenDirName)
+ {
+ //
+ // The lengths match but are the strings the same?
+ //
+ if(!ustrncmp(g_psMountPoints[ui32Loop].pcNamePrefix,
+ pcName + 1, iLenDirName))
+ {
+ //
+ // Yes - we have a match. Set the stripped filename to
+ // the second '/' and return the mount point index.
+ //
+ *ppcFSFilename = pcSlash;
+ return(ui32Loop);
+ }
+ }
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find a specific mount point for
+ // this file so just return the filename passed and the default mount
+ // point.
+ //
+ *ppcFSFilename = (char *)pcName;
+
+ return(g_ui32DefaultMountIndex);
+}
+
+//*****************************************************************************
+//
+//! Initializes the file system wrapper.
+//!
+//! \param psMountPoints points to an array of fs_mount_data structures. Each
+//! element in the array maps a top level directory name to a particular
+//! file system image or to the FAT file system and a logical drive number.
+//! \param ui32NumMountPoints provides the number of populated elements in the
+//! \e psMountPoints array.
+//!
+//! This function should be called to initialize the file system wrapper and
+//! provide it with the information required to access the files in multiple
+//! file system images via a single filename space.
+//!
+//! Each entry in \e psMountPoints describes a top level directory in the
+//! unified namespace and indicates to fswrapper where the files for that
+//! directory can be found. Each entry can describe either a file system
+//! image in system memory or a logical disk handled via the FatFs file system
+//! driver.
+//!
+//! For example, consider the following 3 entry mount point table:
+//!
+//! \verbatim
+//! {
+//! { "internal", &g_pui8FSImage, 0, NULL, NULL },
+//! { "sdcard", NULL, 0, SDCardEnable, SDCardDisable },
+//! { NULL, &g_pui8FSDefault, 0, NULL, NULL}
+//! }
+//! \endverbatim
+//!
+//! Requests to open file ``/internal/index.html'' will be handled by
+//! attempting to open ``/index.html'' in the internal file system pointed to
+//! by \e g_pui8FSImage. Similarly, opening ``/sdcard/images/logo.gif'' will
+//! result in a call to the FAT f_open function requesting
+//! ``0:/images/logo.gif''. If a request to open ``index.htm'' is received,
+//! this is handled by attempting to open ``index.htm'' in the default internal
+//! file system image, \e g_pui8FSDefault.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Check for non-zero parameters in debug builds.
+ //
+ ASSERT(psMountPoints);
+ ASSERT(ui32NumMountPoints);
+
+ //
+ // Remember the mount point information we have been given.
+ //
+ if(psMountPoints && ui32NumMountPoints)
+ {
+ //
+ // Remember the information passed.
+ //
+ g_psMountPoints = psMountPoints;
+ g_ui32NumMountPoints = ui32NumMountPoints;
+
+ //
+ // Check to determine if any of the mount points refer to FAT file
+ // system drivers. We also hijack this loop to determine what the
+ // default mount point (if any) is.
+ //
+ g_bFatFsEnabled = false;
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // If the pui8FSImage field of a mount point structure is NULL,
+ // this implies that we are using the FAT file system for that
+ // node.
+ //
+ if(!g_psMountPoints[ui32Loop].pui8FSImage)
+ {
+ g_bFatFsEnabled = true;
+ }
+
+ //
+ // Does this entry describe the default mount point?
+ //
+ if(g_psMountPoints[ui32Loop].pcNamePrefix == NULL)
+ {
+ g_ui32DefaultMountIndex = ui32Loop;
+ }
+ }
+
+ return(true);
+ }
+ else
+ {
+ //
+ // Return an error due to being passed a bad parameter.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Provides a periodic tick for the file system.
+//!
+//! \param ui32TickMS is the number of milliseconds which have elapsed since
+//! the last time this function was called.
+//!
+//! Applications making use of the file system wrapper with underlying FatFs
+//! drives must call this function at least once every 10 milliseconds to
+//! provide a time reference for use by the file system. It is typically
+//! called in the context of the application's SysTick interrupt handler or
+//! from the handler of some other timer interrupt.
+//!
+//! If only binary file system images are in use, this function need not be
+//! called.
+//!
+//! \return None
+//
+//
+//*****************************************************************************
+void
+fs_tick(uint32_t ui32TickMS)
+{
+ static uint32_t ui32TickCounter = 0;
+
+ //
+ // Check if the file system has been enabled yet.
+ //
+ if(!g_bFatFsEnabled)
+ {
+ return;
+ }
+
+ //
+ // Increment the tick counter.
+ //
+ ui32TickCounter += ui32TickMS;
+
+ //
+ // Check to see if the FAT FS tick needs to run.
+ //
+ if(ui32TickCounter >= 10)
+ {
+ ui32TickCounter = 0;
+ disk_timerproc();
+ }
+}
+
+//*****************************************************************************
+//
+//! Opens a file.
+//!
+//! \param pcName points to a NULL terminated string containing the path and
+//! file name to open.
+//!
+//! This function opens a file and returns a handle allowing it to be read.
+//!
+//! \return Returns a valid file handle on success or NULL on failure.
+//
+//*****************************************************************************
+struct fs_file *
+fs_open(const char *pcName)
+{
+ const struct fsdata_file *psTree;
+ const struct fsdata_file *psEnd = NULL;
+ struct fs_file *psFile = NULL;
+ fs_wrapper_data *psWrapper;
+ FRESULT fresult = FR_OK;
+ bool bPosInd = false;
+ char *pcFSFilename;
+ char *pcFilename;
+ uint32_t ui32Length;
+
+ //
+ // Allocate memory for the file system structure.
+ //
+ psFile = mem_malloc(sizeof(struct fs_file));
+ if(NULL == psFile)
+ {
+ return(NULL);
+ }
+
+ //
+ // Allocate memory for our internal control structure.
+ //
+ psFile->pextension = mem_malloc(sizeof(fs_wrapper_data));
+ psWrapper = (fs_wrapper_data *)psFile->pextension;
+
+ if(NULL == psWrapper)
+ {
+ return(NULL);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ psWrapper->ui32MountIndex = fs_find_mount_index(pcName, &pcFSFilename);
+ if(psWrapper->ui32MountIndex == BAD_MOUNT_INDEX)
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ mem_free(psWrapper);
+ mem_free(psFile);
+ return(NULL);
+ }
+
+ //
+ // Enable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Are we opening a file on an internal file system image?
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage)
+ {
+ //
+ // Initialize the file system tree pointer to the root of the linked
+ // list for this mount point's file system image.
+ //
+ psTree = ((const struct fsdata_file *)
+ g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage);
+
+ //
+ // Which type of file system are we dealing with?
+ //
+ if(psTree->next == FILE_SYSTEM_MARKER)
+ {
+ //
+ // If we found the marker, this is a position independent file
+ // system image. Remember this and fix up the pointer to the
+ // first descriptor by skipping over the 4 byte marker and the
+ // 4 byte image size entry. We also keep track of where the file
+ // system image ends since this allows us to do a bit more error
+ // checking later.
+ //
+ bPosInd = true;
+ ui32Length = *(uint32_t *)((uint8_t *)psTree + 4);
+ psTree = (struct fsdata_file *)((int8_t *)psTree + 8);
+ psEnd = (struct fsdata_file *)((int8_t *)psTree + ui32Length);
+ }
+
+ //
+ // Begin processing the linked list, looking for the requested file
+ // name.
+ //
+ while(NULL != psTree)
+ {
+ //
+ // Compare the requested file "name" to the file name in the
+ // current node.
+ //
+ if(ustrncmp(pcFSFilename,
+ FS_POINTER(psTree, psTree->name, bPosInd),
+ psTree->len) == 0)
+ {
+ //
+ // Fill in the data pointer and length values from the
+ // linked list node.
+ //
+ psFile->data = FS_POINTER(psTree, psTree->data, bPosInd);
+ psFile->len = psTree->len;
+
+ //
+ // For now, we setup the read index to the end of the file,
+ // indicating that all data has been read. This indicates that
+ // all the data is currently available in a contiguous block
+ // of memory (which is always the case with an internal file
+ // system image).
+ //
+ psFile->index = psTree->len;
+
+ //
+ // We are not using a FAT file system file and don't need to
+ // remap the filename so set these pointers to NULL.
+ //
+ psWrapper->psFATFile = NULL;
+
+ //
+ // Exit the loop and return the file system pointer.
+ //
+ break;
+ }
+
+ //
+ // If we get here, we did not find the file at this node of the
+ // linked list. Get the next element in the list. We can't just
+ // assign psTree from psTree->next since this will give us the
+ // wrong pointer for a position independent image (where the values
+ // in the structure are offsets from the start of the file
+ // descriptor, not absolute pointers) but we do know that a 0 in
+ // the "next" field does indicate that this is the last file so we
+ // can use that info to force the loop to exit at the end.
+ //
+ if(psTree->next == 0)
+ {
+ psTree = NULL;
+ }
+ else
+ {
+ psTree = (struct fsdata_file *)FS_POINTER(psTree, psTree->next,
+ bPosInd);
+
+ //
+ // If this is a position independent file system image, we can
+ // also check that the new node is within the image. If it
+ // isn't, the image is corrupted to stop the search.
+ //
+ if(bPosInd && (psTree >= psEnd))
+ {
+ psTree = NULL;
+ }
+ }
+ }
+
+ //
+ // If we didn't find the file, ptTee will be NULL. Make sure we
+ // return a NULL pointer if this happens.
+ //
+ if(NULL == psTree)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ else
+ {
+ //
+ // This file is on the FAT file system.
+ //
+
+ //
+ // Allocate memory for the Fat File system handle.
+ //
+ psWrapper->psFATFile = mem_malloc(sizeof(FIL));
+ if(NULL == psWrapper->psFATFile)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ //
+ // Reformat the filename to start with the FAT logical drive
+ // number.
+ //
+ ui32Length = ustrlen(pcFSFilename) + 16;
+ pcFilename = mem_malloc(ui32Length);
+ if(!pcFilename)
+ {
+ //
+ // Can't allocate temporary storage for the reformatted
+ // filename!
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ usnprintf(pcFilename, ui32Length, "%d:%s",
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ ui32DriveNum, pcFSFilename);
+ //
+ // Attempt to open the file on the Fat File System.
+ //
+ fresult = f_open(psWrapper->psFATFile, pcFilename, FA_READ);
+
+ //
+ // Free the filename storage
+ //
+ mem_free(pcFilename);
+
+ //
+ // Did we open the file correctly?
+ //
+ if(FR_OK == fresult)
+ {
+ //
+ // Yes - fill in the file structure to indicate that a
+ // FAT file is in use.
+ //
+ psFile->data = NULL;
+ psFile->len = 0;
+ psFile->index = 0;
+ }
+ else
+ {
+ //
+ // If we get here, we failed to find the file on the FAT
+ // file system so free up the FAT handle/object.
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psWrapper);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ }
+ }
+
+ //
+ // Disable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ return(psFile);
+}
+
+//*****************************************************************************
+//
+//! Closes a file.
+//!
+//! \param phFile is the handle of the file that is to be closed. This will
+//! have been returned by an earlier call to fs_open().
+//!
+//! This function closes the file identified by \e phFile and frees all
+//! resources associated with the file handle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+fs_close(struct fs_file *phFile)
+{
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // If a Fat file was opened, free its object.
+ //
+ if(psWrapper->psFATFile)
+ {
+ //
+ // Close the file.
+ //
+ f_close(psWrapper->psFATFile);
+
+ //
+ // Free the file object.
+ //
+ mem_free(psWrapper->psFATFile);
+ }
+
+ //
+ // Free our file wrapper control structure.
+ //
+ mem_free(phFile->pextension);
+
+ //
+ // Free the main file system object.
+ //
+ mem_free(phFile);
+}
+
+//*****************************************************************************
+//
+//! Reads data from an open file.
+//!
+//! \param phFile is the handle of the file which is to be read. This will
+//! have been returned by a previous call to fs_open().
+//! \param pcBuffer points to the first byte of the buffer into which the
+//! data read from the file will be copied. This buffer must be large enough
+//! to hold \e iCount bytes.
+//! \param iCount is the maximum number of bytes of data that are to be read
+//! from the file.
+//!
+//! This function reads the next block of data from the given file into a
+//! buffer and returns the number of bytes read or -1 if the end of the file
+//! has been reached.
+//!
+//! \return Returns the number of bytes read from the file or -1 if the end of
+//! the file has been reached and no more data is available.
+//
+//*****************************************************************************
+int
+fs_read(struct fs_file *phFile, char *pcBuffer, int iCount)
+{
+ int iAvailable, iRetcode;
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // Call the application's enable function for this physical medium (if
+ // an enable function has been provided).
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Check to see if a Fat File was opened and process it.
+ //
+ if(psWrapper->psFATFile)
+ {
+ uint32_t ui32BytesRead;
+ FRESULT fresult;
+
+ //
+ // Read the data.
+ //
+ fresult = f_read(psWrapper->psFATFile, pcBuffer, iCount,
+ (UINT*)&ui32BytesRead);
+ if((fresult != FR_OK) || (ui32BytesRead == 0))
+ {
+ iRetcode = -1;
+ }
+ else
+ {
+ iRetcode = (int)ui32BytesRead;
+ }
+ }
+ else
+ {
+ //
+ // We are reading a file from a file system image. Check to see if
+ // more data is available.
+ //
+ if(phFile->len == phFile->index)
+ {
+ //
+ // There is no remaining data. Return a -1 for EOF indication.
+ //
+ return(-1);
+ }
+
+ //
+ // Determine how much data we can copy. The minimum of the 'iCount'
+ // parameter or the available data in the file system buffer.
+ //
+ iAvailable = phFile->len - phFile->index;
+ if(iAvailable > iCount)
+ {
+ iAvailable = iCount;
+ }
+
+ //
+ // Copy the data.
+ //
+ memcpy(pcBuffer, phFile->data + phFile->index, iAvailable);
+ phFile->index += iAvailable;
+
+ //
+ // Return the count of data that we copied.
+ //
+ iRetcode = iAvailable;
+ }
+
+ //
+ // Call the application's disable function now that we have finished
+ // accessing the file.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Return the number of bytes read.
+ //
+ return(iRetcode);
+}
+
+//*****************************************************************************
+//
+//! Maps a path string containing mount point names to a path suitable for
+//! use in calls to the FatFs APIs.
+//!
+//! \param pcPath points to a string containing a path in the namespace
+//! defined by the mount information passed to fs_init().
+//! \param pcMapped points to a buffer into which the mapped path string will
+//! be written.
+//! \param iLen is the size, in bytes, of the buffer pointed to by pcMapped.
+//!
+//! This function may be used by applications which want to make use of FatFs
+//! functions which are not directly mapped by the fswrapper layer. A path
+//! in the namespace defined by the mount points passed to function fs_init()
+//! is translated to an equivalent path in the FatFs namespace and this may
+//! then be used in a direct call to functions such as f_opendir() or
+//! f_getfree().
+//!
+//! \return Returns \b true on success or \b false if fs_init() has not
+//! been called, if the path provided maps to an internal file system image
+//! rather than a FatFs logical drive or if the buffer pointed to by
+//! \e pcMapped is too small to fit the output string.
+//
+//*****************************************************************************
+bool
+fs_map_path(const char *pcPath, char *pcMapped, int iLen)
+{
+ char *pcFSFilename;
+ uint32_t ui32MountIndex;
+ int iCount;
+
+ //
+ // If no mount points have been defined, return an error.
+ //
+ if(!g_psMountPoints)
+ {
+ return(false);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ ui32MountIndex = fs_find_mount_index(pcPath, &pcFSFilename);
+
+ //
+ // If we got a bad mount index or the index returned represents a mount
+ // point that is not in the FAT file system, return an error.
+ //
+ if((ui32MountIndex == BAD_MOUNT_INDEX) ||
+ (g_psMountPoints[ui32MountIndex].pui8FSImage))
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ return(false);
+ }
+
+ //
+ // Now we can generate the FatFs namespace path string.
+ //
+ iCount = usnprintf(pcMapped, iLen, "%d:%s",
+ g_psMountPoints[ui32MountIndex].ui32DriveNum,
+ pcFSFilename);
+
+ //
+ // Tell the user how we got on. The count returned by usnprintf is the
+ // number of characters that should have been written, excluding the
+ // terminating NULL so we use this to check for overflow of the output
+ // buffer.
+ //
+ return((iLen >= (iCount + 1)) ? true : false);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************