From 77655e13d64f15d964b76f57b73fe2260a1f4b52 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 28 Sep 2009 18:41:51 +0000 Subject: [PATCH] - Import FullFAT and add it to build. svn path=/trunk/; revision=43212 --- reactos/include/reactos/libs/fullfat/fat.h | 83 + reactos/include/reactos/libs/fullfat/ff_blk.h | 53 + .../include/reactos/libs/fullfat/ff_config.h | 171 ++ reactos/include/reactos/libs/fullfat/ff_crc.h | 49 + reactos/include/reactos/libs/fullfat/ff_dir.h | 105 + .../include/reactos/libs/fullfat/ff_error.h | 98 + reactos/include/reactos/libs/fullfat/ff_fat.h | 77 + .../include/reactos/libs/fullfat/ff_file.h | 95 + .../include/reactos/libs/fullfat/ff_hash.h | 56 + .../include/reactos/libs/fullfat/ff_ioman.h | 232 +++ .../include/reactos/libs/fullfat/ff_memory.h | 56 + .../include/reactos/libs/fullfat/ff_safety.h | 59 + .../include/reactos/libs/fullfat/ff_string.h | 54 + .../include/reactos/libs/fullfat/ff_time.h | 65 + .../include/reactos/libs/fullfat/ff_types.h | 74 + .../include/reactos/libs/fullfat/fullfat.h | 46 + reactos/lib/3rdparty/3rdparty.rbuild | 3 + reactos/lib/3rdparty/fullfat/ff_blk.c | 85 + reactos/lib/3rdparty/fullfat/ff_crc.c | 194 ++ reactos/lib/3rdparty/fullfat/ff_dir.c | 1772 +++++++++++++++++ reactos/lib/3rdparty/fullfat/ff_dir.h | 105 + reactos/lib/3rdparty/fullfat/ff_error.c | 107 + reactos/lib/3rdparty/fullfat/ff_fat.c | 750 +++++++ reactos/lib/3rdparty/fullfat/ff_file.c | 1411 +++++++++++++ reactos/lib/3rdparty/fullfat/ff_hash.c | 119 ++ reactos/lib/3rdparty/fullfat/ff_ioman.c | 909 +++++++++ reactos/lib/3rdparty/fullfat/ff_memory.c | 134 ++ reactos/lib/3rdparty/fullfat/ff_safety.c | 112 ++ reactos/lib/3rdparty/fullfat/ff_string.c | 234 +++ reactos/lib/3rdparty/fullfat/ff_time.c | 72 + 30 files changed, 7380 insertions(+) create mode 100644 reactos/include/reactos/libs/fullfat/fat.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_blk.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_config.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_crc.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_dir.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_error.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_fat.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_file.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_hash.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_ioman.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_memory.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_safety.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_string.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_time.h create mode 100644 reactos/include/reactos/libs/fullfat/ff_types.h create mode 100644 reactos/include/reactos/libs/fullfat/fullfat.h create mode 100644 reactos/lib/3rdparty/fullfat/ff_blk.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_crc.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_dir.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_dir.h create mode 100644 reactos/lib/3rdparty/fullfat/ff_error.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_fat.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_file.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_hash.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_ioman.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_memory.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_safety.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_string.c create mode 100644 reactos/lib/3rdparty/fullfat/ff_time.c diff --git a/reactos/include/reactos/libs/fullfat/fat.h b/reactos/include/reactos/libs/fullfat/fat.h new file mode 100644 index 00000000000..908cb36a801 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/fat.h @@ -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 . * + * * + * 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 index 00000000000..2cc14ec46a3 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_blk.h @@ -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 . * + * * + * 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 index 00000000000..f81c79ac7c9 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_config.h @@ -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 . * + * * + * 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 index 00000000000..7349269d836 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_crc.h @@ -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 . * + * * + * 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 index 00000000000..7415eac06e6 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_dir.h @@ -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 . * + * * + * 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 + +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 index 00000000000..8a48c8f1cce --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_error.h @@ -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 . * + * * + * 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 index 00000000000..2e6ff6702b9 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_fat.h @@ -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 . * + * * + * 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 index 00000000000..e74d4a6a6ed --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_file.h @@ -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 . * + * * + * 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 +#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 index 00000000000..70f61afd109 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_hash.h @@ -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 . * + * * + * 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 index 00000000000..187ffa347f9 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_ioman.h @@ -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 . * + * * + * 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 // 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 index 00000000000..ba4ef54e9b9 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_memory.h @@ -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 . * + * * + * 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 index 00000000000..424531d26b9 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_safety.h @@ -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 . * + * * + * 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 +#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 index 00000000000..e3789102e4b --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_string.h @@ -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 . * + * * + * 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 index 00000000000..57b8e54826f --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_time.h @@ -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 . * + * * + * 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 index 00000000000..59a599670a3 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/ff_types.h @@ -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 . * + * * + * 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 index 00000000000..dd8da071cf5 --- /dev/null +++ b/reactos/include/reactos/libs/fullfat/fullfat.h @@ -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 . * + * * + * 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 diff --git a/reactos/lib/3rdparty/3rdparty.rbuild b/reactos/lib/3rdparty/3rdparty.rbuild index bd623250eb6..2766780b542 100644 --- a/reactos/lib/3rdparty/3rdparty.rbuild +++ b/reactos/lib/3rdparty/3rdparty.rbuild @@ -13,6 +13,9 @@ + + + diff --git a/reactos/lib/3rdparty/fullfat/ff_blk.c b/reactos/lib/3rdparty/fullfat/ff_blk.c new file mode 100644 index 00000000000..d97b1a628c4 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_blk.c @@ -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 . * + * * + * 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 index 00000000000..9c6ea469334 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_crc.c @@ -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 . * + * * + * 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 index 00000000000..6bba0b79020 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_dir.c @@ -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 . * + * * + * 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 + +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 index 00000000000..7415eac06e6 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_dir.h @@ -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 . * + * * + * 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 + +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 index 00000000000..483bf964ce3 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_error.c @@ -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 . * + * * + * 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 index 00000000000..1cbd420ffad --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_fat.c @@ -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 . * + * * + * 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 + +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 index 00000000000..7f014a4515d --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_file.c @@ -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 . * + * * + * 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 index 00000000000..1418b2a8b77 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_hash.c @@ -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 . * + * * + * 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 +#include + +#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 index 00000000000..e9fcc0dbb3d --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_ioman.c @@ -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 . * + * * + * 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.c + * @author James Walmsley + * @ingroup IOMAN + * + * @defgroup IOMAN I/O Manager + * @brief Handles IO buffers for FullFAT safely. + * + * Provides a simple static interface to the rest of FullFAT to manage + * buffers. It also defines the public interfaces for Creating and + * Destroying a FullFAT IO object. + **/ + +#include "ff_ioman.h" // Includes ff_types.h, ff_safety.h, +#include "fat.h" + +extern FF_T_UINT32 FF_FindFreeCluster (FF_IOMAN *pIoman); +extern FF_T_UINT32 FF_CountFreeClusters (FF_IOMAN *pIoman); + +static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman); + +/** + * @public + * @brief Creates an FF_IOMAN object, to initialise FullFAT + * + * @param pCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc). + * @param Size The size of the provided buffer, or size of the cache to be created. + * @param BlkSize The block size of devices to be attached. If in doubt use 512. + * @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 Returns a pointer to an FF_IOMAN type object. NULL on Error, check the contents of + * @return pError + **/ +FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 BlkSize, FF_ERROR *pError) { + + FF_IOMAN *pIoman = NULL; + FF_T_UINT32 *pLong = NULL; // Force malloc to malloc memory on a 32-bit boundary. +#ifdef FF_PATH_CACHE + FF_T_UINT32 i; +#endif + + if(pError) { + *pError = FF_ERR_NONE; + } + + if((BlkSize % 512) != 0 || Size == 0) { + if(pError) { + *pError = FF_ERR_IOMAN_BAD_BLKSIZE; + } + return NULL; // BlkSize Size not a multiple of 512 > 0 + } + + if((Size % BlkSize) != 0 || Size == 0) { + if(pError) { + *pError = FF_ERR_IOMAN_BAD_MEMSIZE; + } + return NULL; // Memory Size not a multiple of BlkSize > 0 + } + + pIoman = (FF_IOMAN *) malloc(sizeof(FF_IOMAN)); + + if(!pIoman) { // Ensure malloc() succeeded. + if(pError) { + *pError = FF_ERR_NOT_ENOUGH_MEMORY; + } + return NULL; + } + + // This is just a bit-mask, to use a byte to keep track of memory. + // pIoman->MemAllocation = 0x00; // Unset all allocation identifiers. + pIoman->pBlkDevice = NULL; + pIoman->pBuffers = NULL; + pIoman->pCacheMem = NULL; + pIoman->pPartition = NULL; + pIoman->pSemaphore = NULL; + + pIoman->pPartition = (FF_PARTITION *) malloc(sizeof(FF_PARTITION)); + if(pIoman->pPartition) { // If succeeded, flag that allocation. + pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART; + pIoman->pPartition->LastFreeCluster = 0; + pIoman->pPartition->PartitionMounted = FF_FALSE; // This should be checked by FF_Open(); +#ifdef FF_PATH_CACHE + pIoman->pPartition->PCIndex = 0; + for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { + pIoman->pPartition->PathCache[i].DirCluster = 0; + pIoman->pPartition->PathCache[i].Path[0] = '\0'; +#ifdef FF_HASH_TABLE_SUPPORT + pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable(); + pIoman->pPartition->PathCache[i].bHashed = FF_FALSE; +#endif + } +#endif + } else { + FF_DestroyIOMAN(pIoman); + return NULL; + } + + pIoman->pBlkDevice = (FF_BLK_DEVICE *) malloc(sizeof(FF_BLK_DEVICE)); + if(pIoman->pBlkDevice) { // If succeeded, flag that allocation. + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; + + // Make sure all pointers are NULL + pIoman->pBlkDevice->fnReadBlocks = NULL; + pIoman->pBlkDevice->fnWriteBlocks = NULL; + pIoman->pBlkDevice->pParam = NULL; + + } else { + FF_DestroyIOMAN(pIoman); + return NULL; + } + + // Organise the memory provided, or create our own! + if(pCacheMem) { + pIoman->pCacheMem = pCacheMem; + }else { // No-Cache buffer provided (malloc) + pLong = (FF_T_UINT32 *) malloc(Size); + pIoman->pCacheMem = (FF_T_UINT8 *) pLong; + if(!pIoman->pCacheMem) { + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFFERS; + FF_DestroyIOMAN(pIoman); + return NULL; + } + + } + + pIoman->BlkSize = BlkSize; + pIoman->CacheSize = (FF_T_UINT16) (Size / BlkSize); + pIoman->FirstFile = NULL; + pIoman->Locks = 0; + + /* Malloc() memory for buffer objects. (FullFAT never refers to a buffer directly + but uses buffer objects instead. Allows us to provide thread safety. + */ + pIoman->pBuffers = (FF_BUFFER *) malloc(sizeof(FF_BUFFER) * pIoman->CacheSize); + + if(pIoman->pBuffers) { + pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFDESCR; + FF_IOMAN_InitBufferDescriptors(pIoman); + } else { + FF_DestroyIOMAN(pIoman); + } + + // Finally create a Semaphore for Buffer Description modifications. + pIoman->pSemaphore = FF_CreateSemaphore(); + + return pIoman; // Sucess, return the created object. +} + +/** + * @public + * @brief Destroys an FF_IOMAN object, and frees all assigned memory. + * + * @param pIoman Pointer to an FF_IOMAN object, as returned from FF_CreateIOMAN. + * + * @return FF_ERR_NONE on sucess, or a documented error code on failure. (FF_ERR_NULL_POINTER) + * + **/ +FF_ERROR FF_DestroyIOMAN(FF_IOMAN *pIoman) { + + // Ensure no NULL pointer was provided. + if(!pIoman) { + return FF_ERR_NULL_POINTER; + } + + // Ensure pPartition pointer was allocated. + if((pIoman->MemAllocation & FF_IOMAN_ALLOC_PART)) { + free(pIoman->pPartition); + } + + // Ensure pBlkDevice pointer was allocated. + if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BLKDEV)) { + free(pIoman->pBlkDevice); + } + + // Ensure pBuffers pointer was allocated. + if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFDESCR)) { + free(pIoman->pBuffers); + } + + // Ensure pCacheMem pointer was allocated. + if((pIoman->MemAllocation & FF_IOMAN_ALLOC_BUFFERS)) { + free(pIoman->pCacheMem); + } + + // Destroy any Semaphore that was created. + if(pIoman->pSemaphore) { + FF_DestroySemaphore(pIoman->pSemaphore); + } + + // Finally free the FF_IOMAN object. + free(pIoman); + + return FF_ERR_NONE; +} + +/** + * @private + * @brief Initialises Buffer Descriptions as part of the FF_IOMAN object initialisation. + * + * @param pIoman IOMAN Object. + * + **/ +static void FF_IOMAN_InitBufferDescriptors(FF_IOMAN *pIoman) { + FF_T_UINT16 i; + FF_BUFFER *pBuffer = pIoman->pBuffers; + pIoman->LastReplaced = 0; + for(i = 0; i < pIoman->CacheSize; i++) { + pBuffer->Mode = 0; + pBuffer->NumHandles = 0; + pBuffer->Persistance = 0; + pBuffer->LRU = 0; + pBuffer->Sector = 0; + pBuffer->pBuffer = (FF_T_UINT8 *)((pIoman->pCacheMem) + (pIoman->BlkSize * i)); + pBuffer->Modified = FF_FALSE; + pBuffer->Valid = FF_FALSE; + pBuffer++; + } +} + +/** + * @private + * @brief Tests the Mode for validity. + * + * @param Mode Mode of buffer to check. + * + * @return FF_TRUE when valid, else FF_FALSE. + **/ +/*static FF_T_BOOL FF_IOMAN_ModeValid(FF_T_UINT8 Mode) { + if(Mode == FF_MODE_READ || Mode == FF_MODE_WRITE) { + return FF_TRUE; + } + return FF_FALSE; +}*/ + + +/** + * @private + * @brief Fills a buffer with the appropriate sector via the device driver. + * + * @param pIoman FF_IOMAN object. + * @param Sector LBA address of the sector to fetch. + * @param pBuffer Pointer to a byte-wise buffer to store the fetched data. + * + * @return FF_TRUE when valid, else FF_FALSE. + **/ +static FF_ERROR FF_IOMAN_FillBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) { + FF_T_SINT32 retVal = 0; + if(pIoman->pBlkDevice->fnReadBlocks) { // Make sure we don't execute a NULL. + do{ + retVal = pIoman->pBlkDevice->fnReadBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam); + if(retVal == FF_ERR_DRIVER_BUSY) { + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } + } while(retVal == FF_ERR_DRIVER_BUSY); + if(retVal < 0) { + return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail! + } else { + if(retVal == 1) { + return 0; // 1 Block was sucessfully read. + } else { + return -1; // 0 Blocks we're read, Error! + } + } + } + return -1; // error no device diver registered. +} + + +/** + * @private + * @brief Flushes a buffer to the device driver. + * + * @param pIoman FF_IOMAN object. + * @param Sector LBA address of the sector to fetch. + * @param pBuffer Pointer to a byte-wise buffer to store the fetched data. + * + * @return FF_TRUE when valid, else FF_FALSE. + **/ +static FF_ERROR FF_IOMAN_FlushBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 *pBuffer) { + FF_T_SINT32 retVal = 0; + if(pIoman->pBlkDevice->fnWriteBlocks) { // Make sure we don't execute a NULL. + do{ + retVal = pIoman->pBlkDevice->fnWriteBlocks(pBuffer, Sector, 1, pIoman->pBlkDevice->pParam); + if(retVal == FF_ERR_DRIVER_BUSY) { + FF_Sleep(FF_DRIVER_BUSY_SLEEP); + } + } while(retVal == FF_ERR_DRIVER_BUSY); + if(retVal < 0) { + return -1; // FF_ERR_DRIVER_FATAL_ERROR was returned Fail! + } else { + if(retVal == 1) { + return FF_ERR_NONE; // 1 Block was sucessfully written. + } else { + return -1; // 0 Blocks we're written, Error! + } + } + } + return -1; // error no device diver registered. +} + + +/** + * @private + * @brief Flushes all Write cache buffers with no active Handles. + * + * @param pIoman IOMAN Object. + * + * @return FF_ERR_NONE on Success. + **/ +FF_ERROR FF_FlushCache(FF_IOMAN *pIoman) { + + FF_T_UINT16 i,x; + + if(!pIoman) { + return FF_ERR_NULL_POINTER; + } + + FF_PendSemaphore(pIoman->pSemaphore); + { + for(i = 0; i < pIoman->CacheSize; i++) { + if((pIoman->pBuffers + i)->NumHandles == 0 && (pIoman->pBuffers + i)->Modified == FF_TRUE) { + + FF_IOMAN_FlushBuffer(pIoman, (pIoman->pBuffers + i)->Sector, (pIoman->pBuffers + i)->pBuffer); + + // Buffer has now been flushed, mark it as a read buffer and unmodified. + (pIoman->pBuffers + i)->Mode = FF_MODE_READ; + (pIoman->pBuffers + i)->Modified = FF_FALSE; + + // Search for other buffers that used this sector, and mark them as modified + // So that further requests will result in the new sector being fetched. + for(x = 0; x < pIoman->CacheSize; x++) { + if(x != i) { + if((pIoman->pBuffers + x)->Sector == (pIoman->pBuffers + i)->Sector && (pIoman->pBuffers + x)->Mode == FF_MODE_READ) { + (pIoman->pBuffers + x)->Modified = FF_TRUE; + } + } + } + } + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + + return FF_ERR_NONE; +} + +/*static FF_T_BOOL FF_isFATSector(FF_IOMAN *pIoman, FF_T_UINT32 Sector) { + if(Sector >= pIoman->pPartition->FatBeginLBA && Sector < (pIoman->pPartition->FatBeginLBA + pIoman->pPartition->ReservedSectors)) { + return FF_TRUE; + } + return FF_FALSE; +}*/ + +FF_BUFFER *FF_GetBuffer(FF_IOMAN *pIoman, FF_T_UINT32 Sector, FF_T_UINT8 Mode) { + FF_BUFFER *pBuffer; + FF_BUFFER *pBufLRU = NULL; + FF_BUFFER *pBufLHITS = NULL; + FF_BUFFER *pBufMatch = NULL; + + FF_T_UINT32 i; + + while(!pBufMatch) { + FF_PendSemaphore(pIoman->pSemaphore); + { + for(i = 0; i < pIoman->CacheSize; i++) { + pBuffer = (pIoman->pBuffers + i); + if(pBuffer->Sector == Sector && pBuffer->Valid == FF_TRUE) { + pBufMatch = pBuffer; + } else { + if(pBuffer->NumHandles == 0) { + pBuffer->LRU += 1; + + if(!pBufLRU) { + pBufLRU = pBuffer; + } + if(!pBufLHITS) { + pBufLHITS = pBuffer; + } + + if(pBuffer->LRU >= pBufLRU->LRU) { + if(pBuffer->LRU == pBufLRU->LRU) { + if(pBuffer->Persistance > pBufLRU->Persistance) { + pBufLRU = pBuffer; + } + } else { + pBufLRU = pBuffer; + } + } + + if(pBuffer->Persistance < pBufLHITS->Persistance) { + pBufLHITS = pBuffer; + } + } + } + } + + if(pBufMatch) { + // A Match was found process! + if(Mode == FF_MODE_READ && pBufMatch->Mode == FF_MODE_READ) { + pBufMatch->NumHandles += 1; + pBufMatch->Persistance += 1; + FF_ReleaseSemaphore(pIoman->pSemaphore); + return pBufMatch; + } + + if(pBufMatch->Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) { // This buffer has no attached handles. + pBufMatch->Mode = Mode; + pBufMatch->NumHandles = 1; + pBufMatch->Persistance += 1; + FF_ReleaseSemaphore(pIoman->pSemaphore); + return pBufMatch; + } + + if(pBufMatch->Mode == FF_MODE_READ && Mode == FF_MODE_WRITE && pBufMatch->NumHandles == 0) { + pBufMatch->Mode = Mode; + pBufMatch->Modified = FF_TRUE; + pBufMatch->NumHandles = 1; + pBufMatch->Persistance += 1; + FF_ReleaseSemaphore(pIoman->pSemaphore); + return pBufMatch; + } + + pBufMatch = NULL; // Sector is already in use, keep yielding until its available! + + } else { + // Choose a suitable buffer! + if(pBufLRU) { + // Process the suitable candidate. + if(pBufLRU->Modified == FF_TRUE) { + FF_IOMAN_FlushBuffer(pIoman, pBufLRU->Sector, pBufLRU->pBuffer); + } + pBufLRU->Mode = Mode; + pBufLRU->Persistance = 1; + pBufLRU->LRU = 0; + pBufLRU->NumHandles = 1; + pBufLRU->Sector = Sector; + + if(Mode == FF_MODE_WRITE) { + pBufLRU->Modified = FF_TRUE; + } else { + pBufLRU->Modified = FF_FALSE; + } + + FF_IOMAN_FillBuffer(pIoman, Sector, pBufLRU->pBuffer); + pBufLRU->Valid = FF_TRUE; + FF_ReleaseSemaphore(pIoman->pSemaphore); + return pBufLRU; + } + + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + FF_Yield(); + } + + return pBufMatch; // Return the Matched Buffer! +} + + +/** + * @private + * @brief Releases a buffer resource. + * + * @param pIoman Pointer to an FF_IOMAN object. + * @param pBuffer Pointer to an FF_BUFFER object. + * + **/ +void FF_ReleaseBuffer(FF_IOMAN *pIoman, FF_BUFFER *pBuffer) { + // Protect description changes with a semaphore. + FF_PendSemaphore(pIoman->pSemaphore); + { + pBuffer->NumHandles--; + } + FF_ReleaseSemaphore(pIoman->pSemaphore); +} + +/** + * @public + * @brief Registers a device driver with FullFAT + * + * The device drivers must adhere to the specification provided by + * FF_WRITE_BLOCKS and FF_READ_BLOCKS. + * + * @param pIoman FF_IOMAN object. + * @param BlkSize Block Size that the driver deals in. (Minimum 512, larger values must be a multiple of 512). + * @param fnWriteBlocks Pointer to the Write Blocks to device function, as described by FF_WRITE_BLOCKS. + * @param fnReadBlocks Pointer to the Read Blocks from device function, as described by FF_READ_BLOCKS. + * @param pParam Pointer to a parameter for use in the functions. + * + * @return 0 on success, FF_ERR_IOMAN_DEV_ALREADY_REGD if a device was already hooked, FF_ERR_IOMAN_NULL_POINTER if a pIoman object wasn't provided. + **/ +FF_ERROR FF_RegisterBlkDevice(FF_IOMAN *pIoman, FF_T_UINT16 BlkSize, FF_WRITE_BLOCKS fnWriteBlocks, FF_READ_BLOCKS fnReadBlocks, void *pParam) { + if(!pIoman) { // We can't do anything without an IOMAN object. + return FF_ERR_NULL_POINTER; + } + + if((BlkSize % 512) != 0 || BlkSize == 0) { + return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 + } + + if((BlkSize % pIoman->BlkSize) != 0 || BlkSize == 0) { + return FF_ERR_IOMAN_DEV_INVALID_BLKSIZE; // BlkSize Size not a multiple of IOMAN's Expected BlockSize > 0 + } + + // Ensure that a device cannot be re-registered "mid-flight" + // Doing so would corrupt the context of FullFAT + if(pIoman->pBlkDevice->fnReadBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD; + } + if(pIoman->pBlkDevice->fnWriteBlocks) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD; + } + if(pIoman->pBlkDevice->pParam) { + return FF_ERR_IOMAN_DEV_ALREADY_REGD; + } + + // Here we shall just set the values. + // FullFAT checks before using any of these values. + pIoman->pBlkDevice->devBlkSize = BlkSize; + pIoman->pBlkDevice->fnReadBlocks = fnReadBlocks; + pIoman->pBlkDevice->fnWriteBlocks = fnWriteBlocks; + pIoman->pBlkDevice->pParam = pParam; + + return FF_ERR_NONE; // Success +} + +/** + * @private + **/ +static FF_ERROR FF_DetermineFatType(FF_IOMAN *pIoman) { + + FF_PARTITION *pPart; + FF_BUFFER *pBuffer; + FF_T_UINT32 testLong; + if(pIoman) { + pPart = pIoman->pPartition; + + if(pPart->NumClusters < 4085) { + // FAT12 + pPart->Type = FF_T_FAT12; +#ifdef FF_FAT_CHECK +#ifdef FF_FAT12_SUPPORT + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); + } + FF_ReleaseBuffer(pIoman, pBuffer); + if((testLong & 0x3FF) != 0x3F8) { + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + } +#else + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; +#endif +#endif +#ifdef FF_FAT12_SUPPORT + return FF_ERR_NONE; +#endif + + } else if(pPart->NumClusters < 65525) { + // FAT 16 + pPart->Type = FF_T_FAT16; +#ifdef FF_FAT_CHECK + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + testLong = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, 0x0000); + } + FF_ReleaseBuffer(pIoman, pBuffer); + if(testLong != 0xFFF8) { + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + } +#endif + return FF_ERR_NONE; + } + else { + // FAT 32! + pPart->Type = FF_T_FAT32; +#ifdef FF_FAT_CHECK + pBuffer = FF_GetBuffer(pIoman, pIoman->pPartition->FatBeginLBA, FF_MODE_READ); + { + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + testLong = FF_getLong(pBuffer->pBuffer, 0x0000); + } + FF_ReleaseBuffer(pIoman, pBuffer); + if((testLong & 0x0FFFFFF8) != 0x0FFFFFF8) { + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + } +#endif + return FF_ERR_NONE; + } + } + + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; +} +/** + * @public + * @brief Mounts the Specified partition, the volume specified by the FF_IOMAN object provided. + * + * The device drivers must adhere to the specification provided by + * FF_WRITE_BLOCKS and FF_READ_BLOCKS. + * + * @param pIoman FF_IOMAN object. + * @param PartitionNumber The primary partition number to be mounted. (0 - 3). + * + * @return 0 on success. + * @return FF_ERR_NULL_POINTER if a pIoman object wasn't provided. + * @return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range. + * @return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found. + * @return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data. + * @return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see ff_config.h) + * + **/ +FF_ERROR FF_MountPartition(FF_IOMAN *pIoman, FF_T_UINT8 PartitionNumber) { + FF_PARTITION *pPart; + FF_BUFFER *pBuffer = 0; + + if(!pIoman) { + return FF_ERR_NULL_POINTER; + } + + if(PartitionNumber > 3) { + return FF_ERR_IOMAN_INVALID_PARTITION_NUM; + } + + pPart = pIoman->pPartition; + + pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); + + if((pPart->BlkSize % 512) == 0 && pPart->BlkSize > 0) { + // Volume is not partitioned (MBR Found) + pPart->BeginLBA = 0; + } else { + // Primary Partitions to deal with! + pPart->BeginLBA = FF_getLong(pBuffer->pBuffer, (FF_T_UINT16)(FF_FAT_PTBL + FF_FAT_PTBL_LBA + (16 * PartitionNumber))); + FF_ReleaseBuffer(pIoman, pBuffer); + + if(!pPart->BeginLBA) { + return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION; + } + // Now we get the Partition sector. + pBuffer = FF_GetBuffer(pIoman, pPart->BeginLBA, FF_MODE_READ); + if(!pBuffer) { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + pPart->BlkSize = FF_getShort(pBuffer->pBuffer, FF_FAT_BYTES_PER_SECTOR); + if((pPart->BlkSize % 512) != 0 || pPart->BlkSize == 0) { + FF_ReleaseBuffer(pIoman, pBuffer); + return FF_ERR_IOMAN_INVALID_FORMAT; + } + } + // Assume FAT16, then we'll adjust if its FAT32 + pPart->ReservedSectors = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); + pPart->FatBeginLBA = pPart->BeginLBA + pPart->ReservedSectors; + + pPart->NumFATS = (FF_T_UINT8) FF_getShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS); + pPart->SectorsPerFAT = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT); + + pPart->SectorsPerCluster = FF_getChar(pBuffer->pBuffer, FF_FAT_SECTORS_PER_CLUS); + + pPart->BlkFactor = (FF_T_UINT8) (pPart->BlkSize / pIoman->BlkSize); // Set the BlockFactor (How many real-blocks in a fake block!). + + if(pPart->SectorsPerFAT == 0) { // FAT32 + pPart->SectorsPerFAT = FF_getLong(pBuffer->pBuffer, FF_FAT_32_SECTORS_PER_FAT); + pPart->RootDirCluster = FF_getLong(pBuffer->pBuffer, FF_FAT_ROOT_DIR_CLUSTER); + pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); + pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); + if(pPart->TotalSectors == 0) { + pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); + } + } else { // FAT16 + pPart->ClusterBeginLBA = pPart->BeginLBA + pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT); + pPart->TotalSectors = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); + pPart->RootDirCluster = 1; // 1st Cluster is RootDir! + if(pPart->TotalSectors == 0) { + pPart->TotalSectors = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); + } + } + + FF_ReleaseBuffer(pIoman, pBuffer); // Release the buffer finally! + pPart->RootDirSectors = ((FF_getShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT) * 32) + pPart->BlkSize - 1) / pPart->BlkSize; + pPart->FirstDataSector = pPart->ClusterBeginLBA + pPart->RootDirSectors; + pPart->DataSectors = pPart->TotalSectors - (pPart->ReservedSectors + (pPart->NumFATS * pPart->SectorsPerFAT) + pPart->RootDirSectors); + pPart->NumClusters = pPart->DataSectors / pPart->SectorsPerCluster; + + if(FF_DetermineFatType(pIoman)) { + return FF_ERR_IOMAN_NOT_FAT_FORMATTED; + } + +#ifdef FF_MOUNT_FIND_FREE + pPart->LastFreeCluster = FF_FindFreeCluster(pIoman); + pPart->FreeClusterCount = FF_CountFreeClusters(pIoman); +#else + pPart->LastFreeCluster = 0; + pPart->FreeClusterCount = 0; +#endif + + return FF_ERR_NONE; +} + +/** + * @public + * @brief Unregister a Blockdevice, so that the IOMAN can be re-used for another device. + * + * Any active partitions must be Unmounted first. + * + * @param pIoman FF_IOMAN object. + * + * @return FF_ERR_NONE on success. + **/ +FF_ERROR FF_UnregisterBlkDevice(FF_IOMAN *pIoman) { + + FF_T_SINT8 RetVal = FF_ERR_NONE; + + if(!pIoman) { + return FF_ERR_NULL_POINTER; + } + + FF_PendSemaphore(pIoman->pSemaphore); + { + if(pIoman->pPartition->PartitionMounted == FF_FALSE) { + pIoman->pBlkDevice->devBlkSize = 0; + pIoman->pBlkDevice->fnReadBlocks = NULL; + pIoman->pBlkDevice->fnWriteBlocks = NULL; + pIoman->pBlkDevice->pParam = NULL; + } else { + RetVal = FF_ERR_IOMAN_PARTITION_MOUNTED; + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + + return RetVal; +} + +/** + * @private + * @brief Checks the cache for Active Handles + * + * @param pIoman FF_IOMAN Object. + * + * @return FF_TRUE if an active handle is found, else FF_FALSE. + * + * @pre This function must be wrapped with the cache handling semaphore. + **/ +static FF_T_BOOL FF_ActiveHandles(FF_IOMAN *pIoman) { + FF_T_UINT32 i; + FF_BUFFER *pBuffer; + + for(i = 0; i < pIoman->CacheSize; i++) { + pBuffer = (pIoman->pBuffers + i); + if(pBuffer->NumHandles) { + return FF_TRUE; + } + } + + return FF_FALSE; +} + + +/** + * @public + * @brief Unmounts the active partition. + * + * @param pIoman FF_IOMAN Object. + * + * @return FF_ERR_NONE on success. + **/ +FF_ERROR FF_UnmountPartition(FF_IOMAN *pIoman) { + FF_T_SINT8 RetVal = FF_ERR_NONE; + + if(!pIoman) { + return FF_ERR_NULL_POINTER; + } + + FF_PendSemaphore(pIoman->pSemaphore); // Ensure that there are no File Handles + { + if(!FF_ActiveHandles(pIoman)) { + if(pIoman->FirstFile == NULL) { + FF_FlushCache(pIoman); // Flush any unwritten sectors to disk. + pIoman->pPartition->PartitionMounted = FF_FALSE; + } else { + RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; + } + } else { + RetVal = FF_ERR_IOMAN_ACTIVE_HANDLES; // Active handles found on the cache. + } + } + FF_ReleaseSemaphore(pIoman->pSemaphore); + + return RetVal; +} + + +FF_ERROR FF_IncreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { + + //FF_PendSemaphore(pIoman->pSemaphore); + //{ + if(!pIoman->pPartition->FreeClusterCount) { + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + } + pIoman->pPartition->FreeClusterCount += Count; + //} + //FF_ReleaseSemaphore(pIoman->pSemaphore); + + return FF_ERR_NONE; +} + +FF_ERROR FF_DecreaseFreeClusters(FF_IOMAN *pIoman, FF_T_UINT32 Count) { + + //FF_lockFAT(pIoman); + //{ + if(!pIoman->pPartition->FreeClusterCount) { + pIoman->pPartition->FreeClusterCount = FF_CountFreeClusters(pIoman); + } + pIoman->pPartition->FreeClusterCount -= Count; + //} + //FF_unlockFAT(pIoman); + + return FF_ERR_NONE; +} + + +/** + * @brief Returns the Block-size of a mounted Partition + * + * The purpose of this function is to provide API access to information + * that might be useful in special cases. Like USB sticks that require a sector + * knocking sequence for security. After the sector knock, some secure USB + * sticks then present a different BlockSize. + * + * @param pIoman FF_IOMAN Object returned from FF_CreateIOMAN() + * + * @return The blocksize of the partition. A value less than 0 when an error occurs. + * @return Any negative value can be cast to the FF_ERROR type. + **/ +FF_T_SINT32 FF_GetPartitionBlockSize(FF_IOMAN *pIoman) { + + if(pIoman) { + return (FF_T_SINT32) pIoman->pPartition->BlkSize; + } + + return FF_ERR_NULL_POINTER; +} + +#ifdef FF_64_NUM_SUPPORT +/** + * @brief Returns the number of bytes contained within the mounted partition or volume. + * + * @param pIoman FF_IOMAN Object returned from FF_CreateIOMAN() + * + * @return The total number of bytes that the mounted partition or volume contains. + * + **/ +FF_T_UINT64 FF_GetVolumeSize(FF_IOMAN *pIoman) { + if(pIoman) { + FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; + return (FF_T_UINT64) ((FF_T_UINT64)TotalClusters * (FF_T_UINT64)((FF_T_UINT64)pIoman->pPartition->SectorsPerCluster * (FF_T_UINT64)pIoman->pPartition->BlkSize)); + } + return 0; +} + +#else +FF_T_UINT32 FF_GetVolumeSize(FF_IOMAN *pIoman) { + FF_T_UINT32 TotalClusters = pIoman->pPartition->DataSectors / pIoman->pPartition->SectorsPerCluster; + return (FF_T_UINT32) (TotalClusters * (pIoman->pPartition->SectorsPerCluster * pIoman->pPartition->BlkSize)); +} +#endif + diff --git a/reactos/lib/3rdparty/fullfat/ff_memory.c b/reactos/lib/3rdparty/fullfat/ff_memory.c new file mode 100644 index 00000000000..cdbb2acf02d --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_memory.c @@ -0,0 +1,134 @@ +/***************************************************************************** + * 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 . * + * * + * 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.c + * @author James Walmsley + * @ingroup MEMORY + * + * @defgroup MEMORY FullFAT Memory Access Routines + * @brief Handles memory access in a portable way. + * + * Provides simple, fast, and portable access to memory routines. + * These are only used to read data from buffers. That are LITTLE ENDIAN + * due to the FAT specification. + * + * These routines may need to be modified to your platform. + * + **/ + +#include "ff_memory.h" +#include "ff_config.h" + +#ifdef FF_LITTLE_ENDIAN + +/** + * @public + * @brief 8 bit memory access routines. + **/ +/* + These functions swap the byte-orders of shorts and longs. A getChar function is provided + incase there is a system that doesn't have byte-wise access to all memory. + + These functions can be replaced with your own platform specific byte-order swapping routines + for more efficiency. + + The provided functions should work on almost all platforms. +*/ +FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT8) (pBuffer[offset]); +} + +FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT16) (pBuffer[offset] & 0x00FF) | ((FF_T_UINT16) (pBuffer[offset+1] << 8) & 0xFF00); +} + +FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT32) (pBuffer[offset] & 0x000000FF) | ((FF_T_UINT32) (pBuffer[offset+1] << 8) & 0x0000FF00) | ((FF_T_UINT32) (pBuffer[offset+2] << 16) & 0x00FF0000) | ((FF_T_UINT32) (pBuffer[offset+3] << 24) & 0xFF000000); +} + +void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value) { + pBuffer[offset] = Value; +} + +void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value) { + FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; + pBuffer[offset] = Val[0]; + pBuffer[offset + 1] = Val[1]; +} + +void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value) { + FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; + pBuffer[offset] = Val[0]; + pBuffer[offset + 1] = Val[1]; + pBuffer[offset + 2] = Val[2]; + pBuffer[offset + 3] = Val[3]; +} + +#endif + +#ifdef FF_BIG_ENDIAN +/* + These haven't been tested or checked. They should work in theory :) + Please contact james@worm.me.uk if they don't work, and also any fix. +*/ +FF_T_UINT8 FF_getChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT8) (pBuffer[offset]); +} + +FF_T_UINT16 FF_getShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT16) ((pBuffer[offset] & 0xFF00) << 8) | ((FF_T_UINT16) (pBuffer[offset+1]) & 0x00FF); +} + +FF_T_UINT32 FF_getLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset) { + return (FF_T_UINT32) ((pBuffer[offset] << 24) & 0xFF0000) | ((FF_T_UINT32) (pBuffer[offset+1] << 16) & 0x00FF0000) | ((FF_T_UINT32) (pBuffer[offset+2] << 8) & 0x0000FF00) | ((FF_T_UINT32) (pBuffer[offset+3]) & 0x000000FF); +} + +void FF_putChar(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT8 Value) { + pBuffer[offset] = Value; +} + +void FF_putShort(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT16 Value) { + FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; + pBuffer[offset] = Val[1]; + pBuffer[offset + 1] = Val[0]; +} + +void FF_putLong(FF_T_UINT8 *pBuffer, FF_T_UINT16 offset, FF_T_UINT32 Value) { + FF_T_UINT8 *Val = (FF_T_UINT8 *) &Value; + pBuffer[offset] = Val[3]; + pBuffer[offset + 1] = Val[2]; + pBuffer[offset + 2] = Val[1]; + pBuffer[offset + 3] = Val[0]; +} +#endif + + diff --git a/reactos/lib/3rdparty/fullfat/ff_safety.c b/reactos/lib/3rdparty/fullfat/ff_safety.c new file mode 100644 index 00000000000..9659f5a57eb --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_safety.c @@ -0,0 +1,112 @@ +/***************************************************************************** + * 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 . * + * * + * 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.c + * @author James Walmsley + * @ingroup SAFETY + * + * @defgroup SAFETY Process Safety for FullFAT + * @brief Provides semaphores, and thread-safety for FullFAT. + * + * This module aims to be as portable as possible. It is necessary to modify + * the functions FF_CreateSemaphore, FF_PendSemaphore, FF_ReleaseSemaphore, + * and FF_DestroySemaphore, as appropriate for your platform. + * + * If your application has no OS and is therefore single threaded, simply + * have: + * + * FF_CreateSemaphore() return NULL. + * + * FF_PendSemaphore() should do nothing. + * + * FF_ReleaseSemaphore() should do nothing. + * + * FF_DestroySemaphore() should do nothing. + * + **/ + +#include "ff_safety.h" // Íncludes ff_types.h + +void *FF_CreateSemaphore(void) { + // Call your OS's CreateSemaphore function + // + + // return pointer to semaphore + return NULL; // Comment this out for your implementation. +} + +void FF_PendSemaphore(void *pSemaphore) { + // Call your OS's PendSemaphore with the provided pSemaphore pointer. + // + // This should block indefinitely until the Semaphore + // becomes available. (No timeout!) + // If your OS doesn't do it for you, you should sleep + // this thread until the Semaphore is available. + pSemaphore = 0; +} + +void FF_ReleaseSemaphore(void *pSemaphore) { + // Call your OS's ReleaseSemaphore with the provided pSemaphore pointer. + // + + // + pSemaphore = 0; +} + +void FF_DestroySemaphore(void *pSemaphore) { + // Call your OS's DestroySemaphore with the provided pSemaphore pointer. + // + + // + pSemaphore = 0; +} + +void FF_Yield(void) { + // Call your OS's thread Yield function. + // If this doesn't work, then a deadlock will occur +} + +void FF_Sleep(FF_T_UINT32 TimeMs) { + // Call your OS's thread sleep function, + // Sleep for TimeMs milliseconds + TimeMs = 0; +} + + +/** + * Notes on implementation. + * + * + * + **/ + + diff --git a/reactos/lib/3rdparty/fullfat/ff_string.c b/reactos/lib/3rdparty/fullfat/ff_string.c new file mode 100644 index 00000000000..6913ee7082f --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_string.c @@ -0,0 +1,234 @@ +/***************************************************************************** + * 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 . * + * * + * 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 + * + * + **/ + +#include +#include +#include "ff_string.h" + +/* + * These will eventually be moved into a platform independent string + * library. Which will be optional. (To allow the use of system specific versions). + */ + +/** + * @private + * @brief Converts an ASCII string to lowercase. + **/ +void FF_tolower(FF_T_INT8 *string, FF_T_UINT32 strLen) { + FF_T_UINT32 i; + for(i = 0; i < strLen; i++) { + if(string[i] >= 'A' && string[i] <= 'Z') + string[i] += 32; + if(string[i] == '\0') + break; + } +} + +/** + * @private + * @brief Converts an ASCII string to uppercase. + **/ +void FF_toupper(FF_T_INT8 *string, FF_T_UINT32 strLen) { + FF_T_UINT32 i; + for(i = 0; i < strLen; i++) { + if(string[i] >= 'a' && string[i] <= 'z') + string[i] -= 32; + if(string[i] == '\0') + break; + } +} + + +/** + * @private + * @brief Compares 2 strings for the specified length, and returns FF_TRUE is they are identical + * otherwise FF_FALSE is returned. + * + **/ +FF_T_BOOL FF_strmatch(const FF_T_INT8 *str1, const FF_T_INT8 *str2, FF_T_UINT16 len) { + register FF_T_UINT16 i; + register FF_T_INT8 char1, char2; + + if(!len) { + if(strlen(str1) != strlen(str2)) { + return FF_FALSE; + } + len = (FF_T_UINT16) strlen(str1); + } + + for(i = 0; i < len; i++) { + char1 = str1[i]; + char2 = str2[i]; + if(char1 >= 'A' && char1 <= 'Z') { + char1 += 32; + } + if(char2 >= 'A' && char2 <= 'Z') { + char2 += 32; + } + + if(char1 != char2) { + return FF_FALSE; + } + } + + return FF_TRUE; +} + +/** + * @private + * @brief A re-entrant Strtok function. No documentation is provided :P + * Use at your own risk. (This is for FullFAT's use only). + **/ +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_UINT16 strLen = Length; + FF_T_UINT16 i,y, tokenStart, tokenEnd = 0; + + i = 0; + y = 0; + + if(string[i] == '\\' || string[i] == '/') { + i++; + } + + tokenStart = i; + + while(i < strLen) { + if(string[i] == '\\' || string[i] == '/') { + y++; + if(y == *tokenNumber) { + tokenStart = (FF_T_UINT16)(i + 1); + } + if(y == (*tokenNumber + 1)) { + tokenEnd = i; + break; + } + } + i++; + } + + if(!tokenEnd) { + if(*last == FF_TRUE) { + return NULL; + } else { + *last = FF_TRUE; + } + tokenEnd = i; + } + + memcpy(token, (string + tokenStart), (FF_T_UINT32)(tokenEnd - tokenStart)); + token[tokenEnd - tokenStart] = '\0'; + *tokenNumber += 1; + + return token; +} + + +FF_T_BOOL FF_wildcompare(const FF_T_INT8 *pszWildCard, const FF_T_INT8 *pszString) { + /* Check to see if the string contains the wild card */ + if (!memchr(pszWildCard, '*', strlen(pszWildCard))) + { + /* if it does not then do a straight string compare */ + if (strcmp(pszWildCard, pszString)) + { + return FF_FALSE; + } + } + else + { + while ((*pszWildCard) + && (*pszString)) + { + /* Test for the wild card */ + if (*pszWildCard == '*') + { + /* Eat more than one */ + while (*pszWildCard == '*') + { + pszWildCard++; + } + /* If there are more chars in the string */ + if (*pszWildCard) + { + /* Search for the next char */ + pszString = memchr(pszString, (int)*pszWildCard, strlen(pszString)); + /* if it does not exist then the strings don't match */ + if (!pszString) + { + return FF_FALSE; + } + + } + else + { + if (*pszWildCard) + { + /* continue */ + break; + } + else + { + return FF_TRUE; + } + } + } + else + { + /* Fail if they don't match */ + if (*pszWildCard != *pszString) + { + return FF_FALSE; + } + } + /* Bump both pointers */ + pszWildCard++; + pszString++; + } + /* fail if different lengths */ + if (*pszWildCard != *pszString) + { + return FF_FALSE; + } + } + + return FF_TRUE; +} + diff --git a/reactos/lib/3rdparty/fullfat/ff_time.c b/reactos/lib/3rdparty/fullfat/ff_time.c new file mode 100644 index 00000000000..b3749354e77 --- /dev/null +++ b/reactos/lib/3rdparty/fullfat/ff_time.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * 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 . * + * * + * 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. * + *****************************************************************************/ + + +#include "ff_time.h" + + +/** + * @file ff_time.c + * @author James Walmsley + * @ingroup TIME + * + * @defgroup TIME Real-Time Clock Interface + * @brief Allows FullFAT to time-stamp files. + * + * Provides a means for receiving the time on any platform. + **/ + +#ifdef FF_TIME_SUPPORT +/** + * @public + * @brief Populates an FF_SYSTEMTIME object with the current time from the system. + * + * The developer must modify this function so that it is suitable for their platform. + * The function must return with 0, and if the time is not available all elements of the + * FF_SYSTEMTIME object must be zero'd, as in the examples provided. + * + * @param pTime Pointer to an FF_TIME object. + * + * @return Always returns 0. + **/ +FF_T_SINT32 FF_GetSystemTime(FF_SYSTEMTIME *pTime) { + + pTime->Hour = 0; + pTime->Minute = 0; + pTime->Second = 0; + pTime->Day = 0; + pTime->Month = 0; + pTime->Year = 0; + + return 0; +} + +#endif -- 2.17.1