Skip to content

Commit 9d8e3ee

Browse files
committed
Raised buffer size to 8 MiB for large cards.
Added experimental exFAT support.
1 parent 2952644 commit 9d8e3ee

File tree

16 files changed

+1107
-232
lines changed

16 files changed

+1107
-232
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
Unfortunately SDFormatter isn't available for Linux so i made this. It is a tool to format your SD card the way the SD Association intended but under Linux.
33

44
Multiple SD cards with different capacities have been tested and this tool formats them 1:1 the same as SDFormatter with the following exceptions:
5-
* SDFormatter does not set the jmp instruction offset in the boot sector. sdFormatLinux does.
6-
* sdFormatLinux does not support exFAT right now.
5+
* SDFormatter does not set the jmp instruction offset in the boot sector for FAT12/16/32. sdFormatLinux does.
6+
* For exFAT sdFormatLinux clears unused FAT entries SDFormatter leaves untouched and SDFormatter clears more areas after root directory cluster. As far as i can tell these differences don't matter.
7+
* sdFormatLinux currently does not preserve OEM flash parameters when reformatting in exFAT. It will recalculate the correct values instead.
78

89
## Examples
9-
Erase (TRIM) and format SD card (recommended). TRIM will not work with USB card readers and is ignored.
10+
Erase (TRIM) and format SD card (recommended). TRIM will not work with USB card readers and is ignored if used with one.
1011
`sudo sdFormatLinux -e trim /dev/mmcblkX` where X is a number.
1112

1213
Erase and format with label.

include/buffered_fs_writer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// Padding for alignment is filled with zeros (no read-modify-write).
1515
class BufferedFsWriter final : private BlockDev
1616
{
17-
static constexpr u32 m_blkSize = 1024 * 1024 * 4; // Must be >=512 and power of 2.
17+
static constexpr u32 m_blkSize = 1024 * 1024 * 8; // Must be >=512 and power of 2.
1818
static constexpr u32 m_blkMask = m_blkSize - 1;
1919
static_assert(m_blkSize > 512 && (m_blkSize & m_blkMask) == 0, "Invalid buffer size for BufferedFsWriter.");
2020

include/exfat.h

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
#include <cstddef>
66
#include "types.h"
77
#include "format.h"
8+
#include "buffered_fs_writer.h"
89

910
// References:
10-
// exFAT: https://learn.microsoft.com/en-us/windows/win32/fileio/exfat-specification
11+
// https://learn.microsoft.com/en-us/windows/win32/fileio/exfat-specification
1112

1213

1314
// Boot Sector.
@@ -21,7 +22,7 @@ typedef struct
2122
u32 fatOffset; // Minimum "24", maximum "ClusterHeapOffset - (FatLength * NumberOfFats)".
2223
u32 fatLength; // Minimum "(ClusterCount + 2) * 2^2 / 2^BytesPerSectorShift" rounded up to nearest integer, maximum "(ClusterHeapOffset - FatOffset) / NumberOfFats" rounded down to nearest integer.
2324
u32 clusterHeapOffset; // Minimum "FatOffset + FatLength * NumberOfFats", maximum "2^32 - 1" or "VolumeLength - (ClusterCount * 2^SectorsPerClusterShift)" whichever is smaller.
24-
u32 clusterCount; // Shall be the lesser of "(VolumeLength - ClusterHeapOffset) / 2^SectorsPerClusterShiftrounded down to the nearest integer" or "2^32 - 11". Recommended no more than "2^24 - 2".
25+
u32 clusterCount; // Shall be the lesser of "(VolumeLength - ClusterHeapOffset) / 2^SectorsPerClusterShift rounded down to the nearest integer" or "2^32 - 11". Recommended no more than "2^24 - 2".
2526
u32 firstClusterOfRootDirectory; // Minimum "2", maximum "ClusterCount + 1".
2627
u32 volumeSerialNumber; // Volume serial number generated from date and time.
2728
u16 fileSystemRevision; // versionHigh<<8 | (u8)versionLow. Version high 1-99, versionLow 0-99. Usually 1.00.
@@ -35,16 +36,99 @@ typedef struct
3536
u8 bootCode[390]; // Bootstrapping code or 0xF4 filled (x86 halt).
3637
u16 bootSignature; // 0xAA55.
3738
//u8 excessSpace[(1u<<bytesPerSectorShift) - 512];
38-
} BootSector;
39-
static_assert(offsetof(BootSector, bootSignature) == 510, "Member bootSignature of BootSector not at offsetof 510.");
39+
} ExfatBootSec;
40+
static_assert(offsetof(ExfatBootSec, bootSignature) == 510, "Member bootSignature of ExfatBootSec not at offsetof 510.");
4041

41-
// Extended Boot Sector.
42-
/*typedef struct
42+
typedef struct
43+
{
44+
u8 guid[16]; // {0A0C7E46-3399-4021-90C8-FA6D389C4BA2} (467E0C0A 9933 2140 90C8 FA6D389C4BA2 in memory).
45+
u32 eraseBlockSize;
46+
u32 pageSize;
47+
u32 spareSectors;
48+
u32 randomAccessTime;
49+
u32 programmingTime;
50+
u32 readCycle;
51+
u32 writeCycle;
52+
u32 reserved;
53+
} FlashParameters;
54+
static_assert(offsetof(FlashParameters, reserved) == 44, "Member reserved of FlashParameters not at offsetof 44.");
55+
56+
typedef struct
4357
{
44-
u8 extendedBootCode[(1u<<bytesPerSectorShift) - 4];
45-
u32 extendedBootSignature; // 0xAA550000.
46-
} ExtendedBootSector;*/
58+
u8 entryType;
59+
union
60+
{
61+
struct __attribute__((packed))
62+
{
63+
u8 bitmapFlags;
64+
u8 reserved[18];
65+
u32 firstCluster;
66+
u64 dataLength;
67+
} bitmap;
68+
struct __attribute__((packed))
69+
{
70+
u8 reserved1[3];
71+
u32 tableChecksum;
72+
u8 reserved2[12];
73+
u32 firstCluster;
74+
u64 dataLength;
75+
} upCase;
76+
struct __attribute__((packed))
77+
{
78+
u8 characterCount;
79+
u16 volumeLabel[11];
80+
u8 reserved[8];
81+
} label;
82+
// TODO: Other entry types.
83+
};
84+
} ExfatDirEnt;
85+
static_assert(sizeof(ExfatDirEnt) == 32, "ExfatDirEnt is not 32 bytes.");
86+
87+
88+
// Boot Sector.
89+
#define BS_JUMP_BOOT "\xEB\x76\x90"
90+
#define BS_FILE_SYS_NAME "EXFAT "
91+
#define BS_FILE_SYS_REV_1_00 (1u<<8 | 0) // 1.00.
92+
#define BS_DRIVE_SELECT (0x80u)
93+
#define BS_BOOT_SIG (0xAA55u)
94+
95+
// Extended Boot Sectors.
96+
#define EBS_EXT_BOOT_SIG (0xAA550000u)
97+
98+
// OEM Parameters.
99+
#define OEM_FLASH_PARAMS_GUID "\x46\x7E\x0C\x0A\x99\x33\x21\x40\x90\xC8\xFA\x6D\x38\x9C\x4B\xA2"
100+
101+
// File Allocation Table.
102+
#define EXFAT_FIRST_ENT (2u) // Index 0 and 1 are reserved.
103+
#define EXFAT_MAX_CLUS (0xFFFFFFF5u) // "2^32 - 11, which is the maximum number of clusters a FAT can describe"
104+
105+
#define EXFAT_FREE (0u)
106+
#define EXFAT_BAD (0xFFFFFFF7u)
107+
#define EXFAT_RESERVED (0xFFFFFFF8u)
108+
#define EXFAT_EOF (0xFFFFFFFFu)
109+
110+
// Directory Entry.
111+
// Bits 0-4 TypeCode.
112+
#define TYPE_IMPORTANCE_CRITICAL (0u)
113+
#define TYPE_IMPORTANCE_BENIGN (1u<<5)
114+
#define TYPE_CATEGORY_PRIMARY (0u)
115+
#define TYPE_CATEGORY_SECONDARY (1u<<6)
116+
#define TYPE_IN_USE (1u<<7)
117+
118+
#define TYPE_END_OF_DIR ( TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 0u)
119+
#define TYPE_INVALID (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 0u)
120+
#define TYPE_BITMAP (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 1u)
121+
#define TYPE_UP_CASE (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 2u)
122+
#define TYPE_VOL_LABEL (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 3u)
123+
#define TYPE_FILE (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_CRITICAL | 5u) // Or directory.
124+
#define TYPE_GUID (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_BENIGN | 0u)
125+
#define TYPE_TEXFAT_PADDING (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_BENIGN | 1u)
126+
#define TYPE_WIN_CE_ACT (TYPE_IN_USE | TYPE_CATEGORY_PRIMARY | TYPE_IMPORTANCE_BENIGN | 2u)
127+
#define TYPE_STREAM (TYPE_IN_USE | TYPE_CATEGORY_SECONDARY | TYPE_IMPORTANCE_CRITICAL | 0u)
128+
#define TYPE_NAME (TYPE_IN_USE | TYPE_CATEGORY_SECONDARY | TYPE_IMPORTANCE_CRITICAL | 1u)
129+
#define TYPE_WIN_CE_AC (TYPE_IN_USE | TYPE_CATEGORY_SECONDARY | TYPE_IMPORTANCE_CRITICAL | 2u)
47130

48131

49132

50133
void calcFormatExFat(FormatParams &params);
134+
int makeFsExFat(const FormatParams &params, BufferedFsWriter &dev, const std::u16string &label);

0 commit comments

Comments
 (0)