- Import FullFAT and add it to build.
authorAleksey Bragin <aleksey@reactos.org>
Mon, 28 Sep 2009 18:41:51 +0000 (18:41 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Mon, 28 Sep 2009 18:41:51 +0000 (18:41 +0000)
svn path=/trunk/; revision=43212

30 files changed:
reactos/include/reactos/libs/fullfat/fat.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_blk.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_config.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_crc.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_dir.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_error.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_fat.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_file.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_hash.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_ioman.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_memory.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_safety.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_string.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_time.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/ff_types.h [new file with mode: 0644]
reactos/include/reactos/libs/fullfat/fullfat.h [new file with mode: 0644]
reactos/lib/3rdparty/3rdparty.rbuild
reactos/lib/3rdparty/fullfat/ff_blk.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_crc.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_dir.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_dir.h [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_error.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_fat.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_file.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_hash.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_ioman.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_memory.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_safety.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_string.c [new file with mode: 0644]
reactos/lib/3rdparty/fullfat/ff_time.c [new file with mode: 0644]

diff --git a/reactos/include/reactos/libs/fullfat/fat.h b/reactos/include/reactos/libs/fullfat/fat.h
new file mode 100644 (file)
index 0000000..908cb36
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+#ifndef _FAT_H_
+#define _FAT_H_
+
+/*
+       This file defines offsets to various data for the FAT specification.
+*/
+
+// MBR / PBR Offsets
+
+#define FF_FAT_BYTES_PER_SECTOR                0x00B
+#define FF_FAT_SECTORS_PER_CLUS                0x00D
+#define FF_FAT_RESERVED_SECTORS                0x00E
+#define FF_FAT_NUMBER_OF_FATS          0x010
+#define FF_FAT_ROOT_ENTRY_COUNT                0x011
+#define FF_FAT_16_TOTAL_SECTORS                0x013
+#define FF_FAT_32_TOTAL_SECTORS                0x020
+#define FF_FAT_16_SECTORS_PER_FAT      0x016
+#define FF_FAT_32_SECTORS_PER_FAT      0x024
+#define FF_FAT_ROOT_DIR_CLUSTER                0x02C
+
+#define FF_FAT_PTBL                                    0x1BE
+#define FF_FAT_PTBL_LBA                                0x008
+
+#define FF_FAT_DELETED                         0xE5
+
+// Directory Entry Offsets
+#define FF_FAT_DIRENT_SHORTNAME                0x000
+#define FF_FAT_DIRENT_ATTRIB           0x00B
+#define FF_FAT_DIRENT_CREATE_TIME      0x00E   ///< Creation Time.
+#define FF_FAT_DIRENT_CREATE_DATE      0x010   ///< Creation Date.
+#define FF_FAT_DIRENT_LASTACC_DATE     0x012   ///< Date of Last Access.
+#define FF_FAT_DIRENT_CLUS_HIGH                0x014
+#define FF_FAT_DIRENT_LASTMOD_TIME     0x016   ///< Time of Last modification.
+#define FF_FAT_DIRENT_LASTMOD_DATE     0x018   ///< Date of Last modification.
+#define FF_FAT_DIRENT_CLUS_LOW         0x01A
+#define FF_FAT_DIRENT_FILESIZE         0x01C
+#define FF_FAT_LFN_ORD                         0x000
+#define FF_FAT_LFN_NAME_1                      0x001
+#define        FF_FAT_LFN_CHECKSUM                     0x00D
+#define FF_FAT_LFN_NAME_2                      0x00E
+#define FF_FAT_LFN_NAME_3                      0x01C
+
+// Dirent Attributes
+#define FF_FAT_ATTR_READONLY           0x01
+#define FF_FAT_ATTR_HIDDEN                     0x02
+#define FF_FAT_ATTR_SYSTEM                     0x04
+#define FF_FAT_ATTR_VOLID                      0x08
+#define FF_FAT_ATTR_DIR                                0x10
+#define FF_FAT_ATTR_ARCHIVE                    0x20
+#define FF_FAT_ATTR_LFN                                0x0F
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_blk.h b/reactos/include/reactos/libs/fullfat/ff_blk.h
new file mode 100644 (file)
index 0000000..2cc14ec
--- /dev/null
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_blk.h
+ *     @author         James Walmsley
+ *     @ingroup        BLK
+ *
+ *     Helps calculate block numbers.
+ **/
+
+#ifndef _FF_BLK_H_
+#define _FF_BLK_H_
+
+#include "ff_ioman.h"
+
+// PROTOTYPES:
+FF_T_UINT32 FF_getClusterPosition      (FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize);
+FF_T_UINT32 FF_getClusterChainNumber(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize);
+FF_T_UINT32 FF_getMajorBlockNumber     (FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize);
+FF_T_UINT8     FF_getMinorBlockNumber  (FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize);
+FF_T_UINT32 FF_getMinorBlockEntry      (FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_config.h b/reactos/include/reactos/libs/fullfat/ff_config.h
new file mode 100644 (file)
index 0000000..f81c79a
--- /dev/null
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+#ifndef _FF_CONFIG_H_
+#define _FF_CONFIG_H_
+/*
+       Here you can change the configuration of FullFAT as appropriate to your
+       platform.
+*/
+
+//---------- ENDIANESS
+#define FF_LITTLE_ENDIAN               // Choosing the Byte-order of your system is important. 
+//#define FF_BIG_ENDIAN                        // You may be able to provide better Byte-order swapping routines to FullFAT.
+                                                               // See ff_memory.c for more information.
+
+//---------- LFN (Long File-name) SUPPORT
+#define FF_LFN_SUPPORT                 // Comment this out if you don't want to worry about Patent Issues.
+                                                               // FullFAT works great with LFNs and without. You choose, its your project!
+
+//---------- LEGAL LFNS
+//#define FF_LEGAL_LFNS                        // Enabling this define causes FullFAT to not infringe on any of Microsoft's patents when making LFN names.
+                                                               // To do this, it will only create LFNs and no shortnames. Microsofts patents are only relevent when mapping
+                                                               // a shortname to a long name. This is the same way that Linux gets around the FAT legal issues:
+                                                               // see http://lkml.org/lkml/2009/6/26/314
+                                                               //
+                                                               // Enabling this may break compatibility with devices that cannot read LFN filenames.
+                                                               // Enabling this option causes no compatibility issues when reading any media.
+
+//---------- TIME SUPPORT
+#define FF_TIME_SUPPORT                        // Should FullFAT use time stamping. Only if you have provided the relevant time drivers in ff_time.c
+                                                               // Note, by default ff_time.c is set-up for the Windows Demonstration. Please see ff_time.c to disable.
+
+//---------- FILE SPACE ALLOCATION PERFORMANCE
+                                                               // Uncomment the prefered method. (Can only choose a single method).
+#define FF_ALLOC_DEFAULT               // Only allocate as much as is needed. (Provides good performance, without wasting space).
+//#define FF_ALLOC_DOUBLE              // Doubles the size of a file each time allocation is required. (When high-performance writing is required).
+
+//---------- Use Native STDIO.h
+//#define FF_USE_NATIVE_STDIO  // Makes FullFAT conform to values provided by your native STDIO.h file.
+
+//---------- FREE SPACE CALCULATION
+//#define FF_MOUNT_FIND_FREE   // Uncomment this option to check for Freespace on a volume mount. (Performance Penalty while mounting).
+                                                               // If not done in the mount, it will be done on the first call to FF_GetFreeSize() function.
+
+//---------- PATH CACHE
+#define FF_PATH_CACHE                  // Enables a simply Path Caching mechanism that increases performance of repeated operations
+                                                               // within the same path. E.g. a copy \dir1\*.* \dir2\*.* command.
+                                                               // This command requires FF_MAX_PATH number of bytes of memory. (Defined below, default 2600).
+
+
+#define FF_PATH_CACHE_DEPTH    2       // The Number of PATH's to Cache.
+
+//---------- DON'T USE MALLOC
+//#define FF_NO_MALLOC
+
+//---------- DON'T 
+
+
+//---------- Hash Table Support
+//#define FF_HASH_TABLE_SUPPORT        // Enable HASH to speed up file creation.
+#ifdef FF_HASH_TABLE_SUPPORT
+#define FF_HASH_FUNCTION       CRC16
+//#define FF_HASH_FUNCTION     CRC8
+#endif
+
+
+
+//---------- FAT12 SUPPORT
+#define FF_FAT12_SUPPORT               // Enable FAT12 Suppport. You can reduce the code-size by commenting this out.
+                                                               // If you don't need FAT12 support, why have it. FAT12 is more complex to process,
+                                                               // therefore savings can be made by not having it.
+
+//---------- 64-Bit Number Support
+#define FF_64_NUM_SUPPORT              // This helps to give information about the FreeSpace and VolumeSize of a partition or volume.
+                                                               // If you cannot support 64-bit integers, then FullFAT still works, its just that the functions:
+                                                               // FF_GetFreeSize() and FF_GetVolumeSize() don't make sense when reporting sizes > 4GB.
+
+//---------- Driver Sleep Time // How long FullFAT should sleep the thread for in ms, if FF_ERR_DRIVER_BUSY is recieved.
+#define FF_DRIVER_BUSY_SLEEP   20      
+
+//---------- Debugging Features
+#define FF_DEBUG                               // Enable the Error Code string functions. const FF_T_INT8 *FF_GetErrMessage( FF_T_SINT32 iErrorCode);
+                                                               // Uncommenting this just stops FullFAT error strings being compiled.
+
+//---------- Actively Determine if partition is FAT
+#define FF_FAT_CHECK                   // This is experimental, so if FullFAT won't mount your volume, comment this out
+                                                               // Also report the problem to james@worm.me.uk
+
+
+//---------- AUTOMATIC SETTINGS DO NOT EDIT -- These configure your options from above, and check sanity!
+
+#ifdef FF_LFN_SUPPORT
+#define FF_MAX_FILENAME                260
+#else
+#define        FF_MAX_FILENAME         13
+#endif
+
+#ifdef FF_USE_NATIVE_STDIO
+#ifdef MAX_PATH
+#define FF_MAX_PATH MAX_PATH
+#else
+#define FF_MAX_PATH    2600
+#endif
+#else
+#define FF_MAX_PATH    2600
+#endif
+
+#ifndef FF_ALLOC_DOUBLE
+#ifndef FF_ALLOC_DEFAULT
+#error FullFAT Invalid ff_config.h file: A file allocation method must be specified. See ff_config.h file.
+#endif
+#endif
+
+#ifdef FF_ALLOC_DOUBLE
+#ifdef FF_ALLOC_DEFAULT
+#error FullFAT Invalid ff_config.h file: Must choose a single option for File Allocation Method. DOUBLE or DEFAULT. See ff_config.h file.
+#endif
+#endif
+
+#ifndef FF_LITTLE_ENDIAN
+#ifndef FF_BIG_ENDIAN
+#error FullFAT Invalid ff_config.h file: An ENDIANESS must be defined for your platform. See ff_config.h file.
+#endif
+#endif
+
+#ifdef FF_LITTLE_ENDIAN
+#ifdef FF_BIG_ENDIAN
+#error FullFAT Invalid ff_config.h file: Cannot be BIG and LITTLE ENDIAN, choose either or BIG or LITTLE. See ff_config.h file.
+#endif
+#endif
+
+#ifdef FF_HASH_TABLE_SUPPORT
+
+#if FF_HASH_FUNCTION == CRC16
+#define FF_HASH_TABLE_SIZE 8192
+#elif FF_HASH_FUNCTION == CRC8
+#define FF_HASH_TABLE_SIZE 32
+#else
+#error Invalid Hashing function selected. CRC16 or CRC8! 
+#endif
+
+#endif
+
+#endif
diff --git a/reactos/include/reactos/libs/fullfat/ff_crc.h b/reactos/include/reactos/libs/fullfat/ff_crc.h
new file mode 100644 (file)
index 0000000..7349269
--- /dev/null
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_crc.h
+ *     @author         James Walmsley
+ *     @ingroup        CRC
+ *
+ **/
+
+#ifndef _FF_CRC_H_
+#define _FF_CRC_H_
+
+#include "ff_types.h"
+#include "ff_config.h"
+
+FF_T_UINT8     FF_GetCRC8      (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength);
+FF_T_UINT16 FF_GetCRC16        (FF_T_UINT8 *pbyData, FF_T_UINT32 stLength);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_dir.h b/reactos/include/reactos/libs/fullfat/ff_dir.h
new file mode 100644 (file)
index 0000000..7415eac
--- /dev/null
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_dir.h
+ *     @author         James Walmsley
+ *     @ingroup        DIR
+ **/
+#ifndef _FF_DIR_H_
+#define _FF_DIR_H_
+
+#include "ff_types.h"
+#include "ff_config.h"
+#include "ff_error.h"
+#include "ff_ioman.h"
+#include "ff_blk.h"
+#include "ff_fat.h"
+#include "fat.h"
+#include "ff_memory.h"
+#include "ff_time.h"
+#include "ff_hash.h"
+#include "ff_crc.h"
+#include "ff_file.h"
+#include <string.h>
+
+typedef struct {
+       FF_T_INT8       FileName[FF_MAX_FILENAME];
+       FF_T_UINT8      Attrib;
+       FF_T_UINT32 Filesize;
+       FF_T_UINT32     ObjectCluster;
+
+#ifdef FF_TIME_SUPPORT 
+       FF_SYSTEMTIME   CreateTime;             ///< Date and Time Created.
+       FF_SYSTEMTIME   ModifiedTime;   ///< Date and Time Modified.
+       FF_SYSTEMTIME   AccessedTime;   ///< Date of Last Access.
+#endif
+
+       //---- Book Keeping for FF_Find Functions
+       FF_T_UINT16     CurrentItem;    
+       FF_T_UINT32     DirCluster;
+       FF_T_UINT32     CurrentCluster;
+       FF_T_UINT32 AddrCurrentCluster;
+       //FF_T_UINT8    NumLFNs;
+} FF_DIRENT;
+
+               FF_ERROR        FF_GetEntry             (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_SINT8  FF_PutEntry         (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_SINT8      FF_FindEntry    (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
+               FF_ERROR        FF_FindFirst    (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
+               FF_ERROR        FF_FindNext             (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
+               void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
+               FF_T_SINT8      FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry);
+               FF_T_SINT8      FF_FetchEntry   (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
+               FF_T_SINT8      FF_PushEntry    (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
+               FF_T_BOOL       FF_isEndOfDir   (FF_T_UINT8 *EntryBuffer);
+               FF_T_SINT8      FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent);
+               FF_T_SINT8      FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
+
+void           FF_lockDIR              (FF_IOMAN *pIoman);
+void           FF_unlockDIR    (FF_IOMAN *pIoman);
+FF_T_UINT32                    FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent);
+FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path);
+FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen);
+
+
+FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
+FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
+void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+
+void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_error.h b/reactos/include/reactos/libs/fullfat/ff_error.h
new file mode 100644 (file)
index 0000000..8a48c8f
--- /dev/null
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+#ifndef _FF_ERROR_H_
+#define _FF_ERROR_H_
+
+/**
+ *     @file           ff_error.h
+ *     @author         James Walmsley
+ *     @ingroup        ERROR
+ **/
+
+#include "ff_config.h"
+#include "ff_types.h"
+
+/*     FullFAT defines different Error-Code spaces for each module. This ensures
+       that all error codes remain unique, and their meaning can be quickly identified.
+*/
+// Global Error Codes
+#define FF_ERR_NONE                                                              0     ///< No Error
+#define FF_ERR_NULL_POINTER                                             -2     ///< pIoman was NULL.
+#define FF_ERR_NOT_ENOUGH_MEMORY                                -3     ///< malloc() failed! - Could not allocate handle memory.
+#define FF_ERR_DEVICE_DRIVER_FAILED                             -4     ///< The Block Device driver reported a FATAL error, cannot continue.
+
+
+// IOMAN Error Codes
+#define        FF_ERR_IOMAN_BAD_BLKSIZE                                -11     ///< The provided blocksize was not a multiple of 512.
+#define FF_ERR_IOMAN_BAD_MEMSIZE                               -12     ///< The memory size was not a multiple of the blocksize.
+#define FF_ERR_IOMAN_DEV_ALREADY_REGD                  -13 ///< Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device.
+#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION            -14     ///< A mountable partition could not be found on the device.
+#define FF_ERR_IOMAN_INVALID_FORMAT                            -15     ///< The 
+#define FF_ERR_IOMAN_INVALID_PARTITION_NUM             -16     ///< The partition number provided was out of range.
+#define FF_ERR_IOMAN_NOT_FAT_FORMATTED                 -17     ///< The partition did not look like a FAT partition.
+#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE               -18 ///< IOMAN object BlkSize is not compatible with the blocksize of this device driver.
+#define FF_ERR_IOMAN_PARTITION_MOUNTED                 -19     ///< Device is in use by an actively mounted partition. Unmount the partition first.
+#define FF_ERR_IOMAN_ACTIVE_HANDLES                            -20 ///< The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache).
+
+
+// File Error Codes                                                            -30 +
+#define FF_ERR_FILE_ALREADY_OPEN                               -30     ///< File is in use.
+#define FF_ERR_FILE_NOT_FOUND                                  -31     ///< File was not found.
+#define FF_ERR_FILE_OBJECT_IS_A_DIR                            -32     ///< Tried to FF_Open() a Directory.
+#define FF_ERR_FILE_IS_READ_ONLY                               -33     ///< Tried to FF_Open() a file marked read only.
+#define FF_ERR_FILE_INVALID_PATH                               -34     ///< The path of the file was not found.
+#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE   -35
+#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE            -36
+#define FF_ERR_FILE_EXTEND_FAILED                              -37     ///< Could not extend the file.
+#define FF_ERR_FILE_DESTINATION_EXISTS                 -38
+#define FF_ERR_FILE_SOURCE_NOT_FOUND                   -39
+#define FF_ERR_FILE_DIR_NOT_FOUND                              -40
+#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT            -41
+
+// Directory Error Codes                                               -50 +
+#define FF_ERR_DIR_OBJECT_EXISTS                               -50     ///< A file or folder of the same name already exists in the current directory.
+#define FF_ERR_DIR_DIRECTORY_FULL                              -51     ///< No more items could be added to the directory.
+#define FF_ERR_DIR_END_OF_DIR                                  -52     ///
+#define FF_ERR_DIR_NOT_EMPTY                                   -53     ///< Cannot delete a directory that contains files or folders.
+#define FF_ERR_DIR_INVALID_PATH                                        -54 ///< Could not find the directory specified by the path.
+#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR                        -55     ///< Can't extend the root dir.
+
+// Fat Error Codes                                                             -70 +
+#define FF_ERR_FAT_NO_FREE_CLUSTERS                            -70     ///< No more free space is available on the disk.
+
+#ifdef FF_DEBUG
+const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode);
+#else
+#define FF_GetErrMessage(X) ""                                 // A special MACRO incase FF_GetErrMessage() isn't gated with FF_DEBUG
+#endif                                                                                 // Function call is safely replaced with a NULL string.
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_fat.h b/reactos/include/reactos/libs/fullfat/ff_fat.h
new file mode 100644 (file)
index 0000000..2e6ff67
--- /dev/null
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_fat.h
+ *     @author         James Walmsley
+ *     @ingroup        FAT
+ **/
+
+#ifndef _FF_FAT_H_
+#define _FF_FAT_H_
+
+#include "ff_config.h"
+#include "fat.h"
+#include "ff_ioman.h"
+#include "ff_blk.h"
+#include "ff_types.h"
+
+//---------- ERROR CODES
+
+
+//---------- PROTOTYPES
+
+               FF_T_UINT32 FF_getRealLBA                       (FF_IOMAN *pIoman, FF_T_UINT32 LBA);
+               FF_T_UINT32 FF_Cluster2LBA                      (FF_IOMAN *pIoman, FF_T_UINT32 Cluster);
+               FF_T_UINT32 FF_LBA2Cluster                      (FF_IOMAN *pIoman, FF_T_UINT32 Address);
+               FF_T_SINT32 FF_getFatEntry                      (FF_IOMAN *pIoman, FF_T_UINT32 nCluster);
+               FF_T_BOOL       FF_isEndOfChain                 (FF_IOMAN *pIoman, FF_T_UINT32 fatEntry);
+               FF_T_SINT8      FF_putFatEntry                  (FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value);
+               FF_T_UINT32 FF_FindFreeCluster          (FF_IOMAN *pIoman);
+               FF_T_UINT32     FF_ExtendClusterChain   (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count);
+               FF_T_SINT8      FF_UnlinkClusterChain   (FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count);
+               FF_T_UINT32     FF_TraverseFAT                  (FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count);
+               FF_T_UINT32 FF_CreateClusterChain       (FF_IOMAN *pIoman);
+               FF_T_UINT32 FF_GetChainLength           (FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain);
+               FF_T_UINT32 FF_FindEndOfChain           (FF_IOMAN *pIoman, FF_T_UINT32 Start);
+               FF_T_SINT8      FF_ClearCluster                 (FF_IOMAN *pIoman, FF_T_UINT32 nCluster);
+#ifdef FF_64_NUM_SUPPORT
+               FF_T_UINT64 FF_GetFreeSize                      (FF_IOMAN *pIoman);
+#else
+               FF_T_UINT32 FF_GetFreeSize                      (FF_IOMAN *pIoman);
+#endif
+               FF_T_UINT32 FF_FindFreeCluster          (FF_IOMAN *pIoman);
+               FF_T_UINT32 FF_CountFreeClusters        (FF_IOMAN *pIoman);
+               void            FF_lockFAT                              (FF_IOMAN *pIoman);
+               void            FF_unlockFAT                    (FF_IOMAN *pIoman);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_file.h b/reactos/include/reactos/libs/fullfat/ff_file.h
new file mode 100644 (file)
index 0000000..e74d4a6
--- /dev/null
@@ -0,0 +1,95 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_file.h
+ *     @author         James Walmsley
+ *     @ingroup        FILEIO
+ **/
+#ifndef _FF_FILE_H_
+#define _FF_FILE_H_
+
+#include "ff_config.h"
+#include "ff_types.h"
+#include "ff_ioman.h"
+#include "ff_dir.h"
+
+#ifdef FF_USE_NATIVE_STDIO
+#include <stdio.h>
+#define FF_SEEK_SET    SEEK_SET
+#define FF_SEEK_CUR    SEEK_CUR
+#define FF_SEEK_END    SEEK_END
+#else
+#define FF_SEEK_SET    1
+#define FF_SEEK_CUR    2
+#define FF_SEEK_END    3
+#endif
+
+typedef struct _FF_FILE {
+       FF_IOMAN                *pIoman;                        ///< Ioman Pointer!
+       FF_T_UINT32              Filesize;                      ///< File's Size.
+       FF_T_UINT32              ObjectCluster;         ///< File's Start Cluster.
+       FF_T_UINT32              iChainLength;          ///< Total Length of the File's cluster chain.
+       FF_T_UINT32              CurrentCluster;        ///< Prevents FAT Thrashing.
+       FF_T_UINT32              AddrCurrentCluster;///< Address of the current cluster.
+       FF_T_UINT32              iEndOfChain;           ///< Address of the last cluster in the chain.
+       FF_T_UINT32              FilePointer;           ///< Current Position Pointer.
+       //FF_T_UINT32    AppendPointer;         ///< Points to the Append from position. (The original filesize at open).
+       FF_T_UINT8               Mode;                          ///< Mode that File Was opened in.
+       FF_T_UINT32              DirCluster;            ///< Cluster Number that the Dirent is in.
+       FF_T_UINT16              DirEntry;                      ///< Dirent Entry Number describing this file.
+       //FF_T_UINT8             NumLFNs;                       ///< Number of LFNs associated with this file.
+       FF_T_BOOL                FileDeleted;
+       struct _FF_FILE *Next;                          ///< Pointer to the next file object in the linked list.
+} FF_FILE,
+*PFF_FILE;
+
+//---------- PROTOTYPES
+// PUBLIC (Interfaces):
+
+FF_FILE                *FF_Open                (FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError);
+FF_ERROR        FF_Close               (FF_FILE *pFile);
+FF_T_SINT32     FF_GetC                (FF_FILE *pFile);
+FF_T_SINT32     FF_Read                (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer);
+FF_T_SINT32     FF_Write               (FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer);
+FF_T_BOOL       FF_isEOF               (FF_FILE *pFile);
+FF_ERROR        FF_Seek                (FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin);
+FF_T_SINT32     FF_PutC                (FF_FILE *pFile, FF_T_UINT8 Value);
+FF_T_UINT32     FF_Tell                (FF_FILE *pFile);
+FF_ERROR        FF_RmFile              (FF_IOMAN *pIoman, const FF_T_INT8 *path);
+FF_ERROR        FF_RmDir               (FF_IOMAN *pIoman, const FF_T_INT8 *path);
+FF_T_BOOL       FF_isDirEmpty  (FF_IOMAN *pIoman, const FF_T_INT8 *Path);
+FF_ERROR        FF_Move                (FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile);
+FF_T_UINT8      FF_GetModeBits (FF_T_INT8 *Mode);
+
+// Private :
+
+#endif
diff --git a/reactos/include/reactos/libs/fullfat/ff_hash.h b/reactos/include/reactos/libs/fullfat/ff_hash.h
new file mode 100644 (file)
index 0000000..70f61af
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_hash.h
+ *     @author         James Walmsley
+ *     @ingroup        HASH
+ *
+ **/
+
+#ifndef _FF_HASH_H_
+#define _FF_HASH_H_
+
+#include "ff_config.h"
+#include "ff_types.h"
+#include "ff_error.h"
+
+struct                 _FF_HASH_TABLE;
+typedef struct _FF_HASH_TABLE *FF_HASH_TABLE;
+
+FF_HASH_TABLE  FF_CreateHashTable      ();
+FF_ERROR               FF_DestroyHashTable     (FF_HASH_TABLE pHash);
+FF_ERROR               FF_ClearHashTable       (FF_HASH_TABLE pHash);
+FF_ERROR               FF_ClearHash            (FF_HASH_TABLE pHash, FF_T_UINT32 nHash);
+FF_ERROR               FF_SetHash                      (FF_HASH_TABLE pHash, FF_T_UINT32 nHash);
+FF_T_BOOL              FF_isHashSet            (FF_HASH_TABLE pHash, FF_T_UINT32 nHash);
+
+#endif
diff --git a/reactos/include/reactos/libs/fullfat/ff_ioman.h b/reactos/include/reactos/libs/fullfat/ff_ioman.h
new file mode 100644 (file)
index 0000000..187ffa3
--- /dev/null
@@ -0,0 +1,232 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_ioman.h
+ *     @author         James Walmsley
+ *     @ingroup        IOMAN
+ **/
+
+#ifndef _FF_IOMAN_H_
+#define _FF_IOMAN_H_
+
+#include <stdlib.h>                                                    // Use of malloc()
+#include "ff_error.h"
+#include "ff_config.h"
+#include "ff_types.h"
+#include "ff_safety.h"                                         // Provide thread-safety via semaphores.
+#include "ff_memory.h"                                         // Memory access routines for ENDIAN independence.
+#include "ff_hash.h"
+
+//#define      FF_MAX_PARTITION_NAME   5               ///< Partition name length.
+
+#define FF_T_FAT12                             0x0A
+#define FF_T_FAT16                             0x0B
+#define FF_T_FAT32                             0x0C
+
+#define FF_MODE_READ                   0x01            ///< Buffer / FILE Mode for Read Access.
+#define        FF_MODE_WRITE                   0x02            ///< Buffer / FILE Mode for Write Access.
+#define FF_MODE_APPEND                 0x04            ///< FILE Mode Append Access.
+#define        FF_MODE_CREATE                  0x08            ///< FILE Mode Create file if not existing.
+#define FF_MODE_TRUNCATE               0x10            ///< FILE Mode Truncate an Existing file.
+#define FF_MODE_DIR                            0x80            ///< Special Mode to open a Dir. (Internal use ONLY!)
+
+#define FF_BUF_MAX_HANDLES             0xFFFF          ///< Maximum number handles sharing a buffer. (16 bit integer, we don't want to overflow it!)
+
+/**
+ *     I/O Driver Definitions
+ *     Provide access to any Block Device via the following interfaces.
+ *     Returns the number of blocks actually read or written.
+ **/
+
+/**
+ *     A special information structure for the FullFAT mass storage device
+ *     driver model.
+ **/
+typedef struct {
+       FF_T_UINT16 BlkSize;
+       FF_T_UINT32     TotalBlocks;
+} FF_DEVICE_INFO;
+
+typedef FF_T_SINT32 (*FF_WRITE_BLOCKS) (FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAddress, FF_T_UINT32 Count, void *pParam);
+typedef FF_T_SINT32 (*FF_READ_BLOCKS)  (FF_T_UINT8 *pBuffer, FF_T_UINT32 SectorAddress, FF_T_UINT32 Count, void *pParam);
+
+#define FF_ERR_DRIVER_BUSY                     -10
+#define FF_ERR_DRIVER_FATAL_ERROR      -11
+
+/**
+ *     @public
+ *     @brief  Describes the block device driver interface to FullFAT.
+ **/
+typedef struct {
+       FF_WRITE_BLOCKS fnWriteBlocks;  ///< Function Pointer, to write a block(s) from a block device.
+       FF_READ_BLOCKS  fnReadBlocks;   ///< Function Pointer, to read a block(s) from a block device.
+       FF_T_UINT16             devBlkSize;             ///< Block size that the driver deals with.
+       void                    *pParam;                ///< Pointer to some parameters e.g. for a Low-Level Driver Handle
+} FF_BLK_DEVICE;
+
+/**
+ *     @private
+ *     @brief  FullFAT handles memory with buffers, described as below.
+ *     @note   This may change throughout development.
+ **/
+typedef struct {
+       FF_T_UINT32             Sector;                 ///< The LBA of the Cached sector.
+       FF_T_UINT8              Mode;                   ///< Read or Write mode.
+       FF_T_UINT16             NumHandles;             ///< Number of objects using this buffer.
+       FF_T_UINT16             Persistance;    ///< For the persistance algorithm.
+       FF_T_UINT32             LRU;                    ///< For the Least Recently Used algorithm.
+       FF_T_BOOL               Modified;               ///< If the sector was modified since read.
+       FF_T_BOOL               Valid;                  ///< Initially FALSE.
+       FF_T_UINT8              *pBuffer;               ///< Pointer to the cache block.
+} FF_BUFFER;
+
+typedef struct {
+       FF_T_INT8       Path[FF_MAX_PATH];
+       FF_T_UINT32     DirCluster;
+#ifdef FF_HASH_TABLE_SUPPORT
+       FF_HASH_TABLE pHashTable;
+       FF_T_BOOL       bHashed;
+#endif
+} FF_PATHCACHE;
+
+/**
+ *     @private
+ *     @brief  FullFAT identifies a partition with the following data.
+ *     @note   This may shrink as development and optimisation goes on.
+ **/
+typedef struct {
+       //FF_T_UINT8            ID;                                     ///< Partition Incremental ID number.
+       FF_T_UINT8              Type;                           ///< Partition Type Identifier.
+       FF_T_UINT16             BlkSize;                        ///< Size of a Sector Block in bytes.
+       FF_T_UINT8      BlkFactor;                      ///< Scale Factor for blocksizes above 512!
+       //FF_T_INT8             Name[FF_MAX_PARTITION_NAME];    ///< Partition Identifier e.g. c: sd0: etc.
+       //FF_T_INT8             VolLabel[12];           ///< Volume Label of the partition.
+       FF_T_UINT32             BeginLBA;                       ///< LBA start address of the partition.
+       FF_T_UINT32             PartSize;                       ///< Size of Partition in number of sectors.
+       FF_T_UINT32             FatBeginLBA;            ///< LBA of the FAT tables.
+       FF_T_UINT8              NumFATS;                        ///< Number of FAT tables.
+       FF_T_UINT32             SectorsPerFAT;          ///< Number of sectors per Fat.
+       FF_T_UINT8              SectorsPerCluster;      ///< Number of sectors per Cluster.
+       FF_T_UINT32             TotalSectors;
+       FF_T_UINT32             DataSectors;
+       FF_T_UINT32             RootDirSectors;
+       FF_T_UINT32             FirstDataSector;
+       FF_T_UINT16             ReservedSectors;
+       FF_T_UINT32             ClusterBeginLBA;        ///< LBA of first cluster.
+       FF_T_UINT32             NumClusters;            ///< Number of clusters.
+       FF_T_UINT32             RootDirCluster;         ///< Cluster number of the root directory entry.
+       FF_T_UINT32             LastFreeCluster;
+       FF_T_UINT32             FreeClusterCount;       ///< Records free space on mount.
+       FF_T_BOOL               PartitionMounted;       ///< FF_TRUE if the partition is mounted, otherwise FF_FALSE.
+#ifdef FF_PATH_CACHE
+       FF_PATHCACHE    PathCache[FF_PATH_CACHE_DEPTH];
+       FF_T_UINT32             PCIndex;
+#endif
+} FF_PARTITION;
+
+
+
+/**
+ *     @public
+ *     @brief  FF_IOMAN Object description.
+ *
+ *     FullFAT functions around an object like this.
+ **/
+#define FF_FAT_LOCK                    0x01    ///< Lock bit mask for FAT table locking.
+#define FF_DIR_LOCK                    0x02    ///< Lock bit mask for DIR modification locking.
+//#define FF_PATHCACHE_LOCK    0x04
+
+/**
+ *     @public
+ *     @brief  FF_IOMAN Object. A developer should not touch these values.
+ *     
+ *     In the commercial version these values are encapsulated. In the open-source
+ *     version they are left completely open, in case someone really "needs" :P to
+ *     do something stupid and access their members themselves. Also to help the
+ *     open-source community help me improve FullFAT, and aid understanding.
+ *
+ *     THIS WOULD BE VERY STUPID, SO DON'T DO IT. Unless your're writing a patch or
+ *     something!
+ *
+ **/
+typedef struct {
+       FF_BLK_DEVICE   *pBlkDevice;            ///< Pointer to a Block device description.
+       FF_PARTITION    *pPartition;            ///< Pointer to a partition description.
+       FF_BUFFER               *pBuffers;                      ///< Pointer to the first buffer description.
+       FF_T_UINT32             LastReplaced;           ///< Marks which sector was last replaced in the cache.
+       FF_T_UINT16             BlkSize;                        ///< The Block size that IOMAN is configured to.
+       FF_T_UINT8              *pCacheMem;                     ///< Pointer to a block of memory for the cache.
+       FF_T_UINT16             CacheSize;                      ///< Size of the cache in number of Sectors.
+       FF_T_UINT8              MemAllocation;          ///< Bit-Mask identifying allocated pointers.
+       FF_T_UINT8              Locks;                          ///< Lock Flag for FAT & DIR Locking etc (This must be accessed via a semaphore).
+       void                    *pSemaphore;            ///< Pointer to a Semaphore object. (For buffer description modifications only!).
+       void                    *FirstFile;                     ///< Pointer to the first File object.
+} FF_IOMAN;
+
+// Bit-Masks for Memory Allocation testing.
+#define FF_IOMAN_ALLOC_BLKDEV  0x01    ///< Flags the pBlkDevice pointer is allocated.
+#define FF_IOMAN_ALLOC_PART            0x02    ///< Flags the pPartition pointer is allocated.
+#define        FF_IOMAN_ALLOC_BUFDESCR 0x04    ///< Flags the pBuffers pointer is allocated.
+#define        FF_IOMAN_ALLOC_BUFFERS  0x08    ///< Flags the pCacheMem pointer is allocated.
+#define FF_IOMAN_ALLOC_RESERVED        0xF0    ///< Reserved Section.
+
+
+//---------- PROTOTYPES (in order of appearance)
+
+// PUBLIC (Interfaces):
+FF_IOMAN       *FF_CreateIOMAN                 (FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 BlkSize, FF_ERROR *pError);
+FF_ERROR       FF_DestroyIOMAN                 (FF_IOMAN *pIoman);
+FF_ERROR       FF_RegisterBlkDevice    (FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam);
+FF_ERROR       FF_UnregisterBlkDevice  (FF_IOMAN *pIoman);
+FF_ERROR       FF_MountPartition               (FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber);
+FF_ERROR       FF_UnmountPartition             (FF_IOMAN *pIoman);
+FF_ERROR       FF_FlushCache                   (FF_IOMAN *pIoman);
+FF_T_SINT32 FF_GetPartitionBlockSize(FF_IOMAN *pIoman);
+
+#ifdef FF_64_NUM_SUPPORT
+FF_T_UINT64 FF_GetVolumeSize(FF_IOMAN *pIoman);
+#else
+FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman);
+#endif
+
+// PUBLIC  (To FullFAT Only):
+FF_ERROR       FF_IncreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count);
+FF_ERROR       FF_DecreaseFreeClusters (FF_IOMAN *pIoman, FF_T_UINT32 Count);
+FF_BUFFER      *FF_GetBuffer                   (FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode);
+void           FF_ReleaseBuffer                (FF_IOMAN *pIoman, FF_BUFFER *pBuffer);
+
+// PRIVATE (For this module only!):
+
+
+#endif
+
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_memory.h b/reactos/include/reactos/libs/fullfat/ff_memory.h
new file mode 100644 (file)
index 0000000..ba4ef54
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_memory.h
+ *     @author         James Walmsley
+ *     @ingroup        MEMORY
+ **/
+
+#ifndef _FF_MEMORY_H_
+#define _FF_MEMORY_H_
+
+#include "ff_config.h"
+#include "ff_types.h"
+
+
+//---------- PROTOTYPES
+
+FF_T_UINT8             FF_getChar      (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset);
+FF_T_UINT16            FF_getShort     (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset);
+FF_T_UINT32            FF_getLong      (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset);
+
+void                   FF_putChar      (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value);
+void                   FF_putShort     (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value);
+void                   FF_putLong      (FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_safety.h b/reactos/include/reactos/libs/fullfat/ff_safety.h
new file mode 100644 (file)
index 0000000..424531d
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_safety.h
+ *     @author         James Walmsley
+ *     @ingroup        SAFETY
+ **/
+
+#ifndef _FF_SAFETY_H_
+#define        _FF_SAFETY_H_
+
+#include <stdlib.h>
+#include "ff_types.h"
+
+
+//---------- PROTOTYPES (in order of appearance)
+
+// PUBLIC:
+
+
+// PRIVATE:
+void           *FF_CreateSemaphore             (void);
+void           FF_PendSemaphore                (void *pSemaphore);
+void           FF_ReleaseSemaphore             (void *pSemaphore);
+void           FF_DestroySemaphore             (void *pSemaphore);
+void           FF_Yield                                (void);
+void           FF_Sleep                                (FF_T_UINT32 TimeMs);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_string.h b/reactos/include/reactos/libs/fullfat/ff_string.h
new file mode 100644 (file)
index 0000000..e378910
--- /dev/null
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_string.c
+ *     @author         James Walmsley
+ *     @ingroup        STRING
+ *
+ *     @defgroup       STRING  FullFAT String Library
+ *     @brief          Portable String Library for FullFAT
+ *
+ *
+ **/
+
+#ifndef _FF_STRING_H_
+#define _FF_STRING_H_
+
+#include "ff_types.h"
+
+void                   FF_tolower      (FF_T_INT8 *string, FF_T_UINT32 strLen);
+void                   FF_toupper      (FF_T_INT8 *string, FF_T_UINT32 strLen);
+FF_T_BOOL              FF_strmatch     (const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len);
+FF_T_INT8              *FF_strtok      (const FF_T_INT8 *string, FF_T_INT8 *token, FF_T_UINT16 *tokenNumber, FF_T_BOOL *last, FF_T_UINT16 Length);
+FF_T_BOOL              FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString);
+
+#endif
diff --git a/reactos/include/reactos/libs/fullfat/ff_time.h b/reactos/include/reactos/libs/fullfat/ff_time.h
new file mode 100644 (file)
index 0000000..57b8e54
--- /dev/null
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_time.h
+ *     @author         James Walmsley
+ *     @ingroup        TIME
+ *
+ *     Provides a means for receiving the time on any platform.
+ **/
+
+#ifndef _FF_TIME_H_
+#define _FF_TIME_H_
+
+#include "ff_config.h"
+#include "ff_types.h"
+
+/**
+ *     @public
+ *     @brief  A TIME and DATE object for FullFAT. A FullFAT time driver must populate these values.
+ *
+ **/
+typedef struct {
+       FF_T_UINT16     Year;           ///< Year       (e.g. 2009).
+       FF_T_UINT16 Month;              ///< Month      (e.g. 1 = Jan, 12 = Dec).
+       FF_T_UINT16     Day;            ///< Day        (1 - 31).
+       FF_T_UINT16 Hour;               ///< Hour       (0 - 23).
+       FF_T_UINT16 Minute;             ///< Min        (0 - 59).
+       FF_T_UINT16 Second;             ///< Second     (0 - 59).
+} FF_SYSTEMTIME;
+
+//---------- PROTOTYPES
+
+FF_T_SINT32    FF_GetSystemTime(FF_SYSTEMTIME *pTime);
+
+#endif
+
diff --git a/reactos/include/reactos/libs/fullfat/ff_types.h b/reactos/include/reactos/libs/fullfat/ff_types.h
new file mode 100644 (file)
index 0000000..59a5996
--- /dev/null
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     This file defines some portable types.
+ *     You should change these as appropriate for your platform, as necessary.
+ *
+ **/
+
+#ifndef _FF_TYPES_H_
+#define _FF_TYPES_H_
+
+#include "ff_config.h"
+
+//---------------- BOOLEAN TYPES
+typedef        char                            FF_T_BOOL;              ///< This can be a char if your compiler isn't C99.
+
+#define FF_TRUE                                1                               ///< 1 if bool not supported.
+#define FF_FALSE                       0                               ///< 0 if bool not supported.
+
+//---------------- 8 BIT INTEGERS
+typedef        char                            FF_T_INT8;              ///< 8 bit default integer.
+typedef        unsigned char           FF_T_UINT8;             ///< 8 bit unsigned integer.
+typedef signed char                    FF_T_SINT8;             ///< 8 bit signed integer.
+
+//---------------- 16 BIT INTEGERS
+typedef        short                           FF_T_INT16;             ///< 16 bit default integer.
+typedef        unsigned short          FF_T_UINT16;    ///< 16 bit unsigned integer.
+typedef        signed short            FF_T_SINT16;    ///< 16 bit signed integer.
+
+//---------------- 32 BIT INTEGERS
+typedef        long                            FF_T_INT32;             ///< 32 bit default integer.
+typedef        unsigned long           FF_T_UINT32;    ///< 32 bit unsigned integer.
+typedef        signed long                     FF_T_SINT32;    ///< 32 bit signed integer.
+
+#ifdef FF_64_NUM_SUPPORT
+//---------------- 64 BIT INTEGERS                     // If you cannot define these, then make sure you see ff_config.h
+typedef long long                      FF_T_INT64;             // about 64-bit number support.
+typedef unsigned long long     FF_T_UINT64;    // It means that FF_GetVolumeSize() cannot return a size
+typedef signed long long       FF_T_SINT64;    // > 4GB in bytes if you cannot support 64-bits integers.
+                                                                                       // No other function makes use of 64-bit numbers.
+#endif
+
+typedef FF_T_SINT32                    FF_ERROR;               ///< A special error code type to ease some inconsistencies in Error reporting.
+
+#endif // end of include guard
diff --git a/reactos/include/reactos/libs/fullfat/fullfat.h b/reactos/include/reactos/libs/fullfat/fullfat.h
new file mode 100644 (file)
index 0000000..dd8da07
--- /dev/null
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+#ifndef _FULLFAT_H_
+#define _FULLFAT_H_
+
+#include "ff_config.h"
+#include "ff_ioman.h"
+#include "ff_fat.h"
+#include "ff_file.h"
+#include "ff_dir.h"
+#include "ff_time.h"
+#include "ff_crc.h"
+#include "ff_hash.h"
+#include "ff_string.h"
+
+
+#endif
index bd62325..2766780 100644 (file)
@@ -13,6 +13,9 @@
        <directory name="freetype">
                <xi:include href="freetype/freetype.rbuild" />
        </directory>
+       <directory name="fullfat">
+               <xi:include href="fullfat/fullfat.rbuild" />
+       </directory>
        <directory name="icu4ros">
                <xi:include href="icu4ros/icu4ros.rbuild" />
        </directory>
diff --git a/reactos/lib/3rdparty/fullfat/ff_blk.c b/reactos/lib/3rdparty/fullfat/ff_blk.c
new file mode 100644 (file)
index 0000000..d97b1a6
--- /dev/null
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_blk.c
+ *     @author         James Walmsley
+ *     @ingroup        BLK
+ *
+ *     @defgroup       BLK Block Calculater
+ *     @brief          Handle Block Number conversions
+ *
+ *     Helps calculate block numbers.
+ **/
+
+#include "ff_blk.h"
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_getClusterChainNumber(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize) {
+       FF_PARTITION *pPart                             = pIoman->pPartition;
+       FF_T_UINT32 clusterChainNumber  = nEntry / (pIoman->BlkSize * (pPart->SectorsPerCluster * pPart->BlkFactor) / nEntrySize);
+       return clusterChainNumber;
+}
+
+FF_T_UINT32 FF_getClusterPosition(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize) {
+       return nEntry % ((pIoman->BlkSize * (pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkFactor)) / nEntrySize);
+}
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_getMajorBlockNumber(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize) {
+       FF_PARTITION *pPart = pIoman->pPartition;
+       FF_T_UINT32 relClusterEntry             = nEntry % (pIoman->BlkSize * (pPart->SectorsPerCluster * pPart->BlkFactor) / nEntrySize);
+       FF_T_UINT32 majorBlockNumber    = relClusterEntry / (pPart->BlkSize / nEntrySize);
+       return majorBlockNumber;
+}
+/**
+ *     @private
+ **/
+FF_T_UINT8 FF_getMinorBlockNumber(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize) {
+       FF_PARTITION *pPart                             = pIoman->pPartition;
+       FF_T_UINT32 relClusterEntry             = nEntry % (pIoman->BlkSize * (pPart->SectorsPerCluster * pPart->BlkFactor) / nEntrySize);
+       FF_T_UINT16 relmajorBlockEntry  = (FF_T_UINT16)(relClusterEntry % (pPart->BlkSize / nEntrySize));
+       FF_T_UINT8 minorBlockNumber             = (FF_T_UINT8) (relmajorBlockEntry / (pIoman->BlkSize / nEntrySize));
+       return minorBlockNumber;
+}
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_getMinorBlockEntry(FF_IOMAN *pIoman, FF_T_UINT32 nEntry, FF_T_UINT16 nEntrySize) {
+       FF_PARTITION *pPart                             = pIoman->pPartition;
+       FF_T_UINT32 relClusterEntry             = nEntry % (pIoman->BlkSize * (pPart->SectorsPerCluster * pPart->BlkFactor) / nEntrySize);
+       FF_T_UINT32 relmajorBlockEntry  = (FF_T_UINT32)(relClusterEntry % (pPart->BlkSize / nEntrySize));
+       FF_T_UINT32 minorBlockEntry             = (FF_T_UINT32)(relmajorBlockEntry % (pIoman->BlkSize / nEntrySize));
+       return minorBlockEntry;
+}
+
diff --git a/reactos/lib/3rdparty/fullfat/ff_crc.c b/reactos/lib/3rdparty/fullfat/ff_crc.c
new file mode 100644 (file)
index 0000000..9c6ea46
--- /dev/null
@@ -0,0 +1,194 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_crc.c
+ *     @author         James Walmsley
+ *     @ingroup        CRC
+ *
+ *     @defgroup       CRC CRC Checksums for Strings
+ *     @brief          Provides fast hashing functions.
+ *
+ **/
+
+#include "ff_crc.h"
+
+static const FF_T_UINT8 CRC16_Low[256] = 
+{
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, 
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
+    0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
+};
+
+static const FF_T_UINT8 CRC16_High[256] = 
+{
+    0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2,
+    0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004,
+    0x0cc, 0x00c, 0x00d, 0x0cd, 0x00f, 0x0cf, 0x0ce, 0x00e,
+    0x00a, 0x0ca, 0x0cb, 0x00b, 0x0c9, 0x009, 0x008, 0x0c8,
+    0x0d8, 0x018, 0x019, 0x0d9, 0x01b, 0x0db, 0x0da, 0x01a,
+    0x01e, 0x0de, 0x0df, 0x01f, 0x0dd, 0x01d, 0x01c, 0x0dc,
+    0x014, 0x0d4, 0x0d5, 0x015, 0x0d7, 0x017, 0x016, 0x0d6,
+    0x0d2, 0x012, 0x013, 0x0d3, 0x011, 0x0d1, 0x0d0, 0x010,
+    0x0f0, 0x030, 0x031, 0x0f1, 0x033, 0x0f3, 0x0f2, 0x032,
+    0x036, 0x0f6, 0x0f7, 0x037, 0x0f5, 0x035, 0x034, 0x0f4,
+    0x03c, 0x0fc, 0x0fd, 0x03d, 0x0ff, 0x03f, 0x03e, 0x0fe,
+    0x0fa, 0x03a, 0x03b, 0x0fb, 0x039, 0x0f9, 0x0f8, 0x038,
+    0x028, 0x0e8, 0x0e9, 0x029, 0x0eb, 0x02b, 0x02a, 0x0ea,
+    0x0ee, 0x02e, 0x02f, 0x0ef, 0x02d, 0x0ed, 0x0ec, 0x02c,
+    0x0e4, 0x024, 0x025, 0x0e5, 0x027, 0x0e7, 0x0e6, 0x026,
+    0x022, 0x0e2, 0x0e3, 0x023, 0x0e1, 0x021, 0x020, 0x0e0,
+    0x0a0, 0x060, 0x061, 0x0a1, 0x063, 0x0a3, 0x0a2, 0x062,
+    0x066, 0x0a6, 0x0a7, 0x067, 0x0a5, 0x065, 0x064, 0x0a4,
+    0x06c, 0x0ac, 0x0ad, 0x06d, 0x0af, 0x06f, 0x06e, 0x0ae,
+    0x0aa, 0x06a, 0x06b, 0x0ab, 0x069, 0x0a9, 0x0a8, 0x068,
+    0x078, 0x0b8, 0x0b9, 0x079, 0x0bb, 0x07b, 0x07a, 0x0ba,
+    0x0be, 0x07e, 0x07f, 0x0bf, 0x07d, 0x0bd, 0x0bc, 0x07c,
+    0x0b4, 0x074, 0x075, 0x0b5, 0x077, 0x0b7, 0x0b6, 0x076,
+    0x072, 0x0b2, 0x0b3, 0x073, 0x0b1, 0x071, 0x070, 0x0b0,
+    0x050, 0x090, 0x091, 0x051, 0x093, 0x053, 0x052, 0x092,
+    0x096, 0x056, 0x057, 0x097, 0x055, 0x095, 0x094, 0x054,
+    0x09c, 0x05c, 0x05d, 0x09d, 0x05f, 0x09f, 0x09e, 0x05e,
+    0x05a, 0x09a, 0x09b, 0x05b, 0x099, 0x059, 0x058, 0x098,
+    0x088, 0x048, 0x049, 0x089, 0x04b, 0x08b, 0x08a, 0x04a,
+    0x04e, 0x08e, 0x08f, 0x04f, 0x08d, 0x04d, 0x04c, 0x08c,
+    0x044, 0x084, 0x085, 0x045, 0x087, 0x047, 0x046, 0x086,
+    0x082, 0x042, 0x043, 0x083, 0x041, 0x081, 0x080, 0x040,
+};
+
+/*****************************************************************************
+ * Description: Function to 16 bit CRC check a block of memory
+
+ *
+ * Parameters:  pbyData - Pointer to the source data
+ *              stLength - The length to CRC
+ *
+ * Return value: The 16 bit CRC value
+ *
+ *****************************************************************************/
+
+FF_T_UINT16 FF_GetCRC16(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) {
+    FF_T_UINT8 bTableValue;
+    FF_T_UINT16 wCRC = 0;
+
+    while (stLength--)    {
+        bTableValue = (FF_T_UINT8)((wCRC & 0x00FF) ^ *pbyData++);
+        wCRC = (FF_T_UINT16)(((CRC16_High[bTableValue]) << 8)
+             + (CRC16_Low[bTableValue] ^ ((wCRC >> 8) & 0x00FF)));
+    }
+
+    return wCRC;
+}
+
+
+static const FF_T_UINT8 byCRCLookUpTable[256] =
+{
+    0,   94,  188, 226, 97,  63,  221, 131, 
+    194, 156, 126, 32,  163, 253, 31,  65,
+    157, 195, 33,  127, 252, 162, 64,  30,
+    95,  1,   227, 189, 62,  96,  130, 220,
+    35,  125, 159, 193, 66,  28,  254, 160,
+    225, 191, 93,  3,   128, 222, 60,  98,
+    190, 224, 2,   92,  223, 129, 99,  61,
+    124, 34,  192, 158, 29,  67,  161, 255,
+    70,  24,  250, 164, 39,  121, 155, 197,
+    132, 218, 56,  102, 229, 187, 89,  7,
+    219, 133, 103, 57,  186, 228, 6,   88,
+    25,  71,  165, 251, 120, 38,  196, 154,
+    101, 59,  217, 135, 4,   90,  184, 230,
+    167, 249, 27,  69,  198, 152, 122, 36,
+    248, 166, 68,  26,  153, 199, 37,  123,
+    58,  100, 134, 216, 91,  5,   231, 185,
+    140, 210, 48,  110, 237, 179, 81,  15, 
+    78,  16,  242, 172, 47,  113, 147, 205,
+    17,  79,  173, 243, 112, 46,  204, 146,
+    211, 141, 111, 49,  178, 236, 14,  80,
+    175, 241, 19,  77,  206, 144, 114, 44,
+    109, 51,  209, 143, 12,  82,  176, 238,
+    50,  108, 142, 208, 83,  13,  239, 177,
+    240, 174, 76,  18,  145, 207, 45,  115,
+    202, 148, 118, 40,  171, 245, 23,  73, 
+    8,   86,  180, 234, 105, 55,  213, 139,
+    87,  9,   235, 181, 54,  104, 138, 212,
+    149, 203, 41,  119, 244, 170, 72,  22,
+    233, 183, 85,  11,  136, 214, 52,  106,
+    43,  117, 151, 201, 74,  20,  246, 168,
+    116, 42,  200, 150, 21,  75,  169, 247,
+    182, 232, 10,  84,  215, 137, 107, 53
+};
+/*****************************************************************************
+ * Description: Function to CRC check a block of memory
+ *
+ * Parameters:  pbyData - Pointer to the source data
+ *              stLength - The length to CRC
+ *
+ * Return value: The 8 bit CRC value
+ *
+ *****************************************************************************/
+
+FF_T_UINT8 FF_GetCRC8(FF_T_UINT8 *pbyData, FF_T_UINT32 stLength) {
+    FF_T_UINT8 byCRC = 0, byData;
+    while (stLength--) {
+        byData = *pbyData++;
+        byCRC = byCRCLookUpTable[(byCRC ^ byData)];
+    }
+    return byCRC;
+}
diff --git a/reactos/lib/3rdparty/fullfat/ff_dir.c b/reactos/lib/3rdparty/fullfat/ff_dir.c
new file mode 100644 (file)
index 0000000..6bba0b7
--- /dev/null
@@ -0,0 +1,1772 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_dir.c
+ *     @author         James Walmsley
+ *     @ingroup        DIR
+ *
+ *     @defgroup       DIR Handles Directory Traversal
+ *     @brief          Handles DIR access and traversal.
+ *
+ *     Provides FindFirst() and FindNext() Interfaces
+ **/
+
+#include "ff_dir.h"
+#include "ff_string.h"
+#include <stdio.h>
+
+static void FF_ProcessShortName(FF_T_INT8 *name);
+
+void FF_lockDIR(FF_IOMAN *pIoman) {
+       FF_PendSemaphore(pIoman->pSemaphore);   // Use Semaphore to protect FAT modifications.
+       {
+               while((pIoman->Locks & FF_DIR_LOCK)) {
+                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+                       FF_Yield();                                             // Keep Releasing and Yielding until we have the Fat protector.
+                       FF_PendSemaphore(pIoman->pSemaphore);
+               }
+               pIoman->Locks |= FF_DIR_LOCK;
+       }
+       FF_ReleaseSemaphore(pIoman->pSemaphore);
+}
+
+void FF_unlockDIR(FF_IOMAN *pIoman) {
+       FF_PendSemaphore(pIoman->pSemaphore);
+       {
+               pIoman->Locks &= ~FF_DIR_LOCK;
+       }
+       FF_ReleaseSemaphore(pIoman->pSemaphore);
+}
+
+static FF_T_UINT8 FF_CreateChkSum(const FF_T_UINT8 *pa_pShortName) {
+       FF_T_UINT8      cNameLen;
+       FF_T_UINT8      ChkSum = 0;
+
+       for(cNameLen = 11; cNameLen != 0; cNameLen--) {
+               ChkSum = ((ChkSum & 1) ? 0x80 : 0) + (ChkSum >> 1) + *pa_pShortName++;
+       }
+       return ChkSum;
+}
+
+FF_T_SINT8 FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) {
+       
+       FF_T_UINT8      numLFNs;
+       FF_T_UINT8      EntryBuffer[32];
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       //pDirent->NumLFNs = 0;
+       
+       for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) {
+               if(FF_FetchEntry(pIoman, DirCluster, pDirent->CurrentItem, EntryBuffer)) {
+                       return -2;
+               }
+               if(EntryBuffer[0] != 0xE5) {
+                       if(FF_isEndOfDir(EntryBuffer)){
+                               return -2;
+                       }
+                       pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+                       if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) {
+                               // LFN Processing
+                               numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40);
+                               //pDirent->NumLFNs = numLFNs;
+#ifdef FF_LFN_SUPPORT
+                               FF_PopulateLongDirent(pIoman, pDirent, DirCluster, pDirent->CurrentItem);
+                               return 0;
+#else 
+                               pDirent->CurrentItem += (numLFNs - 1);
+#endif
+                       } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) {
+                               // Do Nothing
+                       
+                       } else {
+                               FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer);
+                               pDirent->CurrentItem += 1;
+                               return 0;
+                       }
+               }
+       }
+       
+       return -1;
+}
+/*
+FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) {
+
+       FF_DIRENT MyDir;
+
+       if(FF_FindEntry(pIoman, DirCluster, name, &MyDir, FF_FALSE)) {
+               return FF_FALSE;
+       }
+       
+       return FF_TRUE;
+}*/
+
+FF_T_BOOL FF_ShortNameExists(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name) {
+
+    FF_T_UINT16 i;
+    FF_T_UINT8      EntryBuffer[32];
+    FF_T_UINT8      Attrib;
+
+#ifdef FF_HASH_TABLE_SUPPORT
+
+               if(!FF_DirHashed(pIoman, DirCluster)) {
+                       for(i = 0; i < 0xFFFF; i++) {
+                               if(FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer)) {
+                                       FF_SetDirHashed(pIoman, DirCluster);
+                                       break;
+                               }
+                               Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB);
+                               if(FF_getChar(EntryBuffer, 0x00) != 0xE5) {
+                                       if(Attrib != FF_FAT_ATTR_LFN) {
+                                               if(FF_isEndOfDir(EntryBuffer)) {
+                                                       FF_SetDirHashed(pIoman, DirCluster);
+                                                       break;
+                                               }
+                                               FF_ProcessShortName((FF_T_INT8 *)EntryBuffer);
+                                               FF_AddDirentHash(pIoman, DirCluster, FF_GetCRC16((FF_T_UINT8 *) EntryBuffer, strlen(EntryBuffer)));
+                                       }
+                               }
+                       }
+               }
+
+#if FF_HASH_FUNCTION == CRC16
+               if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) name, strlen(name)))) {
+#elif FF_HASH_FUNCTION == CRC8
+               if(FF_CheckDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) name, strlen(name)))) {
+#else
+               {
+#endif
+#endif
+
+                       for(i = 0; i < 0xFFFF; i++) {
+                               FF_FetchEntry(pIoman, DirCluster, i, EntryBuffer);
+                               Attrib = FF_getChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB);
+                               if(FF_getChar(EntryBuffer, 0x00) != 0xE5) {
+                                       if(Attrib != FF_FAT_ATTR_LFN) {
+                                               FF_ProcessShortName((FF_T_INT8 *)EntryBuffer);
+                                               if(FF_isEndOfDir(EntryBuffer)) {
+                                                               return FF_FALSE;
+                                               }
+                                               if(strcmp(name, (FF_T_INT8 *)EntryBuffer) == 0) {
+                                                               return FF_TRUE;
+                                               }
+                                       }
+                               }
+                       }
+#ifdef FF_HASH_TABLE_SUPPORT
+               }
+#endif
+        
+        return FF_FALSE;
+}
+
+FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent) {
+
+       FF_T_UINT16             fnameLen;
+       FF_T_UINT16             compareLength;
+       FF_T_UINT16             nameLen;
+       FF_T_INT8               Filename[FF_MAX_FILENAME];
+       FF_T_INT8               MyFname[FF_MAX_FILENAME];
+       FF_T_BOOL               bBreak = FF_FALSE;
+       
+       pDirent->CurrentItem = 0;
+       nameLen = (FF_T_UINT16) strlen(name);
+
+       while(!bBreak) {        
+               if(FF_FindNextInDir(pIoman, DirCluster, pDirent)) {
+                       break;  // end of dir, file not found!
+               }
+
+               if((pDirent->Attrib & pa_Attrib) == pa_Attrib){
+                       strcpy(Filename, pDirent->FileName);
+                       fnameLen = (FF_T_UINT16) strlen(Filename);
+                       FF_tolower(Filename, (FF_T_UINT32) fnameLen);
+                       if(nameLen < FF_MAX_FILENAME) {
+                               memcpy(MyFname, name, nameLen + 1);
+                       } else {
+                               memcpy(MyFname, name, FF_MAX_FILENAME);
+                               MyFname[FF_MAX_FILENAME - 1] = '\0';
+                       }
+                       FF_tolower(MyFname, (FF_T_UINT32) nameLen);
+                       if(nameLen > fnameLen) {
+                               compareLength = nameLen;
+                       } else {
+                               compareLength = fnameLen;
+                       }
+                       if(strncmp(MyFname, Filename, (FF_T_UINT32) compareLength) == 0) {
+                               // Object found!
+                               return pDirent->ObjectCluster;  // Return the cluster number
+                       }
+               }
+       }
+       
+       return 0;
+}
+
+/*
+#define FF_DIR_LFN_TRAVERSED   0x01
+#define FF_DIR_LFN_DELETED             0x02
+
+FF_T_SINT8 FF_PopulateLongBufEntry(FF_IOMAN *pIoman, FF_BUFFER **ppBuffer, FF_DIRENT *pDirent) {
+       // Relative positions!
+       FF_T_UINT32     RelBlockNum;
+       FF_T_UINT32 RelBlockPos = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32);
+       FF_T_UINT32     iItemLBA;
+       FF_T_INT8       *DirBuffer      = ((*ppBuffer)->pBuffer + (RelBlockPos * 32));
+       FF_T_UINT8      numLFNs         = (FF_getChar(DirBuffer, (FF_T_UINT16) 0) & ~0x40);
+       FF_T_UINT16     x,i,y,myShort, lenlfn = 0;
+       FF_T_UINT32     CurrentCluster;
+       FF_T_SINT8      RetVal  = FF_ERR_NONE;
+       FF_T_INT8       ShortName[13];
+       FF_T_UINT8      CheckSum = FF_getChar(DirBuffer, FF_FAT_LFN_CHECKSUM);
+
+       while(numLFNs > 0) {
+               
+               for(i = 0, y = 0; i < 5; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13)] = DirBuffer[FF_FAT_LFN_NAME_1 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 6; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = DirBuffer[FF_FAT_LFN_NAME_2 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 2; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = DirBuffer[FF_FAT_LFN_NAME_3 + y];
+                       lenlfn++;
+               }
+               numLFNs--;
+               pDirent->CurrentItem += 1;
+               
+               CurrentCluster  = FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32);
+               RelBlockNum             = FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32);
+               RelBlockPos             = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32);
+               iItemLBA                = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum;
+               
+               if(CurrentCluster > pDirent->CurrentCluster) {
+                       pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1);
+                       pDirent->CurrentCluster += 1;
+                       iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster) + RelBlockNum;
+                       FF_ReleaseBuffer(pIoman, *ppBuffer);
+                       *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ);
+                       RetVal |= FF_DIR_LFN_TRAVERSED;
+               } else if(iItemLBA > ((*ppBuffer)->Sector)) {
+                       FF_ReleaseBuffer(pIoman, *ppBuffer);
+                       *ppBuffer = FF_GetBuffer(pIoman, iItemLBA, FF_MODE_READ);
+                       RetVal |= FF_DIR_LFN_TRAVERSED;
+               }
+
+               DirBuffer = ((*ppBuffer)->pBuffer + (RelBlockPos * 32));
+       }
+
+       if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) == FF_FAT_DELETED) {
+               RetVal |= FF_DIR_LFN_DELETED;
+               return RetVal;
+       }
+
+       pDirent->FileName[lenlfn] = '\0';
+       
+       // Process the ShortName Entry
+       memcpy(ShortName, DirBuffer, 11);
+       if(CheckSum != FF_CreateChkSum(ShortName)) {
+               FF_ProcessShortName(ShortName);
+               strcpy(pDirent->FileName, ShortName);
+       } else {
+               FF_ProcessShortName(ShortName);
+       }
+       
+       myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH));
+       pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16);
+       myShort = FF_getShort(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW));
+       pDirent->ObjectCluster |= myShort;
+
+       // Get the filesize.
+       pDirent->Filesize = FF_getLong(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE));
+       // Get the attribute.
+       pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+
+       return RetVal;
+}*/
+
+/*
+FF_T_SINT8 FF_FindEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs) {
+       
+       FF_T_UINT32             iItemLBA;
+       FF_BUFFER               *pBuffer;
+       FF_T_INT8               *DirBuffer;
+       FF_T_UINT32             fatEntry = DirCluster;
+       FF_T_UINT32             i,x;
+       FF_T_UINT32             numLFNs;
+       FF_T_UINT16             NameLen, DirentNameLen;
+       FF_T_BOOL               Compare = FF_FALSE;
+       FF_T_SINT8              RetVal = 0;
+       FF_T_UINT16             RelEntry;
+
+       pDirent->CurrentItem = 0;
+       pDirent->AddrCurrentCluster = DirCluster;
+       pDirent->CurrentCluster = 0;
+       pDirent->DirCluster = DirCluster;
+
+       do {
+               
+               pDirent->AddrCurrentCluster = fatEntry;
+               iItemLBA = FF_Cluster2LBA(pIoman, pDirent->AddrCurrentCluster);
+
+               for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) {
+                       
+                       if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) {
+                               break;
+                       }
+
+                       pBuffer = FF_GetBuffer(pIoman, iItemLBA + i, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               pBuffer->Persistance = 1;
+                               RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32);
+                               for(x = RelEntry; x < (pIoman->BlkSize / 32); x++) {
+                                       if(FF_getMajorBlockNumber(pIoman, pDirent->CurrentItem, 32) > i) {
+                                               break;
+                                       }
+                                       if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) {
+                                               break;
+                                       }
+                                       RelEntry = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32);
+                                       x = RelEntry;
+                                       if(x >= (pIoman->BlkSize / 32)) {
+                                               break;
+                                       }
+                                       DirBuffer = (pBuffer->pBuffer + (32 * x));
+                                       // Process each entry and Compare to Name!
+                                       if(FF_getChar(DirBuffer, (FF_T_UINT16) 0) != FF_FAT_DELETED) {
+                                               if(DirBuffer[0] == 0x00) {
+                                                       FF_ReleaseBuffer(pIoman, pBuffer);
+                                                       return FF_ERR_DIR_END_OF_DIR;
+                                               }
+                                               pDirent->Attrib = FF_getChar(DirBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+                                               if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) {
+                                                       numLFNs = (FF_T_UINT8)(DirBuffer[0] & ~0x40);
+                                                       if(LFNs) {
+                                                               RetVal = FF_PopulateLongBufEntry(pIoman, &pBuffer, pDirent);
+                                                               if((RetVal & FF_DIR_LFN_DELETED)) {
+                                                                       Compare = FF_FALSE;
+                                                                       RetVal &= ~FF_DIR_LFN_DELETED;
+                                                               } else {
+                                                                       Compare = FF_TRUE;
+                                                               }
+
+                                                               pDirent->CurrentItem += 1;
+                                                       } else {
+                                                               pDirent->CurrentItem += numLFNs;
+                                                       }
+                                                       
+                                               } else {
+                                                       FF_PopulateShortDirent(pDirent, DirBuffer);
+                                                       Compare = FF_TRUE;
+                                                       pDirent->CurrentItem += 1;
+                                               }
+
+                                               if(Compare) {
+                                                       // Compare the Items
+                                                       NameLen = strlen(Name);
+                                                       DirentNameLen = strlen(pDirent->FileName);
+
+                                                       if(NameLen == DirentNameLen) {  // Names are same length, possible match.
+                                                               if(FF_StrMatch(Name, pDirent->FileName, NameLen)) {
+                                                                       FF_ReleaseBuffer(pIoman, pBuffer);
+                                                                       return FF_ERR_NONE;     // Success Item found!
+                                                               }
+                                                       }
+                                                       Compare = FF_FALSE;
+                                               }
+
+                                               if((RetVal & FF_DIR_LFN_TRAVERSED)) {
+                                                       break;          
+                                               }
+
+                                       } else {
+                                               pDirent->CurrentItem += 1;
+                                       }
+                               }
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       if((RetVal & FF_DIR_LFN_TRAVERSED)) {
+                               break;          
+                       }
+               }
+
+               // Traverse!
+               
+               if((RetVal & FF_DIR_LFN_TRAVERSED)) {
+                       RetVal = FF_ERR_NONE;
+                       fatEntry = pDirent->AddrCurrentCluster;
+               } else {
+                       if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) {
+                               fatEntry = FF_getFatEntry(pIoman, pDirent->AddrCurrentCluster);
+                               pDirent->AddrCurrentCluster = FF_TraverseFAT(pIoman, pDirent->AddrCurrentCluster, 1);
+                               pDirent->CurrentCluster += 1;
+                       }
+               }
+       } while(!FF_isEndOfChain(pIoman, fatEntry));
+
+       return FF_ERR_DIR_END_OF_DIR;
+}*/
+
+
+/**
+ *     @private
+ **/
+/*FF_T_UINT32 FF_FindEntry(FF_IOMAN *pIoman, FF_T_SINT8 *path, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent) {
+       
+       FF_T_INT32              retVal;
+       FF_T_INT8               name[FF_MAX_FILENAME];
+       FF_T_INT8               Filename[FF_MAX_FILENAME];
+       FF_T_UINT16             fnameLen;
+       FF_T_UINT16             compareLength;
+       FF_T_UINT16             nameLen;
+       FF_T_UINT16             i = strlen(path);
+
+
+       while(i != 0) {
+               if(path[i] == '\\' || path[i] == '/') {
+                       break;
+               }
+               i--;
+       }
+       
+       if(i == 0) {
+               i = 1;
+       }
+
+       nameLen = strlen((path + i));
+       strncpy(name, (path + i), nameLen);
+       name[nameLen] = '\0';   
+       
+
+       if(FF_FindFirst(pIoman, pDirent, path)) {
+               return 0; // file not found.
+       }
+
+       if((pDirent->Attrib & pa_Attrib) == pa_Attrib){
+               strcpy(Filename, pDirent->FileName);
+               fnameLen = (FF_T_UINT16) strlen(Filename);
+               FF_tolower(Filename, (FF_T_UINT32) fnameLen);
+               FF_tolower(name, (FF_T_UINT32) nameLen);
+               if(nameLen > fnameLen) {
+                       compareLength = nameLen;
+               } else {
+                       compareLength = fnameLen;
+               }
+               if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) {
+                       // Object found!!
+                       return pDirent->ObjectCluster;  // Return the cluster number
+               }
+       }
+
+       while(1) {      
+               if(FF_FindNext(pIoman, pDirent)) {
+                       return 0;       // end of dir, file not found!
+               }
+
+               if((pDirent->Attrib & pa_Attrib) == pa_Attrib){
+                       strcpy(Filename, pDirent->FileName);
+                       fnameLen = (FF_T_UINT16) strlen(Filename);
+                       FF_tolower(Filename, (FF_T_UINT32) fnameLen);
+                       FF_tolower(name, (FF_T_UINT32) nameLen);
+                       if(nameLen > fnameLen) {
+                               compareLength = nameLen;
+                       } else {
+                               compareLength = fnameLen;
+                       }
+                       if(strncmp(name, Filename, (FF_T_UINT32) compareLength) == 0) {
+                               // Object found!
+                               return pDirent->ObjectCluster;  // Return the cluster number
+                       }
+               }
+       }
+       return 0;
+}*/
+
+/**
+ *     @private
+ **/
+
+FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen) {
+    FF_T_UINT32     dirCluster = pIoman->pPartition->RootDirCluster;
+    FF_T_INT8       mytoken[FF_MAX_FILENAME];
+    FF_T_INT8       *token;
+    FF_T_UINT16     it = 0;         // Re-entrancy Variables for FF_strtok()
+    FF_T_BOOL       last = FF_FALSE;
+    FF_DIRENT       MyDir;
+#ifdef FF_PATH_CACHE
+       FF_T_UINT32             i;
+#endif
+
+    if(pathLen == 1) {      // Must be the root dir! (/ or \)
+               return pIoman->pPartition->RootDirCluster;
+    }
+    
+    if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') {
+               pathLen--;      
+    }
+       
+#ifdef FF_PATH_CACHE   // Is the requested path in the PATH CACHE?
+       FF_PendSemaphore(pIoman->pSemaphore);   // Thread safety on shared object!
+       {
+               for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+                       if(strlen(pIoman->pPartition->PathCache[i].Path) == pathLen) {
+                               if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, pathLen)) {
+                                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+                                       return pIoman->pPartition->PathCache[i].DirCluster;
+                               }
+                       }
+               }
+       }
+       FF_ReleaseSemaphore(pIoman->pSemaphore);
+#endif
+
+    token = FF_strtok(path, mytoken, &it, &last, pathLen);
+
+     do{
+            //lastDirCluster = dirCluster;
+            MyDir.CurrentItem = 0;
+            dirCluster = FF_FindEntryInDir(pIoman, dirCluster, token, FF_FAT_ATTR_DIR, &MyDir);
+                       /*if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir.
+                               dirCluster = pIoman->pPartition->RootDirCluster;
+            }*/
+            token = FF_strtok(path, mytoken, &it, &last, pathLen);
+    }while(token != NULL);
+
+#ifdef FF_PATH_CACHE   // Update the PATH CACHE with a new PATH
+        if(dirCluster) {       // Only cache if the dir was actually found!
+               FF_PendSemaphore(pIoman->pSemaphore);
+               {
+                       if(pathLen < FF_MAX_PATH) {     // Ensure the PATH won't cause a buffer overrun.
+                               memcpy(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path, path, pathLen);
+                               pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].Path[pathLen] = '\0';
+                               pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].DirCluster = dirCluster;
+#ifdef FF_HASH_TABLE_SUPPORT                           
+                               FF_ClearHashTable(pIoman->pPartition->PathCache[pIoman->pPartition->PCIndex].pHashTable);
+#endif                 
+                               pIoman->pPartition->PCIndex += 1;
+                               if(pIoman->pPartition->PCIndex >= FF_PATH_CACHE_DEPTH) {
+                                       pIoman->pPartition->PCIndex = 0;
+                               }
+                       }
+               }
+               FF_ReleaseSemaphore(pIoman->pSemaphore);
+        }
+#endif
+
+    return dirCluster;
+}
+
+/*
+FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, FF_T_INT8 *path, FF_T_UINT16 pathLen) {
+    FF_T_UINT32                dirCluster = pIoman->pPartition->RootDirCluster;
+    FF_T_INT8       mytoken[FF_MAX_FILENAME];
+    FF_T_INT8       *token;
+    FF_T_UINT16     it = 0;         // Re-entrancy Variables for FF_strtok()
+    FF_T_BOOL       last = FF_FALSE;
+    FF_DIRENT       MyDir;
+
+    if(pathLen == 1) {      // Must be the root dir! (/ or \)
+            return pIoman->pPartition->RootDirCluster;
+    }
+    
+    if(path[pathLen-1] == '\\' || path[pathLen-1] == '/') {
+            pathLen--;      
+    }
+
+    token = FF_strtok(path, mytoken, &it, &last, pathLen);
+
+     do{
+            //lastDirCluster = dirCluster;
+            MyDir.CurrentItem = 0;
+                       if(FF_FindEntry(pIoman, dirCluster, token, &MyDir, FF_TRUE)) {
+                               return 0;
+                       } else {
+                               dirCluster = MyDir.ObjectCluster;
+                       }
+                       if(MyDir.Attrib != FF_FAT_ATTR_DIR) {
+                               return 0;
+                       }
+                       if(dirCluster == 0 && MyDir.CurrentItem == 2 && MyDir.FileName[0] == '.') { // .. Dir Entry pointing to root dir.
+                               dirCluster = pIoman->pPartition->RootDirCluster;
+            }
+            token = FF_strtok(path, mytoken, &it, &last, pathLen);
+    }while(token != NULL);
+
+    return dirCluster;
+}
+*/
+
+#ifdef FF_LFN_SUPPORT
+/**
+ *     @private
+ **//*
+FF_T_SINT8 FF_getLFN(FF_IOMAN *pIoman, FF_BUFFER *pBuffer, FF_DIRENT *pDirent, FF_T_INT8 *filename) {
+
+       FF_T_UINT8              numLFNs;
+       FF_T_UINT16             lenlfn = 0;
+       FF_T_UINT8              tester;
+       FF_T_UINT16             i,y;
+       FF_T_UINT32             CurrentCluster;
+       FF_T_UINT32             fatEntry;
+       FF_T_UINT8              *buffer         = pBuffer->pBuffer;
+       FF_T_UINT32             Sector          = pBuffer->Sector;
+       FF_T_UINT32             Entry           = FF_getMinorBlockEntry(pIoman, pDirent->CurrentItem, 32);
+
+       tester = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(Entry * 32));
+       numLFNs = (FF_T_UINT8) (tester & ~0x40);
+
+       while(numLFNs > 0) {
+               if(FF_getClusterChainNumber(pIoman, pDirent->CurrentItem, 32) > pDirent->CurrentCluster) {
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       fatEntry = FF_getFatEntry(pIoman, pDirent->DirCluster);
+                       if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) {
+                               return FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+
+                       if(FF_isEndOfChain(pIoman, fatEntry)) {
+                               CurrentCluster = pDirent->DirCluster;
+                               // ERROR THIS SHOULD NOT OCCUR!
+                       } else {
+                               CurrentCluster = fatEntry;
+                       }
+
+                       pBuffer = FF_GetBuffer(pIoman, FF_getRealLBA(pIoman, FF_Cluster2LBA(pIoman, CurrentCluster)), FF_MODE_READ);
+                       if(!pBuffer) {
+                               return FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+                       Entry = 0;      
+               }
+
+               if(Entry > 15) {
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       Sector += 1;
+                       pBuffer = FF_GetBuffer(pIoman, Sector, FF_MODE_READ);
+                       if(!pBuffer) {
+                               return FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+                       buffer = pBuffer->pBuffer;
+                       Entry = 0;
+               }
+
+               for(i = 0, y = 0; i < 5; i++, y += 2) {
+                       filename[i + ((numLFNs - 1) * 13)] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_1 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 6; i++, y += 2) {
+                       filename[i + ((numLFNs - 1) * 13) + 5] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_2 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 2; i++, y += 2) {
+                       filename[i + ((numLFNs - 1) * 13) + 11] = buffer[(Entry * 32) + FF_FAT_LFN_NAME_3 + y];
+                       lenlfn++;
+               }
+
+               numLFNs--;
+
+               Entry++;
+               pDirent->CurrentItem += 1;
+       }
+
+       filename[lenlfn] = '\0';
+
+       return 0;
+}*/
+#endif
+
+/**
+ *     @private
+ **/
+static void FF_ProcessShortName(FF_T_INT8 *name) {
+       FF_T_INT8       shortName[13];
+       FF_T_UINT8      i;
+       memcpy(shortName, name, 11);
+       
+       for(i = 0; i < 8; i++) {
+               if(shortName[i] == 0x20) {
+                       name[i] = '\0';
+                       break;
+               }
+               name[i] = shortName[i];
+       }
+
+       if(shortName[8] != 0x20){
+               name[i] = '.';
+               name[i+1] = shortName[8];
+               name[i+2] = shortName[9];
+               name[i+3] = shortName[10];
+               name[i+4] = '\0';
+               for(i = 0; i < 11; i++) {
+                       if(name[i] == 0x20) {
+                               name[i] = '\0';
+                               break;
+                       }
+               }
+       } else {
+               name[i] = '\0';
+       }
+
+}
+
+#ifdef FF_TIME_SUPPORT
+static void FF_PlaceTime(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) {
+       FF_T_UINT16             myShort;
+       FF_SYSTEMTIME   str_t;
+
+       FF_GetSystemTime(&str_t);
+                               
+       myShort = 0;
+       myShort |= ((str_t.Hour    << 11) & 0xF800);
+       myShort |= ((str_t.Minute  <<  5) & 0x07E0);
+       myShort |= ((str_t.Second   /  2) & 0x001F);
+       FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort);
+}
+
+static void FF_PlaceDate(FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) {
+       FF_T_UINT16             myShort;
+       FF_SYSTEMTIME   str_t;
+
+       FF_GetSystemTime(&str_t);
+       
+       myShort = 0;
+       myShort |= (((str_t.Year- 1980)  <<  9) & 0xFE00) ;
+       myShort |= ((str_t.Month <<  5) & 0x01E0);
+       myShort |= (str_t.Day & 0x001F);
+       FF_putShort(EntryBuffer, (FF_T_UINT16) Offset, myShort);
+}
+
+
+static void FF_GetTime(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) {
+       FF_T_UINT16 myShort;
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16) Offset);
+       pTime->Hour             = (((myShort & 0xF800) >> 11) & 0x001F);
+       pTime->Minute   = (((myShort & 0x07E0) >>  5) & 0x003F);
+       pTime->Second   = 2 * (myShort & 0x01F);
+}
+
+static void FF_GetDate(FF_SYSTEMTIME *pTime, FF_T_UINT8 *EntryBuffer, FF_T_UINT32 Offset) {
+       FF_T_UINT16 myShort;
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16) Offset);
+       pTime->Year             = 1980 + (((myShort & 0xFE00) >> 9) & 0x07F);
+       pTime->Month    = (((myShort & 0x01E0) >> 5) & 0x000F);
+       pTime->Day              = myShort & 0x01F;
+}
+
+
+
+#endif
+
+void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer) {
+       FF_T_UINT16 myShort;
+       
+       memcpy(pDirent->FileName, EntryBuffer, 11);     // Copy the filename into the Dirent object.
+       FF_ProcessShortName(pDirent->FileName);         // Format the shortname, for pleasant viewing.
+
+#ifdef FF_HASH_TABLE_SUPPORT
+#if FF_HASH_FUNCTION == CRC16
+       FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName)));
+#elif FF_HASH_FUNCTION == CRC8
+       FF_AddDirentHash(pIoman, pDirent->DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) pDirent->FileName, strlen(pDirent->FileName)));
+#endif
+#else
+       pIoman = NULL;
+#endif
+
+       FF_tolower(pDirent->FileName, (FF_T_UINT32)strlen(pDirent->FileName));
+
+       // Get the item's Cluster address.
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH));
+       pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16);
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW));
+       pDirent->ObjectCluster |= myShort;
+#ifdef FF_TIME_SUPPORT
+       // Get the creation Time & Date
+       FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME);
+       FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE);
+       // Get the modified Time & Date
+       FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME);
+       FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE);
+       // Get the last accessed Date.
+       FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE);
+       pDirent->AccessedTime.Hour              = 0;
+       pDirent->AccessedTime.Minute    = 0;
+       pDirent->AccessedTime.Second    = 0;
+#endif
+       // Get the filesize.
+       pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE));
+       // Get the attribute.
+       pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+}
+
+FF_T_SINT8 FF_FetchEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) {
+       FF_BUFFER *pBuffer;
+       FF_T_UINT32 itemLBA;
+       FF_T_UINT32 chainLength         = FF_GetChainLength(pIoman, DirCluster, NULL);  // BottleNeck
+       FF_T_UINT32 clusterNum          = FF_getClusterChainNumber      (pIoman, nEntry, (FF_T_UINT16)32);
+       FF_T_UINT32 relItem                     = FF_getMinorBlockEntry         (pIoman, nEntry, (FF_T_UINT16)32);
+       FF_T_UINT32 clusterAddress      = FF_TraverseFAT(pIoman, DirCluster, clusterNum);       // BottleNeck
+
+       if(pIoman->pPartition->Type != FF_T_FAT32) {
+               if(DirCluster == pIoman->pPartition->RootDirCluster) {
+                       chainLength = pIoman->pPartition->RootDirSectors / pIoman->pPartition->SectorsPerCluster;
+                       if(!chainLength) {              // Some media has RootDirSectors < SectorsPerCluster. This is wrong, as it should be atleast 1 cluster!
+                               chainLength = 1;
+                       }
+                       clusterAddress = DirCluster;
+                       clusterNum = 0;
+                       if(nEntry > ((pIoman->pPartition->RootDirSectors * pIoman->pPartition->BlkSize) / 32)) {
+                               return FF_ERR_DIR_END_OF_DIR;
+                       }
+               }
+       }
+               
+       if((clusterNum + 1) > chainLength) {
+               return FF_ERR_DIR_END_OF_DIR;   // End of Dir was reached!
+       }
+
+       itemLBA = FF_Cluster2LBA(pIoman, clusterAddress)        + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32);
+       itemLBA = FF_getRealLBA (pIoman, itemLBA)                       + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32);
+       
+       pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_READ);
+       {
+               memcpy(buffer, (pBuffer->pBuffer + (relItem*32)), 32);
+               pBuffer->Persistance = 1;
+       }
+       FF_ReleaseBuffer(pIoman, pBuffer);
+    return FF_ERR_NONE;
+}
+
+
+FF_T_SINT8 FF_PushEntry(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer) {
+       FF_BUFFER *pBuffer;
+       FF_T_UINT32 itemLBA;
+       FF_T_UINT32 chainLength         = FF_GetChainLength(pIoman, DirCluster, NULL);  // BottleNeck
+       FF_T_UINT32 clusterNum          = FF_getClusterChainNumber      (pIoman, nEntry, (FF_T_UINT16)32);
+       FF_T_UINT32 relItem                     = FF_getMinorBlockEntry         (pIoman, nEntry, (FF_T_UINT16)32);
+       FF_T_UINT32 clusterAddress      = FF_TraverseFAT(pIoman, DirCluster, clusterNum);       // BottleNeck
+       
+       if((clusterNum + 1) > chainLength) {
+               return FF_ERR_DIR_END_OF_DIR;   // End of Dir was reached!
+       }
+
+       itemLBA = FF_Cluster2LBA(pIoman, clusterAddress)        + FF_getMajorBlockNumber(pIoman, nEntry, (FF_T_UINT16)32);
+       itemLBA = FF_getRealLBA (pIoman, itemLBA)                       + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32);
+       
+       pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE);
+       {
+               memcpy((pBuffer->pBuffer + (relItem*32)), buffer, 32);
+       }
+       FF_ReleaseBuffer(pIoman, pBuffer);
+    return 0;
+}
+
+
+/**
+ *     @private
+ **/
+FF_ERROR FF_GetEntry(FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) {
+       FF_T_UINT8 EntryBuffer[32];
+       FF_T_UINT8 numLFNs;
+       
+       if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer)) {
+                       return FF_ERR_DIR_END_OF_DIR;
+       }
+       if(EntryBuffer[0] != 0xE5) {
+               if(FF_isEndOfDir(EntryBuffer)){
+                       return FF_ERR_DIR_END_OF_DIR;
+               }
+               
+               pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+               
+               if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) {
+                       // LFN Processing
+                       numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40);
+       #ifdef FF_LFN_SUPPORT
+                       FF_PopulateLongDirent(pIoman, pDirent, DirCluster, nEntry);
+                       return 0;
+       #else 
+                       pDirent->CurrentItem += (numLFNs - 1);
+       #endif
+               } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) {
+                       // Do Nothing
+               
+               } else {
+                       FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer);
+                       pDirent->CurrentItem += 1;
+                       return 0;
+               }
+       }
+       return FF_ERR_NONE;
+}
+
+FF_T_BOOL FF_isEndOfDir(FF_T_UINT8 *EntryBuffer) {
+       if(EntryBuffer[0] == 0x00) {
+               return FF_TRUE;
+       }
+       return FF_FALSE;
+}
+
+#ifdef FF_HASH_TABLE_SUPPORT
+FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) {
+       FF_T_UINT32 i;
+       FF_HASH_TABLE pHash = NULL;
+       for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+               if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) {
+                       pHash = pIoman->pPartition->PathCache[i].pHashTable;
+                       break;
+               }
+       }
+
+       if(pHash) {
+               FF_SetHash(pHash, nHash);
+       }
+
+       return FF_ERR_NONE;
+}
+
+FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash) {
+       FF_T_UINT32 i;
+       FF_HASH_TABLE pHash = NULL;
+       for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+               if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) {
+                       pHash = pIoman->pPartition->PathCache[i].pHashTable;
+                       break;
+               }
+       }
+
+       if(pHash) {
+               return FF_isHashSet(pHash, nHash);
+       }
+
+       return FF_FALSE;
+}
+
+FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) {
+       FF_T_UINT32 i;
+       for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+               if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) {
+                       if(pIoman->pPartition->PathCache[i].bHashed) {
+                               return FF_TRUE;
+                       }
+               }
+       }
+
+       return FF_FALSE;
+}
+
+void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) {
+       int i;
+       for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+               if(pIoman->pPartition->PathCache[i].DirCluster == DirCluster) {
+                       pIoman->pPartition->PathCache[i].bHashed = FF_TRUE;
+                       return;
+               }
+       }
+}
+#endif
+
+
+FF_T_SINT8 FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry) {
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_INT8       ShortName[13];
+       FF_T_UINT8 numLFNs;
+       FF_T_UINT8 x;
+       FF_T_UINT8 CheckSum = 0;
+       FF_T_UINT16 i,y;
+       FF_T_UINT16 lenlfn = 0;
+       FF_T_UINT16 myShort;
+       
+       FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer);
+       numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40);
+       // Handle the name
+       CheckSum = FF_getChar(EntryBuffer, FF_FAT_LFN_CHECKSUM);
+
+       x = numLFNs;
+       while(numLFNs) {
+               for(i = 0, y = 0; i < 5; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13)] = EntryBuffer[FF_FAT_LFN_NAME_1 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 6; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13) + 5] = EntryBuffer[FF_FAT_LFN_NAME_2 + y];
+                       lenlfn++;
+               }
+
+               for(i = 0, y = 0; i < 2; i++, y += 2) {
+                       pDirent->FileName[i + ((numLFNs - 1) * 13) + 11] = EntryBuffer[FF_FAT_LFN_NAME_3 + y];
+                       lenlfn++;
+               }
+
+               FF_FetchEntry(pIoman, DirCluster, nEntry++, EntryBuffer);
+               numLFNs--;
+       }
+
+       pDirent->FileName[lenlfn] = '\0';
+       
+       // Process the ShortName Entry
+       memcpy(ShortName, EntryBuffer, 11);
+       if(CheckSum != FF_CreateChkSum(EntryBuffer)) {
+               FF_ProcessShortName(ShortName);
+               strcpy(pDirent->FileName, ShortName);
+       } else {
+               FF_ProcessShortName(ShortName);
+       }
+
+#ifdef FF_HASH_TABLE_SUPPORT
+#if FF_HASH_FUNCTION == CRC16
+       FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC16((FF_T_UINT8 *) ShortName, strlen(ShortName)));
+#elif FF_HASH_FUNCTION == CRC8
+       FF_AddDirentHash(pIoman, DirCluster, (FF_T_UINT32)FF_GetCRC8((FF_T_UINT8 *) ShortName, strlen(ShortName)));
+#endif
+#endif
+       
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH));
+       pDirent->ObjectCluster = (FF_T_UINT32) (myShort << 16);
+       myShort = FF_getShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW));
+       pDirent->ObjectCluster |= myShort;
+
+#ifdef FF_TIME_SUPPORT
+       // Get the creation Time & Date
+       FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_TIME);
+       FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_CREATE_DATE);
+       // Get the modified Time & Date
+       FF_GetTime(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME);
+       FF_GetDate(&pDirent->CreateTime, EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE);
+       // Get the last accessed Date.
+       FF_GetDate(&pDirent->AccessedTime, EntryBuffer, FF_FAT_DIRENT_LASTACC_DATE);
+       pDirent->AccessedTime.Hour              = 0;
+       pDirent->AccessedTime.Minute    = 0;
+       pDirent->AccessedTime.Second    = 0;
+#endif
+
+       // Get the filesize.
+       pDirent->Filesize = FF_getLong(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE));
+       // Get the attribute.
+       pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+       
+       pDirent->CurrentItem = nEntry;
+       return x;
+}
+
+/**
+ *     @public
+ *     @brief  Find's the first directory entry for the provided path.
+ *
+ *     All values recorded in pDirent must be preserved to and between calls to
+ *     FF_FindNext().
+ *
+ *     @param  pIoman          FF_IOMAN object that was created by FF_CreateIOMAN().
+ *     @param  pDirent         FF_DIRENT object to store the entry information.
+ *     @param  path            String to of the path to the Dir being listed.
+ *
+ *     @return 0 on success
+ *     @return FF_ERR_DEVICE_DRIVER_FAILED if device access failed.
+ *     @return -2 if Dir was not found.
+ *
+ **/
+FF_ERROR FF_FindFirst(FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path) {
+       FF_T_UINT8      numLFNs;
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT16     PathLen = (FF_T_UINT16) strlen(path);
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       pDirent->DirCluster = FF_FindDir(pIoman, path, PathLen);        // Get the directory cluster, if it exists.
+
+       if(pDirent->DirCluster == 0) {
+               return FF_ERR_DIR_INVALID_PATH;
+       }
+       
+       for(pDirent->CurrentItem = 0; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) {
+               if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) {
+                       return FF_ERR_DIR_END_OF_DIR;
+               }
+               if(EntryBuffer[0] != FF_FAT_DELETED) {
+                       if(FF_isEndOfDir(EntryBuffer)){
+                               return FF_ERR_DIR_END_OF_DIR;
+                       }
+                       pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+                       if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) {
+                               // LFN Processing
+                               numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40);
+                               // Get the shortname and check if it is marked deleted.
+#ifdef FF_LFN_SUPPORT
+                               // Fetch the shortname, and get it's checksum, or for a deleted item with
+                               // orphaned LFN entries.
+                               if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) {
+                                       return FF_ERR_DIR_END_OF_DIR;
+                               }
+                               
+                               if(EntryBuffer[0] != FF_FAT_DELETED) {
+                                       FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem);
+                                       return FF_ERR_NONE;
+                               }
+#else 
+                               pDirent->CurrentItem += (numLFNs - 1);
+#endif
+                       } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) {
+                               // Do Nothing
+                       
+                       } else {
+                               FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer);
+                               pDirent->CurrentItem += 1;
+                               return FF_ERR_NONE;
+                       }
+               }
+       }
+
+       return FF_ERR_DIR_END_OF_DIR;
+}
+
+/**
+ *     @public
+ *     @brief  Get's the next Entry based on the data recorded in the FF_DIRENT object.
+ *
+ *     All values recorded in pDirent must be preserved to and between calls to
+ *     FF_FindNext().
+ *
+ *     @param  pIoman          FF_IOMAN object that was created by FF_CreateIOMAN().
+ *     @param  pDirent         FF_DIRENT object to store the entry information.
+ *
+ *     @return FF_ERR_DEVICE_DRIVER_FAILED is device access failed.
+ *
+ **/
+FF_ERROR FF_FindNext(FF_IOMAN *pIoman, FF_DIRENT *pDirent) {
+       
+       FF_T_UINT8      numLFNs;
+       FF_T_UINT8      EntryBuffer[32];
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+       
+       for(; pDirent->CurrentItem < 0xFFFF; pDirent->CurrentItem += 1) {
+               if(FF_FetchEntry(pIoman, pDirent->DirCluster, pDirent->CurrentItem, EntryBuffer)) {
+                       return FF_ERR_DIR_END_OF_DIR;
+               }
+               if(EntryBuffer[0] != FF_FAT_DELETED) {
+                       if(FF_isEndOfDir(EntryBuffer)){
+                               return FF_ERR_DIR_END_OF_DIR;
+                       }
+                       pDirent->Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+                       if((pDirent->Attrib & FF_FAT_ATTR_LFN) == FF_FAT_ATTR_LFN) {
+                               // LFN Processing
+                               numLFNs = (FF_T_UINT8)(EntryBuffer[0] & ~0x40);
+                               // Get the shortname and check if it is marked deleted.
+#ifdef FF_LFN_SUPPORT
+                               // Fetch the shortname, and get it's checksum, or for a deleted item with
+                               // orphaned LFN entries.
+                               if(FF_FetchEntry(pIoman, pDirent->DirCluster, (pDirent->CurrentItem + numLFNs), EntryBuffer)) {
+                                       return FF_ERR_DIR_END_OF_DIR;
+                               }
+                               
+                               if(EntryBuffer[0] != FF_FAT_DELETED) {
+                                       FF_PopulateLongDirent(pIoman, pDirent, pDirent->DirCluster, pDirent->CurrentItem);
+                                       return FF_ERR_NONE;
+                               }
+#else 
+                               pDirent->CurrentItem += (numLFNs - 1);
+#endif
+                       } else if((pDirent->Attrib & FF_FAT_ATTR_VOLID) == FF_FAT_ATTR_VOLID) {
+                               // Do Nothing
+                       
+                       } else {
+                               FF_PopulateShortDirent(pIoman, pDirent, EntryBuffer);
+                               pDirent->CurrentItem += 1;
+                               return FF_ERR_NONE;
+                       }
+               }
+       }
+       
+       return FF_ERR_DIR_END_OF_DIR;
+}
+
+
+FF_T_SINT8 FF_RewindFind(FF_IOMAN *pIoman, FF_DIRENT *pDirent) {
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+       pDirent->CurrentItem = 0;
+       return 0;
+}
+
+
+FF_T_SINT32 FF_FindFreeDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 Sequential) {
+
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT16     i = 0;
+       FF_T_UINT16 nEntry;
+       FF_T_SINT8      RetVal;
+       FF_T_UINT32     DirLength;
+       FF_T_UINT32     iEndOfChain;
+       
+       for(nEntry = 0; nEntry < 0xFFFF; nEntry++) {
+               if(FF_FetchEntry(pIoman, DirCluster, nEntry, EntryBuffer) == FF_ERR_DIR_END_OF_DIR) {
+                       RetVal = FF_ExtendDirectory(pIoman, DirCluster);
+                       if(RetVal != FF_ERR_NONE) {
+                               return RetVal;
+                       }
+                       return nEntry;
+               }
+               if(FF_isEndOfDir(EntryBuffer)) {        // If its the end of the Dir, then FreeDirents from here.
+                       // Check Dir is long enough!
+                       DirLength = FF_GetChainLength(pIoman, DirCluster, &iEndOfChain);
+                       if((nEntry + Sequential) > (FF_T_UINT16)(((pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize) * DirLength) / 32)) {
+                               FF_ExtendDirectory(pIoman, DirCluster);
+                       }
+                       return nEntry;
+               }
+               if(EntryBuffer[0] == 0xE5) {
+                       i++;
+               } else {
+                       i = 0;
+               }
+
+               if(i == Sequential) {
+                       return (nEntry - (Sequential - 1));// Return the beginning entry in the sequential sequence.
+               }
+       }
+       
+       return FF_ERR_DIR_DIRECTORY_FULL;       
+}
+
+
+
+
+FF_T_SINT8 FF_PutEntry(FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) {
+       FF_BUFFER *pBuffer;
+       FF_T_UINT32 itemLBA;
+       FF_T_UINT32 clusterNum          = FF_getClusterChainNumber      (pIoman, Entry, (FF_T_UINT16)32);
+       FF_T_UINT32 relItem                     = FF_getMinorBlockEntry         (pIoman, Entry, (FF_T_UINT16)32);
+       FF_T_UINT32 clusterAddress      = FF_TraverseFAT(pIoman, DirCluster, clusterNum);
+
+       itemLBA = FF_Cluster2LBA(pIoman, clusterAddress)        + FF_getMajorBlockNumber(pIoman, Entry, (FF_T_UINT16)32);
+       itemLBA = FF_getRealLBA (pIoman, itemLBA)                       + FF_getMinorBlockNumber(pIoman, relItem, (FF_T_UINT16)32);
+       
+       pBuffer = FF_GetBuffer(pIoman, itemLBA, FF_MODE_WRITE);
+       {
+               // Modify the Entry!
+               //memcpy((pBuffer->pBuffer + (32*relItem)), pDirent->FileName, 11);
+               FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB + (32 * relItem)), pDirent->Attrib);
+               FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster >> 16));
+               FF_putShort(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW  + (32 * relItem)), (FF_T_UINT16)(pDirent->ObjectCluster));
+               FF_putLong(pBuffer->pBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE  + (32 * relItem)), pDirent->Filesize);
+#ifdef FF_TIME_SUPPORT
+       FF_PlaceDate((pBuffer->pBuffer + (32 * relItem)), FF_FAT_DIRENT_LASTACC_DATE);  // Last accessed date.
+#endif
+       }
+       FF_ReleaseBuffer(pIoman, pBuffer);
+    return 0;
+}
+
+
+/*static FF_T_BOOL FF_isShortName(const FF_T_UINT8 *Name, FF_T_UINT16 StrLen) {
+       FF_T_UINT16 i;
+       for(i = 0; i < StrLen; i++) {
+               if(Name[i] == '.') {
+                       i--;
+               }
+       }
+       if(i < 11) {
+               return FF_TRUE;
+       }
+       return FF_FALSE;
+}*/
+
+FF_T_SINT8 FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName) {
+       FF_T_UINT16 i,x,y;
+       FF_T_INT8       TempName[FF_MAX_FILENAME];
+       FF_T_INT8       MyShortName[13];
+       FF_T_UINT16 NameLen; 
+       FF_T_BOOL       FitsShort = FF_FALSE;
+       FF_DIRENT       MyDir;
+       //FF_T_SINT8    RetVal = 0;
+       FF_T_INT8       NumberBuf[6];
+       // Create a Short Name
+       strncpy(TempName, LongName, FF_MAX_FILENAME);
+       NameLen = (FF_T_UINT16) strlen(TempName);
+       FF_toupper(TempName, NameLen);
+
+       // Initialise Shortname
+
+       for(i = 0; i < 11; i++) {
+               ShortName[i] = 0x20;
+       }
+
+       // Does LongName fit a shortname?
+
+       for(i = 0, x = 0; i < NameLen; i++) {
+               if(TempName[i] != '.') {
+                       x++;
+               }
+       }
+
+       if(x <= 11) {
+               //FitsShort = FF_TRUE;
+       }
+
+       // Main part of the name
+       for(i = 0, x = 0; i < 8; i++, x++) {
+               if(i == 0 && TempName[x] == '.') {
+                       i--;
+               } else {
+                       if(TempName[x] == '.') {
+                               break;
+                       } else if(TempName[x] == ' ') {
+                               i--;
+                       } else {
+                               ShortName[i] = TempName[x];
+                               if(ShortName[i] == 0x00) {
+                                       ShortName[i] = 0x20;
+                               }
+                       }
+               }
+       }
+       
+       for(i = NameLen; i > x; i--) {
+               if(TempName[i] == '.') {
+                       break;
+               }
+       }
+
+       if(TempName[i] == '.') {
+               x = i + 1;
+               for(i = 0; i < 3; i++) {
+                       if(x < NameLen) {
+                               ShortName[8 + i] = TempName[x++];
+                       }
+               }
+       }
+
+       // Tail :
+       memcpy(MyShortName, ShortName, 11);
+       FF_ProcessShortName(MyShortName);
+       
+       if(!FF_FindEntryInDir(pIoman, DirCluster, MyShortName, 0x00, &MyDir) && FitsShort) {
+               return 0;
+       } else {
+               if(FitsShort) {
+                       return FF_ERR_DIR_OBJECT_EXISTS;
+               }
+               for(i = 1; i < 0x0000FFFF; i++) { // Max Number of Entries in a DIR!
+                       sprintf(NumberBuf, "%d", i);
+                       NameLen = (FF_T_UINT16) strlen(NumberBuf);
+                       x = 7 - NameLen;
+                       ShortName[x++] = '~';
+                       for(y = 0; y < NameLen; y++) {
+                               ShortName[x+y] = NumberBuf[y];
+                       }
+                       memcpy(MyShortName, ShortName, 11);
+                       FF_ProcessShortName(MyShortName);
+                       if(!FF_ShortNameExists(pIoman, DirCluster, MyShortName)) {
+                               return 0;
+                       }
+               }
+               // Add a tail and special number until we're happy :D
+       }
+
+       return FF_ERR_DIR_DIRECTORY_FULL;
+}
+#ifdef FF_LFN_SUPPORT
+static FF_T_SINT8 FF_CreateLFNEntry(FF_T_UINT8 *EntryBuffer, FF_T_INT8 *Name, FF_T_UINT8 NameLen, FF_T_UINT8 nLFN, FF_T_UINT8 CheckSum) {
+       
+       FF_T_UINT8 i, x;
+       
+       memset(EntryBuffer, 0, 32);
+
+       FF_putChar(EntryBuffer, FF_FAT_LFN_ORD,                 (FF_T_UINT8) ((nLFN & ~0x40)));
+       FF_putChar(EntryBuffer, FF_FAT_DIRENT_ATTRIB,   (FF_T_UINT8) FF_FAT_ATTR_LFN);
+       FF_putChar(EntryBuffer, FF_FAT_LFN_CHECKSUM,    (FF_T_UINT8) CheckSum);
+
+       // Name_1
+       for(i = 0, x = 0; i < 5; i++, x += 2) {
+               if(i < NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_1 + x] = Name[i];
+               } else if (i == NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_1 + x] = '\0';
+               }else {
+                       EntryBuffer[FF_FAT_LFN_NAME_1 + x]              = 0xFF;
+                       EntryBuffer[FF_FAT_LFN_NAME_1 + x + 1]  = 0xFF;
+               }
+       }
+
+       // Name_2
+       for(i = 0, x = 0; i < 6; i++, x += 2) {
+               if((i + 5) < NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_2 + x] = Name[i+5];
+               } else if ((i + 5) == NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_2 + x] = '\0';
+               }else {
+                       EntryBuffer[FF_FAT_LFN_NAME_2 + x]              = 0xFF;
+                       EntryBuffer[FF_FAT_LFN_NAME_2 + x + 1]  = 0xFF;
+               }
+       }
+
+       // Name_3
+       for(i = 0, x = 0; i < 2; i++, x += 2) {
+               if((i + 11) < NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_3 + x] = Name[i+11];
+               } else if ((i + 11) == NameLen) {
+                       EntryBuffer[FF_FAT_LFN_NAME_3 + x] = '\0';
+               }else {
+                       EntryBuffer[FF_FAT_LFN_NAME_3 + x]              = 0xFF;
+                       EntryBuffer[FF_FAT_LFN_NAME_3 + x + 1]  = 0xFF;
+               }
+       }
+       
+       return FF_ERR_NONE;
+}
+
+static FF_T_SINT8 FF_CreateLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_T_UINT8 CheckSum, FF_T_UINT16 nEntry) {
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT16 NameLen = (FF_T_UINT16) strlen(Name);
+       FF_T_UINT8      NumLFNs = (FF_T_UINT8)  (NameLen / 13);
+       FF_T_UINT8      i;
+       FF_T_UINT8      EndPos = (NameLen % 13);
+
+       if(EndPos) {
+               NumLFNs ++;
+       } else {
+               EndPos = 13;
+       }
+
+       for(i = NumLFNs; i > 0; i--) {
+               if(i == NumLFNs) {
+                       FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), EndPos, i, CheckSum);
+                       EntryBuffer[0] |= 0x40;
+               } else {
+                       FF_CreateLFNEntry(EntryBuffer, (Name + (13 * (i - 1))), 13, i, CheckSum);
+               }
+               FF_PushEntry(pIoman, DirCluster, nEntry + (NumLFNs - i), EntryBuffer);
+       }
+
+       return FF_ERR_NONE;
+}
+#endif
+
+FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster) {
+       FF_T_UINT32 CurrentCluster;
+       FF_T_UINT32 NextCluster;
+
+       if(pIoman->pPartition->Type != FF_T_FAT32) {
+               if(DirCluster == pIoman->pPartition->RootDirCluster) {
+                       return FF_ERR_DIR_CANT_EXTEND_ROOT_DIR;
+               }
+       }
+
+       if(!pIoman->pPartition->FreeClusterCount) {
+               pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman);
+               if(pIoman->pPartition->FreeClusterCount == 0) {
+                       return FF_ERR_FAT_NO_FREE_CLUSTERS;
+               }
+       }
+       
+       FF_lockFAT(pIoman);
+       {
+               CurrentCluster = FF_FindEndOfChain(pIoman, DirCluster);
+               NextCluster = FF_FindFreeCluster(pIoman);
+               FF_putFatEntry(pIoman, CurrentCluster, NextCluster);
+               FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF);
+       }
+       FF_unlockFAT(pIoman);
+
+       FF_ClearCluster(pIoman, NextCluster);
+       FF_DecreaseFreeClusters(pIoman, 1);
+
+       return FF_ERR_NONE;
+}
+
+static void FF_MakeNameCompliant(FF_T_INT8 *Name) {
+       
+       if((FF_T_UINT8) Name[0] == 0xE5) {      // Support Japanese KANJI symbol.
+               Name[0] = 0x05;
+       }
+       
+       while(*Name) {
+               if(*Name < 0x20 || *Name == 0x7F || *Name == 0x22 || *Name == 0x7C) {   // Leave all extended chars as they are.
+                       *Name = '_';
+               }
+               if(*Name >= 0x2A && *Name <= 0x2F && *Name != 0x2B && *Name != 0x2E) {
+                       *Name = '_';
+               }
+               if(*Name >= 0x3A && *Name <= 0x3F) {
+                       *Name = '_';
+               }
+               if(*Name >= 0x5B && *Name <= 0x5C) {
+                       *Name = '_';
+               }
+               Name++;
+       }
+}
+
+FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent) {
+       
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT16     NameLen = (FF_T_UINT16) strlen(pDirent->FileName);
+       FF_T_UINT8      numLFNs = (FF_T_UINT8) (NameLen / 13);
+       FF_T_SINT32     FreeEntry;
+       FF_T_SINT8      RetVal = 0;
+       FF_T_UINT8      Entries;
+#ifdef FF_LFN_SUPPORT
+       FF_T_UINT8      CheckSum;
+#endif
+
+       FF_MakeNameCompliant(pDirent->FileName);        // Ensure we don't break the Dir tables.
+       memset(EntryBuffer, 0, 32);
+
+
+
+       if(NameLen % 13) {
+               numLFNs ++;
+       }
+
+#ifdef FF_LFN_SUPPORT
+       // Create and push the LFN's
+       Entries = numLFNs + 1;  // Find enough places for the LFNs and the ShortName    
+#else
+       Entries = 1;
+#endif
+
+       // Create the ShortName
+       FF_lockDIR(pIoman);
+       {
+               if((FreeEntry = FF_FindFreeDirent(pIoman, DirCluster, Entries)) >= 0) {
+                       RetVal = FF_CreateShortName(pIoman, DirCluster, (FF_T_INT8 *) EntryBuffer, pDirent->FileName);
+                       
+                       if(!RetVal) {
+#ifdef FF_LFN_SUPPORT
+                               CheckSum = FF_CreateChkSum(EntryBuffer);
+                               FF_CreateLFNs(pIoman, DirCluster, pDirent->FileName, CheckSum, (FF_T_UINT16) FreeEntry);
+#else
+                               numLFNs = 0;
+#endif                         
+                               
+#ifdef FF_TIME_SUPPORT
+                               FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_CREATE_TIME);
+                               FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_CREATE_DATE);
+                               FF_PlaceTime(EntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME);
+                               FF_PlaceDate(EntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE);
+#endif
+
+                               FF_putChar(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), pDirent->Attrib);
+                               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(pDirent->ObjectCluster >> 16));
+                               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16)(pDirent->ObjectCluster));
+                               FF_putLong(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), pDirent->Filesize);
+
+                               FF_PushEntry(pIoman, DirCluster, (FF_T_UINT16) (FreeEntry + numLFNs), EntryBuffer);
+                       }
+               }else {
+                       RetVal = (FF_T_SINT8) FreeEntry;
+               }
+       }
+       FF_unlockDIR(pIoman);
+
+       if(RetVal) {
+               return RetVal;
+       }
+
+       if(pDirent) {
+               pDirent->CurrentItem = (FF_T_UINT16) (FreeEntry + numLFNs);
+       }
+       
+       return 0;
+}
+
+FF_T_UINT32 FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent) {
+       FF_DIRENT MyFile;
+       strncpy(MyFile.FileName, FileName, FF_MAX_FILENAME);
+
+       MyFile.Attrib = 0x00;
+       MyFile.Filesize = 0;
+       MyFile.ObjectCluster = FF_CreateClusterChain(pIoman);
+       MyFile.CurrentItem = 0;
+
+       if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) {
+               FF_UnlinkClusterChain(pIoman, MyFile.ObjectCluster, 0);
+               FF_FlushCache(pIoman);
+               return 0;
+       }
+
+       FF_FlushCache(pIoman);
+
+       if(pDirent) {
+               memcpy(pDirent, &MyFile, sizeof(FF_DIRENT));
+       }
+
+       return MyFile.ObjectCluster;
+}
+
+
+/**
+ *     @brief Creates a Directory of the specified path.
+ *
+ *     @param  pIoman  Pointer to the FF_IOMAN object.
+ *     @param  Path    Path of the directory to create.
+ *
+ *     @return FF_ERR_NULL_POINTER if pIoman was NULL.
+ *     @return FF_ERR_DIR_OBJECT_EXISTS if the object specified by path already exists.
+ *     @return FF_ERR_DIR_INVALID_PATH
+ *     @return FF_ERR_NONE on success.
+ **/
+FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path) {
+       FF_DIRENT       MyDir;
+       FF_T_UINT32 DirCluster;
+       FF_T_INT8       DirName[FF_MAX_FILENAME];
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT32 DotDotCluster;
+       FF_T_UINT16     i;
+       FF_T_SINT8      RetVal = 0;
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       i = (FF_T_UINT16) strlen(Path);
+
+       while(i != 0) {
+               if(Path[i] == '\\' || Path[i] == '/') {
+                       break;
+               }
+               i--;
+       }
+
+       strncpy(DirName, (Path + i + 1), FF_MAX_FILENAME);
+
+       if(i == 0) {
+               i = 1;
+       }
+
+       DirCluster = FF_FindDir(pIoman, Path, i);
+
+       if(DirCluster) {
+
+               /*if(!FF_FindEntry(pIoman, DirCluster, DirName, &MyDir, FF_TRUE)) {
+                       return FF_ERR_DIR_OBJECT_EXISTS;
+               }*/
+               if(FF_FindEntryInDir(pIoman, DirCluster, DirName, 0x00, &MyDir)) {
+                       return FF_ERR_DIR_OBJECT_EXISTS;
+               }
+
+               strncpy(MyDir.FileName, DirName, FF_MAX_FILENAME);
+               MyDir.Filesize          = 0;
+               MyDir.Attrib            = FF_FAT_ATTR_DIR;
+               MyDir.ObjectCluster     = FF_CreateClusterChain(pIoman);
+               FF_ClearCluster(pIoman, MyDir.ObjectCluster);
+
+               RetVal = FF_CreateDirent(pIoman, DirCluster, &MyDir);
+
+               if(RetVal) {
+                       FF_UnlinkClusterChain(pIoman, MyDir.ObjectCluster, 0);
+                       FF_FlushCache(pIoman);
+                       return RetVal;
+               }
+               
+               memset(EntryBuffer, 0, 32);
+               EntryBuffer[0] = '.';
+               for(i = 1; i < 11; i++) {
+                       EntryBuffer[i] = 0x20;
+               }
+               FF_putChar(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR);
+               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(MyDir.ObjectCluster >> 16));
+               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) MyDir.ObjectCluster);
+               FF_putLong(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0);
+
+               FF_PushEntry(pIoman, MyDir.ObjectCluster, 0, EntryBuffer);
+
+               memset(EntryBuffer, 0, 32);
+               EntryBuffer[0] = '.';
+               EntryBuffer[1] = '.';
+               for(i = 2; i < 11; i++) {
+                       EntryBuffer[i] = 0x20;
+               }
+               
+               if(DirCluster == pIoman->pPartition->RootDirCluster) {
+                       DotDotCluster = 0;
+               } else {
+                       DotDotCluster = DirCluster;
+               }
+
+               FF_putChar(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB), FF_FAT_ATTR_DIR);
+               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_HIGH), (FF_T_UINT16)(DotDotCluster >> 16));
+               FF_putShort(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_CLUS_LOW), (FF_T_UINT16) DotDotCluster);
+               FF_putLong(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_FILESIZE), 0);
+               
+               FF_PushEntry(pIoman, MyDir.ObjectCluster, 1, EntryBuffer);
+               
+               FF_FlushCache(pIoman);  // Ensure dir was flushed to the disk!
+
+               return FF_ERR_NONE;
+       }
+       
+       return FF_ERR_DIR_INVALID_PATH;
+}
+
+
+
+void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry) {
+
+       FF_T_UINT8      EntryBuffer[32];
+
+       DirEntry--;
+
+       do {
+               FF_FetchEntry(pIoman, DirCluster, DirEntry, EntryBuffer);
+               
+               if(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN) {
+                       FF_putChar(EntryBuffer, (FF_T_UINT16) 0, (FF_T_UINT8) 0xE5);
+                       FF_PushEntry(pIoman, DirCluster, DirEntry, EntryBuffer);
+               }
+
+               if(DirEntry == 0) {
+                       break;
+               }
+               DirEntry--;
+       }while(FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)) == FF_FAT_ATTR_LFN);
+
+}
+
diff --git a/reactos/lib/3rdparty/fullfat/ff_dir.h b/reactos/lib/3rdparty/fullfat/ff_dir.h
new file mode 100644 (file)
index 0000000..7415eac
--- /dev/null
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_dir.h
+ *     @author         James Walmsley
+ *     @ingroup        DIR
+ **/
+#ifndef _FF_DIR_H_
+#define _FF_DIR_H_
+
+#include "ff_types.h"
+#include "ff_config.h"
+#include "ff_error.h"
+#include "ff_ioman.h"
+#include "ff_blk.h"
+#include "ff_fat.h"
+#include "fat.h"
+#include "ff_memory.h"
+#include "ff_time.h"
+#include "ff_hash.h"
+#include "ff_crc.h"
+#include "ff_file.h"
+#include <string.h>
+
+typedef struct {
+       FF_T_INT8       FileName[FF_MAX_FILENAME];
+       FF_T_UINT8      Attrib;
+       FF_T_UINT32 Filesize;
+       FF_T_UINT32     ObjectCluster;
+
+#ifdef FF_TIME_SUPPORT 
+       FF_SYSTEMTIME   CreateTime;             ///< Date and Time Created.
+       FF_SYSTEMTIME   ModifiedTime;   ///< Date and Time Modified.
+       FF_SYSTEMTIME   AccessedTime;   ///< Date of Last Access.
+#endif
+
+       //---- Book Keeping for FF_Find Functions
+       FF_T_UINT16     CurrentItem;    
+       FF_T_UINT32     DirCluster;
+       FF_T_UINT32     CurrentCluster;
+       FF_T_UINT32 AddrCurrentCluster;
+       //FF_T_UINT8    NumLFNs;
+} FF_DIRENT;
+
+               FF_ERROR        FF_GetEntry             (FF_IOMAN *pIoman, FF_T_UINT16 nEntry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_SINT8  FF_PutEntry         (FF_IOMAN *pIoman, FF_T_UINT16 Entry, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_SINT8      FF_FindEntry    (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *Name, FF_DIRENT *pDirent, FF_T_BOOL LFNs);
+               FF_ERROR        FF_FindFirst    (FF_IOMAN *pIoman, FF_DIRENT *pDirent, const FF_T_INT8 *path);
+               FF_ERROR        FF_FindNext             (FF_IOMAN *pIoman, FF_DIRENT *pDirent);
+               void FF_PopulateShortDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT8 *EntryBuffer);
+               FF_T_SINT8      FF_PopulateLongDirent(FF_IOMAN *pIoman, FF_DIRENT *pDirent, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry);
+               FF_T_SINT8      FF_FetchEntry   (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
+               FF_T_SINT8      FF_PushEntry    (FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 nEntry, FF_T_UINT8 *buffer);
+               FF_T_BOOL       FF_isEndOfDir   (FF_T_UINT8 *EntryBuffer);
+               FF_T_SINT8      FF_FindNextInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+               FF_T_UINT32 FF_FindEntryInDir(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *name, FF_T_UINT8 pa_Attrib, FF_DIRENT *pDirent);
+               FF_T_SINT8      FF_CreateShortName(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *ShortName, FF_T_INT8 *LongName);
+
+void           FF_lockDIR              (FF_IOMAN *pIoman);
+void           FF_unlockDIR    (FF_IOMAN *pIoman);
+FF_T_UINT32                    FF_CreateFile(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_INT8 *FileName, FF_DIRENT *pDirent);
+FF_ERROR FF_MkDir(FF_IOMAN *pIoman, const FF_T_INT8 *Path);
+FF_T_SINT8 FF_CreateDirent(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_DIRENT *pDirent);
+FF_T_SINT8 FF_ExtendDirectory(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+FF_T_UINT32 FF_FindDir(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT16 pathLen);
+
+
+FF_T_BOOL FF_CheckDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
+FF_T_BOOL FF_DirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+FF_ERROR FF_AddDirentHash(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT32 nHash);
+void FF_SetDirHashed(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster);
+
+void FF_RmLFNs(FF_IOMAN *pIoman, FF_T_UINT32 DirCluster, FF_T_UINT16 DirEntry);
+
+#endif
+
diff --git a/reactos/lib/3rdparty/fullfat/ff_error.c b/reactos/lib/3rdparty/fullfat/ff_error.c
new file mode 100644 (file)
index 0000000..483bf96
--- /dev/null
@@ -0,0 +1,107 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_error.c
+ *     @author         James Walmsley
+ *     @ingroup        ERROR
+ *
+ *     @defgroup       ERR Error Message
+ *     @brief          Used to return pretty strings for FullFAT error codes.
+ *
+ **/
+#include "ff_config.h"
+#include "ff_types.h"
+#include "ff_error.h"
+
+#ifdef FF_DEBUG
+const struct _FFERRTAB
+{
+    const FF_T_INT8 * const strErrorString;
+    const FF_T_SINT32 iErrorCode;
+
+} gcpFullFATErrorTable[] =
+{
+       {"Unknown or Generic Error! - Please contact FullFAT DEV - james@worm.me.uk",   -1000},
+       {"No Error.",                                                                                                                                   FF_ERR_NONE},
+       {"Null Pointer provided, (probably for IOMAN).",                                                                FF_ERR_NULL_POINTER},
+    {"Not enough memory (malloc() returned NULL).",                                                                    FF_ERR_NOT_ENOUGH_MEMORY},
+    {"Device Driver returned a FATAL error!.",                                                                         FF_ERR_DEVICE_DRIVER_FAILED},
+    {"The blocksize is not 512 multiple.",                                                                                     FF_ERR_IOMAN_BAD_BLKSIZE},
+    {"The provided memory size, is not a multiple of the blocksize.",                          FF_ERR_IOMAN_BAD_MEMSIZE},
+    {"Device is already registered, use FF_UnregisterBlkDevice() first.",                      FF_ERR_IOMAN_DEV_ALREADY_REGD},
+    {"No mountable partition was found on the specified device.",                                      FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION},
+    {"The format of the MBR was unrecognised.",                                                                                FF_ERR_IOMAN_INVALID_FORMAT},
+    {"The provided partition number is out-of-range (0 - 3).",                                         FF_ERR_IOMAN_INVALID_PARTITION_NUM},
+    {"The selected partition / volume doesn't appear to be FAT formatted.",                    FF_ERR_IOMAN_NOT_FAT_FORMATTED},
+    {"Cannot register device. (BlkSize not a multiple of 512).",                                       FF_ERR_IOMAN_DEV_INVALID_BLKSIZE},
+    {"Cannot unregister device, a partition is still mounted.",                                                FF_ERR_IOMAN_PARTITION_MOUNTED},
+    {"Cannot unmount the partition while there are active FILE handles.",                      FF_ERR_IOMAN_ACTIVE_HANDLES},
+    {"Cannot open the file, file already in use.",                                                                     FF_ERR_FILE_ALREADY_OPEN},
+    {"The specified file could not be found.",                                                                         FF_ERR_FILE_NOT_FOUND},
+    {"Cannot open a Directory.",                                                                                                       FF_ERR_FILE_OBJECT_IS_A_DIR},
+       {"Cannot open for writing: File is marked as Read-Only.",                                               FF_ERR_FILE_IS_READ_ONLY},
+    {"Path not found.",                                                                                                                                FF_ERR_FILE_INVALID_PATH},
+    {"A file or folder of the same name already exists.",                                                      FF_ERR_DIR_OBJECT_EXISTS},
+    {"FF_ERR_DIR_DIRECTORY_FULL",                                                                                                      FF_ERR_DIR_DIRECTORY_FULL},
+    {"FF_ERR_DIR_END_OF_DIR",                                                                                                          FF_ERR_DIR_END_OF_DIR},
+    {"The directory is not empty.",                                                                                                    FF_ERR_DIR_NOT_EMPTY},
+       {"Could not extend File or Folder - No Free Space!",                                                    FF_ERR_FAT_NO_FREE_CLUSTERS},
+       {"Could not find the directory specified by the path.",                                                 FF_ERR_DIR_INVALID_PATH},
+       {"The Root Dir is full, and cannot be extended on Fat12 or 16 volumes.",                FF_ERR_DIR_CANT_EXTEND_ROOT_DIR},
+       {"File operation failed - the file was not opened for writing.",                                FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE},
+       {"File operation failed - the file was not opened for reading.",                                FF_ERR_FILE_NOT_OPENED_IN_READ_MODE},
+       {"File operation failed - could not extend file.",                                                              FF_ERR_FILE_EXTEND_FAILED},
+       {"Destination file already exists.",                                                                                    FF_ERR_FILE_DESTINATION_EXISTS},
+       {"Source file was not found.",                                                                                                  FF_ERR_FILE_SOURCE_NOT_FOUND},
+       {"Destination path (dir) was not found.",                                                                               FF_ERR_FILE_DIR_NOT_FOUND},
+       {"Failed to create the directory Entry.",                                                                               FF_ERR_FILE_COULD_NOT_CREATE_DIRENT},
+};
+
+/**
+ *     @public
+ *     @brief  Returns a pointer to a string relating to a FullFAT error code.
+ *     
+ *     @param  iErrorCode      The error code.
+ *
+ *     @return Pointer to a string describing the error.
+ *
+ **/
+const FF_T_INT8 *FF_GetErrMessage(FF_ERROR iErrorCode) {
+    FF_T_UINT32 stCount = sizeof (gcpFullFATErrorTable) / sizeof ( struct _FFERRTAB);
+    while (stCount--){
+        if (gcpFullFATErrorTable[stCount].iErrorCode == iErrorCode) {
+            return gcpFullFATErrorTable[stCount].strErrorString;
+        }
+    }
+       return gcpFullFATErrorTable[0].strErrorString;
+}
+#endif
diff --git a/reactos/lib/3rdparty/fullfat/ff_fat.c b/reactos/lib/3rdparty/fullfat/ff_fat.c
new file mode 100644 (file)
index 0000000..1cbd420
--- /dev/null
@@ -0,0 +1,750 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_fat.c
+ *     @author         James Walmsley
+ *     @ingroup        FAT
+ *
+ *     @defgroup       FAT Fat File-System
+ *     @brief          Handles FAT access and traversal.
+ *
+ *     Provides file-system interfaces for the FAT file-system.
+ **/
+
+#include "ff_fat.h"
+#include "ff_config.h"
+#include <string.h>
+
+void FF_lockFAT(FF_IOMAN *pIoman) {
+       FF_PendSemaphore(pIoman->pSemaphore);   // Use Semaphore to protect FAT modifications.
+       {
+               while((pIoman->Locks & FF_FAT_LOCK)) {
+                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+                       FF_Yield();                                             // Keep Releasing and Yielding until we have the Fat protector.
+                       FF_PendSemaphore(pIoman->pSemaphore);
+               }
+               pIoman->Locks |= FF_FAT_LOCK;
+       }
+       FF_ReleaseSemaphore(pIoman->pSemaphore);
+}
+
+void FF_unlockFAT(FF_IOMAN *pIoman) {
+       FF_PendSemaphore(pIoman->pSemaphore);
+       {
+               pIoman->Locks &= ~FF_FAT_LOCK;
+       }
+       FF_ReleaseSemaphore(pIoman->pSemaphore);
+}
+
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_getRealLBA(FF_IOMAN *pIoman, FF_T_UINT32 LBA) {
+       return LBA * pIoman->pPartition->BlkFactor;
+}
+
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_Cluster2LBA(FF_IOMAN *pIoman, FF_T_UINT32 Cluster) {
+       FF_T_UINT32 lba = 0;
+       FF_PARTITION *pPart;
+       if(pIoman) {
+               pPart = pIoman->pPartition;
+
+               if(Cluster > 1) {
+                       lba = ((Cluster - 2) * pPart->SectorsPerCluster) + pPart->FirstDataSector;
+               } else {
+                       lba = pPart->ClusterBeginLBA;
+               }
+       }
+       return lba;
+}
+
+/**
+ *     @private
+ **/
+FF_T_UINT32 FF_LBA2Cluster(FF_IOMAN *pIoman, FF_T_UINT32 Address) {
+       FF_T_UINT32 cluster = 0;
+       FF_PARTITION *pPart;
+       if(pIoman) {
+               pPart = pIoman->pPartition;
+               if(pPart->Type == FF_T_FAT32) {
+                       cluster = ((Address - pPart->ClusterBeginLBA) / pPart->SectorsPerCluster) + 2;
+               } else {
+                       cluster = ((Address - pPart->ClusterBeginLBA) / pPart->SectorsPerCluster);
+               }
+       }
+       return cluster;
+}
+
+/**
+ *     @private
+ **/
+FF_T_SINT32 FF_getFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
+
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32 FatOffset;
+       FF_T_UINT32 FatSector;
+       FF_T_UINT32 FatSectorEntry;
+       FF_T_UINT32 FatEntry;
+       FF_T_UINT8      LBAadjust;
+       FF_T_UINT16 relClusterEntry;
+
+#ifdef FF_FAT12_SUPPORT
+       FF_T_UINT8      F12short[2];            // For FAT12 FAT Table Across sector boundary traversal.
+#endif
+       
+       if(pIoman->pPartition->Type == FF_T_FAT32) {
+               FatOffset = nCluster * 4;
+       } else if(pIoman->pPartition->Type == FF_T_FAT16) {
+               FatOffset = nCluster * 2;
+       }else {
+               FatOffset = nCluster + (nCluster / 2);
+       }
+       
+       FatSector               = pIoman->pPartition->FatBeginLBA + (FatOffset / pIoman->pPartition->BlkSize);
+       FatSectorEntry  = FatOffset % pIoman->pPartition->BlkSize;
+       
+       LBAadjust               = (FF_T_UINT8)  (FatSectorEntry / pIoman->BlkSize);
+       relClusterEntry = (FF_T_UINT16) (FatSectorEntry % pIoman->BlkSize);
+       
+       FatSector = FF_getRealLBA(pIoman, FatSector);
+       
+#ifdef FF_FAT12_SUPPORT
+       if(pIoman->pPartition->Type == FF_T_FAT12) {
+               if(relClusterEntry == (pIoman->BlkSize - 1)) {
+                       // Fat Entry SPANS a Sector!
+                       // First Buffer get the last Byte in buffer (first byte of our address)!
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1));                         
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       // Second Buffer get the first Byte in buffer (second byte of out address)!
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               F12short[1] = FF_getChar(pBuffer->pBuffer, 0);                          
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       
+                       FatEntry = (FF_T_UINT32) FF_getShort((FF_T_UINT8*)&F12short, 0);        // Guarantee correct Endianess!
+
+                       if(nCluster & 0x0001) {
+                               FatEntry = FatEntry >> 4;
+                       } 
+                       FatEntry &= 0x0FFF;
+                       return (FF_T_SINT32) FatEntry;
+               }
+       }
+#endif
+       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ);
+       {
+               if(!pBuffer) {
+                       return FF_ERR_DEVICE_DRIVER_FAILED;
+               }
+               
+               switch(pIoman->pPartition->Type) {
+                       case FF_T_FAT32:
+                               FatEntry = FF_getLong(pBuffer->pBuffer, relClusterEntry);
+                               FatEntry &= 0x0fffffff; // Clear the top 4 bits.
+                               break;
+
+                       case FF_T_FAT16:
+                               FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, relClusterEntry);
+                               break;
+
+#ifdef FF_FAT12_SUPPORT
+                       case FF_T_FAT12:
+                               FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, relClusterEntry);
+                               if(nCluster & 0x0001) {
+                                       FatEntry = FatEntry >> 4;
+                               } 
+                               FatEntry &= 0x0FFF;
+                               break;
+#endif
+                       default:
+                               FatEntry = 0;
+                               break;
+               }
+       }
+       FF_ReleaseBuffer(pIoman, pBuffer);
+
+       return (FF_T_SINT32) FatEntry;
+}
+
+FF_T_SINT8 FF_ClearCluster(FF_IOMAN *pIoman, FF_T_UINT32 nCluster) {
+       FF_BUFFER *pBuffer;
+       FF_T_UINT16 i;
+       FF_T_UINT32     BaseLBA;
+       FF_T_SINT8      RetVal = 0;
+
+       BaseLBA = FF_Cluster2LBA(pIoman, nCluster);
+       BaseLBA = FF_getRealLBA(pIoman, BaseLBA);
+
+       for(i = 0; i < pIoman->pPartition->SectorsPerCluster; i++) {
+               pBuffer = FF_GetBuffer(pIoman, BaseLBA++, FF_MODE_WRITE);
+               {
+                       if(pBuffer) {
+                               memset(pBuffer->pBuffer, 0x00, 512);
+                       } else {
+                               RetVal = FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+               }
+               FF_ReleaseBuffer(pIoman, pBuffer);
+       }
+
+       return RetVal;
+}
+
+/**
+ *     @private
+ *     @brief  Returns the Cluster address of the Cluster number from the beginning of a chain.
+ *     
+ *     @param  pIoman          FF_IOMAN Object
+ *     @param  Start           Cluster address of the first cluster in the chain.
+ *     @param  Count           Number of Cluster in the chain, 
+ *
+ *     @return FF_TRUE if it is an end of chain, otherwise FF_FALSE.
+ *
+ **/
+FF_T_UINT32 FF_TraverseFAT(FF_IOMAN *pIoman, FF_T_UINT32 Start, FF_T_UINT32 Count) {
+       
+       FF_T_UINT32 i;
+       FF_T_UINT32 fatEntry = Start, currentCluster = Start;
+
+       for(i = 0; i < Count; i++) {
+               fatEntry = FF_getFatEntry(pIoman, currentCluster);
+               if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) {
+                       return 0;
+               }
+
+               if(FF_isEndOfChain(pIoman, fatEntry)) {
+                       return currentCluster;
+               } else {
+                       currentCluster = fatEntry;
+               }       
+       }
+       
+       return fatEntry;
+}
+
+FF_T_UINT32 FF_FindEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 Start) {
+
+       FF_T_UINT32 fatEntry = Start, currentCluster = Start;
+
+       while(!FF_isEndOfChain(pIoman, fatEntry)) {
+               fatEntry = FF_getFatEntry(pIoman, currentCluster);
+               if(fatEntry == (FF_T_UINT32) FF_ERR_DEVICE_DRIVER_FAILED) {
+                       return 0;
+               }
+
+               if(FF_isEndOfChain(pIoman, fatEntry)) {
+                       return currentCluster;
+               } else {
+                       currentCluster = fatEntry;
+               }       
+       }
+       
+       return fatEntry;
+}
+
+
+/**
+ *     @private
+ *     @brief  Tests if the fatEntry is an End of Chain Marker.
+ *     
+ *     @param  pIoman          FF_IOMAN Object
+ *     @param  fatEntry        The fat entry from the FAT table to be checked.
+ *
+ *     @return FF_TRUE if it is an end of chain, otherwise FF_FALSE.
+ *
+ **/
+FF_T_BOOL FF_isEndOfChain(FF_IOMAN *pIoman, FF_T_UINT32 fatEntry) {
+       FF_T_BOOL result = FF_FALSE;
+       if(pIoman->pPartition->Type == FF_T_FAT32) {
+               if((fatEntry & 0x0fffffff) >= 0x0ffffff8) {
+                       result = FF_TRUE;
+               }
+       } else if(pIoman->pPartition->Type == FF_T_FAT16) {
+               if(fatEntry >= 0x0000fff8) {
+                       result = FF_TRUE;
+               }
+       } else {
+               if(fatEntry >= 0x00000ff8) {
+                       result = FF_TRUE;
+               }       
+       }
+       if(fatEntry == 0x00000000) {
+               result = FF_TRUE;       //Perhaps trying to read a deleted file!
+       }
+       return result;
+}
+
+
+/**
+ *     @private
+ *     @brief  Writes a new Entry to the FAT Tables.
+ *     
+ *     @param  pIoman          IOMAN object.
+ *     @param  nCluster        Cluster Number to be modified.
+ *     @param  Value           The Value to store.
+ **/
+FF_T_SINT8 FF_putFatEntry(FF_IOMAN *pIoman, FF_T_UINT32 nCluster, FF_T_UINT32 Value) {
+
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32 FatOffset;
+       FF_T_UINT32 FatSector;
+       FF_T_UINT32 FatSectorEntry;
+       FF_T_UINT32 FatEntry;
+       FF_T_UINT8      LBAadjust;
+       FF_T_UINT16 relClusterEntry;
+#ifdef FF_FAT12_SUPPORT        
+       FF_T_UINT8      F12short[2];            // For FAT12 FAT Table Across sector boundary traversal.
+#endif
+       
+       if(pIoman->pPartition->Type == FF_T_FAT32) {
+               FatOffset = nCluster * 4;
+       } else if(pIoman->pPartition->Type == FF_T_FAT16) {
+               FatOffset = nCluster * 2;
+       }else {
+               FatOffset = nCluster + (nCluster / 2);
+       }
+       
+       FatSector = pIoman->pPartition->FatBeginLBA + (FatOffset / pIoman->pPartition->BlkSize);
+       FatSectorEntry = FatOffset % pIoman->pPartition->BlkSize;
+       
+       LBAadjust = (FF_T_UINT8) (FatSectorEntry / pIoman->BlkSize);
+       relClusterEntry = (FF_T_UINT16)(FatSectorEntry % pIoman->BlkSize);
+       
+       FatSector = FF_getRealLBA(pIoman, FatSector);
+
+#ifdef FF_FAT12_SUPPORT        
+       if(pIoman->pPartition->Type == FF_T_FAT12) {
+               if(relClusterEntry == (FF_T_UINT16) (pIoman->BlkSize - 1)) {
+                       // Fat Entry SPANS a Sector!
+                       // First Buffer get the last Byte in buffer (first byte of our address)!
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               F12short[0] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1));                         
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       // Second Buffer get the first Byte in buffer (second byte of out address)!
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               F12short[1] = FF_getChar(pBuffer->pBuffer, (FF_T_UINT16) 0x0000);                               
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                                       
+                       FatEntry = FF_getShort((FF_T_UINT8*)&F12short, (FF_T_UINT16) 0x0000);   // Guarantee correct Endianess!
+                       if(nCluster & 0x0001) {
+                               FatEntry   &= 0x000F;
+                               Value           = (Value << 4);
+                               Value      &= 0xFFF0;
+                       }  else {
+                               FatEntry        &= 0xF000;
+                               Value           &= 0x0FFF;
+                       }
+
+                       FF_putShort((FF_T_UINT8 *)F12short, 0x0000, (FF_T_UINT16) (FatEntry | Value));
+
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_WRITE);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               FF_putChar(pBuffer->pBuffer, (FF_T_UINT16)(pIoman->BlkSize - 1), F12short[0]);                          
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+                       // Second Buffer get the first Byte in buffer (second byte of out address)!
+                       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust + 1, FF_MODE_READ);
+                       {
+                               if(!pBuffer) {
+                                       return FF_ERR_DEVICE_DRIVER_FAILED;
+                               }
+                               FF_putChar(pBuffer->pBuffer, 0x0000, F12short[1]);                              
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                       return FF_ERR_NONE;
+               }
+       }
+#endif
+       
+       pBuffer = FF_GetBuffer(pIoman, FatSector + LBAadjust, FF_MODE_WRITE);
+       {
+               if(!pBuffer) {
+                       return FF_ERR_DEVICE_DRIVER_FAILED;
+               }
+               if(pIoman->pPartition->Type == FF_T_FAT32) {
+                       Value &= 0x0fffffff;    // Clear the top 4 bits.
+                       FF_putLong(pBuffer->pBuffer, relClusterEntry, Value);
+               } else if(pIoman->pPartition->Type == FF_T_FAT16) {
+                       FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) Value);
+               } else {
+                       FatEntry        = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, relClusterEntry);
+                       if(nCluster & 0x0001) {
+                               FatEntry   &= 0x000F;
+                               Value           = (Value << 4);
+                               Value      &= 0xFFF0;
+                       }  else {
+                               FatEntry        &= 0xF000;
+                               Value           &= 0x0FFF;
+                       }
+                       
+                       FF_putShort(pBuffer->pBuffer, relClusterEntry, (FF_T_UINT16) (FatEntry | Value));
+               }
+       }
+       FF_ReleaseBuffer(pIoman, pBuffer);
+
+       return 0;
+}
+
+
+
+/**
+ *     @private
+ *     @brief  Finds a Free Cluster and returns its number.
+ *
+ *     @param  pIoman  IOMAN Object.
+ *
+ *     @return The number of the cluster found to be free.
+ *     @return 0 on error.
+ **/
+#ifdef FF_FAT12_SUPPORT
+FF_T_UINT32 FF_FindFreeClusterOLD(FF_IOMAN *pIoman) {
+       FF_T_UINT32 nCluster;
+       FF_T_UINT32 fatEntry;
+
+       for(nCluster = pIoman->pPartition->LastFreeCluster; nCluster < pIoman->pPartition->NumClusters; nCluster++) {
+               fatEntry = FF_getFatEntry(pIoman, nCluster);
+               if(fatEntry == 0x00000000) {
+                       pIoman->pPartition->LastFreeCluster = nCluster;
+                       return nCluster;
+               }
+       }
+       return 0;
+}
+#endif
+
+FF_T_UINT32 FF_FindFreeCluster(FF_IOMAN *pIoman) {
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32     i, x, nCluster = pIoman->pPartition->LastFreeCluster;
+       FF_T_UINT32     FatOffset;
+       FF_T_UINT32     FatSector;
+       FF_T_UINT32     FatSectorEntry;
+       FF_T_UINT32     EntriesPerSector;
+       FF_T_UINT32 FatEntry = 1;
+
+#ifdef FF_FAT12_SUPPORT
+       if(pIoman->pPartition->Type == FF_T_FAT12) {    // FAT12 tables are too small to optimise, and would make it very complicated!
+               return FF_FindFreeClusterOLD(pIoman);
+       }
+#endif
+
+       if(pIoman->pPartition->Type == FF_T_FAT32) {
+               EntriesPerSector = pIoman->BlkSize / 4;
+               FatOffset = nCluster * 4;
+       } else {
+               EntriesPerSector = pIoman->BlkSize / 2;
+               FatOffset = nCluster * 2;
+       }
+
+       FatSector = (FatOffset / pIoman->pPartition->BlkSize);
+       
+       for(i = FatSector; i < pIoman->pPartition->SectorsPerFAT; i++) {
+               pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ);
+               {
+                       for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) {
+                               if(pIoman->pPartition->Type == FF_T_FAT32) {
+                                       FatOffset = x * 4;
+                                       FatSectorEntry  = FatOffset % pIoman->pPartition->BlkSize;
+                                       FatEntry = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry);
+                                       FatEntry &= 0x0fffffff; // Clear the top 4 bits.
+                               } else {
+                                       FatOffset = x * 2;
+                                       FatSectorEntry  = FatOffset % pIoman->pPartition->BlkSize;
+                                       FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry);
+                               }
+                               if(FatEntry == 0x00000000) {
+                                       FF_ReleaseBuffer(pIoman, pBuffer);
+                                       pIoman->pPartition->LastFreeCluster = nCluster;
+                                       
+                                       return nCluster;
+                               }
+                               
+                               nCluster++;
+                       }       
+               }
+               FF_ReleaseBuffer(pIoman, pBuffer);
+       }
+
+       return 0;
+}
+
+/**
+ * @private
+ * @brief      Create's a Cluster Chain
+ **/
+FF_T_UINT32 FF_CreateClusterChain(FF_IOMAN *pIoman) {
+       FF_T_UINT32     iStartCluster;
+       FF_lockFAT(pIoman);
+       {
+               iStartCluster = FF_FindFreeCluster(pIoman);
+               FF_putFatEntry(pIoman, iStartCluster, 0xFFFFFFFF); // Mark the cluster as EOC
+       }
+       FF_unlockFAT(pIoman);
+       return iStartCluster;
+}
+
+FF_T_UINT32 FF_GetChainLength(FF_IOMAN *pIoman, FF_T_UINT32 pa_nStartCluster, FF_T_UINT32 *piEndOfChain) {
+       FF_T_UINT32 iLength = 0;
+       
+       FF_lockFAT(pIoman);
+       {
+               while(!FF_isEndOfChain(pIoman, pa_nStartCluster)) {
+                       pa_nStartCluster = FF_getFatEntry(pIoman, pa_nStartCluster);
+                       iLength++;
+               }
+               if(piEndOfChain) {
+                       *piEndOfChain = pa_nStartCluster;
+               }
+       }
+       FF_unlockFAT(pIoman);
+
+       return iLength;
+}
+
+/**
+ *     @private
+ *     @brief Extend a Cluster chain by Count number of Clusters
+ *     
+ *     @param  pIoman                  IOMAN object.
+ *     @param  StartCluster    Cluster Number that starts the chain.
+ *     @param  Count                   Number of clusters to extend the chain with.
+ *
+ **/
+/*
+FF_T_UINT32 FF_ExtendClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Count) {
+       
+       FF_T_UINT32 currentCluster = StartCluster, nextCluster;
+       FF_T_UINT32 clusEndOfChain;
+       FF_T_UINT32 i;
+       
+       clusEndOfChain = FF_FindEndOfChain(pIoman, StartCluster);
+
+       nextCluster = FF_FindFreeCluster(pIoman);       // Find Free clusters!
+
+       FF_putFatEntry(pIoman, clusEndOfChain, nextCluster);
+
+       for(i = 0; i <= Count; i++) {
+               currentCluster = nextCluster;
+               if(i == Count) {
+                       FF_putFatEntry(pIoman, currentCluster, 0xFFFFFFFF);
+                       break;
+               }
+
+               nextCluster = FF_FindFreeCluster(pIoman);
+               FF_putFatEntry(pIoman, currentCluster, ++nextCluster);
+       }
+       FF_FlushCache(pIoman);
+       return currentCluster;
+}*/
+
+
+/**
+ *     @private
+ *     @brief Free's Disk space by freeing unused links on Cluster Chains
+ *
+ *     @param  pIoman,                 IOMAN object.
+ *     @param  StartCluster    Cluster Number that starts the chain.
+ *     @param  Count                   Number of Clusters from the end of the chain to unlink.
+ *     @param  Count                   0 Means Free the entire chain (delete file).
+ *
+ *     @return 0 On Success.
+ *     @return -1 If the device driver failed to provide access.
+ *
+ **/
+FF_T_SINT8 FF_UnlinkClusterChain(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT16 Count) {
+       
+       FF_T_UINT32 fatEntry;
+       FF_T_UINT32 currentCluster, chainLength = 0;
+       FF_T_UINT32     iLen = 0;
+
+       fatEntry = StartCluster;
+
+       if(Count == 0) {
+               // Free all clusters in the chain!
+               currentCluster = StartCluster;
+               fatEntry = currentCluster;
+        do {
+                       fatEntry = FF_getFatEntry(pIoman, fatEntry);
+                       FF_putFatEntry(pIoman, currentCluster, 0x00000000);
+                       currentCluster = fatEntry;
+                       iLen ++;
+               }while(!FF_isEndOfChain(pIoman, fatEntry));
+               FF_IncreaseFreeClusters(pIoman, iLen);
+       } else {
+               // Truncation - This is quite hard, because we can only do it backwards.
+               do {
+                       fatEntry = FF_getFatEntry(pIoman, fatEntry);
+                       chainLength++;
+               }while(!FF_isEndOfChain(pIoman, fatEntry));
+       }
+
+       return FF_ERR_NONE;
+}
+
+#ifdef FF_FAT12_SUPPORT
+FF_T_UINT32 FF_CountFreeClustersOLD(FF_IOMAN *pIoman) {
+       FF_T_UINT32 i;
+       FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster;
+       FF_T_UINT32 FatEntry;
+       FF_T_UINT32 FreeClusters = 0;
+
+       for(i = 0; i < TotalClusters; i++) {
+               FatEntry = FF_getFatEntry(pIoman, i);
+               if(!FatEntry) {
+                       FreeClusters++;
+               }
+       }
+
+       return FreeClusters;
+}
+#endif
+
+
+FF_T_UINT32 FF_CountFreeClusters(FF_IOMAN *pIoman) {
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32     i, x, nCluster = 0;
+       FF_T_UINT32     FatOffset;
+       FF_T_UINT32     FatSector;
+       FF_T_UINT32     FatSectorEntry;
+       FF_T_UINT32     EntriesPerSector;
+       FF_T_UINT32 FatEntry = 1;
+       FF_T_UINT32     FreeClusters = 0;
+
+#ifdef FF_FAT12_SUPPORT
+       if(pIoman->pPartition->Type == FF_T_FAT12) {    // FAT12 tables are too small to optimise, and would make it very complicated!
+               return FF_CountFreeClustersOLD(pIoman);
+       }
+#endif
+
+       if(pIoman->pPartition->Type == FF_T_FAT32) {
+               EntriesPerSector = pIoman->BlkSize / 4;
+               FatOffset = nCluster * 4;
+       } else {
+               EntriesPerSector = pIoman->BlkSize / 2;
+               FatOffset = nCluster * 2;
+       }
+
+       FatSector = (FatOffset / pIoman->pPartition->BlkSize);
+       
+       for(i = 0; i < pIoman->pPartition->SectorsPerFAT; i++) {
+               pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA + i, FF_MODE_READ);
+               {
+                       for(x = nCluster % EntriesPerSector; x < EntriesPerSector; x++) {
+                               if(pIoman->pPartition->Type == FF_T_FAT32) {
+                                       FatOffset = x * 4;
+                                       FatSectorEntry  = FatOffset % pIoman->pPartition->BlkSize;
+                                       FatEntry = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry);
+                                       FatEntry &= 0x0fffffff; // Clear the top 4 bits.
+                               } else {
+                                       FatOffset = x * 2;
+                                       FatSectorEntry  = FatOffset % pIoman->pPartition->BlkSize;
+                                       FatEntry = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, (FF_T_UINT16)FatSectorEntry);
+                               }
+                               if(FatEntry == 0x00000000) {
+                                       FreeClusters += 1;
+                               }
+                               
+                               nCluster++;
+                       }       
+               }
+               FF_ReleaseBuffer(pIoman, pBuffer);
+       }
+
+       return FreeClusters;
+}
+
+#ifdef FF_64_NUM_SUPPORT
+FF_T_UINT64 FF_GetFreeSize(FF_IOMAN *pIoman) {
+       FF_T_UINT32 FreeClusters;
+       FF_T_UINT64 FreeSize;
+       
+       if(pIoman) {
+               FF_lockFAT(pIoman);
+               {       
+                       if(!pIoman->pPartition->FreeClusterCount) {
+                               pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman);
+                       }
+                       FreeClusters = pIoman->pPartition->FreeClusterCount;
+               }
+               FF_unlockFAT(pIoman);
+               FreeSize = (FF_T_UINT64) ((FF_T_UINT64)FreeClusters * (FF_T_UINT64)((FF_T_UINT64)pIoman->pPartition->SectorsPerCluster * (FF_T_UINT64)pIoman->pPartition->BlkSize));
+               return FreeSize;
+       }
+       return 0;
+}
+#else
+FF_T_UINT32 FF_GetFreeSize(FF_IOMAN *pIoman) {
+       FF_T_UINT32 FreeClusters;
+       FF_T_UINT32 FreeSize;
+       
+       if(pIoman) {
+               FF_lockFAT(pIoman);
+               {       
+                       if(!pIoman->pPartition->FreeClusterCount) {
+                               pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman);
+                       }
+                       FreeClusters = pIoman->pPartition->FreeClusterCount;
+               }
+               FF_unlockFAT(pIoman);
+               FreeSize = (FF_T_UINT32) ((FF_T_UINT32)FreeClusters * (FF_T_UINT32)((FF_T_UINT32)pIoman->pPartition->SectorsPerCluster * (FF_T_UINT32)pIoman->pPartition->BlkSize));
+               return FreeSize;
+       }
+       return 0;
+}
+#endif
diff --git a/reactos/lib/3rdparty/fullfat/ff_file.c b/reactos/lib/3rdparty/fullfat/ff_file.c
new file mode 100644 (file)
index 0000000..7f014a4
--- /dev/null
@@ -0,0 +1,1411 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_file.c
+ *     @author         James Walmsley
+ *     @ingroup        FILEIO
+ *
+ *     @defgroup       FILEIO FILE I/O Access
+ *     @brief          Provides an interface to allow File I/O on a mounted IOMAN.
+ *
+ *     Provides file-system interfaces for the FAT file-system.
+ **/
+
+#include "ff_file.h"
+#include "ff_string.h"
+
+/**
+ *     @public
+ *     @brief  Converts STDIO mode strings into the equivalent FullFAT mode.
+ *
+ *     @param  Mode    The mode string e.g. "rb" "rb+" "w" "a" "r" "w+" "a+" etc
+ *
+ *     @return Returns the mode bits that should be passed to the FF_Open function.
+ **/
+FF_T_UINT8 FF_GetModeBits(FF_T_INT8 *Mode) {
+       FF_T_UINT8 ModeBits = 0x00;
+       while(*Mode) {
+               switch(*Mode) {
+                       case 'r':       // Allow Read
+                       case 'R':
+                               ModeBits |= FF_MODE_READ;
+                               break;
+
+                       case 'w':       // Allow Write
+                       case 'W':
+                               ModeBits |= FF_MODE_WRITE;
+                               ModeBits |= FF_MODE_CREATE;     // Create if not exist.
+                               ModeBits |= FF_MODE_TRUNCATE;
+                               break;
+
+                       case 'a':       // Append new writes to the end of the file.
+                       case 'A':
+                               ModeBits |= FF_MODE_WRITE;
+                               ModeBits |= FF_MODE_APPEND;
+                               ModeBits |= FF_MODE_CREATE;     // Create if not exist.
+                               break;
+
+                       case '+':       // Update the file, don't Append!
+                               ModeBits |= FF_MODE_READ;       // RW Mode
+                               ModeBits |= FF_MODE_WRITE;      // RW Mode
+                               break;
+
+                       /*case 'D':     // Internal use only!
+                               ModeBits |= FF_MODE_DIR;
+                               break;*/
+
+                       default:        // b|B flags not supported (Binary mode is native anyway).
+                               break;
+               }
+               Mode++;
+       }
+
+       return ModeBits;
+}
+
+/**
+ * FF_Open() Mode Information
+ * - FF_MODE_WRITE
+ *   - Allows WRITE access to the file.
+ *   .
+ * - FF_MODE_READ
+ *   - Allows READ access to the file.
+ *   .
+ * - FF_MODE_CREATE
+ *   - Create file if it doesn't exist.
+ *   .
+ * - FF_MODE_TRUNCATE
+ *   - Erase the file if it already exists and overwrite.
+ *   *
+ * - FF_MODE_APPEND
+ *   - Causes all writes to occur at the end of the file. (Its impossible to overwrite other data in a file with this flag set).
+ *   . 
+ * .
+ *
+ * Some sample modes:
+ * - (FF_MODE_WRITE | FF_MODE_CREATE | FF_MODE_TRUNCATE)
+ *   - Write access to the file. (Equivalent to "w").
+ *   .
+ * - (FF_MODE_WRITE | FF_MODE_READ)
+ *   - Read and Write access to the file. (Equivalent to "rb+").
+ *   .
+ * - (FF_MODE_WRITE | FF_MODE_READ | FF_MODE_APPEND | FF_MODE_CREATE)
+ *   - Read and Write append mode access to the file. (Equivalent to "a+").
+ *   .
+ * .
+ * Be careful when choosing modes. For those using FF_Open() at the application layer
+ * its best to use the provided FF_GetModeBits() function, as this complies to the same
+ * behaviour as the stdio.h fopen() function.
+ *
+ **/
+
+
+/**
+ *     @public
+ *     @brief  Opens a File for Access
+ *
+ *     @param  pIoman          FF_IOMAN object that was created by FF_CreateIOMAN().
+ *     @param  path            Path to the File or object.
+ *     @param  Mode            Access Mode required. Modes are a little complicated, the function FF_GetModeBits()
+ *     @param  Mode            will convert a stdio Mode string into the equivalent Mode bits for this parameter.
+ *     @param  pError          Pointer to a signed byte for error checking. Can be NULL if not required.
+ *     @param  pError          To be checked when a NULL pointer is returned.
+ *
+ *     @return NULL pointer on Error, in which case pError should be checked for more information.
+ *     @return pError can be:
+ **/
+FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) {
+       FF_FILE         *pFile;
+       FF_FILE         *pFileChain;
+       FF_DIRENT       Object;
+       FF_T_UINT32 DirCluster, FileCluster;
+       FF_T_UINT32     nBytesPerCluster;
+       FF_T_INT8       filename[FF_MAX_FILENAME];
+
+       FF_T_UINT16     i;
+
+       if(pError) {
+               *pError = 0;
+       }
+       
+       if(!pIoman) {
+               if(pError) {
+                       *pError = FF_ERR_NULL_POINTER;
+               }
+               return (FF_FILE *)NULL;
+       }
+       pFile = malloc(sizeof(FF_FILE));
+       if(!pFile) {
+               if(pError) {
+                       *pError = FF_ERR_NOT_ENOUGH_MEMORY;
+               }
+               return (FF_FILE *)NULL;
+       }
+
+       // Get the Mode Bits.
+       pFile->Mode = Mode;
+
+       i = (FF_T_UINT16) strlen(path);
+
+       while(i != 0) {
+               if(path[i] == '\\' || path[i] == '/') {
+                       break;
+               }
+               i--;
+       }
+
+       strncpy(filename, (path + i + 1), FF_MAX_FILENAME);
+
+       if(i == 0) {
+               i = 1;
+       }
+       
+
+       DirCluster = FF_FindDir(pIoman, path, i);
+
+       if(DirCluster) {
+               //RetVal = //FF_FindEntry(pIoman, DirCluster, filename, &Object, FF_TRUE);
+               //if(RetVal >= 0) {
+                       //FileCluster = Object.ObjectCluster;//FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object);
+               //} else {
+               //      FileCluster = 0;
+               //}
+
+               FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object);
+
+               if(!FileCluster) {      // If 0 was returned, it might be because the file has no allocated cluster
+                       if(strlen(filename) == strlen(Object.FileName)) {
+                               if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) {
+                                       // The file really was found!
+                                       FileCluster = 1;
+                               } 
+                       }
+               }
+
+               if(!FileCluster) {
+                       if((pFile->Mode & FF_MODE_CREATE)) {
+                               FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object);
+                               Object.CurrentItem += 1;
+                       }
+               }
+               
+               if(FileCluster) {
+                       if(Object.Attrib == FF_FAT_ATTR_DIR) {
+                               if(!(pFile->Mode & FF_MODE_DIR)) {
+                                       // Not the object, File Not Found!
+                                       free(pFile);
+                                       if(pError) {
+                                               *pError = FF_ERR_FILE_OBJECT_IS_A_DIR;
+                                       }
+                                       return (FF_FILE *) NULL;
+                               }
+                       }
+                       
+                       //---------- Ensure Read-Only files don't get opened for Writing.
+                       if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) {
+                               if((Object.Attrib & FF_FAT_ATTR_READONLY)) {
+                                       free(pFile);
+                                       if(pError) {
+                                               *pError = FF_ERR_FILE_IS_READ_ONLY;
+                                       }
+                                       return (FF_FILE *) NULL;
+                               }
+                       }
+                       pFile->pIoman                           = pIoman;
+                       pFile->FilePointer                      = 0;
+                       pFile->ObjectCluster            = Object.ObjectCluster;
+                       pFile->Filesize                         = Object.Filesize;
+                       pFile->CurrentCluster           = 0;
+                       pFile->AddrCurrentCluster       = pFile->ObjectCluster;
+                       //pFile->Mode                                   = Mode;
+                       pFile->Next                                     = NULL;
+                       pFile->DirCluster                       = DirCluster;
+                       pFile->DirEntry                         = Object.CurrentItem - 1;
+                       nBytesPerCluster                        = pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize;
+                       pFile->iChainLength                     = 0;
+                       pFile->iEndOfChain                      = 0;
+                       pFile->FileDeleted                      = FF_FALSE;
+
+                       // File Permission Processing
+                       // Only "w" and "w+" mode strings can erase a file's contents.
+                       // Any other combinations will not cause an erase.
+                       if((pFile->Mode & FF_MODE_TRUNCATE)) {
+                               pFile->Filesize = 0;
+                               pFile->FilePointer = 0;
+                       }
+
+                       /*
+                               Add pFile onto the end of our linked list of FF_FILE objects.
+                       */
+                       FF_PendSemaphore(pIoman->pSemaphore);
+                       {
+                               if(!pIoman->FirstFile) {
+                                       pIoman->FirstFile = pFile;
+                               } else {
+                                       pFileChain = (FF_FILE *) pIoman->FirstFile;
+                                       do {
+                                               if(pFileChain->ObjectCluster == pFile->ObjectCluster) {
+                                                       // File is already open! DON'T ALLOW IT!
+                                                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+                                                       free(pFile);
+                                                       if(pError) {
+                                                               *pError = FF_ERR_FILE_ALREADY_OPEN;
+                                                       }
+                                                       return (FF_FILE *) NULL;
+                                               }
+                                               if(!pFileChain->Next) {
+                                                       pFileChain->Next = pFile;
+                                                       break;
+                                               }
+                                               pFileChain = (FF_FILE *) pFileChain->Next;
+                                       }while(pFileChain != NULL);
+                               }
+                       }
+                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+
+                       return pFile;
+               }else {
+                       free(pFile);
+                       if(pError) {
+                               *pError = FF_ERR_FILE_NOT_FOUND;
+                       }
+                       return (FF_FILE *) NULL;
+               } 
+       }
+       if(pError) {
+               *pError = FF_ERR_FILE_INVALID_PATH;
+       }
+
+       free(pFile);
+
+       return (FF_FILE *)NULL;
+}
+
+
+/**
+ *     @public
+ *     @brief  Tests if a Directory contains any other files or folders.
+ *
+ *     @param  pIoman  FF_IOMAN object returned from the FF_CreateIOMAN() function.
+ *
+ **/
+FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) {
+       
+       FF_DIRENT       MyDir;
+       FF_ERROR        RetVal = FF_ERR_NONE;
+       FF_T_UINT8      i = 0;
+
+       if(!pIoman) {
+               return FF_FALSE;
+       }
+       
+       RetVal = FF_FindFirst(pIoman, &MyDir, Path);
+       while(RetVal == 0) {
+               i++;
+               RetVal = FF_FindNext(pIoman, &MyDir);
+               if(i > 2) {
+                       return FF_FALSE;
+               }
+       }
+
+       return FF_TRUE;
+}
+
+FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) {
+       FF_FILE *pFile;
+       FF_ERROR Error = FF_ERR_NONE;
+       FF_T_UINT8 EntryBuffer[32];
+       FF_T_SINT8 RetVal = FF_ERR_NONE;
+#ifdef FF_PATH_CACHE
+       FF_T_UINT32 i;
+#endif
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error);
+
+       if(!pFile) {
+               return Error;   // File in use or File not found!
+       }
+
+       pFile->FileDeleted = FF_TRUE;
+       
+       FF_lockDIR(pIoman);
+       {
+               if(FF_isDirEmpty(pIoman, path)) {
+                       FF_lockFAT(pIoman);
+                       {
+                               FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain!
+                       }
+                       FF_unlockFAT(pIoman);
+                       
+                       // Edit the Directory Entry! (So it appears as deleted);
+                       FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry);
+                       FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer);
+                       EntryBuffer[0] = 0xE5;
+                       FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer);
+#ifdef FF_PATH_CACHE
+                       FF_PendSemaphore(pIoman->pSemaphore);   // Thread safety on shared object!
+                       {
+                               for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) {
+                                       if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) {
+                                               pIoman->pPartition->PathCache[i].Path[0] = '\0';
+                                               pIoman->pPartition->PathCache[i].DirCluster = 0;
+                                               FF_ReleaseSemaphore(pIoman->pSemaphore);
+                                       }
+                               }
+                       }
+                       FF_ReleaseSemaphore(pIoman->pSemaphore);
+#endif
+                       
+                       FF_IncreaseFreeClusters(pIoman, pFile->iChainLength);
+
+                       FF_FlushCache(pIoman);
+               } else {
+                       RetVal = FF_ERR_DIR_NOT_EMPTY;
+               }
+       }
+       FF_unlockDIR(pIoman);
+       
+       FF_Close(pFile); // Free the file pointer resources
+       // File is now lost!
+       return RetVal;
+}
+
+FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) {
+       FF_FILE *pFile;
+       FF_ERROR Error = 0;
+       FF_T_UINT8 EntryBuffer[32];
+
+       pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error);
+
+       if(!pFile) {
+               return Error;   // File in use or File not found!
+       }
+
+       pFile->FileDeleted = FF_TRUE;
+
+       FF_lockFAT(pIoman);     // Lock the FAT so its thread-safe.
+       {
+               FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain!
+       }
+       FF_unlockFAT(pIoman);
+
+       // Edit the Directory Entry! (So it appears as deleted);
+       FF_lockDIR(pIoman);
+       {
+               FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry);
+               FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer);
+               EntryBuffer[0] = 0xE5;
+               FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer);
+       }
+       FF_unlockDIR(pIoman);
+
+       FF_FlushCache(pIoman);
+       
+       FF_Close(pFile); // Free the file pointer resources
+       return 0;
+}
+
+/**
+ *     @public
+ *     @brief  Moves a file or directory from source to destination.
+ *
+ *     @param  pIoman                          The FF_IOMAN object pointer.
+ *     @param  szSourceFile            String of the source file to be moved or renamed.
+ *     @param  szDestinationFile       String of the destination file to where the source should be moved or renamed.
+ *
+ *     @return FF_ERR_NONE on success.
+ *     @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists.
+ *     @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!).
+ *     @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found.
+ *     @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found.
+ *
+ **/
+FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) {
+       FF_ERROR        Error;
+       FF_FILE         *pSrcFile, *pDestFile;
+       FF_DIRENT       MyFile;
+       FF_T_UINT8      EntryBuffer[32];
+       FF_T_UINT16 i;
+       FF_T_UINT32     DirCluster;
+
+       if(!pIoman) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       // Check destination file doesn't exist!
+       pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error);
+
+       if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) {
+               FF_Close(pDestFile);
+               return FF_ERR_FILE_DESTINATION_EXISTS;  // YES -- FAIL
+       }
+
+       pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error);
+
+       if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) {
+               // Open a directory for moving!
+               pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error);
+       }
+
+       if(pSrcFile) {
+
+               // Create the new dirent.
+               FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer);
+               MyFile.Attrib                   = FF_getChar(EntryBuffer,  (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB));
+               MyFile.Filesize                 = pSrcFile->Filesize;
+               MyFile.ObjectCluster    = pSrcFile->ObjectCluster;
+               MyFile.CurrentItem              = 0;
+
+               i = (FF_T_UINT16) strlen(szDestinationFile);
+
+               while(i != 0) {
+                       if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') {
+                               break;
+                       }
+                       i--;
+               }
+
+               strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME);
+
+               if(i == 0) {
+                       i = 1;
+               }
+               
+
+               DirCluster = FF_FindDir(pIoman, szDestinationFile, i);
+               
+               if(DirCluster) {
+
+                       // Destination Dir was found, we can now create the new entry.
+                       if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) {
+                               FF_Close(pSrcFile);
+                               return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT;     // FAILED
+                       }
+
+                       // Edit the Directory Entry! (So it appears as deleted);
+                       FF_lockDIR(pIoman);
+                       {
+                               FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry);
+                               FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer);
+                               EntryBuffer[0] = 0xE5;
+                               FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer);
+                       }
+                       FF_unlockDIR(pIoman);
+                       FF_Close(pSrcFile);
+
+                       FF_FlushCache(pIoman);
+
+                       return FF_ERR_NONE;
+               }
+
+               return FF_ERR_FILE_DIR_NOT_FOUND;
+
+       }
+               
+       return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found!
+}
+
+
+/**
+ *     @public
+ *     @brief  Get's the next Entry based on the data recorded in the FF_DIRENT object.
+ *
+ *     @param  pFile   FF_FILE object that was created by FF_Open().
+ *
+ *     @return FF_TRUE if End of File was reached. FF_FALSE if not.
+ *     @return FF_FALSE if a null pointer was provided.
+ *
+ **/
+FF_T_BOOL FF_isEOF(FF_FILE *pFile) {
+       if(!pFile) {
+               return FF_FALSE;
+       }
+       if(pFile->FilePointer >= pFile->Filesize) {
+               return FF_TRUE;
+       } else {
+               return FF_FALSE;
+       }
+}
+
+static FF_T_UINT32 FF_GetSequentialClusters(FF_IOMAN *pIoman, FF_T_UINT32 StartCluster, FF_T_UINT32 Limit) {
+       FF_T_UINT32 CurrentCluster;
+       FF_T_UINT32 NextCluster = StartCluster;
+       FF_T_UINT32 i = 0;
+
+       do {
+               CurrentCluster = NextCluster;
+               NextCluster = FF_getFatEntry(pIoman, CurrentCluster);
+               if(NextCluster == (CurrentCluster + 1)) {
+                       i++;
+               } else {
+                       break;
+               }
+
+               if(Limit) {
+                       if(i == Limit) {
+                               break;
+                       }
+               }
+       }while(NextCluster == (CurrentCluster + 1));
+
+       return i;
+}
+
+static FF_T_SINT32 FF_ReadClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
+       FF_T_UINT32 Sectors;
+       FF_T_UINT32 SequentialClusters = 0;
+       FF_T_UINT32 nItemLBA;
+       FF_T_SINT32 RetVal;     
+
+       while(Count != 0) {
+               if((Count - 1) > 0) {
+                       SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1));
+               }
+               Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster;
+               nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster);
+               nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA);
+
+               do {
+                       if(pFile->pIoman->pBlkDevice->fnReadBlocks) {
+                               RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam);
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       } else {
+                               RetVal = FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+                       
+               }while(RetVal == FF_ERR_DRIVER_BUSY);   
+               
+               Count -= (SequentialClusters + 1);
+               pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1));
+               pFile->CurrentCluster += (SequentialClusters + 1);
+               buffer += Sectors * pFile->pIoman->BlkSize;
+               SequentialClusters = 0;
+       }
+
+       return 0;
+}
+
+
+static FF_ERROR FF_ExtendFile(FF_FILE *pFile, FF_T_UINT32 Size) {
+       FF_IOMAN        *pIoman = pFile->pIoman;
+       FF_T_UINT32 nBytesPerCluster = pIoman->pPartition->BlkSize * pIoman->pPartition->SectorsPerCluster;
+       FF_T_UINT32 nTotalClustersNeeded = Size / nBytesPerCluster;
+       FF_T_UINT32 nClusterToExtend; 
+       FF_T_UINT32 CurrentCluster, NextCluster;
+       FF_T_UINT32     i;
+       FF_DIRENT       OriginalEntry;
+
+       if((pFile->Mode & FF_MODE_WRITE) != FF_MODE_WRITE) {
+               return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE;
+       }
+
+       if(pFile->Filesize == 0 && pFile->ObjectCluster == 0) { // No Allocated clusters.
+               // Create a Cluster chain!
+               pFile->AddrCurrentCluster = FF_CreateClusterChain(pFile->pIoman);
+               if(!FF_GetEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry)) {
+                       OriginalEntry.ObjectCluster = pFile->AddrCurrentCluster;
+                       FF_PutEntry(pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry);
+               } else {
+                       return FF_ERR_FILE_EXTEND_FAILED;
+               }
+               pFile->ObjectCluster = pFile->AddrCurrentCluster;
+               pFile->iChainLength = 1;
+               pFile->CurrentCluster = 0;
+               pFile->iEndOfChain = pFile->AddrCurrentCluster;
+       }
+       
+       if(Size % nBytesPerCluster) {
+               nTotalClustersNeeded += 1;
+       }
+
+       if(pFile->iChainLength == 0) {  // First extension requiring the chain length, 
+               pFile->iChainLength = FF_GetChainLength(pIoman, pFile->ObjectCluster, &pFile->iEndOfChain);
+       }
+
+       nClusterToExtend = (nTotalClustersNeeded - pFile->iChainLength);
+
+       if(nTotalClustersNeeded > pFile->iChainLength) {
+
+               NextCluster = pFile->AddrCurrentCluster;
+               FF_lockFAT(pIoman);
+               {
+                       for(i = 0; i <= nClusterToExtend; i++) {
+                               CurrentCluster = FF_FindEndOfChain(pIoman, NextCluster);
+                               NextCluster = FF_FindFreeCluster(pIoman);
+                               if(!NextCluster) {
+                                       FF_unlockFAT(pIoman);
+                                       return FF_ERR_FAT_NO_FREE_CLUSTERS;
+                               }
+                               FF_putFatEntry(pIoman, CurrentCluster, NextCluster);
+                               FF_putFatEntry(pIoman, NextCluster, 0xFFFFFFFF);
+                       }
+                       
+                       pFile->iEndOfChain = FF_FindEndOfChain(pIoman, NextCluster);
+               }
+               FF_unlockFAT(pIoman);
+               
+               pFile->iChainLength += i;
+               FF_DecreaseFreeClusters(pIoman, i);     // Keep Tab of Numbers for fast FreeSize()
+       }
+
+       return FF_ERR_NONE;
+}
+
+static FF_T_SINT32 FF_WriteClusters(FF_FILE *pFile, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
+       FF_T_UINT32 Sectors;
+       FF_T_UINT32 SequentialClusters = 0;
+       FF_T_UINT32 nItemLBA;
+       FF_T_SINT32 RetVal;     
+
+       while(Count != 0) {
+               if((Count - 1) > 0) {
+                       SequentialClusters = FF_GetSequentialClusters(pFile->pIoman, pFile->AddrCurrentCluster, (Count - 1));
+               }
+               Sectors = (SequentialClusters + 1) * pFile->pIoman->pPartition->SectorsPerCluster;
+               nItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster);
+               nItemLBA = FF_getRealLBA(pFile->pIoman, nItemLBA);
+
+               do {
+                       if(pFile->pIoman->pBlkDevice->fnWriteBlocks) {
+                               RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, Sectors, pFile->pIoman->pBlkDevice->pParam);
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       } else {
+                               RetVal = FF_ERR_DEVICE_DRIVER_FAILED;
+                       }
+                       
+               }while(RetVal == FF_ERR_DRIVER_BUSY);
+               
+               Count -= (SequentialClusters + 1);
+               pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, (SequentialClusters + 1));
+               pFile->CurrentCluster += (SequentialClusters + 1);
+               buffer += Sectors * pFile->pIoman->BlkSize;
+               SequentialClusters = 0;
+       }
+
+       return 0;
+}
+
+/**
+ *     @public
+ *     @brief  Equivalent to fread()
+ *
+ *     @param  pFile           FF_FILE object that was created by FF_Open().
+ *     @param  ElementSize     The size of an element to read.
+ *     @param  Count           The number of elements to read.
+ *     @param  buffer          A pointer to a buffer of adequate size to be filled with the requested data.
+ *
+ *     @return Number of bytes read.
+ *
+ **/
+FF_T_SINT32 FF_Read(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
+       FF_T_UINT32 nBytes = ElementSize * Count;
+       FF_T_UINT32     nBytesRead = 0;
+       FF_T_UINT32 nBytesToRead;
+       FF_IOMAN        *pIoman;
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32 nRelBlockPos;
+       FF_T_UINT32     nItemLBA;
+       FF_T_SINT32     RetVal = 0;
+       FF_T_UINT16     sSectors;
+       FF_T_UINT32 nRelClusterPos;
+       FF_T_UINT32 nBytesPerCluster;
+       FF_T_UINT32     nClusterDiff;
+
+       if(!pFile) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       if(!(pFile->Mode & FF_MODE_READ)) {
+               return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE;
+       }
+
+       pIoman = pFile->pIoman;
+
+       if(pFile->FilePointer == pFile->Filesize) {
+               return 0;
+       }
+
+       if((pFile->FilePointer + nBytes) > pFile->Filesize) {
+               nBytes = pFile->Filesize - pFile->FilePointer;
+       }
+       
+       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+       if(nClusterDiff) {
+               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                       pFile->CurrentCluster += nClusterDiff;
+               }
+       }
+
+       nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block.
+       
+       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+
+       if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size.
+               pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
+               {
+                       memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytes);
+               }
+               FF_ReleaseBuffer(pIoman, pBuffer);
+
+               pFile->FilePointer += nBytes;
+               
+               return nBytes;          // Return the number of bytes read.
+
+       } else {
+
+               //---------- Read (memcpy) to a Sector Boundary
+               if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known.
+                       nBytesToRead = pIoman->BlkSize - nRelBlockPos;
+                       pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
+                       {
+                               // Here we copy to the sector boudary.
+                               memcpy(buffer, (pBuffer->pBuffer + nRelBlockPos), nBytesToRead);
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                       nBytes                          -= nBytesToRead;
+                       nBytesRead                      += nBytesToRead;
+                       pFile->FilePointer      += nBytesToRead;
+                       buffer                          += nBytesToRead;
+                       
+               }
+
+               //---------- Read to a Cluster Boundary
+               
+               nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1);
+               nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize);
+               if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+               
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+
+                       sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize));
+                       
+                       do {
+                               if(pIoman->pBlkDevice->fnReadBlocks) {
+                                       RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
+                               }
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       }while(RetVal == FF_ERR_DRIVER_BUSY);
+                       
+                       nBytesToRead             = sSectors * pIoman->BlkSize;
+                       nBytes                          -= nBytesToRead;
+                       buffer                          += nBytesToRead;
+                       nBytesRead                      += nBytesToRead;
+                       pFile->FilePointer      += nBytesToRead;
+
+               }
+
+               //---------- Read Clusters
+               if(nBytes >= nBytesPerCluster) {
+                       //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check.
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+                       //----- End of Contributor fix.
+
+                       FF_ReadClusters(pFile, (nBytes / nBytesPerCluster), buffer);
+                       nBytesToRead = (nBytesPerCluster *  (nBytes / nBytesPerCluster));
+
+                       pFile->FilePointer      += nBytesToRead;
+
+                       nBytes                  -= nBytesToRead;
+                       buffer                  += nBytesToRead;
+                       nBytesRead              += nBytesToRead;
+               }
+
+               //---------- Read Remaining Blocks
+               if(nBytes >= pIoman->BlkSize) {
+                       sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize);
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+                       
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+                       
+                       do {
+                               if(pIoman->pBlkDevice->fnReadBlocks) {
+                                       RetVal = pFile->pIoman->pBlkDevice->fnReadBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
+                               }
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       }while(RetVal == FF_ERR_DRIVER_BUSY);
+                       
+                       nBytesToRead = sSectors * pIoman->BlkSize;
+                       pFile->FilePointer      += nBytesToRead;
+                       nBytes                          -= nBytesToRead;
+                       buffer                          += nBytesToRead;
+                       nBytesRead                      += nBytesToRead;
+               }
+
+               //---------- Read (memcpy) Remaining Bytes
+               if(nBytes > 0) {
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+                       
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+                       pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_READ);
+                       {
+                               memcpy(buffer, pBuffer->pBuffer, nBytes);
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                       nBytesToRead = nBytes;
+                       pFile->FilePointer      += nBytesToRead;
+                       nBytes                          -= nBytesToRead;
+                       buffer                          += nBytesToRead;
+                       nBytesRead                      += nBytesToRead;
+
+               }
+       }
+
+       return nBytesRead;
+}
+
+
+
+
+/**
+ *     @public
+ *     @brief  Equivalent to fgetc()
+ *
+ *     @param  pFile           FF_FILE object that was created by FF_Open().
+ *
+ *     @return The character that was read (cast as a 32-bit interger). -1 on EOF.
+ *     @return -2 If a null file pointer was provided.
+ *     @return -3 Device access failed.
+ *
+ **/
+FF_T_SINT32 FF_GetC(FF_FILE *pFile) {
+       FF_T_UINT32             fileLBA;
+       FF_BUFFER               *pBuffer;
+       FF_T_UINT8              retChar;
+       FF_T_UINT32             relMinorBlockPos;
+       FF_T_UINT32     clusterNum;
+       FF_T_UINT32             nClusterDiff;
+       
+       
+       if(!pFile) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       if(!(pFile->Mode & FF_MODE_READ)) {
+               return FF_ERR_FILE_NOT_OPENED_IN_READ_MODE;
+       }
+       
+       if(pFile->FilePointer >= pFile->Filesize) {
+               return -1; // EOF!      
+       }
+
+       relMinorBlockPos        = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1);
+       clusterNum                      = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1);
+
+       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+       if(nClusterDiff) {
+               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                       pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                       pFile->CurrentCluster += nClusterDiff;
+               }
+       }
+       
+
+       fileLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster)      + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1);
+       fileLBA = FF_getRealLBA (pFile->pIoman, fileLBA)                + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1);
+       
+       pBuffer = FF_GetBuffer(pFile->pIoman, fileLBA, FF_MODE_READ);
+       {
+               if(!pBuffer) {
+                       return -3;
+               }
+               retChar = pBuffer->pBuffer[relMinorBlockPos];
+       }
+       FF_ReleaseBuffer(pFile->pIoman, pBuffer);
+
+       pFile->FilePointer += 1;
+
+       return (FF_T_INT32) retChar;
+}
+
+FF_T_UINT32 FF_Tell(FF_FILE *pFile) {
+       return pFile->FilePointer;
+}
+
+
+/**
+ *     @public
+ *     @brief  Writes data to a File.
+ *
+ *     @param  pFile                   FILE Pointer.
+ *     @param  ElementSize             Size of an Element of Data to be copied. (in bytes). 
+ *     @param  Count                   Number of Elements of Data to be copied. (ElementSize * Count must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best.
+ *     @param  buffer                  Byte-wise buffer containing the data to be written.
+ *
+ *     @return
+ **/
+FF_T_SINT32 FF_Write(FF_FILE *pFile, FF_T_UINT32 ElementSize, FF_T_UINT32 Count, FF_T_UINT8 *buffer) {
+       FF_T_UINT32 nBytes = ElementSize * Count;
+       FF_T_UINT32     nBytesWritten = 0;
+       FF_T_UINT32 nBytesToWrite;
+       FF_IOMAN        *pIoman;
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32 nRelBlockPos;
+       FF_T_UINT32     nItemLBA;
+       FF_T_SINT32     RetVal = 0;
+       FF_T_UINT16     sSectors;
+       FF_T_UINT32 nRelClusterPos;
+       FF_T_UINT32 nBytesPerCluster, nClusterDiff, nClusters;
+       FF_ERROR        Error;
+
+       if(!pFile) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       if(!(pFile->Mode & FF_MODE_WRITE)) {
+               return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE;
+       }
+
+       // Make sure a write is after the append point.
+       if((pFile->Mode & FF_MODE_APPEND)) {
+               if(pFile->FilePointer < pFile->Filesize) {
+                       FF_Seek(pFile, 0, FF_SEEK_END);
+               }
+       }
+
+       pIoman = pFile->pIoman;
+
+       nBytesPerCluster = (pIoman->pPartition->SectorsPerCluster * pIoman->BlkSize);
+
+       // Extend File for atleast nBytes!
+       // Handle file-space allocation
+       Error = FF_ExtendFile(pFile, pFile->FilePointer + nBytes);
+
+       if(Error) {
+               return Error;   
+       }
+
+       nRelBlockPos = FF_getMinorBlockEntry(pIoman, pFile->FilePointer, 1); // Get the position within a block.
+       
+       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+       if(nClusterDiff) {
+               if(pFile->CurrentCluster != FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                       pFile->CurrentCluster += nClusterDiff;
+               }
+       }
+       
+       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+
+       if((nRelBlockPos + nBytes) < pIoman->BlkSize) { // Bytes to read are within a block and less than a block size.
+               pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
+               {
+                       memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytes);
+               }
+               FF_ReleaseBuffer(pIoman, pBuffer);
+
+               pFile->FilePointer += nBytes;
+               nBytesWritten = nBytes;
+               //return nBytes;                // Return the number of bytes read.
+
+       } else {
+
+               //---------- Write (memcpy) to a Sector Boundary
+               if(nRelBlockPos != 0) { // Not on a sector boundary, at this point the LBA is known.
+                       nBytesToWrite = pIoman->BlkSize - nRelBlockPos;
+                       pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
+                       {
+                               // Here we copy to the sector boudary.
+                               memcpy((pBuffer->pBuffer + nRelBlockPos), buffer, nBytesToWrite);
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                       nBytes                          -= nBytesToWrite;
+                       nBytesWritten           += nBytesToWrite;
+                       pFile->FilePointer      += nBytesToWrite;
+                       buffer                          += nBytesToWrite;
+               }
+
+               //---------- Write to a Cluster Boundary
+               
+               nRelClusterPos = FF_getClusterPosition(pIoman, pFile->FilePointer, 1);
+               if(nRelClusterPos != 0 && nBytes >= nBytesPerCluster) { // Need to get to cluster boundary
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+               
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+
+                       sSectors = (FF_T_UINT16) (pIoman->pPartition->SectorsPerCluster - (nRelClusterPos / pIoman->BlkSize));
+                       
+                       do {
+                               if(pIoman->pBlkDevice->fnWriteBlocks) {
+                                       RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
+                               }
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       }while(RetVal == FF_ERR_DRIVER_BUSY);
+                       
+                       nBytesToWrite            = sSectors * pIoman->BlkSize;
+                       nBytes                          -= nBytesToWrite;
+                       buffer                          += nBytesToWrite;
+                       nBytesWritten           += nBytesToWrite;
+                       pFile->FilePointer      += nBytesToWrite;
+
+               }
+
+               //---------- Write Clusters
+               if(nBytes >= nBytesPerCluster) {
+                       //----- Thanks to Christopher Clark of DigiPen Institute of Technology in Redmond, US adding this traversal check.
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+                       //----- End of Contributor fix.
+
+                       nClusters = (nBytes / nBytesPerCluster);
+                       
+                       FF_WriteClusters(pFile, nClusters, buffer);
+                       
+                       nBytesToWrite = (nBytesPerCluster *  nClusters);
+                       
+                       pFile->FilePointer      += nBytesToWrite;
+
+                       nBytes                          -= nBytesToWrite;
+                       buffer                          += nBytesToWrite;
+                       nBytesWritten           += nBytesToWrite;
+               }
+
+               //---------- Write Remaining Blocks
+               if(nBytes >= pIoman->BlkSize) {
+                       sSectors = (FF_T_UINT16) (nBytes / pIoman->BlkSize);
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }                       
+                       
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+                       
+                       do {
+                               if(pIoman->pBlkDevice->fnWriteBlocks) {
+                                       RetVal = pFile->pIoman->pBlkDevice->fnWriteBlocks(buffer, nItemLBA, sSectors, pIoman->pBlkDevice->pParam);
+                               }
+                               if(RetVal == FF_ERR_DRIVER_BUSY) {
+                                       FF_Yield();
+                                       FF_Sleep(FF_DRIVER_BUSY_SLEEP);
+                               }
+                       }while(RetVal == FF_ERR_DRIVER_BUSY);
+                       
+                       nBytesToWrite = sSectors * pIoman->BlkSize;
+                       pFile->FilePointer      += nBytesToWrite;
+                       nBytes                          -= nBytesToWrite;
+                       buffer                          += nBytesToWrite;
+                       nBytesWritten           += nBytesToWrite;
+
+               }
+
+               //---------- Write (memcpy) Remaining Bytes
+               if(nBytes > 0) {
+                       
+                       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+                       if(nClusterDiff) {
+                               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                                       pFile->AddrCurrentCluster = FF_TraverseFAT(pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                                       pFile->CurrentCluster += nClusterDiff;
+                               }
+                       }
+                       
+                       nItemLBA = FF_Cluster2LBA(pIoman, pFile->AddrCurrentCluster);
+                       nItemLBA = FF_getRealLBA(pIoman, nItemLBA + FF_getMajorBlockNumber(pIoman, pFile->FilePointer, 1)) + FF_getMinorBlockNumber(pIoman, pFile->FilePointer, 1);
+                       pBuffer = FF_GetBuffer(pIoman, nItemLBA, FF_MODE_WRITE);
+                       {
+                               memcpy(pBuffer->pBuffer, buffer, nBytes);
+                       }
+                       FF_ReleaseBuffer(pIoman, pBuffer);
+
+                       nBytesToWrite = nBytes;
+                       pFile->FilePointer      += nBytesToWrite;
+                       nBytes                          -= nBytesToWrite;
+                       buffer                          += nBytesToWrite;
+                       nBytesWritten                   += nBytesToWrite;
+
+               }
+       }
+
+       if(pFile->FilePointer > pFile->Filesize) {
+               pFile->Filesize = pFile->FilePointer;
+       }
+
+       return nBytesWritten;
+}
+
+
+/**
+ *     @public
+ *     @brief  Writes a char to a FILE.
+ *
+ *     @param  pFile           FILE Pointer.
+ *     @param  pa_cValue       Char to be placed in the file.
+ *
+ *     @return Returns the value written to the file, or a value less than 0.
+ *
+ **/
+FF_T_SINT32 FF_PutC(FF_FILE *pFile, FF_T_UINT8 pa_cValue) {
+       FF_BUFFER       *pBuffer;
+       FF_T_UINT32 iItemLBA;
+       FF_T_UINT32 iRelPos;
+       FF_T_UINT32 nClusterDiff;
+       
+       if(!pFile) {    // Ensure we don't have a Null file pointer on a Public interface.
+               return FF_ERR_NULL_POINTER;
+       }
+
+       if(!(pFile->Mode & FF_MODE_WRITE)) {
+               return FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE;
+       }
+
+       // Make sure a write is after the append point.
+       if((pFile->Mode & FF_MODE_APPEND)) {
+               if(pFile->FilePointer < pFile->Filesize) {
+                       FF_Seek(pFile, 0, FF_SEEK_END);
+               }
+       }
+
+       iRelPos = FF_getMinorBlockEntry(pFile->pIoman, pFile->FilePointer, 1);
+       
+       // Handle File Space Allocation.
+       FF_ExtendFile(pFile, pFile->FilePointer + 1);
+       
+       nClusterDiff = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1) - pFile->CurrentCluster;
+       if(nClusterDiff) {
+               if(pFile->CurrentCluster < FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1)) {
+                       pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->AddrCurrentCluster, nClusterDiff);
+                       pFile->CurrentCluster += nClusterDiff;
+               }
+       }
+
+       iItemLBA = FF_Cluster2LBA(pFile->pIoman, pFile->AddrCurrentCluster) + FF_getMajorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1);
+       iItemLBA = FF_getRealLBA (pFile->pIoman, iItemLBA)                      + FF_getMinorBlockNumber(pFile->pIoman, pFile->FilePointer, (FF_T_UINT16) 1);
+       
+       pBuffer = FF_GetBuffer(pFile->pIoman, iItemLBA, FF_MODE_WRITE);
+       {
+               if(!pBuffer) {
+                       return FF_ERR_DEVICE_DRIVER_FAILED;
+               }
+               FF_putChar(pBuffer->pBuffer, (FF_T_UINT16) iRelPos, pa_cValue);
+       }
+       FF_ReleaseBuffer(pFile->pIoman, pBuffer);
+
+       pFile->FilePointer += 1;
+       if(pFile->Filesize < (pFile->FilePointer)) {
+               pFile->Filesize += 1;
+       }
+       return pa_cValue;
+}
+
+
+
+/**
+ *     @public
+ *     @brief  Equivalent to fseek()
+ *
+ *     @param  pFile           FF_FILE object that was created by FF_Open().
+ *     @param  Offset          An integer (+/-) to seek to, from the specified origin.
+ *     @param  Origin          Where to seek from. (FF_SEEK_SET seek from start, FF_SEEK_CUR seek from current position, or FF_SEEK_END seek from end of file).
+ *
+ *     @return 0 on Sucess, 
+ *     @return -2 if offset results in an invalid position in the file. 
+ *     @return -1 if a FF_FILE pointer was not recieved.
+ *     @return -3 if an invalid origin was provided.
+ *     
+ **/
+FF_ERROR FF_Seek(FF_FILE *pFile, FF_T_SINT32 Offset, FF_T_INT8 Origin) {
+       
+       if(!pFile) {
+               return FF_ERR_NULL_POINTER;
+       }
+
+       switch(Origin) {
+               case FF_SEEK_SET:
+                       if((FF_T_UINT32) Offset <= pFile->Filesize && Offset >= 0) {
+                               pFile->FilePointer = Offset;
+                               pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1);
+                               pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster);
+                       } else {
+                               return -2;
+                       }
+                       break;
+
+               case FF_SEEK_CUR:
+                       if((Offset + pFile->FilePointer) <= pFile->Filesize && (Offset + (FF_T_SINT32) pFile->FilePointer) >= 0) {
+                               pFile->FilePointer = Offset + pFile->FilePointer;
+                               pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1);
+                               pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster);
+                       } else {
+                               return -2;
+                       }
+                       break;
+       
+               case FF_SEEK_END:
+                       if((Offset + (FF_T_SINT32) pFile->Filesize) >= 0 && (Offset + pFile->Filesize) <= pFile->Filesize) {
+                               pFile->FilePointer = Offset + pFile->Filesize;
+                               pFile->CurrentCluster = FF_getClusterChainNumber(pFile->pIoman, pFile->FilePointer, 1);
+                               pFile->AddrCurrentCluster = FF_TraverseFAT(pFile->pIoman, pFile->ObjectCluster, pFile->CurrentCluster);
+                       } else {
+                               return -2;
+                       }
+                       break;
+
+               default:
+                       return -3;
+               
+       }
+
+       return 0;
+}
+
+
+/**
+ *     @public
+ *     @brief  Equivalent to fclose()
+ *
+ *     @param  pFile           FF_FILE object that was created by FF_Open().
+ *
+ *     @return 0 on sucess.
+ *     @return -1 if a null pointer was provided.
+ *
+ **/
+FF_ERROR FF_Close(FF_FILE *pFile) {
+
+       FF_FILE         *pFileChain;
+       FF_DIRENT       OriginalEntry;
+       FF_ERROR        Error;
+
+       if(!pFile) {
+               return FF_ERR_NULL_POINTER;     
+       }
+       // UpDate Dirent if File-size has changed?
+
+       // Update the Dirent!
+       Error = FF_GetEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry);
+       if(Error) {
+               return Error;
+       }
+       
+       if(!pFile->FileDeleted) {
+               if(pFile->Filesize != OriginalEntry.Filesize) {
+                       OriginalEntry.Filesize = pFile->Filesize;
+                       FF_PutEntry(pFile->pIoman, pFile->DirEntry, pFile->DirCluster, &OriginalEntry);
+               }
+       }
+
+       //if(pFile->Mode == FF_MODE_WRITE) {
+       FF_FlushCache(pFile->pIoman);           // Ensure all modfied blocks are flushed to disk!
+       //}
+       
+       // Handle Linked list!
+       FF_PendSemaphore(pFile->pIoman->pSemaphore);
+       {       // Semaphore is required, or linked list could become corrupted.
+               if(pFile->pIoman->FirstFile == pFile) {
+                       pFile->pIoman->FirstFile = pFile->Next;
+               } else {
+                       pFileChain = (FF_FILE *) pFile->pIoman->FirstFile;
+                       while(pFileChain->Next != pFile) {
+                               pFileChain = pFileChain->Next;
+                       }
+                       pFileChain->Next = pFile->Next;
+               }
+       }       // Semaphore released, linked list was shortened!
+       FF_ReleaseSemaphore(pFile->pIoman->pSemaphore);
+
+       // If file written, flush to disk
+       free(pFile);
+       // Simply free the pointer!
+       return FF_ERR_NONE;
+}
diff --git a/reactos/lib/3rdparty/fullfat/ff_hash.c b/reactos/lib/3rdparty/fullfat/ff_hash.c
new file mode 100644 (file)
index 0000000..1418b2a
--- /dev/null
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *  (James Walmsley). For more information consult LICENSING.TXT to obtain   *
+ *  a Commercial license.                                                    *
+ *                                                                           *
+ *  See RESTRICTIONS.TXT for extra restrictions on the use of FullFAT.       *
+ *                                                                           *
+ *  Removing the above notice is illegal and will invalidate this license.   *
+ *****************************************************************************
+ *  See http://worm.me.uk/fullfat for more information.                      *
+ *  Or  http://fullfat.googlecode.com/ for latest releases and the wiki.     *
+ *****************************************************************************/
+
+/**
+ *     @file           ff_hash.c
+ *     @author         James Walmsley
+ *     @ingroup        HASH
+ *
+ *     @defgroup       HASH HASH Table
+ *     @brief          Provides a simple HASH lookup table.
+ *
+ **/
+
+#include "ff_hash.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef FF_HASH_TABLE_SUPPORT
+struct _FF_HASH_TABLE {
+       FF_T_UINT8 bitTable[FF_HASH_TABLE_SIZE];        
+};
+
+/**
+ *
+ *
+ **/
+FF_HASH_TABLE FF_CreateHashTable() {
+       FF_HASH_TABLE pHash = (FF_HASH_TABLE) malloc(sizeof(struct _FF_HASH_TABLE));
+
+       if(pHash) {
+               FF_ClearHashTable(pHash);
+               return pHash;
+       }
+
+       return NULL;
+}
+
+FF_ERROR FF_ClearHashTable(FF_HASH_TABLE pHash) {
+       if(pHash) {
+               memset(pHash->bitTable, 0, FF_HASH_TABLE_SIZE);
+               return FF_ERR_NONE;
+       }
+
+       return FF_ERR_NULL_POINTER;
+}
+
+FF_ERROR FF_SetHash(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) {
+       FF_T_UINT32 tblIndex    = ((nHash / 8) % FF_HASH_TABLE_SIZE);
+       FF_T_UINT32 tblBit              = nHash % 8;
+
+       if(pHash) {
+               pHash->bitTable[tblIndex] |= (0x80 >> tblBit);
+               return FF_ERR_NONE;
+       }
+
+       return FF_ERR_NULL_POINTER;     
+}
+
+FF_ERROR FF_ClearHash(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) {
+       FF_T_UINT32 tblIndex    = ((nHash / 8) % FF_HASH_TABLE_SIZE);
+       FF_T_UINT32 tblBit              = nHash % 8;
+
+       if(pHash) {
+               pHash->bitTable[tblIndex] &= ~(0x80 >> tblBit);
+               return FF_ERR_NONE;
+       }
+
+       return FF_ERR_NULL_POINTER;
+}
+
+FF_T_BOOL FF_isHashSet(FF_HASH_TABLE pHash, FF_T_UINT32 nHash) {
+       FF_T_UINT32 tblIndex    = ((nHash / 8) % FF_HASH_TABLE_SIZE);
+       FF_T_UINT32 tblBit              = nHash % 8;
+
+       if(pHash) {
+               if(pHash->bitTable[tblIndex] & (0x80 >> tblBit)) {
+                       return FF_TRUE;
+               }
+       }
+       return FF_FALSE;
+}
+
+FF_ERROR FF_DestroyHashTable(FF_HASH_TABLE pHash) {
+       if(pHash) {
+               free(pHash);
+               return FF_ERR_NONE;
+       }
+       return FF_ERR_NULL_POINTER;
+}
+
+#endif
diff --git a/reactos/lib/3rdparty/fullfat/ff_ioman.c b/reactos/lib/3rdparty/fullfat/ff_ioman.c
new file mode 100644 (file)
index 0000000..e9fcc0d
--- /dev/null
@@ -0,0 +1,909 @@
+/*****************************************************************************
+ *  FullFAT - High Performance, Thread-Safe Embedded FAT File-System         *
+ *  Copyright (C) 2009  James Walmsley (james@worm.me.uk)                    *
+ *                                                                           *
+ *  This program is free software: you can redistribute it and/or modify     *
+ *  it under the terms of the GNU General Public License as published by     *
+ *  the Free Software Foundation, either version 3 of the License, or        *
+ *  (at your option) any later version.                                      *
+ *                                                                           *
+ *  This program is distributed in the hope that it will be useful,          *
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+ *  GNU General Public License for more details.                             *
+ *                                                                           *
+ *  You should have received a copy of the GNU General Public License        *
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.    *
+ *                                                                           *
+ *  IMPORTANT NOTICE:                                                        *
+ *  =================                                                        *
+ *  Alternative Licensing is available directly from the Copyright holder,   *
+ *&