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