Files
mop3/kernel/fs/fat1.c
kamkow1 baa13fb695
All checks were successful
Build documentation / build-and-deploy (push) Successful in 3m12s
fat_io_lib port WIP
2026-02-26 23:33:03 +01:00

2900 lines
105 KiB
C

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <fs/fat1.h>
#include <fs/fatfs_ctx.h>
#define _KERNEL_LIBK_STRING_H
#define _KERNEL_LIBK_STD_H
#define __FREESTND_C_HDRS_LIMITS_H 1
#undef CHAR_BIT
#define CHAR_BIT __CHAR_BIT__
#define MB_LEN_MAX 1
#undef SCHAR_MAX
#define SCHAR_MAX __SCHAR_MAX__
#undef SCHAR_MIN
#define SCHAR_MIN (-SCHAR_MAX - 1)
#undef UCHAR_MAX
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
#undef CHAR_MAX
#define CHAR_MAX SCHAR_MAX
#undef CHAR_MIN
#define CHAR_MIN SCHAR_MIN
#undef SHRT_MAX
#define SHRT_MAX __SHRT_MAX__
#undef SHRT_MIN
#define SHRT_MIN (-SHRT_MAX - 1)
#undef USHRT_MAX
#define USHRT_MAX (SHRT_MAX * 2 + 1)
#undef INT_MAX
#define INT_MAX __INT_MAX__
#undef INT_MIN
#define INT_MIN (-INT_MAX - 1)
#undef UINT_MAX
#define UINT_MAX (INT_MAX * 2U + 1U)
#undef LONG_MAX
#define LONG_MAX __LONG_MAX__
#undef LONG_MIN
#define LONG_MIN (-LONG_MAX - 1L)
#undef ULONG_MAX
#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
#undef LLONG_MAX
#define LLONG_MAX __LONG_LONG_MAX__
#undef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#undef ULLONG_MAX
#define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
#define __FREESTND_C_HDRS_STDALIGN_H 1
#undef alignas
#define alignas _Alignas
#undef alignof
#define alignof _Alignof
#undef __alignof_is_defined
#define __alignof_is_defined 1
#undef __alignas_is_defined
#define __alignas_is_defined 1
#define __FREESTND_C_HDRS_STDARG_H 1
typedef __builtin_va_list va_list;
#undef va_start
#define va_start(v, l) __builtin_va_start (v, l)
#undef va_end
#define va_end(v) __builtin_va_end (v)
#undef va_arg
#define va_arg(v, l) __builtin_va_arg (v, l)
#undef va_copy
#define va_copy(d, s) __builtin_va_copy (d, s)
#define _STD_ATOMIC_H
#define __FREESTND_C_HDRS_STDINT_H 1
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINTPTR_TYPE__ uintptr_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTMAX_TYPE__ uintmax_t;
typedef __INTMAX_TYPE__ intmax_t;
#define __FREESTND_C_HDRS_C_EXPAND_JOIN(x, suffix) x##suffix
#define __FREESTND_C_HDRS_C_JOIN(x, suffix) __FREESTND_C_HDRS_C_EXPAND_JOIN (x, suffix)
#undef INT8_C
#define INT8_C(x) __FREESTND_C_HDRS_C_JOIN (x, __INT8_C_SUFFIX__)
#undef INT16_C
#define INT16_C(x) __FREESTND_C_HDRS_C_JOIN (x, __INT16_C_SUFFIX__)
#undef INT32_C
#define INT32_C(x) __FREESTND_C_HDRS_C_JOIN (x, __INT32_C_SUFFIX__)
#undef INT64_C
#define INT64_C(x) __FREESTND_C_HDRS_C_JOIN (x, __INT64_C_SUFFIX__)
#undef UINT8_C
#define UINT8_C(x) __FREESTND_C_HDRS_C_JOIN (x, __UINT8_C_SUFFIX__)
#undef UINT16_C
#define UINT16_C(x) __FREESTND_C_HDRS_C_JOIN (x, __UINT16_C_SUFFIX__)
#undef UINT32_C
#define UINT32_C(x) __FREESTND_C_HDRS_C_JOIN (x, __UINT32_C_SUFFIX__)
#undef UINT64_C
#define UINT64_C(x) __FREESTND_C_HDRS_C_JOIN (x, __UINT64_C_SUFFIX__)
#undef INTMAX_C
#define INTMAX_C(x) __FREESTND_C_HDRS_C_JOIN (x, __INTMAX_C_SUFFIX__)
#undef UINTMAX_C
#define UINTMAX_C(x) __FREESTND_C_HDRS_C_JOIN (x, __UINTMAX_C_SUFFIX__)
#undef UINT8_MAX
#define UINT8_MAX __UINT8_MAX__
#undef UINT16_MAX
#define UINT16_MAX __UINT16_MAX__
#undef UINT32_MAX
#define UINT32_MAX __UINT32_MAX__
#undef UINT64_MAX
#define UINT64_MAX __UINT64_MAX__
#undef INT8_MAX
#define INT8_MAX __INT8_MAX__
#undef INT16_MAX
#define INT16_MAX __INT16_MAX__
#undef INT32_MAX
#define INT32_MAX __INT32_MAX__
#undef INT64_MAX
#define INT64_MAX __INT64_MAX__
#undef INT8_MIN
#define INT8_MIN (-INT8_MAX - 1)
#undef INT16_MIN
#define INT16_MIN (-INT16_MAX - 1)
#undef INT32_MIN
#define INT32_MIN (-INT32_MAX - 1)
#undef INT64_MIN
#define INT64_MIN (-INT64_MAX - 1)
#undef UINT_LEAST8_MAX
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
#undef UINT_LEAST16_MAX
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
#undef UINT_LEAST32_MAX
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
#undef UINT_LEAST64_MAX
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
#undef INT_LEAST8_MAX
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
#undef INT_LEAST16_MAX
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
#undef INT_LEAST32_MAX
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
#undef INT_LEAST64_MAX
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
#undef INT_LEAST8_MIN
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
#undef INT_LEAST16_MIN
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
#undef INT_LEAST32_MIN
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
#undef INT_LEAST64_MIN
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
#undef UINT_FAST8_MAX
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
#undef UINT_FAST16_MAX
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
#undef UINT_FAST32_MAX
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#undef UINT_FAST64_MAX
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
#undef INT_FAST8_MAX
#define INT_FAST8_MAX __INT_FAST8_MAX__
#undef INT_FAST16_MAX
#define INT_FAST16_MAX __INT_FAST16_MAX__
#undef INT_FAST32_MAX
#define INT_FAST32_MAX __INT_FAST32_MAX__
#undef INT_FAST64_MAX
#define INT_FAST64_MAX __INT_FAST64_MAX__
#undef INT_FAST8_MIN
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
#undef INT_FAST16_MIN
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
#undef INT_FAST32_MIN
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
#undef INT_FAST64_MIN
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
#undef UINTPTR_MAX
#define UINTPTR_MAX __UINTPTR_MAX__
#undef INTPTR_MAX
#define INTPTR_MAX __INTPTR_MAX__
#undef INTPTR_MIN
#define INTPTR_MIN (-INTPTR_MAX - 1)
#undef UINTMAX_MAX
#define UINTMAX_MAX __UINTMAX_MAX__
#undef INTMAX_MAX
#define INTMAX_MAX __INTMAX_MAX__
#undef INTMAX_MIN
#define INTMAX_MIN (-INTMAX_MAX - 1)
#undef PTRDIFF_MAX
#define PTRDIFF_MAX __PTRDIFF_MAX__
#undef PTRDIFF_MIN
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#undef SIG_ATOMIC_MAX
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
#undef SIG_ATOMIC_MIN
#define SIG_ATOMIC_MIN (-SIG_ATOMIC_MAX - 1)
#undef SIZE_MAX
#define SIZE_MAX __SIZE_MAX__
#undef WCHAR_MAX
#define WCHAR_MAX __WCHAR_MAX__
#undef WCHAR_MIN
#define WCHAR_MIN (-WCHAR_MAX - 1)
#undef WINT_MAX
#define WINT_MAX __WINT_MAX__
#undef WINT_MIN
#define WINT_MIN (-WINT_MAX - 1)
#define __FREESTND_C_HDRS_STDDEF_H 1
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __WCHAR_TYPE__ wchar_t;
#undef NULL
#define NULL ((void*)0)
#undef offsetof
#define offsetof(s, m) __builtin_offsetof (s, m)
typedef enum memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
typedef _Atomic (_Bool) atomic_bool;
typedef _Atomic (char) atomic_char;
typedef _Atomic (signed char) atomic_schar;
typedef _Atomic (unsigned char) atomic_uchar;
typedef _Atomic (short) atomic_short;
typedef _Atomic (unsigned short) atomic_ushort;
typedef _Atomic (int) atomic_int;
typedef _Atomic (unsigned int) atomic_uint;
typedef _Atomic (long) atomic_long;
typedef _Atomic (unsigned long) atomic_ulong;
typedef _Atomic (long long) atomic_llong;
typedef _Atomic (unsigned long long) atomic_ullong;
typedef _Atomic (uint_least16_t) atomic_char16_t;
typedef _Atomic (uint_least32_t) atomic_char32_t;
typedef _Atomic (wchar_t) atomic_wchar_t;
typedef _Atomic (int_least8_t) atomic_int_least8_t;
typedef _Atomic (uint_least8_t) atomic_uint_least8_t;
typedef _Atomic (int_least16_t) atomic_int_least16_t;
typedef _Atomic (uint_least16_t) atomic_uint_least16_t;
typedef _Atomic (int_least32_t) atomic_int_least32_t;
typedef _Atomic (uint_least32_t) atomic_uint_least32_t;
typedef _Atomic (int_least64_t) atomic_int_least64_t;
typedef _Atomic (uint_least64_t) atomic_uint_least64_t;
typedef _Atomic (int_fast8_t) atomic_int_fast8_t;
typedef _Atomic (uint_fast8_t) atomic_uint_fast8_t;
typedef _Atomic (int_fast16_t) atomic_int_fast16_t;
typedef _Atomic (uint_fast16_t) atomic_uint_fast16_t;
typedef _Atomic (int_fast32_t) atomic_int_fast32_t;
typedef _Atomic (uint_fast32_t) atomic_uint_fast32_t;
typedef _Atomic (int_fast64_t) atomic_int_fast64_t;
typedef _Atomic (uint_fast64_t) atomic_uint_fast64_t;
typedef _Atomic (intptr_t) atomic_intptr_t;
typedef _Atomic (uintptr_t) atomic_uintptr_t;
typedef _Atomic (size_t) atomic_size_t;
typedef _Atomic (ptrdiff_t) atomic_ptrdiff_t;
typedef _Atomic (intmax_t) atomic_intmax_t;
typedef _Atomic (uintmax_t) atomic_uintmax_t;
typedef struct atomic_flag {
atomic_bool _Value;
} atomic_flag;
#define ATOMIC_FLAG_INIT ((atomic_flag){0})
#define atomic_store(object, desired) __c11_atomic_store (object, desired, __ATOMIC_SEQ_CST)
#define atomic_store_explicit __c11_atomic_store
#define atomic_load(object) __c11_atomic_load (object, __ATOMIC_SEQ_CST)
#define atomic_load_explicit __c11_atomic_load
#define atomic_exchange(object, desired) __c11_atomic_exchange (object, desired, __ATOMIC_SEQ_CST)
#define atomic_exchange_explicit __c11_atomic_exchange
#define atomic_compare_exchange_strong(object, expected, desired) \
__c11_atomic_compare_exchange_strong (object, expected, desired, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong
#define atomic_compare_exchange_weak(object, expected, desired) \
__c11_atomic_compare_exchange_weak (object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add (object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit __c11_atomic_fetch_add
#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub (object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub
#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or (object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_or_explicit __c11_atomic_fetch_or
#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor (object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor
#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and (object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_and_explicit __c11_atomic_fetch_and
#define atomic_flag_test_and_set(object) \
__c11_atomic_exchange (&(object)->_Value, 1, __ATOMIC_SEQ_CST)
#define atomic_flag_test_and_set_explicit(object, order) \
__c11_atomic_exchange (&(object)->_Value, 1, order)
#define atomic_flag_clear(object) __c11_atomic_store (&(object)->_Value, 0, __ATOMIC_SEQ_CST)
#define atomic_flag_clear_explicit(object, order) __c11_atomic_store (&(object)->_Value, 0, order)
#define __FREESTND_C_HDRS_STDBOOL_H 1
#undef bool
#define bool _Bool
#undef true
#define true 1
#undef false
#define false 0
#undef __bool_true_false_are_defined
#define __bool_true_false_are_defined 1
#define __FREESTND_C_HDRS_STDNORETURN_H 1
#define noreturn _Noreturn
size_t memset (void* dst, uint8_t b, size_t n);
size_t memcpy (void* dst, const void* src, size_t n);
void strncpy (char* dst, const char* src, size_t n);
size_t strlen (const char* str);
int memcmp (const void* s1, const void* s2, size_t n);
int strncmp (const char* s1, const char* s2, size_t n);
int strcmp (const char* s1, const char* s2);
#define strlen_null(x) (strlen ((x)) + 1)
#define __FAT_MISC_H__
#define __FAT_DEFS_H__
#define __FAT_OPTS_H__
#define FATFS_IS_LITTLE_ENDIAN 1
#define FATFS_MAX_LONG_FILENAME 260
#define FATFS_MAX_OPEN_FILES 2
#define FAT_BUFFER_SECTORS 1
#define FAT_BUFFERS 1
#define FATFS_INC_WRITE_SUPPORT 1
#define FATFS_INC_LFN_SUPPORT 1
#define FATFS_DIR_LIST_SUPPORT 1
#define FATFS_INC_TIME_DATE_SUPPORT 0
#define FATFS_INC_FORMAT_SUPPORT 1
#define FAT_SECTOR_SIZE 512
#define __FAT_TYPES_H__
#define FATFS_DEF_UINT32_AS_INT
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
#define FAT_HTONS(n) (n)
#define FAT_HTONL(n) (n)
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED __attribute__ ((packed))
#define BS_JMPBOOT 0
#define BS_OEMNAME 3
#define BPB_BYTSPERSEC 11
#define BPB_SECPERCLUS 13
#define BPB_RSVDSECCNT 14
#define BPB_NUMFATS 16
#define BPB_ROOTENTCNT 17
#define BPB_TOTSEC16 19
#define BPB_MEDIA 21
#define BPB_FATSZ16 22
#define BPB_SECPERTRK 24
#define BPB_NUMHEADS 26
#define BPB_HIDDSEC 28
#define BPB_TOTSEC32 32
#define BS_FAT_DRVNUM 36
#define BS_FAT_BOOTSIG 38
#define BS_FAT_VOLID 39
#define BS_FAT_VOLLAB 43
#define BS_FAT_FILSYSTYPE 54
#define BPB_FAT32_FATSZ32 36
#define BPB_FAT32_EXTFLAGS 40
#define BPB_FAT32_FSVER 42
#define BPB_FAT32_ROOTCLUS 44
#define BPB_FAT32_FSINFO 48
#define BPB_FAT32_BKBOOTSEC 50
#define BS_FAT32_DRVNUM 64
#define BS_FAT32_BOOTSIG 66
#define BS_FAT32_VOLID 67
#define BS_FAT32_VOLLAB 71
#define BS_FAT32_FILSYSTYPE 82
#define FAT_TYPE_FAT12 1
#define FAT_TYPE_FAT16 2
#define FAT_TYPE_FAT32 3
#define SIGNATURE_POSITION 510
#define SIGNATURE_VALUE 0xAA55
#define PARTITION1_TYPECODE_LOCATION 450
#define FAT32_TYPECODE1 0x0B
#define FAT32_TYPECODE2 0x0C
#define PARTITION1_LBA_BEGIN_LOCATION 454
#define PARTITION1_SIZE_LOCATION 458
#define FAT_DIR_ENTRY_SIZE 32
#define FAT_SFN_SIZE_FULL 11
#define FAT_SFN_SIZE_PARTIAL 8
#define FILE_ATTR_READ_ONLY 0x01
#define FILE_ATTR_HIDDEN 0x02
#define FILE_ATTR_SYSTEM 0x04
#define FILE_ATTR_SYSHID 0x06
#define FILE_ATTR_VOLUME_ID 0x08
#define FILE_ATTR_DIRECTORY 0x10
#define FILE_ATTR_ARCHIVE 0x20
#define FILE_ATTR_LFN_TEXT 0x0F
#define FILE_HEADER_BLANK 0x00
#define FILE_HEADER_DELETED 0xE5
#define FILE_TYPE_DIR 0x10
#define FILE_TYPE_FILE 0x20
#define FAT_TIME_HOURS_SHIFT 11
#define FAT_TIME_HOURS_MASK 0x1F
#define FAT_TIME_MINUTES_SHIFT 5
#define FAT_TIME_MINUTES_MASK 0x3F
#define FAT_TIME_SECONDS_SHIFT 0
#define FAT_TIME_SECONDS_MASK 0x1F
#define FAT_TIME_SECONDS_SCALE 2
#define FAT_DATE_YEAR_SHIFT 9
#define FAT_DATE_YEAR_MASK 0x7F
#define FAT_DATE_MONTH_SHIFT 5
#define FAT_DATE_MONTH_MASK 0xF
#define FAT_DATE_DAY_SHIFT 0
#define FAT_DATE_DAY_MASK 0x1F
#define FAT_DATE_YEAR_OFFSET 1980
#define FAT32_LAST_CLUSTER 0xFFFFFFFF
#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
#define MAX_LONGFILENAME_ENTRIES 20
#define MAX_LFN_ENTRY_LENGTH 13
#define GET_32BIT_WORD(buffer, location) \
(((uint32)buffer[location + 3] << 24) + ((uint32)buffer[location + 2] << 16) + \
((uint32)buffer[location + 1] << 8) + (uint32)buffer[location + 0])
#define GET_16BIT_WORD(buffer, location) \
(((uint16)buffer[location + 1] << 8) + (uint16)buffer[location + 0])
#define SET_32BIT_WORD(buffer, location, value) \
{ \
buffer[location + 0] = (uint8)((value) & 0xFF); \
buffer[location + 1] = (uint8)((value >> 8) & 0xFF); \
buffer[location + 2] = (uint8)((value >> 16) & 0xFF); \
buffer[location + 3] = (uint8)((value >> 24) & 0xFF); \
}
#define SET_16BIT_WORD(buffer, location, value) \
{ \
buffer[location + 0] = (uint8)((value) & 0xFF); \
buffer[location + 1] = (uint8)((value >> 8) & 0xFF); \
}
void fatfs_lfn_cache_init (struct lfn_cache* lfn, int wipeTable);
void fatfs_lfn_cache_entry (struct lfn_cache* lfn, uint8* entryBuffer);
char* fatfs_lfn_cache_get (struct lfn_cache* lfn);
int fatfs_entry_lfn_text (struct fat_dir_entry* entry);
int fatfs_entry_lfn_invalid (struct fat_dir_entry* entry);
int fatfs_entry_lfn_exists (struct lfn_cache* lfn, struct fat_dir_entry* entry);
int fatfs_entry_sfn_only (struct fat_dir_entry* entry);
int fatfs_entry_is_dir (struct fat_dir_entry* entry);
int fatfs_entry_is_file (struct fat_dir_entry* entry);
int fatfs_lfn_entries_required (char* filename);
void fatfs_filename_to_lfn (char* filename, uint8* buffer, int entry, uint8 sfnChk);
void fatfs_sfn_create_entry (char* shortfilename, uint32 size, uint32 startCluster,
struct fat_dir_entry* entry, int dir);
int fatfs_lfn_create_sfn (char* sfn_output, char* filename);
int fatfs_lfn_generate_tail (char* sfn_output, char* sfn_input, uint32 tailNum);
void fatfs_convert_from_fat_time (uint16 fat_time, int* hours, int* minutes, int* seconds);
void fatfs_convert_from_fat_date (uint16 fat_date, int* day, int* month, int* year);
uint16 fatfs_convert_to_fat_time (int hours, int minutes, int seconds);
uint16 fatfs_convert_to_fat_date (int day, int month, int year);
void fatfs_print_sector (uint32 sector, uint8* data);
void fatfs_lfn_cache_init (struct lfn_cache* lfn, int wipeTable) {
int i = 0;
lfn->no_of_strings = 0;
if (wipeTable)
for (i = 0; i < MAX_LONGFILENAME_ENTRIES; i++)
memset (lfn->String[i], 0x00, MAX_LFN_ENTRY_LENGTH);
}
void fatfs_lfn_cache_entry (struct lfn_cache* lfn, uint8* entryBuffer) {
uint8 LFNIndex, i;
LFNIndex = entryBuffer[0] & 0x1F;
if (LFNIndex > MAX_LONGFILENAME_ENTRIES)
return;
if (LFNIndex == 0)
return;
if (lfn->no_of_strings == 0)
lfn->no_of_strings = LFNIndex;
lfn->String[LFNIndex - 1][0] = entryBuffer[1];
lfn->String[LFNIndex - 1][1] = entryBuffer[3];
lfn->String[LFNIndex - 1][2] = entryBuffer[5];
lfn->String[LFNIndex - 1][3] = entryBuffer[7];
lfn->String[LFNIndex - 1][4] = entryBuffer[9];
lfn->String[LFNIndex - 1][5] = entryBuffer[0x0E];
lfn->String[LFNIndex - 1][6] = entryBuffer[0x10];
lfn->String[LFNIndex - 1][7] = entryBuffer[0x12];
lfn->String[LFNIndex - 1][8] = entryBuffer[0x14];
lfn->String[LFNIndex - 1][9] = entryBuffer[0x16];
lfn->String[LFNIndex - 1][10] = entryBuffer[0x18];
lfn->String[LFNIndex - 1][11] = entryBuffer[0x1C];
lfn->String[LFNIndex - 1][12] = entryBuffer[0x1E];
for (i = 0; i < MAX_LFN_ENTRY_LENGTH; i++)
if (lfn->String[LFNIndex - 1][i] == 0xFF)
lfn->String[LFNIndex - 1][i] = 0x20;
}
char* fatfs_lfn_cache_get (struct lfn_cache* lfn) {
if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES)
lfn->Null = '\0';
else if (lfn->no_of_strings)
lfn->String[lfn->no_of_strings][0] = '\0';
else
lfn->String[0][0] = '\0';
return (char*)&lfn->String[0][0];
}
int fatfs_entry_lfn_text (struct fat_dir_entry* entry) {
if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT)
return 1;
else
return 0;
}
int fatfs_entry_lfn_invalid (struct fat_dir_entry* entry) {
if ((entry->Name[0] == FILE_HEADER_BLANK) || (entry->Name[0] == FILE_HEADER_DELETED) ||
(entry->Attr == FILE_ATTR_VOLUME_ID) || (entry->Attr & FILE_ATTR_SYSHID))
return 1;
else
return 0;
}
int fatfs_entry_lfn_exists (struct lfn_cache* lfn, struct fat_dir_entry* entry) {
if ((entry->Attr != FILE_ATTR_LFN_TEXT) && (entry->Name[0] != FILE_HEADER_BLANK) &&
(entry->Name[0] != FILE_HEADER_DELETED) && (entry->Attr != FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr & FILE_ATTR_SYSHID)) && (lfn->no_of_strings))
return 1;
else
return 0;
}
int fatfs_entry_sfn_only (struct fat_dir_entry* entry) {
if ((entry->Attr != FILE_ATTR_LFN_TEXT) && (entry->Name[0] != FILE_HEADER_BLANK) &&
(entry->Name[0] != FILE_HEADER_DELETED) && (entry->Attr != FILE_ATTR_VOLUME_ID) &&
(!(entry->Attr & FILE_ATTR_SYSHID)))
return 1;
else
return 0;
}
int fatfs_entry_is_dir (struct fat_dir_entry* entry) {
if (entry->Attr & FILE_TYPE_DIR)
return 1;
else
return 0;
}
int fatfs_entry_is_file (struct fat_dir_entry* entry) {
if (entry->Attr & FILE_TYPE_FILE)
return 1;
else
return 0;
}
int fatfs_lfn_entries_required (char* filename) {
int length = (int)strlen (filename);
if (length)
return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH;
else
return 0;
}
void fatfs_filename_to_lfn (char* filename, uint8* buffer, int entry, uint8 sfnChk) {
int i;
int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1, 3, 5, 7, 9, 0x0E, 0x10,
0x12, 0x14, 0x16, 0x18, 0x1C, 0x1E};
int length = (int)strlen (filename);
int entriesRequired = fatfs_lfn_entries_required (filename);
int start = entry * MAX_LFN_ENTRY_LENGTH;
memset (buffer, 0x00, FAT_DIR_ENTRY_SIZE);
buffer[0] = (uint8)(((entriesRequired - 1) == entry) ? (0x40 | (entry + 1)) : (entry + 1));
buffer[11] = 0x0F;
buffer[13] = sfnChk;
for (i = 0; i < MAX_LFN_ENTRY_LENGTH; i++) {
if ((start + i) < length)
buffer[nameIndexes[i]] = filename[start + i];
else if ((start + i) == length)
buffer[nameIndexes[i]] = 0x00;
else {
buffer[nameIndexes[i]] = 0xFF;
buffer[nameIndexes[i] + 1] = 0xFF;
}
}
}
void fatfs_sfn_create_entry (char* shortfilename, uint32 size, uint32 startCluster,
struct fat_dir_entry* entry, int dir) {
int i;
for (i = 0; i < FAT_SFN_SIZE_FULL; i++)
entry->Name[i] = shortfilename[i];
entry->CrtTimeTenth = 0x00;
entry->CrtTime[1] = entry->CrtTime[0] = 0x00;
entry->CrtDate[1] = 0x00;
entry->CrtDate[0] = 0x20;
entry->LstAccDate[1] = 0x00;
entry->LstAccDate[0] = 0x20;
entry->WrtTime[1] = entry->WrtTime[0] = 0x00;
entry->WrtDate[1] = 0x00;
entry->WrtDate[0] = 0x20;
if (!dir)
entry->Attr = FILE_TYPE_FILE;
else
entry->Attr = FILE_TYPE_DIR;
entry->NTRes = 0x00;
entry->FstClusHI = FAT_HTONS ((uint16)((startCluster >> 16) & 0xFFFF));
entry->FstClusLO = FAT_HTONS ((uint16)((startCluster >> 0) & 0xFFFF));
entry->FileSize = FAT_HTONL (size);
}
int fatfs_lfn_create_sfn (char* sfn_output, char* filename) {
int i;
int dotPos = -1;
char ext[3];
int pos;
int len = (int)strlen (filename);
if (filename[0] == '.')
return 0;
memset (sfn_output, ' ', FAT_SFN_SIZE_FULL);
memset (ext, ' ', 3);
for (i = 0; i < len; i++) {
if (filename[i] == '.')
dotPos = i;
}
if (dotPos != -1) {
for (i = (dotPos + 1); i < (dotPos + 1 + 3); i++)
if (i < len)
ext[i - (dotPos + 1)] = filename[i];
len = dotPos;
}
pos = 0;
for (i = 0; i < len; i++) {
if ((filename[i] != ' ') && (filename[i] != '.')) {
if (filename[i] >= 'a' && filename[i] <= 'z')
sfn_output[pos++] = filename[i] - 'a' + 'A';
else
sfn_output[pos++] = filename[i];
}
if (pos == FAT_SFN_SIZE_PARTIAL)
break;
}
for (i = FAT_SFN_SIZE_PARTIAL; i < FAT_SFN_SIZE_FULL; i++) {
if (ext[i - FAT_SFN_SIZE_PARTIAL] >= 'a' && ext[i - FAT_SFN_SIZE_PARTIAL] <= 'z')
sfn_output[i] = ext[i - FAT_SFN_SIZE_PARTIAL] - 'a' + 'A';
else
sfn_output[i] = ext[i - FAT_SFN_SIZE_PARTIAL];
}
return 1;
}
static void fatfs_itoa (uint32 num, char* s) {
char* cp;
char outbuf[12];
const char digits[] = "0123456789ABCDEF";
cp = outbuf;
do {
*cp++ = digits[(int)(num % 10)];
} while ((num /= 10) > 0);
*cp-- = 0;
while (cp >= outbuf)
*s++ = *cp--;
*s = 0;
}
int fatfs_lfn_generate_tail (char* sfn_output, char* sfn_input, uint32 tailNum) {
int tail_chars;
char tail_str[12];
if (tailNum > 99999)
return 0;
memset (tail_str, 0x00, sizeof (tail_str));
tail_str[0] = '~';
fatfs_itoa (tailNum, tail_str + 1);
memcpy (sfn_output, sfn_input, FAT_SFN_SIZE_FULL);
tail_chars = (int)strlen (tail_str);
memcpy (sfn_output + (FAT_SFN_SIZE_PARTIAL - tail_chars), tail_str, tail_chars);
return 1;
}
#define __FAT_CACHE_H__
#define __FAT_FILELIB_H__
#define __FAT_ACCESS_H__
#define FAT_INIT_OK 0
#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
#define FAT_INIT_INVALID_SIGNATURE (-3)
#define FAT_INIT_ENDIAN_ERROR (-4)
#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
#define FAT_INIT_STRUCT_PACKING (-7)
#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
typedef int (*fn_diskio_read) (struct fatfs_ctx* ctx, uint32 sector, uint8* buffer,
uint32 sector_count);
typedef int (*fn_diskio_write) (struct fatfs_ctx* ctx, uint32 sector, uint8* buffer,
uint32 sector_count);
int fatfs_init (struct fatfs_ctx* ctx, struct fatfs* fs);
uint32 fatfs_lba_of_cluster (struct fatfs* fs, uint32 Cluster_Number);
int fatfs_sector_reader (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Startcluster,
uint32 offset, uint8* target);
int fatfs_sector_read (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 lba, uint8* target,
uint32 count);
int fatfs_sector_write (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 lba, uint8* target,
uint32 count);
int fatfs_read_sector (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster, uint32 sector,
uint8* target);
int fatfs_write_sector (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster, uint32 sector,
uint8* target);
void fatfs_show_details (struct fatfs* fs);
uint32 fatfs_get_root_cluster (struct fatfs* fs);
uint32 fatfs_get_file_entry (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* nametofind, struct fat_dir_entry* sfEntry);
int fatfs_sfn_exists (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster, char* shortname);
int fatfs_update_file_length (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* shortname, uint32 fileLength);
int fatfs_mark_file_deleted (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* shortname);
void fatfs_list_directory_start (struct fatfs* fs, struct fs_dir_list_status* dirls,
uint32 StartCluster);
int fatfs_list_directory_next (struct fatfs_ctx* ctx, struct fatfs* fs,
struct fs_dir_list_status* dirls, struct fs_dir_ent* entry);
int fatfs_update_timestamps (struct fat_dir_entry* directoryEntry, int create, int modify,
int access);
#define __FAT_LIST_H__
#define FAT_ASSERT(x)
#define FAT_INLINE
struct fat_list;
#define fat_list_entry(p, t, m) p ? ((t*)((char*)(p) - (char*)(&((t*)0)->m))) : 0
#define fat_list_next(l, p) (p)->next
#define fat_list_prev(l, p) (p)->previous
#define fat_list_first(l) (l)->head
#define fat_list_last(l) (l)->tail
#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
#define EOF (-1)
struct sFL_FILE;
void fl_init (struct fatfs_ctx* ctx);
void fl_attach_locks (struct fatfs_ctx* ctx, void (*lock) (void), void (*unlock) (void));
int fl_attach_media (struct fatfs_ctx* ctx, fn_diskio_read rd, fn_diskio_write wr);
void fl_shutdown (struct fatfs_ctx* ctx);
void* fl_fopen (struct fatfs_ctx* ctx, const char* path, const char* modifiers);
void fl_fclose (struct fatfs_ctx* ctx, void* file);
int fl_fflush (struct fatfs_ctx* ctx, void* file);
int fl_fgetc (struct fatfs_ctx* ctx, void* file);
char* fl_fgets (struct fatfs_ctx* ctx, char* s, int n, void* f);
int fl_fputc (struct fatfs_ctx* ctx, int c, void* file);
int fl_fputs (struct fatfs_ctx* ctx, const char* str, void* file);
int fl_fwrite (struct fatfs_ctx* ctx, const void* data, int size, int count, void* file);
int fl_fread (struct fatfs_ctx* ctx, void* data, int size, int count, void* file);
int fl_fseek (struct fatfs_ctx* ctx, void* file, long offset, int origin);
int fl_fgetpos (struct fatfs_ctx* ctx, void* file, uint32* position);
long fl_ftell (struct fatfs_ctx* ctx, void* f);
int fl_feof (struct fatfs_ctx* ctx, void* f);
int fl_remove (struct fatfs_ctx* ctx, const char* filename);
typedef struct fs_dir_list_status FL_DIR;
typedef struct fs_dir_ent fl_dirent;
FL_DIR* fl_opendir (struct fatfs_ctx* ctx, const char* path, FL_DIR* dir);
int fl_readdir (struct fatfs_ctx* ctx, FL_DIR* dirls, fl_dirent* entry);
int fl_closedir (struct fatfs_ctx* ctx, FL_DIR* dir);
void fl_listdirectory (struct fatfs_ctx* ctx, const char* path);
int fl_createdirectory (struct fatfs_ctx* ctx, const char* path);
int fl_is_dir (struct fatfs_ctx* ctx, const char* path);
int fl_format (struct fatfs_ctx* ctx, uint32 volume_sectors, const char* name);
int fatfs_cache_init (struct fatfs* fs, FL_FILE* file);
int fatfs_cache_get_next_cluster (struct fatfs* fs, FL_FILE* file, uint32 clusterIdx,
uint32* pNextCluster);
int fatfs_cache_set_next_cluster (struct fatfs* fs, FL_FILE* file, uint32 clusterIdx,
uint32 nextCluster);
int fatfs_cache_init (struct fatfs* fs, FL_FILE* file) { return 1; }
int fatfs_cache_get_next_cluster (struct fatfs* fs, FL_FILE* file, uint32 clusterIdx,
uint32* pNextCluster) {
return 0;
}
int fatfs_cache_set_next_cluster (struct fatfs* fs, FL_FILE* file, uint32 clusterIdx,
uint32 nextCluster) {
return 1;
}
#define __FAT_TABLE_H__
void fatfs_fat_init (struct fatfs* fs);
int fatfs_fat_purge (struct fatfs_ctx* ctx, struct fatfs* fs);
uint32 fatfs_find_next_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 current_cluster);
void fatfs_set_fs_info_next_free_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 newValue);
int fatfs_find_blank_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster,
uint32* free_cluster);
int fatfs_fat_set_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster,
uint32 next_cluster);
int fatfs_fat_add_cluster_to_chain (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster,
uint32 newEntry);
int fatfs_free_cluster_chain (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster);
uint32 fatfs_count_free_clusters (struct fatfs_ctx* ctx, struct fatfs* fs);
#define FAT32_GET_32BIT_WORD(pbuf, location) (GET_32BIT_WORD (pbuf->ptr, location))
#define FAT32_SET_32BIT_WORD(pbuf, location, value) \
{ \
SET_32BIT_WORD (pbuf->ptr, location, value); \
pbuf->dirty = 1; \
}
#define FAT16_GET_16BIT_WORD(pbuf, location) (GET_16BIT_WORD (pbuf->ptr, location))
#define FAT16_SET_16BIT_WORD(pbuf, location, value) \
{ \
SET_16BIT_WORD (pbuf->ptr, location, value); \
pbuf->dirty = 1; \
}
void fatfs_fat_init (struct fatfs* fs) {
int i;
fs->fat_buffer_head = NULL;
for (i = 0; i < FAT_BUFFERS; i++) {
fs->fat_buffers[i].address = FAT32_INVALID_CLUSTER;
fs->fat_buffers[i].dirty = 0;
memset (fs->fat_buffers[i].sector, 0x00, sizeof (fs->fat_buffers[i].sector));
fs->fat_buffers[i].ptr = NULL;
fs->fat_buffers[i].next = fs->fat_buffer_head;
fs->fat_buffer_head = &fs->fat_buffers[i];
}
}
static int fatfs_fat_writeback (struct fatfs_ctx* ctx, struct fatfs* fs, struct fat_buffer* pcur) {
if (pcur) {
if (pcur->dirty) {
if (fs->disk_io.write_media) {
uint32 sectors = FAT_BUFFER_SECTORS;
uint32 offset = pcur->address - fs->fat_begin_lba;
if ((offset + FAT_BUFFER_SECTORS) <= fs->fat_sectors)
sectors = FAT_BUFFER_SECTORS;
else
sectors = fs->fat_sectors - offset;
if (!fs->disk_io.write_media (ctx, pcur->address, pcur->sector, sectors))
return 0;
}
pcur->dirty = 0;
}
return 1;
} else
return 0;
}
static struct fat_buffer* fatfs_fat_read_sector (struct fatfs_ctx* ctx, struct fatfs* fs,
uint32 sector) {
struct fat_buffer* last = NULL;
struct fat_buffer* pcur = fs->fat_buffer_head;
while (pcur) {
if ((sector >= pcur->address) && (sector < (pcur->address + FAT_BUFFER_SECTORS)))
break;
if (pcur->next == NULL) {
if (last)
last->next = NULL;
else
fs->fat_buffer_head = NULL;
}
last = pcur;
pcur = pcur->next;
}
if (pcur) {
pcur->ptr = (uint8*)(pcur->sector + ((sector - pcur->address) * FAT_SECTOR_SIZE));
return pcur;
}
pcur = last;
pcur->next = fs->fat_buffer_head;
fs->fat_buffer_head = pcur;
if (pcur->dirty)
if (!fatfs_fat_writeback (ctx, fs, pcur))
return 0;
pcur->address = sector;
if (!fs->disk_io.read_media (ctx, pcur->address, pcur->sector, FAT_BUFFER_SECTORS)) {
pcur->address = FAT32_INVALID_CLUSTER;
return NULL;
}
pcur->ptr = pcur->sector;
return pcur;
}
int fatfs_fat_purge (struct fatfs_ctx* ctx, struct fatfs* fs) {
struct fat_buffer* pcur = fs->fat_buffer_head;
while (pcur) {
if (pcur->dirty)
if (!fatfs_fat_writeback (ctx, fs, pcur))
return 0;
pcur = pcur->next;
}
return 1;
}
uint32 fatfs_find_next_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 current_cluster) {
uint32 fat_sector_offset, position;
uint32 nextcluster;
struct fat_buffer* pbuf;
if (current_cluster == 0)
current_cluster = 2;
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = current_cluster / 256;
else
fat_sector_offset = current_cluster / 128;
pbuf = fatfs_fat_read_sector (ctx, fs, fs->fat_begin_lba + fat_sector_offset);
if (!pbuf)
return (FAT32_LAST_CLUSTER);
if (fs->fat_type == FAT_TYPE_16) {
position = (current_cluster - (fat_sector_offset * 256)) * 2;
nextcluster = FAT16_GET_16BIT_WORD (pbuf, (uint16)position);
if (nextcluster >= 0xFFF8 && nextcluster <= 0xFFFF)
return (FAT32_LAST_CLUSTER);
} else {
position = (current_cluster - (fat_sector_offset * 128)) * 4;
nextcluster = FAT32_GET_32BIT_WORD (pbuf, (uint16)position);
nextcluster = nextcluster & 0x0FFFFFFF;
if (nextcluster >= 0x0FFFFFF8 && nextcluster <= 0x0FFFFFFF)
return (FAT32_LAST_CLUSTER);
}
return (nextcluster);
}
void fatfs_set_fs_info_next_free_cluster (struct fatfs_ctx* ctx, struct fatfs* fs,
uint32 newValue) {
if (fs->fat_type == FAT_TYPE_16)
;
else {
struct fat_buffer* pbuf = fatfs_fat_read_sector (ctx, fs, fs->lba_begin + fs->fs_info_sector);
if (!pbuf)
return;
FAT32_SET_32BIT_WORD (pbuf, 492, newValue);
fs->next_free_cluster = newValue;
if (fs->disk_io.write_media)
fs->disk_io.write_media (ctx, pbuf->address, pbuf->sector, 1);
pbuf->address = FAT32_INVALID_CLUSTER;
pbuf->dirty = 0;
}
}
int fatfs_find_blank_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster,
uint32* free_cluster) {
uint32 fat_sector_offset, position;
uint32 nextcluster;
uint32 current_cluster = start_cluster;
struct fat_buffer* pbuf;
do {
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = current_cluster / 256;
else
fat_sector_offset = current_cluster / 128;
if (fat_sector_offset < fs->fat_sectors) {
pbuf = fatfs_fat_read_sector (ctx, fs, fs->fat_begin_lba + fat_sector_offset);
if (!pbuf)
return 0;
if (fs->fat_type == FAT_TYPE_16) {
position = (current_cluster - (fat_sector_offset * 256)) * 2;
nextcluster = FAT16_GET_16BIT_WORD (pbuf, (uint16)position);
} else {
position = (current_cluster - (fat_sector_offset * 128)) * 4;
nextcluster = FAT32_GET_32BIT_WORD (pbuf, (uint16)position);
nextcluster = nextcluster & 0x0FFFFFFF;
}
if (nextcluster != 0)
current_cluster++;
} else
return 0;
} while (nextcluster != 0x0);
*free_cluster = current_cluster;
return 1;
}
int fatfs_fat_set_cluster (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster,
uint32 next_cluster) {
struct fat_buffer* pbuf;
uint32 fat_sector_offset, position;
if (fs->fat_type == FAT_TYPE_16)
fat_sector_offset = cluster / 256;
else
fat_sector_offset = cluster / 128;
pbuf = fatfs_fat_read_sector (ctx, fs, fs->fat_begin_lba + fat_sector_offset);
if (!pbuf)
return 0;
if (fs->fat_type == FAT_TYPE_16) {
position = (cluster - (fat_sector_offset * 256)) * 2;
FAT16_SET_16BIT_WORD (pbuf, (uint16)position, ((uint16)next_cluster));
} else {
position = (cluster - (fat_sector_offset * 128)) * 4;
FAT32_SET_32BIT_WORD (pbuf, (uint16)position, next_cluster);
}
return 1;
}
int fatfs_free_cluster_chain (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster) {
uint32 last_cluster;
uint32 next_cluster = start_cluster;
while ((next_cluster != FAT32_LAST_CLUSTER) && (next_cluster != 0x00000000)) {
last_cluster = next_cluster;
next_cluster = fatfs_find_next_cluster (ctx, fs, next_cluster);
fatfs_fat_set_cluster (ctx, fs, last_cluster, 0x00000000);
}
return 1;
}
int fatfs_fat_add_cluster_to_chain (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster,
uint32 newEntry) {
uint32 last_cluster = FAT32_LAST_CLUSTER;
uint32 next_cluster = start_cluster;
if (start_cluster == FAT32_LAST_CLUSTER)
return 0;
while (next_cluster != FAT32_LAST_CLUSTER) {
last_cluster = next_cluster;
next_cluster = fatfs_find_next_cluster (ctx, fs, next_cluster);
if (!next_cluster)
return 0;
}
fatfs_fat_set_cluster (ctx, fs, last_cluster, newEntry);
fatfs_fat_set_cluster (ctx, fs, newEntry, FAT32_LAST_CLUSTER);
return 1;
}
uint32 fatfs_count_free_clusters (struct fatfs_ctx* ctx, struct fatfs* fs) {
uint32 i, j;
uint32 count = 0;
struct fat_buffer* pbuf;
for (i = 0; i < fs->fat_sectors; i++) {
pbuf = fatfs_fat_read_sector (ctx, fs, fs->fat_begin_lba + i);
if (!pbuf)
break;
for (j = 0; j < FAT_SECTOR_SIZE;) {
if (fs->fat_type == FAT_TYPE_16) {
if (FAT16_GET_16BIT_WORD (pbuf, (uint16)j) == 0)
count++;
j += 2;
} else {
if (FAT32_GET_32BIT_WORD (pbuf, (uint16)j) == 0)
count++;
j += 4;
}
}
}
return count;
}
#define __FAT_WRITE_H__
int fatfs_add_file_entry (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 dirCluster,
char* filename, char* shortfilename, uint32 startCluster, uint32 size,
int dir);
int fatfs_add_free_space (struct fatfs_ctx* ctx, struct fatfs* fs, uint32* startCluster,
uint32 clusters);
int fatfs_allocate_free_space (struct fatfs_ctx* ctx, struct fatfs* fs, int newFile,
uint32* startCluster, uint32 size);
#define __FILESTRING_H__
int fatfs_total_path_levels (char* path);
int fatfs_get_substring (char* Path, int levelreq, char* output, int max_len);
int fatfs_split_path (char* FullPath, char* Path, int max_path, char* FileName, int max_filename);
int fatfs_compare_names (char* strA, char* strB);
int fatfs_string_ends_with_slash (char* path);
int fatfs_get_sfn_display_name (char* out, char* in);
int fatfs_get_extension (char* filename, char* out, int maxlen);
int fatfs_create_path_string (char* path, char* filename, char* out, int maxlen);
int fatfs_add_free_space (struct fatfs_ctx* ctx, struct fatfs* fs, uint32* startCluster,
uint32 clusters) {
uint32 i;
uint32 nextcluster;
uint32 start = *startCluster;
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
fatfs_set_fs_info_next_free_cluster (ctx, fs, FAT32_LAST_CLUSTER);
for (i = 0; i < clusters; i++) {
if (fatfs_find_blank_cluster (ctx, fs, fs->rootdir_first_cluster, &nextcluster)) {
fatfs_fat_set_cluster (ctx, fs, start, nextcluster);
fatfs_fat_set_cluster (ctx, fs, nextcluster, FAT32_LAST_CLUSTER);
start = nextcluster;
if (i == 0)
*startCluster = nextcluster;
} else
return 0;
}
return 1;
}
int fatfs_allocate_free_space (struct fatfs_ctx* ctx, struct fatfs* fs, int newFile,
uint32* startCluster, uint32 size) {
uint32 clusterSize;
uint32 clusterCount;
uint32 nextcluster;
if (size == 0)
return 0;
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
fatfs_set_fs_info_next_free_cluster (ctx, fs, FAT32_LAST_CLUSTER);
clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE;
clusterCount = (size / clusterSize);
if (size - (clusterSize * clusterCount))
clusterCount++;
if (newFile) {
if (!fatfs_find_blank_cluster (ctx, fs, fs->rootdir_first_cluster, &nextcluster))
return 0;
if (clusterCount == 1) {
fatfs_fat_set_cluster (ctx, fs, nextcluster, FAT32_LAST_CLUSTER);
*startCluster = nextcluster;
return 1;
}
} else
nextcluster = *startCluster;
if (!fatfs_add_free_space (ctx, fs, &nextcluster, clusterCount))
return 0;
return 1;
}
static int fatfs_find_free_dir_offset (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 dirCluster,
int entryCount, uint32* pSector, uint8* pOffset) {
struct fat_dir_entry* directoryEntry;
uint8 item = 0;
uint16 recordoffset = 0;
uint8 i = 0;
int x = 0;
int possible_spaces = 0;
int start_recorded = 0;
if (entryCount == 0)
return 0;
while (1) {
if (fatfs_sector_reader (ctx, fs, dirCluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry)) {
if (possible_spaces == 0) {
*pSector = x - 1;
*pOffset = item;
start_recorded = 1;
}
possible_spaces++;
} else {
if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED) {
if (possible_spaces == 0) {
*pSector = x - 1;
*pOffset = item;
start_recorded = 1;
}
possible_spaces++;
if (possible_spaces >= entryCount)
return 1;
} else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK) {
if (possible_spaces == 0) {
*pSector = x - 1;
*pOffset = item;
start_recorded = 1;
}
possible_spaces++;
if (possible_spaces >= entryCount)
return 1;
} else {
possible_spaces = 0;
start_recorded = 0;
}
}
}
} else {
uint32 newCluster;
if (!fatfs_find_blank_cluster (ctx, fs, fs->rootdir_first_cluster, &newCluster))
return 0;
if (!fatfs_fat_add_cluster_to_chain (ctx, fs, dirCluster, newCluster))
return 0;
memset (fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE);
for (i = 0; i < fs->sectors_per_cluster; i++) {
if (!fatfs_write_sector (ctx, fs, newCluster, i, 0))
return 0;
}
if (!start_recorded) {
*pSector = (x - 1);
*pOffset = 0;
start_recorded = 1;
}
return 1;
}
}
return 0;
}
int fatfs_add_file_entry (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 dirCluster,
char* filename, char* shortfilename, uint32 startCluster, uint32 size,
int dir) {
uint8 item = 0;
uint16 recordoffset = 0;
uint8 i = 0;
uint32 x = 0;
int entryCount;
struct fat_dir_entry shortEntry;
int dirtySector = 0;
uint32 dirSector = 0;
uint8 dirOffset = 0;
int foundEnd = 0;
uint8 checksum;
uint8* pSname;
if (!fs->disk_io.write_media)
return 0;
entryCount = fatfs_lfn_entries_required (filename);
if (!entryCount)
return 0;
if (!fatfs_find_free_dir_offset (ctx, fs, dirCluster, entryCount + 1, &dirSector, &dirOffset))
return 0;
pSname = (uint8*)shortfilename;
checksum = 0;
for (i = 11; i != 0; i--)
checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++;
x = dirSector;
while (1) {
if (fatfs_sector_reader (ctx, fs, dirCluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
if (foundEnd == 0)
if ((dirSector == (x - 1)) && (dirOffset == item))
foundEnd = 1;
if (foundEnd) {
if (entryCount == 0) {
fatfs_sfn_create_entry (shortfilename, size, startCluster, &shortEntry, dir);
memcpy (&fs->currentsector.sector[recordoffset], &shortEntry, sizeof (shortEntry));
return fs->disk_io.write_media (ctx, fs->currentsector.address,
fs->currentsector.sector, 1);
} else {
entryCount--;
fatfs_filename_to_lfn (filename, &fs->currentsector.sector[recordoffset], entryCount,
checksum);
dirtySector = 1;
}
}
}
if (dirtySector) {
if (!fs->disk_io.write_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1))
return 0;
dirtySector = 0;
}
} else
return 0;
}
return 0;
}
int fatfs_init (struct fatfs_ctx* ctx, struct fatfs* fs) {
uint8 num_of_fats;
uint16 reserved_sectors;
uint32 FATSz;
uint32 root_dir_sectors;
uint32 total_sectors;
uint32 data_sectors;
uint32 count_of_clusters;
uint8 valid_partition = 0;
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0;
fatfs_fat_init (fs);
if (!fs->disk_io.read_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
if (!fs->disk_io.read_media (ctx, 0, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
if (fs->currentsector.sector[SIGNATURE_POSITION] != 0x55 ||
fs->currentsector.sector[SIGNATURE_POSITION + 1] != 0xAA)
return FAT_INIT_INVALID_SIGNATURE;
if (GET_16BIT_WORD (fs->currentsector.sector, SIGNATURE_POSITION) != SIGNATURE_VALUE)
return FAT_INIT_ENDIAN_ERROR;
if (sizeof (struct fat_dir_entry) != FAT_DIR_ENTRY_SIZE)
return FAT_INIT_STRUCT_PACKING;
switch (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION]) {
case 0x0B:
case 0x06:
case 0x0C:
case 0x0E:
case 0x0F:
case 0x05:
valid_partition = 1;
break;
case 0x00:
valid_partition = 0;
break;
default:
if (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION] <= 0x06)
valid_partition = 1;
break;
}
if (valid_partition)
fs->lba_begin = GET_32BIT_WORD (fs->currentsector.sector, PARTITION1_LBA_BEGIN_LOCATION);
else
fs->lba_begin = 0;
if (!fs->disk_io.read_media (ctx, fs->lba_begin, fs->currentsector.sector, 1))
return FAT_INIT_MEDIA_ACCESS_ERROR;
if (GET_16BIT_WORD (fs->currentsector.sector, 0x0B) != FAT_SECTOR_SIZE)
return FAT_INIT_INVALID_SECTOR_SIZE;
fs->sectors_per_cluster = fs->currentsector.sector[BPB_SECPERCLUS];
reserved_sectors = GET_16BIT_WORD (fs->currentsector.sector, BPB_RSVDSECCNT);
num_of_fats = fs->currentsector.sector[BPB_NUMFATS];
fs->root_entry_count = GET_16BIT_WORD (fs->currentsector.sector, BPB_ROOTENTCNT);
if (GET_16BIT_WORD (fs->currentsector.sector, BPB_FATSZ16) != 0)
fs->fat_sectors = GET_16BIT_WORD (fs->currentsector.sector, BPB_FATSZ16);
else
fs->fat_sectors = GET_32BIT_WORD (fs->currentsector.sector, BPB_FAT32_FATSZ32);
fs->rootdir_first_cluster = GET_32BIT_WORD (fs->currentsector.sector, BPB_FAT32_ROOTCLUS);
fs->fs_info_sector = GET_16BIT_WORD (fs->currentsector.sector, BPB_FAT32_FSINFO);
fs->rootdir_first_sector = reserved_sectors + (num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
fs->fat_begin_lba = fs->lba_begin + reserved_sectors;
fs->cluster_begin_lba = fs->fat_begin_lba + (num_of_fats * fs->fat_sectors);
if (GET_16BIT_WORD (fs->currentsector.sector, 0x1FE) != 0xAA55)
return FAT_INIT_INVALID_SIGNATURE;
root_dir_sectors = ((GET_16BIT_WORD (fs->currentsector.sector, BPB_ROOTENTCNT) * 32) +
(GET_16BIT_WORD (fs->currentsector.sector, BPB_BYTSPERSEC) - 1)) /
GET_16BIT_WORD (fs->currentsector.sector, BPB_BYTSPERSEC);
if (GET_16BIT_WORD (fs->currentsector.sector, BPB_FATSZ16) != 0)
FATSz = GET_16BIT_WORD (fs->currentsector.sector, BPB_FATSZ16);
else
FATSz = GET_32BIT_WORD (fs->currentsector.sector, BPB_FAT32_FATSZ32);
if (GET_16BIT_WORD (fs->currentsector.sector, BPB_TOTSEC16) != 0)
total_sectors = GET_16BIT_WORD (fs->currentsector.sector, BPB_TOTSEC16);
else
total_sectors = GET_32BIT_WORD (fs->currentsector.sector, BPB_TOTSEC32);
data_sectors = total_sectors -
(GET_16BIT_WORD (fs->currentsector.sector, BPB_RSVDSECCNT) +
(fs->currentsector.sector[BPB_NUMFATS] * FATSz) + root_dir_sectors);
if (fs->sectors_per_cluster != 0) {
count_of_clusters = data_sectors / fs->sectors_per_cluster;
if (count_of_clusters < 4085)
return FAT_INIT_WRONG_FILESYS_TYPE;
else if (count_of_clusters < 65525) {
fs->rootdir_first_cluster = 0;
fs->fat_type = FAT_TYPE_16;
return FAT_INIT_OK;
} else {
fs->fat_type = FAT_TYPE_32;
return FAT_INIT_OK;
}
} else
return FAT_INIT_WRONG_FILESYS_TYPE;
}
uint32 fatfs_lba_of_cluster (struct fatfs* fs, uint32 Cluster_Number) {
if (fs->fat_type == FAT_TYPE_16)
return (fs->cluster_begin_lba + (fs->root_entry_count * 32 / FAT_SECTOR_SIZE) +
((Cluster_Number - 2) * fs->sectors_per_cluster));
else
return ((fs->cluster_begin_lba + ((Cluster_Number - 2) * fs->sectors_per_cluster)));
}
int fatfs_sector_read (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 lba, uint8* target,
uint32 count) {
return fs->disk_io.read_media (ctx, lba, target, count);
}
int fatfs_sector_write (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 lba, uint8* target,
uint32 count) {
return fs->disk_io.write_media (ctx, lba, target, count);
}
int fatfs_sector_reader (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 start_cluster,
uint32 offset, uint8* target) {
uint32 sector_to_read = 0;
uint32 cluster_to_read = 0;
uint32 cluster_chain = 0;
uint32 i;
uint32 lba;
if (fs->fat_type == FAT_TYPE_16 && start_cluster == 0) {
if (offset < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + offset;
else
return 0;
} else {
cluster_chain = start_cluster;
cluster_to_read = offset / fs->sectors_per_cluster;
sector_to_read = offset - (cluster_to_read * fs->sectors_per_cluster);
for (i = 0; i < cluster_to_read; i++)
cluster_chain = fatfs_find_next_cluster (ctx, fs, cluster_chain);
if (cluster_chain == FAT32_LAST_CLUSTER)
return 0;
lba = fatfs_lba_of_cluster (fs, cluster_chain) + sector_to_read;
}
if (target)
return fs->disk_io.read_media (ctx, lba, target, 1);
else if (lba != fs->currentsector.address) {
fs->currentsector.address = lba;
return fs->disk_io.read_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1);
} else
return 1;
}
int fatfs_read_sector (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster, uint32 sector,
uint8* target) {
if (fs->fat_type == FAT_TYPE_16 && cluster == 0) {
uint32 lba;
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
if (target) {
return fs->disk_io.read_media (ctx, lba, target, 1);
} else {
fs->currentsector.address = lba;
return fs->disk_io.read_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
} else {
if (target) {
uint32 lba = fatfs_lba_of_cluster (fs, cluster) + sector;
return fs->disk_io.read_media (ctx, lba, target, 1);
} else {
fs->currentsector.address = fatfs_lba_of_cluster (fs, cluster) + sector;
return fs->disk_io.read_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
int fatfs_write_sector (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 cluster, uint32 sector,
uint8* target) {
if (!fs->disk_io.write_media)
return 0;
if (fs->fat_type == FAT_TYPE_16 && cluster == 0) {
uint32 lba;
if (sector < fs->rootdir_sectors)
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
else
return 0;
if (target) {
return fs->disk_io.write_media (ctx, lba, target, 1);
} else {
fs->currentsector.address = lba;
return fs->disk_io.write_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
} else {
if (target) {
uint32 lba = fatfs_lba_of_cluster (fs, cluster) + sector;
return fs->disk_io.write_media (ctx, lba, target, 1);
} else {
fs->currentsector.address = fatfs_lba_of_cluster (fs, cluster) + sector;
return fs->disk_io.write_media (ctx, fs->currentsector.address, fs->currentsector.sector, 1);
}
}
}
void fatfs_show_details (struct fatfs* fs) {
FAT_PRINTF (("FAT details:\r\n"));
FAT_PRINTF ((" Type =%s", (fs->fat_type == FAT_TYPE_32) ? "FAT32" : "FAT16"));
FAT_PRINTF ((" Root Dir First Cluster = %x\r\n", fs->rootdir_first_cluster));
FAT_PRINTF ((" FAT Begin LBA = 0x%x\r\n", fs->fat_begin_lba));
FAT_PRINTF ((" Cluster Begin LBA = 0x%x\r\n", fs->cluster_begin_lba));
FAT_PRINTF ((" Sectors Per Cluster = %d\r\n", fs->sectors_per_cluster));
}
uint32 fatfs_get_root_cluster (struct fatfs* fs) { return fs->rootdir_first_cluster; }
uint32 fatfs_get_file_entry (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* name_to_find, struct fat_dir_entry* sfEntry) {
uint8 item = 0;
uint16 recordoffset = 0;
uint8 i = 0;
int x = 0;
char* long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
struct fat_dir_entry* directoryEntry;
fatfs_lfn_cache_init (&lfn, 1);
while (1) {
if (fatfs_sector_reader (ctx, fs, Cluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry))
fatfs_lfn_cache_entry (&lfn, fs->currentsector.sector + recordoffset);
else if (fatfs_entry_lfn_invalid (directoryEntry))
fatfs_lfn_cache_init (&lfn, 0);
else if (fatfs_entry_lfn_exists (&lfn, directoryEntry)) {
long_filename = fatfs_lfn_cache_get (&lfn);
if (fatfs_compare_names (long_filename, name_to_find)) {
memcpy (sfEntry, directoryEntry, sizeof (struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init (&lfn, 0);
} else if (fatfs_entry_sfn_only (directoryEntry)) {
memset (short_filename, 0, sizeof (short_filename));
for (i = 0; i < 8; i++)
short_filename[i] = directoryEntry->Name[i];
dotRequired = 0;
for (i = 8; i < 11; i++) {
short_filename[i + 1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
if (dotRequired) {
if (short_filename[0] != '.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
} else
short_filename[8] = ' ';
if (fatfs_compare_names (short_filename, name_to_find)) {
memcpy (sfEntry, directoryEntry, sizeof (struct fat_dir_entry));
return 1;
}
fatfs_lfn_cache_init (&lfn, 0);
}
}
} else
break;
}
return 0;
}
int fatfs_sfn_exists (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster, char* shortname) {
uint8 item = 0;
uint16 recordoffset = 0;
int x = 0;
struct fat_dir_entry* directoryEntry;
while (1) {
if (fatfs_sector_reader (ctx, fs, Cluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry))
;
else if (fatfs_entry_lfn_invalid (directoryEntry))
;
else if (fatfs_entry_sfn_only (directoryEntry)) {
if (strncmp ((const char*)directoryEntry->Name, shortname, 11) == 0)
return 1;
}
}
} else
break;
}
return 0;
}
int fatfs_update_file_length (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* shortname, uint32 fileLength) {
uint8 item = 0;
uint16 recordoffset = 0;
int x = 0;
struct fat_dir_entry* directoryEntry;
if (!fs->disk_io.write_media)
return 0;
while (1) {
if (fatfs_sector_reader (ctx, fs, Cluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry))
;
else if (fatfs_entry_lfn_invalid (directoryEntry))
;
else if (fatfs_entry_sfn_only (directoryEntry)) {
if (strncmp ((const char*)directoryEntry->Name, shortname, 11) == 0) {
directoryEntry->FileSize = FAT_HTONL (fileLength);
memcpy ((uint8*)(fs->currentsector.sector + recordoffset), (uint8*)directoryEntry,
sizeof (struct fat_dir_entry));
return fs->disk_io.write_media (ctx, fs->currentsector.address,
fs->currentsector.sector, 1);
}
}
}
} else
break;
}
return 0;
}
int fatfs_mark_file_deleted (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 Cluster,
char* shortname) {
uint8 item = 0;
uint16 recordoffset = 0;
int x = 0;
struct fat_dir_entry* directoryEntry;
if (!fs->disk_io.write_media)
return 0;
while (1) {
if (fatfs_sector_reader (ctx, fs, Cluster, x++, 0)) {
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry))
;
else if (fatfs_entry_lfn_invalid (directoryEntry))
;
else if (fatfs_entry_sfn_only (directoryEntry)) {
if (strncmp ((const char*)directoryEntry->Name, shortname, 11) == 0) {
directoryEntry->Name[0] = FILE_HEADER_DELETED;
memcpy ((uint8*)(fs->currentsector.sector + recordoffset), (uint8*)directoryEntry,
sizeof (struct fat_dir_entry));
return fs->disk_io.write_media (ctx, fs->currentsector.address,
fs->currentsector.sector, 1);
}
}
}
} else
break;
}
return 0;
}
void fatfs_list_directory_start (struct fatfs* fs, struct fs_dir_list_status* dirls,
uint32 StartCluster) {
dirls->cluster = StartCluster;
dirls->sector = 0;
dirls->offset = 0;
}
int fatfs_list_directory_next (struct fatfs_ctx* ctx, struct fatfs* fs,
struct fs_dir_list_status* dirls, struct fs_dir_ent* entry) {
uint8 i, item;
uint16 recordoffset;
struct fat_dir_entry* directoryEntry;
char* long_filename = NULL;
char short_filename[13];
struct lfn_cache lfn;
int dotRequired = 0;
int result = 0;
fatfs_lfn_cache_init (&lfn, 0);
while (1) {
if (fatfs_sector_reader (ctx, fs, dirls->cluster, dirls->sector, 0)) {
for (item = dirls->offset; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) {
recordoffset = FAT_DIR_ENTRY_SIZE * item;
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector + recordoffset);
if (fatfs_entry_lfn_text (directoryEntry))
fatfs_lfn_cache_entry (&lfn, fs->currentsector.sector + recordoffset);
else if (fatfs_entry_lfn_invalid (directoryEntry))
fatfs_lfn_cache_init (&lfn, 0);
else if (fatfs_entry_lfn_exists (&lfn, directoryEntry)) {
long_filename = fatfs_lfn_cache_get (&lfn);
strncpy (entry->filename, long_filename, FATFS_MAX_LONG_FILENAME - 1);
if (fatfs_entry_is_dir (directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
entry->size = FAT_HTONL (directoryEntry->FileSize);
entry->cluster =
(FAT_HTONS (directoryEntry->FstClusHI) << 16) | FAT_HTONS (directoryEntry->FstClusLO);
dirls->offset = item + 1;
result = 1;
return 1;
} else if (fatfs_entry_sfn_only (directoryEntry)) {
fatfs_lfn_cache_init (&lfn, 0);
memset (short_filename, 0, sizeof (short_filename));
for (i = 0; i < 8; i++)
short_filename[i] = directoryEntry->Name[i];
dotRequired = 0;
for (i = 8; i < 11; i++) {
short_filename[i + 1] = directoryEntry->Name[i];
if (directoryEntry->Name[i] != ' ')
dotRequired = 1;
}
if (dotRequired) {
if (short_filename[0] != '.')
short_filename[8] = '.';
else
short_filename[8] = ' ';
} else
short_filename[8] = ' ';
fatfs_get_sfn_display_name (entry->filename, short_filename);
if (fatfs_entry_is_dir (directoryEntry))
entry->is_dir = 1;
else
entry->is_dir = 0;
entry->size = FAT_HTONL (directoryEntry->FileSize);
entry->cluster =
(FAT_HTONS (directoryEntry->FstClusHI) << 16) | FAT_HTONS (directoryEntry->FstClusLO);
dirls->offset = item + 1;
result = 1;
return 1;
}
}
dirls->sector++;
dirls->offset = 0;
} else
break;
}
return result;
}
#define __FAT_FORMAT_H__
int fatfs_format (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors, const char* name);
int fatfs_format_fat16 (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors,
const char* name);
int fatfs_format_fat32 (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors,
const char* name);
struct sec_per_clus_table {
uint32 sectors;
uint8 sectors_per_cluster;
};
struct sec_per_clus_table _cluster_size_table16[] = {{32680, 2}, {262144, 4}, {524288, 8},
{1048576, 16}, {2097152, 32}, {4194304, 64},
{8388608, 128}, {0, 0}};
struct sec_per_clus_table _cluster_size_table32[] = {
{532480, 1}, {16777216, 8}, {33554432, 16}, {67108864, 32}, {0xFFFFFFFF, 64}, {0, 0}};
static uint8 fatfs_calc_cluster_size (uint32 sectors, int is_fat32) {
int i;
if (!is_fat32) {
for (i = 0; _cluster_size_table16[i].sectors_per_cluster != 0; i++)
if (sectors <= _cluster_size_table16[i].sectors)
return _cluster_size_table16[i].sectors_per_cluster;
} else {
for (i = 0; _cluster_size_table32[i].sectors_per_cluster != 0; i++)
if (sectors <= _cluster_size_table32[i].sectors)
return _cluster_size_table32[i].sectors_per_cluster;
}
return 0;
}
static int fatfs_erase_sectors (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 lba, int count) {
int i;
memset (fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i = 0; i < count; i++)
if (!fs->disk_io.write_media (ctx, lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
static int fatfs_create_boot_sector (struct fatfs_ctx* ctx, struct fatfs* fs,
uint32 boot_sector_lba, uint32 vol_sectors, const char* name,
int is_fat32) {
uint32 total_clusters;
int i;
memset (fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
fs->currentsector.sector[0] = 0xEB;
fs->currentsector.sector[1] = 0x3C;
fs->currentsector.sector[2] = 0x90;
fs->currentsector.sector[3] = 0x4D;
fs->currentsector.sector[4] = 0x53;
fs->currentsector.sector[5] = 0x44;
fs->currentsector.sector[6] = 0x4F;
fs->currentsector.sector[7] = 0x53;
fs->currentsector.sector[8] = 0x35;
fs->currentsector.sector[9] = 0x2E;
fs->currentsector.sector[10] = 0x30;
fs->currentsector.sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
fs->currentsector.sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
fs->sectors_per_cluster = fatfs_calc_cluster_size (vol_sectors, is_fat32);
if (!fs->sectors_per_cluster)
return 0;
fs->currentsector.sector[13] = fs->sectors_per_cluster;
if (!is_fat32)
fs->reserved_sectors = 8;
else
fs->reserved_sectors = 32;
fs->currentsector.sector[14] = (fs->reserved_sectors >> 0) & 0xFF;
fs->currentsector.sector[15] = (fs->reserved_sectors >> 8) & 0xFF;
fs->num_of_fats = 2;
fs->currentsector.sector[16] = fs->num_of_fats;
if (!is_fat32) {
fs->root_entry_count = 512;
fs->currentsector.sector[17] = (fs->root_entry_count >> 0) & 0xFF;
fs->currentsector.sector[18] = (fs->root_entry_count >> 8) & 0xFF;
} else {
fs->root_entry_count = 0;
fs->currentsector.sector[17] = 0;
fs->currentsector.sector[18] = 0;
}
fs->currentsector.sector[19] = 0x00;
fs->currentsector.sector[20] = 0x00;
fs->currentsector.sector[21] = 0xF8;
if (!is_fat32) {
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters / (FAT_SECTOR_SIZE / 2)) + 1;
fs->currentsector.sector[22] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
fs->currentsector.sector[23] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
fs->currentsector.sector[24] = 0x00;
fs->currentsector.sector[25] = 0x00;
fs->currentsector.sector[26] = 0x00;
fs->currentsector.sector[27] = 0x00;
fs->currentsector.sector[28] = 0x20;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
fs->currentsector.sector[32] = (uint8)((vol_sectors >> 0) & 0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors >> 8) & 0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors >> 16) & 0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors >> 24) & 0xFF);
fs->currentsector.sector[36] = 0x00;
fs->currentsector.sector[37] = 0x00;
fs->currentsector.sector[38] = 0x29;
fs->currentsector.sector[39] = 0x12;
fs->currentsector.sector[40] = 0x34;
fs->currentsector.sector[41] = 0x56;
fs->currentsector.sector[42] = 0x78;
for (i = 0; i < 11; i++) {
if (i < (int)strlen (name))
fs->currentsector.sector[i + 43] = name[i];
else
fs->currentsector.sector[i + 43] = ' ';
}
fs->currentsector.sector[54] = 'F';
fs->currentsector.sector[55] = 'A';
fs->currentsector.sector[56] = 'T';
fs->currentsector.sector[57] = '1';
fs->currentsector.sector[58] = '6';
fs->currentsector.sector[59] = ' ';
fs->currentsector.sector[60] = ' ';
fs->currentsector.sector[61] = ' ';
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
} else {
fs->currentsector.sector[22] = 0;
fs->currentsector.sector[23] = 0;
fs->currentsector.sector[24] = 0x3F;
fs->currentsector.sector[25] = 0x00;
fs->currentsector.sector[26] = 0xFF;
fs->currentsector.sector[27] = 0x00;
fs->currentsector.sector[28] = 0x00;
fs->currentsector.sector[29] = 0x00;
fs->currentsector.sector[30] = 0x00;
fs->currentsector.sector[31] = 0x00;
fs->currentsector.sector[32] = (uint8)((vol_sectors >> 0) & 0xFF);
fs->currentsector.sector[33] = (uint8)((vol_sectors >> 8) & 0xFF);
fs->currentsector.sector[34] = (uint8)((vol_sectors >> 16) & 0xFF);
fs->currentsector.sector[35] = (uint8)((vol_sectors >> 24) & 0xFF);
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
fs->fat_sectors = (total_clusters / (FAT_SECTOR_SIZE / 4)) + 1;
fs->currentsector.sector[36] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
fs->currentsector.sector[37] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
fs->currentsector.sector[38] = (uint8)((fs->fat_sectors >> 16) & 0xFF);
fs->currentsector.sector[39] = (uint8)((fs->fat_sectors >> 24) & 0xFF);
fs->currentsector.sector[40] = 0;
fs->currentsector.sector[41] = 0;
fs->currentsector.sector[42] = 0;
fs->currentsector.sector[43] = 0;
fs->currentsector.sector[44] = (uint8)((fs->rootdir_first_cluster >> 0) & 0xFF);
fs->currentsector.sector[45] = (uint8)((fs->rootdir_first_cluster >> 8) & 0xFF);
fs->currentsector.sector[46] = (uint8)((fs->rootdir_first_cluster >> 16) & 0xFF);
fs->currentsector.sector[47] = (uint8)((fs->rootdir_first_cluster >> 24) & 0xFF);
fs->currentsector.sector[48] = (uint8)((fs->fs_info_sector >> 0) & 0xFF);
fs->currentsector.sector[49] = (uint8)((fs->fs_info_sector >> 8) & 0xFF);
fs->currentsector.sector[50] = 6;
fs->currentsector.sector[51] = 0;
fs->currentsector.sector[64] = 0x00;
fs->currentsector.sector[66] = 0x29;
fs->currentsector.sector[67] = 0x12;
fs->currentsector.sector[68] = 0x34;
fs->currentsector.sector[69] = 0x56;
fs->currentsector.sector[70] = 0x78;
for (i = 0; i < 11; i++) {
if (i < (int)strlen (name))
fs->currentsector.sector[i + 71] = name[i];
else
fs->currentsector.sector[i + 71] = ' ';
}
fs->currentsector.sector[82] = 'F';
fs->currentsector.sector[83] = 'A';
fs->currentsector.sector[84] = 'T';
fs->currentsector.sector[85] = '3';
fs->currentsector.sector[86] = '2';
fs->currentsector.sector[87] = ' ';
fs->currentsector.sector[88] = ' ';
fs->currentsector.sector[89] = ' ';
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
}
if (fs->disk_io.write_media (ctx, boot_sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
static int fatfs_create_fsinfo_sector (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 sector_lba) {
memset (fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
fs->currentsector.sector[0] = 0x52;
fs->currentsector.sector[1] = 0x52;
fs->currentsector.sector[2] = 0x61;
fs->currentsector.sector[3] = 0x41;
fs->currentsector.sector[484] = 0x72;
fs->currentsector.sector[485] = 0x72;
fs->currentsector.sector[486] = 0x41;
fs->currentsector.sector[487] = 0x61;
fs->currentsector.sector[488] = 0xFF;
fs->currentsector.sector[489] = 0xFF;
fs->currentsector.sector[490] = 0xFF;
fs->currentsector.sector[491] = 0xFF;
fs->currentsector.sector[492] = 0xFF;
fs->currentsector.sector[493] = 0xFF;
fs->currentsector.sector[494] = 0xFF;
fs->currentsector.sector[495] = 0xFF;
fs->currentsector.sector[510] = 0x55;
fs->currentsector.sector[511] = 0xAA;
if (fs->disk_io.write_media (ctx, sector_lba, fs->currentsector.sector, 1))
return 1;
else
return 0;
}
static int fatfs_erase_fat (struct fatfs_ctx* ctx, struct fatfs* fs, int is_fat32) {
uint32 i;
memset (fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
if (!is_fat32) {
SET_16BIT_WORD (fs->currentsector.sector, 0, 0xFFF8);
SET_16BIT_WORD (fs->currentsector.sector, 2, 0xFFFF);
} else {
SET_32BIT_WORD (fs->currentsector.sector, 0, 0x0FFFFFF8);
SET_32BIT_WORD (fs->currentsector.sector, 4, 0xFFFFFFFF);
SET_32BIT_WORD (fs->currentsector.sector, 8, 0x0FFFFFFF);
}
if (!fs->disk_io.write_media (ctx, fs->fat_begin_lba + 0, fs->currentsector.sector, 1))
return 0;
memset (fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
for (i = 1; i < fs->fat_sectors * fs->num_of_fats; i++)
if (!fs->disk_io.write_media (ctx, fs->fat_begin_lba + i, fs->currentsector.sector, 1))
return 0;
return 1;
}
int fatfs_format_fat16 (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors,
const char* name) {
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0;
fatfs_fat_init (fs);
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
fs->fat_type = FAT_TYPE_16;
fs->fs_info_sector = 0;
fs->rootdir_first_cluster = 0;
fs->lba_begin = 0;
if (!fatfs_create_boot_sector (ctx, fs, fs->lba_begin, volume_sectors, name, 0))
return 0;
fs->rootdir_first_sector = fs->reserved_sectors + (fs->num_of_fats * fs->fat_sectors);
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
if (!fatfs_erase_fat (ctx, fs, 0))
return 0;
if (!fatfs_erase_sectors (ctx, fs, fs->lba_begin + fs->rootdir_first_sector, fs->rootdir_sectors))
return 0;
return 1;
}
int fatfs_format_fat32 (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors,
const char* name) {
fs->currentsector.address = FAT32_INVALID_CLUSTER;
fs->currentsector.dirty = 0;
fs->next_free_cluster = 0;
fatfs_fat_init (fs);
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
return FAT_INIT_MEDIA_ACCESS_ERROR;
fs->fat_type = FAT_TYPE_32;
fs->fs_info_sector = 1;
fs->rootdir_first_cluster = 2;
fs->lba_begin = 0;
if (!fatfs_create_boot_sector (ctx, fs, fs->lba_begin, volume_sectors, name, 1))
return 0;
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
if (!fatfs_create_fsinfo_sector (ctx, fs, fs->fs_info_sector))
return 0;
if (!fatfs_erase_fat (ctx, fs, 1))
return 0;
if (!fatfs_erase_sectors (ctx, fs, fatfs_lba_of_cluster (fs, fs->rootdir_first_cluster),
fs->sectors_per_cluster))
return 0;
return 1;
}
int fatfs_format (struct fatfs_ctx* ctx, struct fatfs* fs, uint32 volume_sectors,
const char* name) {
if (volume_sectors <= 4194304)
return fatfs_format_fat16 (ctx, fs, volume_sectors, name);
else
return fatfs_format_fat32 (ctx, fs, volume_sectors, name);
}
int fatfs_total_path_levels (char* path) {
int levels = 0;
char expectedchar;
if (!path)
return -1;
if (*path == '/') {
expectedchar = '/';
path++;
} else if (path[1] == ':' || path[2] == '\\') {
expectedchar = '\\';
path += 3;
} else
return -1;
while (*path) {
for (; *path;) {
if (*path == expectedchar) {
path++;
break;
}
path++;
}
levels++;
}
return levels - 1;
}
int fatfs_get_substring (char* path, int levelreq, char* output, int max_len) {
int i;
int pathlen = 0;
int levels = 0;
int copypnt = 0;
char expectedchar;
if (!path || max_len <= 0)
return -1;
if (*path == '/') {
expectedchar = '/';
path++;
} else if (path[1] == ':' || path[2] == '\\') {
expectedchar = '\\';
path += 3;
} else
return -1;
pathlen = (int)strlen (path);
for (i = 0; i < pathlen; i++) {
if (*path == expectedchar)
levels++;
if ((levels == levelreq) && (*path != expectedchar) && (copypnt < (max_len - 1)))
output[copypnt++] = *path;
path++;
}
output[copypnt] = '\0';
if (output[0] != '\0')
return 0;
else
return -1;
}
int fatfs_split_path (char* full_path, char* path, int max_path, char* filename, int max_filename) {
int strindex;
int levels = fatfs_total_path_levels (full_path);
if (levels == -1)
return -1;
if (fatfs_get_substring (full_path, levels, filename, max_filename) != 0)
return -1;
if (levels == 0)
path[0] = '\0';
else {
strindex = (int)strlen (full_path) - (int)strlen (filename);
if (strindex > max_path)
strindex = max_path;
memcpy (path, full_path, strindex);
path[strindex - 1] = '\0';
}
return 0;
}
static int FileString_StrCmpNoCase (char* s1, char* s2, int n) {
int diff;
char a, b;
while (n--) {
a = *s1;
b = *s2;
if ((a >= 'A') && (a <= 'Z'))
a += 32;
if ((b >= 'A') && (b <= 'Z'))
b += 32;
diff = a - b;
if (diff)
return diff;
if ((*s1 == 0) || (*s2 == 0))
break;
s1++;
s2++;
}
return 0;
}
static int FileString_GetExtension (char* str) {
int dotPos = -1;
char* strSrc = str;
while (*strSrc) {
if (*strSrc == '.')
dotPos = (int)(strSrc - str);
strSrc++;
}
return dotPos;
}
static int FileString_TrimLength (char* str, int strLen) {
int length = strLen;
char* strSrc = str + strLen - 1;
while (strLen != 0) {
if (*strSrc == ' ')
length = (int)(strSrc - str);
else
break;
strSrc--;
strLen--;
}
return length;
}
int fatfs_compare_names (char* strA, char* strB) {
char* ext1 = NULL;
char* ext2 = NULL;
int ext1Pos, ext2Pos;
int file1Len, file2Len;
ext1Pos = FileString_GetExtension (strA);
ext2Pos = FileString_GetExtension (strB);
if ((ext1Pos == -1) && (ext2Pos != -1))
return 0;
if ((ext2Pos == -1) && (ext1Pos != -1))
return 0;
if (ext1Pos != -1) {
ext1 = strA + ext1Pos + 1;
ext2 = strB + ext2Pos + 1;
if (strlen (ext1) != strlen (ext2))
return 0;
if (FileString_StrCmpNoCase (ext1, ext2, (int)strlen (ext1)) != 0)
return 0;
file1Len = ext1Pos;
file2Len = ext2Pos;
} else {
file1Len = (int)strlen (strA);
file2Len = (int)strlen (strB);
}
file1Len = FileString_TrimLength (strA, file1Len);
file2Len = FileString_TrimLength (strB, file2Len);
if (file1Len != file2Len)
return 0;
if (FileString_StrCmpNoCase (strA, strB, file1Len) != 0)
return 0;
else
return 1;
}
int fatfs_string_ends_with_slash (char* path) {
if (path) {
while (*path) {
if (!(*(path + 1))) {
if (*path == '\\' || *path == '/')
return 1;
}
path++;
}
}
return 0;
}
int fatfs_get_sfn_display_name (char* out, char* in) {
int len = 0;
while (*in && len <= 11) {
char a = *in++;
if (a == ' ')
continue;
else if ((a >= 'A') && (a <= 'Z'))
a += 32;
*out++ = a;
len++;
}
*out = '\0';
return 1;
}
int fatfs_get_extension (char* filename, char* out, int maxlen) {
int len = 0;
int ext_pos = FileString_GetExtension (filename);
if (ext_pos > 0 && out && maxlen) {
filename += ext_pos + 1;
while (*filename && len < (maxlen - 1)) {
char a = *filename++;
if ((a >= 'A') && (a <= 'Z'))
a += 32;
*out++ = a;
len++;
}
*out = '\0';
return 1;
}
return 0;
}
int fatfs_create_path_string (char* path, char* filename, char* out, int maxlen) {
int len = 0;
char last = 0;
char seperator = '/';
if (path && filename && out && maxlen > 0) {
while (*path && len < (maxlen - 2)) {
last = *path++;
if (last == '\\')
seperator = '\\';
*out++ = last;
len++;
}
if (last != '\\' && last != '/')
*out++ = seperator;
while (*filename && len < (maxlen - 1)) {
*out++ = *filename++;
len++;
}
*out = '\0';
return 1;
}
return 0;
}
#define CHECK_FL_INIT(ctx) \
{ \
if (ctx->_filelib_init == 0) \
fl_init (ctx); \
}
#define FL_LOCK(a) \
do { \
if ((a)->fl_lock) \
(a)->fl_lock (); \
} while (0)
#define FL_UNLOCK(a) \
do { \
if ((a)->fl_unlock) \
(a)->fl_unlock (); \
} while (0)
void fl_init (struct fatfs_ctx* ctx);
static FL_FILE* _allocate_file (struct fatfs_ctx* ctx) {
struct fat_node* node = fat_list_pop_head (&ctx->_free_file_list);
if (node)
fat_list_insert_last (&ctx->_open_file_list, node);
return fat_list_entry (node, FL_FILE, list_node);
}
static int _check_file_open (struct fatfs_ctx* ctx, FL_FILE* file) {
struct fat_node* node;
fat_list_for_each (&ctx->_open_file_list, node) {
FL_FILE* openFile = fat_list_entry (node, FL_FILE, list_node);
if (openFile != file) {
if ((fatfs_compare_names (openFile->path, file->path)) &&
(fatfs_compare_names (openFile->filename, file->filename)))
return 1;
}
}
return 0;
}
static void _free_file (struct fatfs_ctx* ctx, FL_FILE* file) {
fat_list_remove (&ctx->_open_file_list, &file->list_node);
fat_list_insert_last (&ctx->_free_file_list, &file->list_node);
}
static int _open_directory (struct fatfs_ctx* ctx, char* path, uint32* pathCluster) {
int levels;
int sublevel;
char currentfolder[FATFS_MAX_LONG_FILENAME];
struct fat_dir_entry sfEntry;
uint32 startcluster;
startcluster = fatfs_get_root_cluster (&ctx->_fs);
levels = fatfs_total_path_levels (path);
for (sublevel = 0; sublevel < (levels + 1); sublevel++) {
if (fatfs_get_substring (path, sublevel, currentfolder, sizeof (currentfolder)) == -1)
return 0;
if (fatfs_get_file_entry (ctx, &ctx->_fs, startcluster, currentfolder, &sfEntry)) {
if (fatfs_entry_is_dir (&sfEntry))
startcluster =
((FAT_HTONS ((uint32)sfEntry.FstClusHI)) << 16) + FAT_HTONS (sfEntry.FstClusLO);
else
return 0;
} else
return 0;
}
*pathCluster = startcluster;
return 1;
}
static int _create_directory (struct fatfs_ctx* ctx, char* path) {
FL_FILE* file;
struct fat_dir_entry sfEntry;
char shortFilename[FAT_SFN_SIZE_FULL];
int tailNum = 0;
int i;
file = _allocate_file (ctx);
if (!file)
return 0;
memset (file->path, '\0', sizeof (file->path));
memset (file->filename, '\0', sizeof (file->filename));
if (fatfs_split_path ((char*)path, file->path, sizeof (file->path), file->filename,
sizeof (file->filename)) == -1) {
_free_file (ctx, file);
return 0;
}
if (_check_file_open (ctx, file)) {
_free_file (ctx, file);
return 0;
}
if (file->path[0] == 0)
file->parentcluster = fatfs_get_root_cluster (&ctx->_fs);
else {
if (!_open_directory (ctx, file->path, &file->parentcluster)) {
_free_file (ctx, file);
return 0;
}
}
if (fatfs_get_file_entry (ctx, &ctx->_fs, file->parentcluster, file->filename, &sfEntry) == 1) {
_free_file (ctx, file);
return 0;
}
file->startcluster = 0;
if (!fatfs_allocate_free_space (ctx, &ctx->_fs, 1, &file->startcluster, 1)) {
_free_file (ctx, file);
return 0;
}
memset (file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
for (i = 0; i < ctx->_fs.sectors_per_cluster; i++) {
if (!fatfs_write_sector (ctx, &ctx->_fs, file->startcluster, i, file->file_data_sector)) {
_free_file (ctx, file);
return 0;
}
}
tailNum = 0;
do {
fatfs_lfn_create_sfn (shortFilename, file->filename);
if (tailNum != 0)
fatfs_lfn_generate_tail ((char*)file->shortfilename, shortFilename, tailNum);
else
memcpy (file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
if (fatfs_sfn_exists (ctx, &ctx->_fs, file->parentcluster, (char*)file->shortfilename) == 0)
break;
tailNum++;
} while (tailNum < 9999);
if (tailNum == 9999) {
fatfs_free_cluster_chain (ctx, &ctx->_fs, file->startcluster);
_free_file (ctx, file);
return 0;
}
if (!fatfs_add_file_entry (ctx, &ctx->_fs, file->parentcluster, (char*)file->filename,
(char*)file->shortfilename, file->startcluster, 0, 1)) {
fatfs_free_cluster_chain (ctx, &ctx->_fs, file->startcluster);
_free_file (ctx, file);
return 0;
}
file->filelength = 0;
file->bytenum = 0;
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
file->filelength_changed = 0;
file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
fatfs_fat_purge (ctx, &ctx->_fs);
_free_file (ctx, file);
return 1;
}
static FL_FILE* _open_file (struct fatfs_ctx* ctx, const char* path) {
FL_FILE* file;
struct fat_dir_entry sfEntry;
file = _allocate_file (ctx);
if (!file)
return NULL;
memset (file->path, '\0', sizeof (file->path));
memset (file->filename, '\0', sizeof (file->filename));
if (fatfs_split_path ((char*)path, file->path, sizeof (file->path), file->filename,
sizeof (file->filename)) == -1) {
_free_file (ctx, file);
return NULL;
}
if (_check_file_open (ctx, file)) {
_free_file (ctx, file);
return NULL;
}
if (file->path[0] == 0)
file->parentcluster = fatfs_get_root_cluster (&ctx->_fs);
else {
if (!_open_directory (ctx, file->path, &file->parentcluster)) {
_free_file (ctx, file);
return NULL;
}
}
if (fatfs_get_file_entry (ctx, &ctx->_fs, file->parentcluster, file->filename, &sfEntry))
if (fatfs_entry_is_file (&sfEntry)) {
memcpy (file->shortfilename, sfEntry.Name, FAT_SFN_SIZE_FULL);
file->filelength = FAT_HTONL (sfEntry.FileSize);
file->bytenum = 0;
file->startcluster =
((FAT_HTONS ((uint32)sfEntry.FstClusHI)) << 16) + FAT_HTONS (sfEntry.FstClusLO);
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
file->filelength_changed = 0;
file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
fatfs_cache_init (&ctx->_fs, file);
fatfs_fat_purge (ctx, &ctx->_fs);
return file;
}
_free_file (ctx, file);
return NULL;
}
static FL_FILE* _create_file (struct fatfs_ctx* ctx, const char* filename) {
FL_FILE* file;
struct fat_dir_entry sfEntry;
char shortFilename[FAT_SFN_SIZE_FULL];
int tailNum = 0;
if (!ctx->_fs.disk_io.write_media)
return NULL;
file = _allocate_file (ctx);
if (!file)
return NULL;
memset (file->path, '\0', sizeof (file->path));
memset (file->filename, '\0', sizeof (file->filename));
if (fatfs_split_path ((char*)filename, file->path, sizeof (file->path), file->filename,
sizeof (file->filename)) == -1) {
_free_file (ctx, file);
return NULL;
}
if (_check_file_open (ctx, file)) {
_free_file (ctx, file);
return NULL;
}
if (file->path[0] == 0)
file->parentcluster = fatfs_get_root_cluster (&ctx->_fs);
else {
if (!_open_directory (ctx, file->path, &file->parentcluster)) {
_free_file (ctx, file);
return NULL;
}
}
if (fatfs_get_file_entry (ctx, &ctx->_fs, file->parentcluster, file->filename, &sfEntry) == 1) {
_free_file (ctx, file);
return NULL;
}
file->startcluster = 0;
if (!fatfs_allocate_free_space (ctx, &ctx->_fs, 1, &file->startcluster, 1)) {
_free_file (ctx, file);
return NULL;
}
tailNum = 0;
do {
fatfs_lfn_create_sfn (shortFilename, file->filename);
if (tailNum != 0)
fatfs_lfn_generate_tail ((char*)file->shortfilename, shortFilename, tailNum);
else
memcpy (file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
if (fatfs_sfn_exists (ctx, &ctx->_fs, file->parentcluster, (char*)file->shortfilename) == 0)
break;
tailNum++;
} while (tailNum < 9999);
if (tailNum == 9999) {
fatfs_free_cluster_chain (ctx, &ctx->_fs, file->startcluster);
_free_file (ctx, file);
return NULL;
}
if (!fatfs_add_file_entry (ctx, &ctx->_fs, file->parentcluster, (char*)file->filename,
(char*)file->shortfilename, file->startcluster, 0, 0)) {
fatfs_free_cluster_chain (ctx, &ctx->_fs, file->startcluster);
_free_file (ctx, file);
return NULL;
}
file->filelength = 0;
file->bytenum = 0;
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
file->filelength_changed = 0;
file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
fatfs_cache_init (&ctx->_fs, file);
fatfs_fat_purge (ctx, &ctx->_fs);
return file;
}
static uint32 _read_sectors (struct fatfs_ctx* ctx, FL_FILE* file, uint32 offset, uint8* buffer,
uint32 count) {
uint32 Sector = 0;
uint32 ClusterIdx = 0;
uint32 Cluster = 0;
uint32 i;
uint32 lba;
ClusterIdx = offset / ctx->_fs.sectors_per_cluster;
Sector = offset - (ClusterIdx * ctx->_fs.sectors_per_cluster);
if ((Sector + count) > ctx->_fs.sectors_per_cluster)
count = ctx->_fs.sectors_per_cluster - Sector;
if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
Cluster = file->last_fat_lookup.CurrentCluster;
else {
if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1) {
i = file->last_fat_lookup.ClusterIdx;
Cluster = file->last_fat_lookup.CurrentCluster;
} else {
i = 0;
Cluster = file->startcluster;
}
for (; i < ClusterIdx; i++) {
uint32 nextCluster;
if (!fatfs_cache_get_next_cluster (&ctx->_fs, file, i, &nextCluster)) {
nextCluster = fatfs_find_next_cluster (ctx, &ctx->_fs, Cluster);
fatfs_cache_set_next_cluster (&ctx->_fs, file, i, nextCluster);
}
Cluster = nextCluster;
}
if (Cluster != FAT32_LAST_CLUSTER) {
file->last_fat_lookup.CurrentCluster = Cluster;
file->last_fat_lookup.ClusterIdx = ClusterIdx;
}
}
if (Cluster == FAT32_LAST_CLUSTER)
return 0;
lba = fatfs_lba_of_cluster (&ctx->_fs, Cluster) + Sector;
if (fatfs_sector_read (ctx, &ctx->_fs, lba, buffer, count))
return count;
else
return 0;
}
void fl_init (struct fatfs_ctx* ctx) {
int i;
fat_list_init (&ctx->_free_file_list);
fat_list_init (&ctx->_open_file_list);
for (i = 0; i < FATFS_MAX_OPEN_FILES; i++)
fat_list_insert_last (&ctx->_free_file_list, &ctx->_files[i].list_node);
ctx->_filelib_init = 1;
}
void fl_attach_locks (struct fatfs_ctx* ctx, void (*lock) (void), void (*unlock) (void)) {
ctx->_fs.fl_lock = lock;
ctx->_fs.fl_unlock = unlock;
}
int fl_attach_media (struct fatfs_ctx* ctx, fn_diskio_read rd, fn_diskio_write wr) {
int res;
CHECK_FL_INIT (ctx);
ctx->_fs.disk_io.read_media = rd;
ctx->_fs.disk_io.write_media = wr;
if ((res = fatfs_init (ctx, &ctx->_fs)) != FAT_INIT_OK) {
FAT_PRINTF (("FAT_FS: Error could not load FAT details (%d)!\r\n", res));
return res;
}
ctx->_filelib_valid = 1;
return FAT_INIT_OK;
}
void fl_shutdown (struct fatfs_ctx* ctx) {
CHECK_FL_INIT (ctx);
FL_LOCK (&ctx->_fs);
fatfs_fat_purge (ctx, &ctx->_fs);
FL_UNLOCK (&ctx->_fs);
}
void* fl_fopen (struct fatfs_ctx* ctx, const char* path, const char* mode) {
int i;
FL_FILE* file;
uint8 flags = 0;
CHECK_FL_INIT (ctx);
if (!ctx->_filelib_valid)
return NULL;
if (!path || !mode)
return NULL;
for (i = 0; i < (int)strlen (mode); i++) {
switch (mode[i]) {
case 'r':
case 'R':
flags |= FILE_READ;
break;
case 'w':
case 'W':
flags |= FILE_WRITE;
flags |= FILE_ERASE;
flags |= FILE_CREATE;
break;
case 'a':
case 'A':
flags |= FILE_WRITE;
flags |= FILE_APPEND;
flags |= FILE_CREATE;
break;
case '+':
if (flags & FILE_READ)
flags |= FILE_WRITE;
else if (flags & FILE_WRITE) {
flags |= FILE_READ;
flags |= FILE_ERASE;
flags |= FILE_CREATE;
} else if (flags & FILE_APPEND) {
flags |= FILE_READ;
flags |= FILE_WRITE;
flags |= FILE_APPEND;
flags |= FILE_CREATE;
}
break;
case 'b':
case 'B':
flags |= FILE_BINARY;
break;
}
}
file = NULL;
if (!ctx->_fs.disk_io.write_media)
flags &= ~(FILE_CREATE | FILE_WRITE | FILE_APPEND);
FL_LOCK (&ctx->_fs);
if (flags & FILE_READ)
file = _open_file (ctx, path);
if (!file && (flags & FILE_CREATE))
file = _create_file (ctx, path);
if (!(flags & FILE_READ))
if ((flags & FILE_CREATE) && !file)
if (flags & (FILE_WRITE | FILE_APPEND))
file = _open_file (ctx, path);
if (file)
file->flags = flags;
FL_UNLOCK (&ctx->_fs);
return file;
}
static uint32 _write_sectors (struct fatfs_ctx* ctx, FL_FILE* file, uint32 offset, uint8* buf,
uint32 count) {
uint32 SectorNumber = 0;
uint32 ClusterIdx = 0;
uint32 Cluster = 0;
uint32 LastCluster = FAT32_LAST_CLUSTER;
uint32 i;
uint32 lba;
uint32 TotalWriteCount = count;
ClusterIdx = offset / ctx->_fs.sectors_per_cluster;
SectorNumber = offset - (ClusterIdx * ctx->_fs.sectors_per_cluster);
if ((SectorNumber + count) > ctx->_fs.sectors_per_cluster)
count = ctx->_fs.sectors_per_cluster - SectorNumber;
if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
Cluster = file->last_fat_lookup.CurrentCluster;
else {
if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1) {
i = file->last_fat_lookup.ClusterIdx;
Cluster = file->last_fat_lookup.CurrentCluster;
} else {
i = 0;
Cluster = file->startcluster;
}
for (; i < ClusterIdx; i++) {
uint32 nextCluster;
if (!fatfs_cache_get_next_cluster (&ctx->_fs, file, i, &nextCluster)) {
nextCluster = fatfs_find_next_cluster (ctx, &ctx->_fs, Cluster);
fatfs_cache_set_next_cluster (&ctx->_fs, file, i, nextCluster);
}
LastCluster = Cluster;
Cluster = nextCluster;
if (Cluster == FAT32_LAST_CLUSTER)
break;
}
if (Cluster == FAT32_LAST_CLUSTER) {
if (!fatfs_add_free_space (ctx, &ctx->_fs, &LastCluster,
(TotalWriteCount + ctx->_fs.sectors_per_cluster - 1) /
ctx->_fs.sectors_per_cluster))
return 0;
Cluster = LastCluster;
}
file->last_fat_lookup.CurrentCluster = Cluster;
file->last_fat_lookup.ClusterIdx = ClusterIdx;
}
lba = fatfs_lba_of_cluster (&ctx->_fs, Cluster) + SectorNumber;
if (fatfs_sector_write (ctx, &ctx->_fs, lba, buf, count))
return count;
else
return 0;
}
int fl_fflush (struct fatfs_ctx* ctx, void* f) {
FL_FILE* file = (FL_FILE*)f;
CHECK_FL_INIT (ctx);
if (file) {
FL_LOCK (&ctx->_fs);
if (file->file_data_dirty) {
if (_write_sectors (ctx, file, file->file_data_address, file->file_data_sector, 1))
file->file_data_dirty = 0;
}
FL_UNLOCK (&ctx->_fs);
}
return 0;
}
void fl_fclose (struct fatfs_ctx* ctx, void* f) {
FL_FILE* file = (FL_FILE*)f;
CHECK_FL_INIT (ctx);
if (file) {
FL_LOCK (&ctx->_fs);
fl_fflush (ctx, f);
if (file->filelength_changed) {
fatfs_update_file_length (ctx, &ctx->_fs, file->parentcluster, (char*)file->shortfilename,
file->filelength);
file->filelength_changed = 0;
}
file->bytenum = 0;
file->filelength = 0;
file->startcluster = 0;
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
file->filelength_changed = 0;
_free_file (ctx, file);
fatfs_fat_purge (ctx, &ctx->_fs);
FL_UNLOCK (&ctx->_fs);
}
}
int fl_fgetc (struct fatfs_ctx* ctx, void* f) {
int res;
uint8 data = 0;
res = fl_fread (ctx, &data, 1, 1, f);
if (res == 1)
return (int)data;
else
return res;
}
char* fl_fgets (struct fatfs_ctx* ctx, char* s, int n, void* f) {
int idx = 0;
if (n > 0) {
while (idx < (n - 1)) {
int ch = fl_fgetc (ctx, f);
if (ch < 0)
break;
s[idx++] = (char)ch;
if (ch == '\n')
break;
}
if (idx > 0)
s[idx] = '\0';
}
return (idx > 0) ? s : 0;
}
int fl_fread (struct fatfs_ctx* ctx, void* buffer, int size, int length, void* f) {
uint32 sector;
uint32 offset;
int copyCount;
int count = size * length;
int bytesRead = 0;
FL_FILE* file = (FL_FILE*)f;
CHECK_FL_INIT (ctx);
if (buffer == NULL || file == NULL)
return -1;
if (!(file->flags & FILE_READ))
return -1;
if (!count)
return 0;
if (file->bytenum >= file->filelength)
return -1;
if ((file->bytenum + count) > file->filelength)
count = file->filelength - file->bytenum;
sector = file->bytenum / FAT_SECTOR_SIZE;
offset = file->bytenum % FAT_SECTOR_SIZE;
while (bytesRead < count) {
if ((offset == 0) && ((count - bytesRead) >= FAT_SECTOR_SIZE)) {
uint32 sectorsRead = _read_sectors (ctx, file, sector, (uint8*)((uint8*)buffer + bytesRead),
(count - bytesRead) / FAT_SECTOR_SIZE);
if (sectorsRead) {
copyCount = FAT_SECTOR_SIZE * sectorsRead;
sector += sectorsRead;
offset = 0;
} else
break;
} else {
if (file->file_data_address != sector) {
if (file->file_data_dirty)
fl_fflush (ctx, file);
if (!_read_sectors (ctx, file, sector, file->file_data_sector, 1))
break;
file->file_data_address = sector;
file->file_data_dirty = 0;
}
copyCount = FAT_SECTOR_SIZE - offset;
if (copyCount > (count - bytesRead))
copyCount = (count - bytesRead);
memcpy ((uint8*)((uint8*)buffer + bytesRead), (uint8*)(file->file_data_sector + offset),
copyCount);
sector++;
offset = 0;
}
bytesRead += copyCount;
file->bytenum += copyCount;
}
return bytesRead;
}
int fl_fseek (struct fatfs_ctx* ctx, void* f, long offset, int origin) {
FL_FILE* file = (FL_FILE*)f;
int res = -1;
CHECK_FL_INIT (ctx);
if (!file)
return -1;
if (origin == SEEK_END && offset != 0)
return -1;
FL_LOCK (&ctx->_fs);
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
if (origin == SEEK_SET) {
file->bytenum = (uint32)offset;
if (file->bytenum > file->filelength)
file->bytenum = file->filelength;
res = 0;
} else if (origin == SEEK_CUR) {
if (offset >= 0) {
file->bytenum += offset;
if (file->bytenum > file->filelength)
file->bytenum = file->filelength;
} else {
offset = -offset;
if ((uint32)offset > file->bytenum)
file->bytenum = 0;
else
file->bytenum -= offset;
}
res = 0;
} else if (origin == SEEK_END) {
file->bytenum = file->filelength;
res = 0;
} else
res = -1;
FL_UNLOCK (&ctx->_fs);
return res;
}
int fl_fgetpos (struct fatfs_ctx* ctx, void* f, uint32* position) {
FL_FILE* file = (FL_FILE*)f;
if (!file)
return -1;
FL_LOCK (&ctx->_fs);
*position = file->bytenum;
FL_UNLOCK (&ctx->_fs);
return 0;
}
long fl_ftell (struct fatfs_ctx* ctx, void* f) {
uint32 pos = 0;
fl_fgetpos (ctx, f, &pos);
return (long)pos;
}
int fl_feof (struct fatfs_ctx* ctx, void* f) {
FL_FILE* file = (FL_FILE*)f;
int res;
if (!file)
return -1;
FL_LOCK (&ctx->_fs);
if (file->bytenum == file->filelength)
res = EOF;
else
res = 0;
FL_UNLOCK (&ctx->_fs);
return res;
}
int fl_fputc (struct fatfs_ctx* ctx, int c, void* f) {
uint8 data = (uint8)c;
int res;
res = fl_fwrite (ctx, &data, 1, 1, f);
if (res == 1)
return c;
else
return res;
}
int fl_fwrite (struct fatfs_ctx* ctx, const void* data, int size, int count, void* f) {
FL_FILE* file = (FL_FILE*)f;
uint32 sector;
uint32 offset;
uint32 length = (size * count);
uint8* buffer = (uint8*)data;
uint32 bytesWritten = 0;
uint32 copyCount;
CHECK_FL_INIT (ctx);
if (!file)
return -1;
FL_LOCK (&ctx->_fs);
if (!(file->flags & FILE_WRITE)) {
FL_UNLOCK (&ctx->_fs);
return -1;
}
if (file->flags & FILE_APPEND)
file->bytenum = file->filelength;
sector = file->bytenum / FAT_SECTOR_SIZE;
offset = file->bytenum % FAT_SECTOR_SIZE;
while (bytesWritten < length) {
if ((offset == 0) && ((length - bytesWritten) >= FAT_SECTOR_SIZE)) {
uint32 sectorsWrote;
if (file->file_data_address != 0xFFFFFFFF) {
if (file->file_data_dirty)
fl_fflush (ctx, file);
file->file_data_address = 0xFFFFFFFF;
file->file_data_dirty = 0;
}
sectorsWrote = _write_sectors (ctx, file, sector, (uint8*)(buffer + bytesWritten),
(length - bytesWritten) / FAT_SECTOR_SIZE);
copyCount = FAT_SECTOR_SIZE * sectorsWrote;
bytesWritten += copyCount;
file->bytenum += copyCount;
sector += sectorsWrote;
offset = 0;
if (!sectorsWrote)
break;
} else {
copyCount = FAT_SECTOR_SIZE - offset;
if (copyCount > (length - bytesWritten))
copyCount = (length - bytesWritten);
if (file->file_data_address != sector) {
if (file->file_data_dirty)
fl_fflush (ctx, file);
if (copyCount != FAT_SECTOR_SIZE) {
if (!_read_sectors (ctx, file, sector, file->file_data_sector, 1))
memset (file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
}
file->file_data_address = sector;
file->file_data_dirty = 0;
}
memcpy ((uint8*)(file->file_data_sector + offset), (uint8*)(buffer + bytesWritten),
copyCount);
file->file_data_dirty = 1;
bytesWritten += copyCount;
file->bytenum += copyCount;
sector++;
offset = 0;
}
}
if (file->bytenum > file->filelength) {
file->filelength = file->bytenum;
file->filelength_changed = 1;
}
FL_UNLOCK (&ctx->_fs);
return (size * count);
}
int fl_fputs (struct fatfs_ctx* ctx, const char* str, void* f) {
int len = (int)strlen (str);
int res = fl_fwrite (ctx, str, 1, len, f);
if (res == len)
return len;
else
return res;
}
int fl_remove (struct fatfs_ctx* ctx, const char* filename) {
FL_FILE* file;
int res = -1;
FL_LOCK (&ctx->_fs);
file = (FL_FILE*)fl_fopen (ctx, (char*)filename, "r");
if (file) {
if (fatfs_free_cluster_chain (ctx, &ctx->_fs, file->startcluster)) {
if (fatfs_mark_file_deleted (ctx, &ctx->_fs, file->parentcluster,
(char*)file->shortfilename)) {
fl_fclose (ctx, file);
res = 0;
}
}
}
FL_UNLOCK (&ctx->_fs);
return res;
}
int fl_createdirectory (struct fatfs_ctx* ctx, const char* path) {
int res;
CHECK_FL_INIT (ctx);
FL_LOCK (&ctx->_fs);
res = _create_directory (ctx, (char*)path);
FL_UNLOCK (&ctx->_fs);
return res;
}
void fl_listdirectory (struct fatfs_ctx* ctx, const char* path) {
FL_DIR dirstat;
CHECK_FL_INIT (ctx);
FL_LOCK (&ctx->_fs);
FAT_PRINTF (("\r\nDirectory %s\r\n", path));
if (fl_opendir (ctx, path, &dirstat)) {
struct fs_dir_ent dirent;
while (fl_readdir (ctx, &dirstat, &dirent) == 0) {
if (dirent.is_dir) {
FAT_PRINTF (("%s <DIR>\r\n", dirent.filename));
} else {
FAT_PRINTF (("%s [%d bytes]\r\n", dirent.filename, dirent.size));
}
}
fl_closedir (ctx, &dirstat);
}
FL_UNLOCK (&ctx->_fs);
}
FL_DIR* fl_opendir (struct fatfs_ctx* ctx, const char* path, FL_DIR* dir) {
int levels;
int res = 1;
uint32 cluster = FAT32_INVALID_CLUSTER;
CHECK_FL_INIT (ctx);
FL_LOCK (&ctx->_fs);
levels = fatfs_total_path_levels ((char*)path) + 1;
if (levels == 0)
cluster = fatfs_get_root_cluster (&ctx->_fs);
else
res = _open_directory (ctx, (char*)path, &cluster);
if (res)
fatfs_list_directory_start (&ctx->_fs, dir, cluster);
FL_UNLOCK (&ctx->_fs);
return cluster != FAT32_INVALID_CLUSTER ? dir : 0;
}
int fl_readdir (struct fatfs_ctx* ctx, FL_DIR* dirls, fl_dirent* entry) {
int res = 0;
CHECK_FL_INIT (ctx);
FL_LOCK (&ctx->_fs);
res = fatfs_list_directory_next (ctx, &ctx->_fs, dirls, entry);
FL_UNLOCK (&ctx->_fs);
return res ? 0 : -1;
}
int fl_closedir (struct fatfs_ctx* ctx, FL_DIR* dir) { return 0; }
int fl_is_dir (struct fatfs_ctx* ctx, const char* path) {
int res = 0;
FL_DIR dir;
if (fl_opendir (ctx, path, &dir)) {
res = 1;
fl_closedir (ctx, &dir);
}
return res;
}
int fl_format (struct fatfs_ctx* ctx, uint32 volume_sectors, const char* name) {
return fatfs_format (ctx, &ctx->_fs, volume_sectors, name);
}
#pragma clang diagnostic pop