#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" #include #include #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 \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