Skip to content

Commit 7fb8c08

Browse files
committed
Added missing copyright line to every license header.
Fixed a bug that was causing garbage volume labels when no volume label was specified. Corrected details in the README and added a FAQ section. Other small fixes and code cleanup.
1 parent 22bf106 commit 7fb8c08

26 files changed

+360
-178
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Unfortunately SDFormatter [was](https://www.sdcard.org/downloads/sd-memory-card-
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:
55
* 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.
6+
* For exFAT sdFormatLinux clears the area between last FAT entry and cluster heap but SDFormatter doesn't. As far as i can tell this difference doesn't matter.
77
* sdFormatLinux currently does not preserve OEM flash parameters when reformatting in exFAT. It will recalculate the correct values instead.
88

99
## Examples
@@ -13,6 +13,14 @@ Erase (TRIM) and format SD card (recommended). TRIM will not work with USB card
1313
Erase and format with label.
1414
`sudo sdFormatLinux -l 'MY LABEL' -e trim /dev/mmcblkX`
1515

16+
Erase and format a SDXC card to FAT32 (64 KiB clusters).
17+
`sudo sdFormatLinux -e trim -f /dev/mmcblkX`
18+
19+
## FAQ
20+
**Q: Why should i format my SDXC card with this tool to FAT32 instead of using guiformat/other tools?**\
21+
A: Because most of these tools are not designed for flash based media and will format them incorrectly causing lower lifespan and performance.
22+
There is a common myth that you should only use 32 KB (actually KiB) clusters which is false. sdFormatLinux will use 64 KiB clusters when formatting SDXC cards to FAT32 and it works in every device compliant to Microsoft's FAT specification.
23+
1624
## Compiling
1725
Just run `make`. It automatically builds a hardened version.
1826

include/blockdev.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56
#include "types.h"
67

@@ -61,7 +62,7 @@ class BlockDev
6162
*
6263
* @return Returns 0 on success or errno.
6364
*/
64-
int read(u8 *buf, const u64 sector, const u64 count) const noexcept;
65+
int read(void *buf, const u64 sector, const u64 count) const noexcept;
6566

6667
/**
6768
* @brief Writes sectors to the block device.
@@ -72,7 +73,7 @@ class BlockDev
7273
*
7374
* @return Returns 0 on success or errno.
7475
*/
75-
int write(const u8 *buf, const u64 sector, const u64 count) noexcept;
76+
int write(const void *buf, const u64 sector, const u64 count) noexcept;
7677

7778
/**
7879
* @brief Perform a TRIM/erase on the whole block device.

include/buffered_fs_writer.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

5-
#include <cstring>
66
#include <memory>
77
#include <stdexcept>
88
#include "types.h"
@@ -84,7 +84,7 @@ class BufferedFsWriter final : private BlockDev
8484
*
8585
* @return Returns 0 on success or errno.
8686
*/
87-
int write(const u8 *buf, const u64 size) noexcept;
87+
int write(const void *buf, const u64 size) noexcept;
8888

8989
/**
9090
* @brief Fills until offset and writes size bytes from buf.
@@ -95,7 +95,7 @@ class BufferedFsWriter final : private BlockDev
9595
*
9696
* @return Returns 0 on success or errno.
9797
*/
98-
int fillAndWrite(const u8 *buf, const u64 offset, const u64 size) noexcept
98+
int fillAndWrite(const void *buf, const u64 offset, const u64 size) noexcept
9999
{
100100
int res = fill(offset);
101101
if(res == 0) res = write(buf, size);
@@ -111,7 +111,6 @@ class BufferedFsWriter final : private BlockDev
111111
*/
112112
int eraseAll(const bool secure = false) noexcept
113113
{
114-
//memset(m_buf.get(), 0, m_pos & m_blkMask);
115114
m_pos = 0;
116115
return BlockDev::eraseAll(secure);
117116
}

include/errors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56

67
enum

include/exfat.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ typedef struct
5353
} FlashParameters;
5454
static_assert(offsetof(FlashParameters, reserved) == 44, "Member reserved of FlashParameters not at offsetof 44.");
5555

56-
typedef struct
56+
typedef struct alignas(u64) // ARM GCC generates terrible code without alignas(u64).
5757
{
5858
u8 entryType;
5959
union
@@ -76,10 +76,50 @@ typedef struct
7676
struct __attribute__((packed))
7777
{
7878
u8 characterCount;
79-
u16 volumeLabel[11];
79+
char16_t volumeLabel[11];
8080
u8 reserved[8];
8181
} label;
82-
// TODO: Other entry types.
82+
struct __attribute__((packed))
83+
{
84+
u8 secondaryCount;
85+
u16 setChecksum;
86+
u16 fileAttributes;
87+
u8 reserved1[2];
88+
u32 createTimestamp;
89+
u32 lastModifiedTimestamp;
90+
u32 lastAccessedTimestamp;
91+
u8 create10msIncrement;
92+
u8 lastModified10msIncrement;
93+
u8 createUtcOffset;
94+
u8 lastModifiedUtcOffset;
95+
u8 lastAccessedUtcOffset;
96+
u8 reserved2[7];
97+
} file; // And directory.
98+
struct __attribute__((packed))
99+
{
100+
u8 secondaryCount;
101+
u16 setChecksum;
102+
u16 generalPrimaryFlags;
103+
u8 volumeGuid[16];
104+
u8 reserved[10];
105+
} guid;
106+
struct __attribute__((packed))
107+
{
108+
u8 generalSecondaryFlags;
109+
u8 reserved1;
110+
u8 nameLength;
111+
u16 nameHash;
112+
u8 reserved2[2];
113+
u64 validDataLength;
114+
u8 reserved3[4];
115+
u32 firstCluster;
116+
u64 dataLength;
117+
} stream;
118+
struct __attribute__((packed))
119+
{
120+
u8 generalSecondaryFlags;
121+
char16_t fileName[15];
122+
} name;
83123
};
84124
} ExfatDirEnt;
85125
static_assert(sizeof(ExfatDirEnt) == 32, "ExfatDirEnt is not 32 bytes.");

include/exfat_up_case_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56
#include "types.h"
67

78
#define UP_CASE_TABLE_CHECKSUM (0xE619D30Du)
89

910

10-
static const u16 upCaseTable[2918] =
11+
static const char16_t g_upCaseTable[2918] =
1112
{
1213
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B,
1314
0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,

include/fat.h

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56
#include <cstddef>
67
#include "types.h"
@@ -14,17 +15,17 @@
1415
// Boot sector.
1516
typedef struct __attribute__((packed))
1617
{
17-
u8 jmpBoot[3]; // {0xEB, 0xXX, 0x90} or {0xE9, 0xXX, 0xXX}.
18+
u8 jmpBoot[3]; // {0xEB, 0xXX, 0x90} or {0xE9, 0xXX, 0xXX}.
1819
char oemName[8]; // Usually system name that formatted the volume.
1920

2021
// BIOS Parameter Block.
2122
u16 bytesPerSec; // 512, 1024, 2048 or 4096. Usually 512.
22-
u8 secPerClus; // 1, 2, 4, 8, 16, 32, 64 or 128.
23+
u8 secPerClus; // 1, 2, 4, 8, 16, 32, 64 or 128.
2324
u16 rsvdSecCnt; // Must not be 0.
24-
u8 numFats; // Should be 2. 1 is also allowed.
25+
u8 numFats; // Should be 2. 1 is also allowed.
2526
u16 rootEntCnt; // 0 for FAT32.
2627
u16 totSec16; // Must be zero for FAT32.
27-
u8 media; // 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE or 0xFF. Usually 0xF8.
28+
u8 media; // 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE or 0xFF. Usually 0xF8.
2829
u16 fatSz16; // Must be zero for FAT32.
2930
u16 secPerTrk;
3031
u16 numHeads;
@@ -36,13 +37,13 @@ typedef struct __attribute__((packed))
3637
{
3738
struct __attribute__((packed)) // FAT12/FAT16.
3839
{
39-
u8 drvNum; // 0x80 or 0x00.
40-
u8 reserved1; // Must be 0. Used by Windows for dirty flag (bit 0 set = dirty).
41-
u8 bootSig; // 0x29 if one or both of the following 2 fields are non-zero.
40+
u8 drvNum; // 0x80 or 0x00.
41+
u8 reserved1; // Must be 0. Used by Windows for dirty flag (bit 0 set = dirty).
42+
u8 bootSig; // 0x29 if one or both of the following 2 fields are non-zero.
4243
u32 volId; // Volume serial number generated from date and time.
4344
char volLab[11]; // "NO NAME " or space padded label.
4445
char filSysType[8]; // "FAT12 ", "FAT16 " or "FAT ".
45-
u8 bootCode[448];
46+
u8 bootCode[448];
4647
} ebpb;
4748
struct __attribute__((packed)) // FAT32.
4849
{
@@ -52,14 +53,14 @@ typedef struct __attribute__((packed))
5253
u32 rootClus; // Should be 2 or the first non-defective cluster.
5354
u16 fsInfoSector; // Usually 1.
5455
u16 bkBootSec; // 0 or 6. Backup boot sector must be present if the later.
55-
u8 reserved[12]; // Must be 0.
56-
u8 drvNum; // 0x80 or 0x00.
57-
u8 reserved1; // Must be 0. Used by Windows for dirty flag (bit 0 set = dirty).
58-
u8 bootSig; // 0x29 if one or both of the following 2 fields are non-zero.
56+
u8 reserved[12]; // Must be 0.
57+
u8 drvNum; // 0x80 or 0x00.
58+
u8 reserved1; // Must be 0. Used by Windows for dirty flag (bit 0 set = dirty).
59+
u8 bootSig; // 0x29 if one or both of the following 2 fields are non-zero.
5960
u32 volId; // Volume serial number generated from date and time.
6061
char volLab[11]; // "NO NAME " or space padded label.
6162
char filSysType[8]; // "FAT32 ".
62-
u8 bootCode[420];
63+
u8 bootCode[420];
6364
} ebpb32;
6465
};
6566
u16 sigWord; // 0xAA55.
@@ -70,43 +71,43 @@ static_assert(offsetof(BootSec, sigWord) == 510, "Member sigWord of BootSec not
7071

7172
typedef struct
7273
{
73-
u32 leadSig; // Must be 0x41615252.
74-
u8 reserved1[480]; // Must be 0.
75-
u32 strucSig; // Must be 0x61417272.
76-
u32 freeCount; // Number of free clusters or 0xFFFFFFFF if unknown.
77-
u32 nxtFree; // First free cluster number or 0xFFFFFFFF if unknown.
78-
u8 reserved2[12]; // Must be 0.
79-
u32 trailSig; // Must be 0xAA550000.
74+
u32 leadSig; // Must be 0x41615252.
75+
u8 reserved1[480]; // Must be 0.
76+
u32 strucSig; // Must be 0x61417272.
77+
u32 freeCount; // Number of free clusters or 0xFFFFFFFF if unknown.
78+
u32 nxtFree; // First free cluster number or 0xFFFFFFFF if unknown.
79+
u8 reserved2[12]; // Must be 0.
80+
u32 trailSig; // Must be 0xAA550000.
8081
} FsInfo;
8182
static_assert(offsetof(FsInfo, trailSig) == 508, "Member trailSig of FsInfo not at offset 508.");
8283

8384
typedef struct
8485
{
85-
char name[11]; // Short file name in 8:3 format. Maximum 11 characters.
86-
u8 attr; // Attribute bitmask. ATTR_READ_ONLY 0x01, ATTR_HIDDEN 0x02, ATTR_SYSTEM 0x04, ATTR_VOLUME_ID 0x08, ATTR_DIRECTORY 0x10, ATTR_ARCHIVE 0x20.
87-
u8 ntRes; // Must be 0.
88-
u8 crtTimeTenth; // Creation time tenths of a second.
89-
u16 crtTime; // Creation time in 2 second units.
90-
u16 crtDate; // Creation date.
91-
u16 lstAccDate; // Last access date. Updated on write.
92-
u16 fstClusHi; // High u16 of first data cluster. Must be 0 for FAT12/16.
93-
u16 wrtTime; // Last (modification) write time.
94-
u16 wrtDate; // Last (modification) write date.
95-
u16 fstClusLo; // Low u16 of first data cluster.
96-
u32 fileSize; // File/directory size in bytes.
86+
char name[11]; // Short file name in 8:3 format. Maximum 11 characters.
87+
u8 attr; // Attribute bitmask. ATTR_READ_ONLY 0x01, ATTR_HIDDEN 0x02, ATTR_SYSTEM 0x04, ATTR_VOLUME_ID 0x08, ATTR_DIRECTORY 0x10, ATTR_ARCHIVE 0x20.
88+
u8 ntRes; // Must be 0.
89+
u8 crtTimeTenth; // Creation time tenths of a second.
90+
u16 crtTime; // Creation time in 2 second units.
91+
u16 crtDate; // Creation date.
92+
u16 lstAccDate; // Last access date. Updated on write.
93+
u16 fstClusHi; // High u16 of first data cluster. Must be 0 for FAT12/16.
94+
u16 wrtTime; // Last (modification) write time.
95+
u16 wrtDate; // Last (modification) write date.
96+
u16 fstClusLo; // Low u16 of first data cluster.
97+
u32 fileSize; // File/directory size in bytes.
9798
} FatDirEnt;
9899
static_assert(offsetof(FatDirEnt, fileSize) == 28, "Member fileSize of FatDirEnt not at offset 28.");
99100

100101
typedef struct __attribute__((packed))
101102
{
102-
u8 ord; // Order of LDIR entries. Last entry (which comes first) must have LAST_LONG_ENTRY (0x40) set.
103-
u16 name1[5]; // UTF-16 character 1-5 of long name.
104-
u8 attr; // Must be ATTR_LONG_NAME (DIR_ATTR_VOLUME_ID | DIR_ATTR_SYSTEM | DIR_ATTR_HIDDEN | DIR_ATTR_READ_ONLY).
105-
u8 type; // Must be 0 (sub-component of long name). Other values unknown (extensions).
106-
u8 chksum; // Checksum of 11 characters short name.
107-
u16 name2[6]; // UTF-16 character 6-11 of long name.
108-
u16 fstClusLo; // Must be 0.
109-
u16 name3[2]; // UTF-16 character 12-13 of long name.
103+
u8 ord; // Order of LDIR entries. Last entry (which comes first) must have LAST_LONG_ENTRY (0x40) set.
104+
char16_t name1[5]; // UTF-16 character 1-5 of long name.
105+
u8 attr; // Must be ATTR_LONG_NAME (DIR_ATTR_VOLUME_ID | DIR_ATTR_SYSTEM | DIR_ATTR_HIDDEN | DIR_ATTR_READ_ONLY).
106+
u8 type; // Must be 0 (sub-component of long name). Other values unknown (extensions).
107+
u8 chksum; // Checksum of 11 characters short name.
108+
char16_t name2[6]; // UTF-16 character 6-11 of long name.
109+
u16 fstClusLo; // Must be 0.
110+
char16_t name3[2]; // UTF-16 character 12-13 of long name.
110111
} FatLdirEnt;
111112
static_assert(offsetof(FatLdirEnt, name3) == 28, "Member name3 of FatLdirEnt not at offset 28.");
112113

include/format.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56
#include <string>
67
#include "types.h"

include/mbr.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56
#include <cstddef>
67
#include "types.h"
@@ -10,7 +11,7 @@
1011

1112
typedef struct
1213
{
13-
u8 status; // 0x80 active/bootable, 0x00 inactive.
14+
u8 status; // 0x80 active/bootable, 0x00 inactive.
1415
u8 startCHS[3];
1516
u8 type;
1617
u8 endCHS[3];
@@ -23,7 +24,7 @@ typedef struct
2324
{
2425
u8 bootstrap[440];
2526
u32 diskSig;
26-
u16 reserved; // 0x0000. 0x5A5A for copy protected.
27+
u16 reserved; // 0x0000. 0x5A5A for copy protected.
2728
PartEntry partTable[4];
2829
u16 bootSig;
2930
} __attribute__((packed)) Mbr;

include/privileges.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
// SPDX-License-Identifier: MIT
4+
// Copyright (c) 2023 profi200
45

56

67

0 commit comments

Comments
 (0)