/********************************************************************************/
/*                                                                              */
/*    File Name:         ffs_pc.c                                               */
/*                                                                              */
/*    Purpose:           This file contains the internal functions related to   */
/*                       the Flash File System.                                 */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       02/27/02        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/* (C) Copyright 2002 by Texas Instruments Incorporated, All Rights Reserved.   */
/*                                                                              */
/********************************************************************************/

#include "ffs_pc_api.h"

/********************************* NAME LENGTHS *********************************/
/*                                                                              */
/* Define the maximum lengths.                                                  */
#define FFS_MAX_PATH_LENGTH                           (MAX_PATH)
#define FFS_MAX_OBJECT_LENGTH                         (20)


/*************************** INTERNAL FILE DESCRIPTOR ***************************/
/*                                                                              */
/* Define the internal file descriptor.                                         */
/*                                                                              */
/*      __ Open the file for appending.                                         */
/*     |                               __ File handle (30 bits).                */
/*   __|______________________________|_____________________________            */
/*  | ¦ ¦                                                           |           */
/*  |0¦ ¦                                                           |           */
/*  |_¦_¦_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._|           */
typedef union
{
	INT32  fd;
	struct
	{
		INT32  handle : 30;
		INT32  append : 1;
	} ifd;
} T_FFS_IFD;


/* Define the directory nesting depth.                                          */
#define FFS_DIR_NESTING_DEPTH                         (0x06)

/* Define the directory dedicated to the Flash File System.                     */
#define FFS_DIR                                       ("C:\\FFS")


/******************** GLOBAL FLASH FILE SYSTEM CONTROL BLOCK ********************/
/*                                                                              */
/* Define a global structure used to gather information related to the 'Global  */
/* Flash File System Control Block'.                                            */
typedef struct
{
	BOOLEAN        is_running;								  /* Indicates      */
															  /* whether the    */
															  /* Flash File     */
															  /* System is      */
															  /* running.       */
	char           current_working_dir[FFS_MAX_PATH_LENGTH];  /* Indicates the  */
															  /* current        */
															  /* working        */
															  /* directory.     */
} T_FFS_CTRL_BLK;


/******************** GLOBAL FLASH FILE SYSTEM CONTROL BLOCK ********************/
/*                                                                              */
T_FFS_CTRL_BLK gbl_ffs_ctrl_blk;

/* Define a pointer to the 'Global Flash File System Control Block'.            */
T_FFS_CTRL_BLK  *gbl_ffs_ctrl_blk_p = NULL;


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_init_working_folder                                */
/*                                                                              */
/*    Purpose:           This function sets the working directory up.           */
/*                                                                              */
/*    Input Parameter:   None.                                                  */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       02/28/02        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_init_working_folder (void)
{

/******************** ffs_init_working_folder function begins *******************/

	/* First, check whether the current working directory matches the reference */
	/* one. Otherwise, create the reference directory.                          */

  strcpy (gbl_ffs_ctrl_blk_p->current_working_dir, FFS_DIR);

	if ((CreateDirectory (TEXT(gbl_ffs_ctrl_blk_p->current_working_dir), \
						  NULL) == FALSE) && \
		(GetLastError () != ERROR_ALREADY_EXISTS))
	{
		return (EFFS_DRIVER);
	}

	return (EFFS_OK);

} /******************* End of ffs_init_working_folder function ******************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_is_valid_object_name                               */
/*                                                                              */
/*    Purpose:           This function checks whether the name of an object is  */
/*                       valid, according to the Microsoft® Win32® Programmer's */
/*                       Reference.                                             */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       object_name_p      - Points to the name of the object to check         */
/*                            (0-terminated string).                            */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:  None.                                                  */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/27/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_is_valid_object_name (const char  *object_name_p)
{
    /* Declare local variables.                                                 */
	DWORD  object_count = 0x00000000;
    DWORD  path_count   = 0x00000000;

/******************* ffs_is_valid_object_name function begins *******************/

	/* First, check for the leading '/' character.                              */
	if (object_name_p[path_count++] != '/')
	{
		return (EFFS_BADNAME);
	}

	/* Then, check for invalid characters or too long object names.             */
	for (;
		 path_count <= FFS_MAX_PATH_LENGTH;
		 path_count++)
	{

		/* Check for invalid characters.                                        */
		if (((object_name_p[path_count] >= 'a') && (object_name_p[path_count] <= 'z')) || \
			((object_name_p[path_count] >= 'A') && (object_name_p[path_count] <= 'Z')) || \
			((object_name_p[path_count] >= '0') && (object_name_p[path_count] <= '9')) || \
			(object_name_p[path_count] == '#') || \
			(object_name_p[path_count] == '$') || \
			(object_name_p[path_count] == '%') || \
			(object_name_p[path_count] == '+') || \
			(object_name_p[path_count] == '-') || \
			(object_name_p[path_count] == '.') || \
			(object_name_p[path_count] == '_'))
		{

			/* Check for too long object names.                                 */
			if (++object_count > FFS_MAX_OBJECT_LENGTH)
			{
				return (EFFS_NAMETOOLONG);
			}
			continue;
		}

		/* Proceed with the next object name.                                   */
		if (object_name_p[path_count] == '/')
		{

			/* Check for empty object names.                                    */
			if (object_count == 0x00000000)
			{
				break;
			}
			object_count = 0x00000000;
			continue;
		}
		break;
	}

	/* Check for the ending '/' character.                                      */
    if ((object_name_p[path_count] == '\x00') && \
		(object_count == 0x00000000))
	{
		return (EFFS_NOTADIR);
	}

	/* Report an error whether an object name contains some illegal characters. */
    if ((object_name_p[path_count] != '\x00') || \
		(object_count == 0x00000000))
	{
		return (EFFS_BADNAME);
	}
	return (EFFS_OK);

} /****************** End of ffs_is_valid_object_name function ******************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_convert_to_win32_filename                          */
/*                                                                              */
/*    Purpose:           This function converts filenames in accordance with    */
/*                       the Microsoft® Win32® Programmer's Reference.          */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       filename_p         - Points to the filename to convert (0-terminated   */
/*                            string).                                          */
/*                                                                              */
/*    Output Parameter:                                                         */
/*       win32_filename_p   - Points to the filename as defined in the          */
/*                            Microsoft® Win32® Programmer's Reference.         */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/27/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_convert_to_win32_filename (const char  *filename_p,
										 char        win32_filename_p[FFS_MAX_PATH_LENGTH])
{
    /* Declare local variables.                                                 */
	DWORD  filename_len = 0x00000000;
	DWORD  pathname_len = 0x00000000;

/***************** ffs_convert_to_win32_filename function begins ****************/

	/* Get the lengths of both filenames.                                       */
	filename_len = strlen (filename_p);
	pathname_len = strlen (gbl_ffs_ctrl_blk_p->current_working_dir);

	/* Convert the filename in accordance with the Microsoft® Win32®            */
	/* Programmer's Reference. Abort whether the filename is too long.          */
	if ((pathname_len + filename_len + 0x00000001) > FFS_MAX_PATH_LENGTH)
	{
		return (EFFS_NAMETOOLONG);
	}
	(void) memcpy (win32_filename_p,
				   gbl_ffs_ctrl_blk_p->current_working_dir,
				   pathname_len);
	(void) memcpy (win32_filename_p + pathname_len,
				   filename_p,
				   filename_len);
	win32_filename_p[pathname_len + filename_len] = '\x00';
	return (EFFS_OK);

} /**************** End of ffs_convert_to_win32_filename function ***************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_open                                               */
/*                                                                              */
/*    Purpose:           This function opens or creates a file.                 */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       pathname_p         - Points to the name of the file to open or create  */
/*                            (0-terminated string).                            */
/*       flags              - Specifies the modes used to open the file.        */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              The append concept while opening files is not          */
/*                       supported, according to the Microsoft® Win32®          */
/*                       Programmer's Reference.                                */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/27/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_FD ffs_open (const char        *pathname_p,
				   T_FFS_OPEN_FLAGS  flags)
{
    /* Declare local variables.                                                 */
	char       win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	DWORD      desired_access                        = GENERIC_WRITE;
	DWORD      creation_distribution                 = OPEN_EXISTING;
	HANDLE     handle                                = INVALID_HANDLE_VALUE;
	T_FFS_IFD  ifd                                   = {0x00000000};
	T_FFS_RET  return_status                         = EFFS_OK;

/*************************** ffs_open function begins ***************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert the filename as defined in the Microsoft® Win32®           */
	/* Programmer's Reference. Abort whether any error occurred.                */
	if (((return_status = ffs_is_valid_object_name (pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (pathname_p, \
														 win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* Convert flags as defined in the Microsoft® Win32® Programmer's           */
	/* Reference.                                                               */
	switch (flags & FFS_O_RDWR)
	{

		/* The file is opened as 'read-only'.                                   */
		case FFS_O_RDONLY:
			{

				/* 'Read-only' must not be combined with any other options.     */
				if (flags != FFS_O_RDONLY)
				{
					return (EFFS_INVALID);
				}
				desired_access = GENERIC_READ;
				break;
			}

		/* The file is opened as 'read-write'.                                  */
		case FFS_O_RDWR:
			{
				desired_access |= GENERIC_READ;
			}

		/* The file is opened as 'write-only'.                                  */
		case FFS_O_WRONLY:
			{
				switch (flags & ~FFS_O_RDWR)
				{

					/* Create the file if it does not exist, otherwise truncate */
					/* it.                                                      */
					case (FFS_O_CREATE | FFS_O_APPEND | FFS_O_TRUNC):
						{
							(ifd.ifd).append = TRUE;
						}
					case (FFS_O_CREATE | FFS_O_TRUNC):
						{
							creation_distribution = CREATE_ALWAYS;
							break;
						}

					/* Create the file if it does not exist, otherwise open it  */
					/* for appending.                                           */
					case (FFS_O_CREATE | FFS_O_APPEND):
						{
							(ifd.ifd).append      = TRUE;
							creation_distribution = OPEN_ALWAYS;
							break;
						}

					/* Create the file if it does not exist, otherwise the      */
					/* function fails.                                          */
					case (FFS_O_CREATE | FFS_O_EXCL):
						{
							creation_distribution = CREATE_NEW;
							break;
						}

					/* Create the file if it does not exist, otherwise open it. */
					case FFS_O_CREATE:
						{
							creation_distribution = OPEN_ALWAYS;
							break;
						}

					/* Truncate the file if it already exists, otherwise the    */
					/* function fails.                                          */
					case (FFS_O_APPEND | FFS_O_TRUNC):
						{
							(ifd.ifd).append = TRUE;
						}
					case FFS_O_TRUNC:
						{
							creation_distribution = TRUNCATE_EXISTING;
							break;
						}

					/* Open the file for appending if it already exists,        */
					/* otherwise the function fails.                            */
					case FFS_O_APPEND:
						{	
							(ifd.ifd).append = TRUE;
							break;
						}
					default:
						{
							break;
						}
				}
				break;
			}
		default:
			{
				return (EFFS_INVALID);
			}
	}

	/* Open/create the file as specified.                                       */
	if (((handle = CreateFile (win32_pathname_p, \
							   desired_access, \
							   0x0000, \
							   NULL, \
							   creation_distribution, \
							   FILE_ATTRIBUTE_NORMAL, \
							   NULL)) == INVALID_HANDLE_VALUE) || \
		(((ifd.ifd).append) && \
		 (SetFilePointer (handle, \
						  0x00000000, \
						  NULL, \
						  FILE_END) == 0xFFFFFFFF)))
	{

		/* Declare a local block variable.                                      */
		DWORD  error = NO_ERROR;

		/* Get the error code.                                                  */
		error = GetLastError ();

		/* If the file handle is valid, then close the file first.              */
		if (handle != INVALID_HANDLE_VALUE)
		{
			(void) CloseHandle (handle);
		}
		switch (error)
		{

			/* Unable to create a file when it already exists.                  */
			case ERROR_ALREADY_EXISTS:

			/* The file exists.                                                 */
			case ERROR_FILE_EXISTS:
				{
					return (EFFS_EXISTS);
				}

			/* The directory name is invalid.                                   */
			case ERROR_DIRECTORY:

			/* Unable to find the file specified.                               */
			case ERROR_FILE_NOT_FOUND:
				{
					return (EFFS_NOTFOUND);
				}

			/* Unable to open the file because too many files are currently     */
			/* open.                                                            */
			case ERROR_TOO_MANY_OPEN_FILES:
				{
					return (EFFS_NUMFD);
				}

			/* The disk is full.                                                */
			case ERROR_HANDLE_DISK_FULL:
				{
					return (EFFS_FSFULL);
				}

			/* The filename or directory name is syntactically incorrect.       */
			case ERROR_INVALID_NAME:
				{
					return (EFFS_BADNAME);
				}
			default:
				{
					return (EFFS_DRIVER);
				}
		}
	}

	/* If the file handle is invalid, then close the file.                      */
	if (((INT32) (handle)) & 0xC0000000)
	{
		(void) CloseHandle (handle);
		return (EFFS_NUMFD);
	}

	/* Get the file handle.                                                     */
	ifd.fd |= (INT32) (handle);
	return ((T_FFS_FD) (ifd.fd));

} /************************** End of ffs_open function **************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_close                                              */
/*                                                                              */
/*    Purpose:           This function closes an open file.                     */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       fd                 - Specifies the file descriptor associated with the */
/*                            file to close.                                    */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/27/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_close (T_FFS_FD  fd)
{
    /* Declare a local variable.                                                */
	T_FFS_IFD  ifd = {0x00000000};

/*************************** ffs_close function begins **************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, get the file handle.                                               */
	ifd.fd = fd;

	/* At last, close the file.                                                 */
	if (CloseHandle ((HANDLE) ((ifd.ifd).handle)) == FALSE)
	{
		return (EFFS_BADFD);
	}
	return (EFFS_OK);

} /************************** End of ffs_close function *************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_write                                              */
/*                                                                              */
/*    Purpose:           This function writes data to an open file.             */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       fd                 - Specifies the file descriptor associated with the */
/*                            open file.                                        */
/*       buffer_p           - Points to the buffer containing the data to be    */
/*                            written to the file.                              */
/*       size               - Specifies the number of bytes to write to the     */
/*                            file.                                             */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              This function is not responsible for (de)allocating    */
/*                       the buffer containing the data to be written to the    */
/*                       file.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_SIZE ffs_write (T_FFS_FD    fd,
					  void        *buffer_p,
					  T_FFS_SIZE  size)
{
    /* Declare local variables.                                                 */
	DWORD      bytes_written = 0x00000000;
	T_FFS_IFD  ifd           = {0x00000000};

/*************************** ffs_write function begins **************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, get the file handle.                                               */
	ifd.fd = fd;

	/* Then, check whether the file is opened for appending. Indeed, opening a  */
	/* file with append mode shall cause all subsequent writes to the file to   */
	/* be forced to end-of-file (EOF) position, regardless of intervening calls */
	/* to ffs_seek ().                                                          */
	if (((ifd.ifd).append) && \
		(SetFilePointer ((HANDLE) ((ifd.ifd).handle), \
						 0x00000000, \
						 NULL, \
						 FILE_END) == 0xFFFFFFFF))
	{
		return (EFFS_BADFD);
	}

	/* At last, write data to the file.                                         */
	if (WriteFile ((HANDLE) ((ifd.ifd).handle), \
				   buffer_p, \
				   size, \
				   &bytes_written, \
				   NULL) == FALSE)
	{

		/* Get the error code.                                                  */
		switch (GetLastError ())
		{

			/* Access denied.                                                   */
			case ERROR_ACCESS_DENIED:
				{
					return (EFFS_BADOP);
				}

			/* The disk is full.                                                */
			case ERROR_HANDLE_DISK_FULL:
				{
					return (EFFS_NOSPACE);
				}
			default:
				{
					return (EFFS_BADFD);
				}
		}
	}
	return (bytes_written);

} /************************** End of ffs_write function *************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_read                                               */
/*                                                                              */
/*    Purpose:           This function reads data from an open file.            */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       fd                 - Specifies the file descriptor associated with the */
/*                            open file.                                        */
/*       buffer_p           - Points to the buffer that receives the data read  */
/*                            from the file.                                    */
/*       size               - Specifies the number of bytes to be read from the */
/*                            file.                                             */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              This function is not responsible for (de)allocating    */
/*                       the buffer that receives the data read from the file.  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_SIZE ffs_read (T_FFS_FD    fd,
					 void        *buffer_p,
					 T_FFS_SIZE  size)
{
    /* Declare local variables.                                                 */
	DWORD      bytes_read = 0x00000000;
	T_FFS_IFD  ifd        = {0x00000000};

/*************************** ffs_read function begins ***************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, get the file handle.                                               */
	ifd.fd = fd;

	/* At last, read data from the file.                                        */
	if (ReadFile ((HANDLE) ((ifd.ifd).handle), \
				  buffer_p, \
				  size, \
				  &bytes_read, \
				  NULL) == FALSE)
	{
		return (EFFS_BADFD);
	}
	return (bytes_read);

} /************************** End of ffs_read function **************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_seek                                               */
/*                                                                              */
/*    Purpose:           This function moves the file pointer of an open file.  */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       fd                 - Specifies the file descriptor associated with the */
/*                            open file.                                        */
/*       offset             - Specifies the number of bytes to move file        */
/*                            pointer.                                          */
/*       whence             - Specifies the starting point for the file pointer */
/*                            move.                                             */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              This function does not allow the file pointer to be    */
/*                       set beyond the end-of-file (EOF) position, in contrary */
/*                       to the Microsoft® Win32® Programmer's Reference.       */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_SIZE ffs_seek (T_FFS_FD      fd,
					 T_FFS_SIZE    offset,
					 T_FFS_WHENCE  whence)
{
    /* Declare local variables.                                                 */
	DWORD      file_size        = 0x00000000;
	DWORD      new_file_pointer = 0x00000000;
	T_FFS_IFD  ifd              = {0x00000000};

/*************************** ffs_seek function begins ***************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, get the file handle.                                               */
	ifd.fd = fd;

	/* At last, move the file pointer and get the size of the file.             */
	if (((new_file_pointer = SetFilePointer ((HANDLE) ((ifd.ifd).handle), \
											 offset, \
											 NULL, \
											 whence)) != 0xFFFFFFFF) && \
		((file_size = GetFileSize ((HANDLE) ((ifd.ifd).handle), \
								   NULL)) != 0xFFFFFFFF))
	{

		/* Check whether the file pointer is beyond the end-of-file (EOF)       */
		/* position.                                                            */
		if (new_file_pointer <= file_size)
		{
			return (new_file_pointer);
		}

		/* In such a case, back to the former position.                         */
		if (SetFilePointer ((HANDLE) ((ifd.ifd).handle), \
							-offset, \
							NULL, \
							FILE_CURRENT) != 0xFFFFFFFF)
		{
			return (EFFS_INVALID);
		}
	}

	/* Get the error code.                                                      */
	switch (GetLastError ())
	{

		/* Invalid parameters.                                                  */
		case ERROR_INVALID_PARAMETER:

		/* Unable to move the file pointer before the beginning of the file.    */
		case ERROR_NEGATIVE_SEEK:

		/* Unable to set the file pointer on the specified file.                */
		case ERROR_SEEK_ON_DEVICE:
			{
				return (EFFS_INVALID);
			}
		default:
			{
				break;
			}
	}
	return (EFFS_BADFD);

} /************************** End of ffs_seek function **************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_ftruncate                                          */
/*                                                                              */
/*    Purpose:           This function truncates an open file by moving the     */
/*                       end-of-file (EOF) position.                            */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       fd                 - Specifies the file descriptor associated with the */
/*                            open file.                                        */
/*       length             - Specifies the number of bytes to move file        */
/*                            pointer.                                          */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              This function does not allow the file pointer to be    */
/*                       set beyond the end-of-file (EOF) position, in contrary */
/*                       to the Microsoft® Win32® Programmer's Reference.       */
/*                                                                              */
/*    Revision History:                                                         */
/*       02/13/02        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_ftruncate (T_FFS_FD      fd,
						 T_FFS_OFFSET  length)
{
    /* Declare a local variable.                                                */
	T_FFS_IFD  ifd = {0x00000000};

/************************* ffs_ftruncate function begins ************************/

	/* First, check whether the size is greater than the current file pointer   */
	/* position.                                                                */
	if (length < (T_FFS_OFFSET) (ffs_seek (fd, \
										   0, \
										   FFS_SEEK_CUR)))
	{
		return (EFFS_INVALID);
	}

	/* Move the end-of-file (EOF) position.                                     */
	switch (ffs_seek (fd, \
					  length, \
					  FFS_SEEK_SET))
	{

		/* Unable to move the file pointer beyond the end-of-file (EOF)         */
		/* position.                                                            */
		case EFFS_INVALID:
			{
				return (EFFS_OK);
			}

		/* File not found.                                                      */
		case EFFS_BADFD:
			{
				return (EFFS_BADFD);
			}
		default:
			{
				break;
			}
	}

	/* Then, get the file handle.                                               */
	ifd.fd = fd;

	/* At last, set the current file pointer as the end-of-file (EOF) position. */
	if (SetEndOfFile ((HANDLE) ((ifd.ifd).handle)) == FALSE)
	{
		return (EFFS_INVALID);
	}
	return (EFFS_OK);

} /************************ End of ffs_ftruncate function ***********************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_stat                                               */
/*                                                                              */
/*    Purpose:           This function gets information (meta-data) about a     */
/*                       object.                                                */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       pathname_p         - Points to the name of the file or directory       */
/*                            (0-terminated string).                            */
/*                                                                              */
/*    Output Parameter:                                                         */
/*       stat_p             - Points to information (meta-data) about the       */
/*                            object.                                           */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       02/28/01        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_stat (const char  *pathname_p,
					T_FFS_STAT  *stat_p)
{
    /* Declare local variables.                                                 */
	char             win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	HANDLE           search_handle                         = INVALID_HANDLE_VALUE;
	T_FFS_RET        return_status                         = EFFS_OK;
	WIN32_FIND_DATA  find_data;

/*************************** ffs_stat function begins ***************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert the name of the file or the directory as defined in the    */
	/* Microsoft® Win32® Programmer's Reference. Abort whether any error        */
	/* occurred.                                                                */
	if (((return_status = ffs_is_valid_object_name (pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (pathname_p, \
														 win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* Search for a file or a directory whose name matches the specified one.   */
	/* Abort whether the file or directory does not exist.                      */
	if (((search_handle = FindFirstFile (win32_pathname_p, \
										 &find_data)) != INVALID_HANDLE_VALUE) && \
		(find_data.dwFileAttributes != 0xFFFFFFFF))
	{

		/* Get information depending on attributes for the the file or          */
		/* directory.                                                           */
		if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			stat_p->type = OT_DIR;
			stat_p->size = 0x00000000;
		}
		else
		{
			stat_p->type = OT_FILE;
			stat_p->size = find_data.nFileSizeLow;
		}

		/* Close the search handle.                                             */
		(void) FindClose (search_handle);
		return (EFFS_OK);
	}
	return (EFFS_NOTFOUND);

} /************************** End of ffs_stat function **************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_remove                                             */
/*                                                                              */
/*    Purpose:           This function removes a file or a directory.           */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       pathname_p         - Points to the name of the file or directory to    */
/*                            remove (0-terminated string).                     */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              The variable callback_p is a pointer to a function     */
/*                       that follows the C Calling Convention. However, such a */
/*                       variable has to be redefined as a pointer to a         */
/*                       function that follows the Standard Calling Convention  */
/*                       by using _stdcall (avoid 'error C2152: '=' : pointers  */
/*                       to functions with different attributes' error          */
/*                       message).                                              */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_remove (const char  *pathname_p)
{
    /* Declare local variables.                                                 */
	BOOL       (_stdcall *callback_p) (LPCTSTR)      = DeleteFile;
	char       win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	DWORD      attributes                            = 0xFFFFFFFF;
	T_FFS_RET  return_status                         = EFFS_OK;

/************************** ffs_remove function begins **************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert the name of the file or the directory as defined in the    */
	/* Microsoft® Win32® Programmer's Reference. Abort whether any error        */
	/* occurred.                                                                */
	if (((return_status = ffs_is_valid_object_name (pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (pathname_p, \
														 win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* Get attributes for the specified file or directory.                      */
	if ((attributes = GetFileAttributes (win32_pathname_p)) == 0xFFFFFFFF)
	{
		return (EFFS_NOTFOUND);
	}

	/* Check whether the object is a directory.                                 */
	if (attributes & FILE_ATTRIBUTE_DIRECTORY)
	{
		callback_p = RemoveDirectory;
	}

	/* Remove the file or the directory.                                        */
	if ((*callback_p) (win32_pathname_p) == FALSE)
	{

		/* Get the error code.                                                  */
		switch (GetLastError ())
		{

			/* Access denied.                                                   */
			case ERROR_ACCESS_DENIED:

			/* Unable to access the file because it is being used by another    */
			/* process.                                                         */
			case ERROR_SHARING_VIOLATION:
				{
					return (EFFS_LOCKED);
				}

			/* The directory is not empty.                                      */
			case ERROR_DIR_NOT_EMPTY:
				{
					return (EFFS_DIRNOTEMPTY);
				}
			default:
				{
					return (EFFS_DRIVER);
				}
		}
	}
	return (EFFS_OK);

} /************************* End of ffs_remove function *************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_mkdir                                              */
/*                                                                              */
/*    Purpose:           This function creates a new directory.                 */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       pathname_p         - Points to the name of the directory to create     */
/*                            (0-terminated string).                            */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_mkdir (const char  *pathname_p)
{
    /* Declare local variables.                                                 */
	char       *object_name_p                         = NULL;
	char       pathname_parsed_p[FFS_MAX_PATH_LENGTH] = "";
	char       win32_pathname_p[FFS_MAX_PATH_LENGTH]  = "";
	DWORD      dir_nesting_depth                      = 0x00000000;
	T_FFS_RET  return_status                          = EFFS_OK;

/*************************** ffs_mkdir function begins **************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert the name of the directory as defined in the Microsoft®     */
	/* Win32® Programmer's Reference. Abort whether any error occurred.         */
	if (((return_status = ffs_is_valid_object_name (pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (pathname_p, \
														 win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* At last, check whether the directory nesting depth is exceeded. Thus,    */
	/* search for '/' characters from the end of the name of the directory.     */
	(void) strcpy (pathname_parsed_p,
				   pathname_p);
	while (((object_name_p = strrchr (pathname_parsed_p, \
									  '/')) != NULL) && \
		   (dir_nesting_depth <= FFS_DIR_NESTING_DEPTH))
	{

		/* Check for '/..' object names.                                        */
		if (strcmp (object_name_p, \
					"/..") == 0x00000000)
		{
			dir_nesting_depth--;
		}
		else
		{

			/* Check for '/.' object names.                                     */
			if (strcmp (object_name_p, \
						"/.") != 0x00000000)
			{
				dir_nesting_depth++;				
			}
		}

		/* Truncate the name of the directory in order to search for other '/'  */
		/* characters backwards.                                                */
		pathname_parsed_p[object_name_p - pathname_parsed_p] = '\x00';
	}

	/* Abort whether the directory nesting depth is exceeded.                   */
	if (dir_nesting_depth > FFS_DIR_NESTING_DEPTH)
	{
		return (EFFS_PATHTOODEEP);
	}

	/* Create the new directory.                                                */
	if (CreateDirectory (win32_pathname_p, \
						 NULL) == FALSE)
	{

		/* Get the error code.                                                  */
		switch (GetLastError ())
		{

			/* The directory already exists.                                    */
			case ERROR_ALREADY_EXISTS:
				{
					return (EFFS_EXISTS);
				}

			/* Unable to find the specified directory.                          */
			case ERROR_PATH_NOT_FOUND:
				{
					return (EFFS_NOTADIR);
				}
			default:
				{
					return (EFFS_DRIVER);
				}
		}
	}
	return (EFFS_OK);

} /************************** End of ffs_mkdir function *************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_opendir                                            */
/*                                                                              */
/*    Purpose:           This function opens a directory and returns the number */
/*                       of objects included into.                              */
/*                                                                              */
/*    Input Parameter:                                                          */
/*       pathname_p         - Points to the name of the directory to open       */
/*                            (0-terminated string).                            */
/*                                                                              */
/*    Output Parameter:                                                         */
/*       dir_p              - Points to information about the directory (refer  */
/*                            to ffs_readdir (···)).                            */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_SIZE ffs_opendir (const char  *pathname_p,
						T_FFS_DIR   *dir_p)
{
    /* Declare local variables.                                                 */
	char       win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	T_FFS_RET  return_status                         = EFFS_OK;

/************************** ffs_opendir function begins *************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert the name of the directory as defined in the Microsoft®     */
	/* Win32® Programmer's Reference. Abort whether any error occurred.         */
	if (((return_status = ffs_is_valid_object_name (pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (pathname_p, \
														 win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* Search for a directory whose name matches the specified one. Abort       */
	/* whether the directory does not exist.                                    */
	if (((dir_p->search_handle = FindFirstFile (strcat (win32_pathname_p, \
														"//*"), \
												&(dir_p->find_data))) != INVALID_HANDLE_VALUE) && \
		((dir_p->find_data).dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
	{

	    /* Declare local block variables.                                       */
		DWORD            object_count = 0x00000000;
		WIN32_FIND_DATA  find_data;

		/* Go downward through the directory tree.                              */
		while (FindNextFile (dir_p->search_handle, \
							 &find_data) == TRUE)
		{

			/* Disregard '.' and '..' subdirectories.                           */
			if (find_data.cFileName[0] == '.')
			{
				continue;
			}
			object_count++;
		}

		/* Close the search handle since no more objects left.                  */
		if (object_count > 0x00000000)
		{
			(void) FindClose (dir_p->search_handle);
		
			/* Back to the first object included in the directory.              */
			dir_p->search_handle = FindFirstFile (win32_pathname_p,
												  &(dir_p->find_data));
		}
		return (object_count);
	}
	return (EFFS_NOTFOUND);

} /************************* End of ffs_opendir function ************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_readdir                                            */
/*                                                                              */
/*    Purpose:           This function gets the next entry from a directory.    */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       dir_p              - Points to information about the directory (refer  */
/*                            to ffs_opendir (···)).                            */
/*       buffer_p           - Points to the buffer that receives the name of    */
/*                            the next entry.                                   */
/*       size               - Specifies the number of bytes of the buffer that  */
/*                            receives the name of the next entry.              */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              This function is not responsible for (de)allocating    */
/*                       the buffer that receives the name of the next entry.   */
/*                                                                              */
/*    Revision History:                                                         */
/*       06/29/01        David Lamy-Charrier                                    */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_SIZE ffs_readdir (T_FFS_DIR   *dir_p,
						char        *buffer_p,
						T_FFS_SIZE  size)
{

/************************** ffs_readdir function begins *************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Go downward through the directory tree.                                  */
	while (FindNextFile (dir_p->search_handle, \
						 &(dir_p->find_data)) == TRUE)
	{

		/* Disregard '.' and '..' subdirectories.                               */
		if ((dir_p->find_data).cFileName[0] == '.')
		{
			continue;
		}

		/* Copy the name of this entry.                                         */
		(void) strncpy (buffer_p, \
						(dir_p->find_data).cFileName, \
						size);
		return (strlen ((dir_p->find_data).cFileName));
	}

	/* Close the search handle since no more objects left.                      */
	if (GetLastError () == ERROR_NO_MORE_FILES)
	{
		(void) FindClose (dir_p->search_handle);
	}
	return (0x00000000);

} /************************* End of ffs_readdir function ************************/


/********************************************************************************/
/*                                                                              */
/*    Function Name:     ffs_rename                                             */
/*                                                                              */
/*    Purpose:           This function renames a file or a directory.           */
/*                                                                              */
/*    Input Parameters:                                                         */
/*       old_pathname_p     - Points to the name of the existing file or        */
/*                            directory (0-terminated string).                  */
/*       new_pathname_p     - Points to the new name for the file or the        */
/*                            directory (0-terminated string).                  */
/*                                                                              */
/*    Output Parameter:  None.                                                  */
/*                                                                              */
/*    Global Parameter:                                                         */
/*       gbl_ffs_ctrl_blk_p - Points to the 'Global Flash File System Control   */
/*                            Block'.                                           */
/*                                                                              */
/*    Note:              None.                                                  */
/*                                                                              */
/*    Revision History:                                                         */
/*       02/13/02        Pascal Pompei                                          */
/*                          - Create.                                           */
/*                                                                              */
/********************************************************************************/
T_FFS_RET ffs_rename (const char  *old_pathname_p,
					  const char  *new_pathname_p)
{
    /* Declare local variables.                                                 */
	char       old_win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	char       new_win32_pathname_p[FFS_MAX_PATH_LENGTH] = "";
	T_FFS_RET  return_status                             = EFFS_OK;

/************************** ffs_rename function begins **************************/

	/* First, check whether the Flash File System is running.                   */
	if ((gbl_ffs_ctrl_blk_p == NULL) || (gbl_ffs_ctrl_blk_p->is_running == FALSE))
	{
		return (EFFS_AGAIN);
	}

	/* Then, convert both pathnames as defined in the Microsoft® Win32®         */
	/* Programmer's Reference. Abort whether any error occurred.                */
	if (((return_status = ffs_is_valid_object_name (old_pathname_p)) != EFFS_OK) || \
		((return_status = ffs_is_valid_object_name (new_pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (old_pathname_p, \
														 old_win32_pathname_p)) != EFFS_OK) || \
		((return_status = ffs_convert_to_win32_filename (new_pathname_p, \
														 new_win32_pathname_p)) != EFFS_OK))
	{
		return (return_status);
	}

	/* Rename the file or the directory.                                        */
	if (MoveFile (old_win32_pathname_p, \
				  new_win32_pathname_p) == FALSE)
	{

		/* Get the error code.                                                  */
		switch (GetLastError ())
		{

			/* File or directory already exists.                                */
			case ERROR_ALREADY_EXISTS:

			/* The file exists.                                                 */
			case ERROR_FILE_EXISTS:
				{
					return (EFFS_EXISTS);
				}

			/* Access denied.                                                   */
			case ERROR_ACCESS_DENIED:

			/* Unable to access the file because it is being used by another    */
			/* process.                                                         */
			case ERROR_SHARING_VIOLATION:
				{
					return (EFFS_LOCKED);
				}
			default:
				{
					return (EFFS_NOTFOUND);
				}
		}
	}
	return (EFFS_OK);

} /************************* End of ffs_rename function *************************/


/* SAMIR
   Function taken from ffs_env.c               
*/
T_FFS_SIZE ffs_init (void)
{

/*************************** ffs_init function begins ***************************/

  gbl_ffs_ctrl_blk_p = &gbl_ffs_ctrl_blk;

	/* Initialize the current working directory.                                */
	if (ffs_init_working_folder () != EFFS_OK)
	{
		return (EFFS_AGAIN);
	}

	/* State the Flash File System as running.                                  */
	gbl_ffs_ctrl_blk_p->is_running = TRUE;

	return (EFFS_OK);

}