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