Skip to content

Commit 9429509

Browse files
committed
Rewrote large parts of the code.
Added safety checks to prevent formatting the wrong or mounted devs. Instead of doing one large allocation and write a 4 MiB write buffer is now used.
1 parent 6642011 commit 9429509

20 files changed

+969
-554
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.*
2+
!.git

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CXXFLAGS := $(ARCH) -std=c++20 -O2 -g -fstrict-aliasing \
1818
-Wstrict-aliasing=2
1919
ASFLAGS := $(ARCH) -O2 -g -x assembler-with-cpp
2020
ARFLAGS := -rcs
21-
LDFLAGS := $(ARCH) -O2 -g -Wl,--gc-sections
21+
LDFLAGS := $(ARCH) -O2 -s -Wl,--gc-sections
2222

2323
PREFIX :=
2424
CC := $(PREFIX)gcc

include/blockdev.h

+14-16
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
class BlockDev
88
{
9-
bool m_isRegularFile;
10-
bool m_isDevDirty;
9+
static constexpr u32 m_sectorSize = 512;
10+
bool m_dirty;
1111
int m_fd;
12-
u64 m_diskSectors; // TODO: Store sector size along with this. ioctl(..., BLKSSZGET, ...). Or maybe BLKPBSZGET like dosfstools?
12+
u64 m_sectors;
1313

1414

1515
BlockDev(const BlockDev&) noexcept = delete; // Copy
@@ -20,7 +20,7 @@ class BlockDev
2020

2121

2222
public:
23-
BlockDev(void) noexcept : m_isRegularFile(false), m_isDevDirty(false), m_fd(-1), m_diskSectors(0) {}
23+
BlockDev(void) noexcept : m_dirty(false), m_fd(-1), m_sectors(0) {}
2424
~BlockDev(void) noexcept
2525
{
2626
if(m_fd != -1) close();
@@ -36,12 +36,19 @@ class BlockDev
3636
*/
3737
int open(const char *const path, const bool rw = false) noexcept;
3838

39+
/**
40+
* @brief Returns the sector size in bytes.
41+
*
42+
* @return The sector size.
43+
*/
44+
static constexpr u32 getSectorSize(void) {return m_sectorSize;}
45+
3946
/**
4047
* @brief Returns the number of sectors.
4148
*
4249
* @return The number of sectors.
4350
*/
44-
u64 getSectors(void) const noexcept {return m_diskSectors;}
51+
u64 getSectors(void) const noexcept {return m_sectors;}
4552

4653
/**
4754
* @brief Reads sectors from the block device.
@@ -66,18 +73,9 @@ class BlockDev
6673
int write(const u8 *buf, const u64 sector, const u64 count) noexcept;
6774

6875
/**
69-
* @brief Truncates to the specified size if the device is a regular file. Otherwise not supported.
70-
*
71-
* @param[in] sectors The size in sectors.
72-
*
73-
* @return Returns 0 on success or errno.
74-
*/
75-
int truncate(const u64 sectors) noexcept;
76-
77-
/**
78-
* @brief Perform a TRIM/erase on the whole block device. Not supported for regular files.
76+
* @brief Perform a TRIM/erase on the whole block device.
7977
*
80-
* @param[in] secure If true do a secure erase.
78+
* @param[in] secure If true do a secure erase. Currently unsupported by Linux.
8179
*
8280
* @return Returns 0 on success or errno.
8381
*/

include/buffered_fs_writer.h

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#pragma once
2+
3+
#include <cstring>
4+
#include <memory>
5+
#include <stdexcept>
6+
#include "types.h"
7+
#include "blockdev.h"
8+
9+
10+
11+
// Warning: This class is only suitable for overwriting like reformatting.
12+
// Padding for alignment is filled with zeros (no read-modify-write).
13+
class BufferedFsWriter final : private BlockDev
14+
{
15+
static constexpr u32 m_blkSize = 1024 * 1024 * 4; // Must be >=512 and power of 2.
16+
static constexpr u32 m_blkMask = m_blkSize - 1;
17+
static_assert(m_blkSize > 512 && (m_blkSize & m_blkMask) == 0, "Invalid buffer size for BufferedFsWriter.");
18+
19+
const std::unique_ptr<u8[]> m_buf;
20+
u64 m_pos;
21+
22+
23+
BufferedFsWriter(const BufferedFsWriter&) noexcept = delete; // Copy
24+
BufferedFsWriter(BufferedFsWriter&&) noexcept = delete; // Move
25+
26+
BufferedFsWriter& operator =(const BufferedFsWriter&) noexcept = delete; // Copy
27+
BufferedFsWriter& operator =(BufferedFsWriter&&) noexcept = delete; // Move
28+
29+
30+
public:
31+
BufferedFsWriter(void) noexcept : m_buf(new(std::nothrow) u8[m_blkSize]), m_pos(0) {}
32+
~BufferedFsWriter(void) noexcept(false)
33+
{
34+
if(m_pos > 0)
35+
{
36+
// Don't make errors on flushing the buffer go unnoticed.
37+
if(close() != 0) throw std::runtime_error("Failed to flush buffer to device.");
38+
}
39+
}
40+
41+
/**
42+
* @brief Opens the block device.
43+
*
44+
* @param[in] path The path.
45+
*
46+
* @return Returns 0 on success or errno.
47+
*/
48+
int open(const char *const path) noexcept
49+
{
50+
if(!m_buf) return ENOMEM;
51+
return BlockDev::open(path, true);
52+
}
53+
54+
/**
55+
* @brief Returns the number of sectors.
56+
*
57+
* @return The number of sectors.
58+
*/
59+
u64 getSectors(void) const noexcept {return BlockDev::getSectors();}
60+
61+
/**
62+
* @brief Returns the current write position/pointer.
63+
*
64+
* @return The write position/pointer.
65+
*/
66+
u64 tell(void) const noexcept {return m_pos;}
67+
68+
/**
69+
* @brief Seeks to offset and fills the distance with zeros.
70+
*
71+
* @param[in] offset The offset. Must not be lower than the current position.
72+
*
73+
* @return Returns 0 on success or errno.
74+
*/
75+
int fill(const u64 offset) noexcept;
76+
77+
/**
78+
* @brief Writes data.
79+
*
80+
* @param[in] buf The input buffer.
81+
* @param[in] size The number of bytes to write.
82+
*
83+
* @return Returns 0 on success or errno.
84+
*/
85+
int write(const u8 *buf, const u64 size) noexcept;
86+
87+
/**
88+
* @brief Fills until offset and writes size bytes from buf.
89+
*
90+
* @param[in] buf The input buffer.
91+
* @param[in] offset The offset. Must not be lower than the current position.
92+
* @param[in] size The number of bytes to write.
93+
*
94+
* @return Returns 0 on success or errno.
95+
*/
96+
int fillAndWrite(const u8 *buf, const u64 offset, const u64 size) noexcept
97+
{
98+
int res = fill(offset);
99+
if(res == 0) res = write(buf, size);
100+
return res;
101+
}
102+
103+
/**
104+
* @brief Perform a TRIM/erase on the whole block device.
105+
*
106+
* @param[in] secure If true do a secure erase.
107+
*
108+
* @return Returns 0 on success or errno.
109+
*/
110+
int discardAll(const bool secure = false) noexcept
111+
{
112+
memset(m_buf.get(), 0, m_pos & m_blkMask);
113+
m_pos = 0;
114+
return BlockDev::discardAll(secure);
115+
}
116+
117+
/**
118+
* @brief Flushes the buffer and closes the block device.
119+
*
120+
* @return Returns 0 on success or errno.
121+
*/
122+
int close(void) noexcept;
123+
};

include/exfat.h

+4
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ static_assert(offsetof(BootSector, bootSignature) == 510, "Member bootSignature
4141
u8 extendedBootCode[(1u<<bytesPerSectorShift) - 4];
4242
u32 extendedBootSignature; // 0xAA550000.
4343
} ExtendedBootSector;*/
44+
45+
46+
47+
void calcFormatExFat(void); // (const u64 totSec, FormatParams *const paramsOut)

include/fat.h

+12-26
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,13 @@
22

33
#include <cstddef>
44
#include "types.h"
5+
#include "format.h"
6+
#include "buffered_fs_writer.h"
57

68
// References:
79
// FAT12/16/32: http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc
810

911

10-
typedef struct
11-
{
12-
u8 bootable;
13-
u8 startH;
14-
u16 startSC;
15-
u8 id;
16-
u8 endH;
17-
u16 endSC;
18-
u32 startLba;
19-
u32 sectorsLba;
20-
} __attribute__((packed)) PartInfo;
21-
static_assert(offsetof(PartInfo, sectorsLba) == 12, "Member sectorsLba of PartInfonfo not at offsetof 12.");
22-
23-
typedef struct
24-
{
25-
u8 code[440];
26-
u32 diskId;
27-
u16 reserved;
28-
PartInfo partTable[4];
29-
u16 magic;
30-
} __attribute__((packed)) Mbr;
31-
static_assert(offsetof(Mbr, magic) == 510, "Member magic of Mbr not at offsetof 510.");
32-
3312
// Volume Boot Record.
3413
typedef struct
3514
{
@@ -81,6 +60,7 @@ typedef struct
8160
u8 bootCode[420];
8261
} fat32;
8362
};
63+
8464
u16 sigWord; // 0xAA55.
8565
} __attribute__((packed)) Vbr;
8666
static_assert(offsetof(Vbr, fat16.bootCode) == 62, "Member fat16.bootCode of Vbr not at offsetof 62.");
@@ -104,9 +84,9 @@ typedef struct
10484
char name[11]; // Short file name in 8:3 format. Maximum 11 characters.
10585
u8 attr; // Attribute bitmask. ATTR_READ_ONLY 0x01, ATTR_HIDDEN 0x02, ATTR_SYSTEM 0x04, ATTR_VOLUME_ID 0x08, ATTR_DIRECTORY 0x10, ATTR_ARCHIVE 0x20.
10686
u8 ntRes; // Must be 0.
107-
u8 ctrTimeTenth; // Creation time tenths of a second.
108-
u16 ctrTime; // Creation time in 2 second units.
109-
u16 ctrDate; // Creation date.
87+
u8 crtTimeTenth; // Creation time tenths of a second.
88+
u16 crtTime; // Creation time in 2 second units.
89+
u16 crtDate; // Creation date.
11090
u16 lstAccDate; // Last access date. Updated on write.
11191
u16 fstClusHi; // High u16 of first data cluster. Must be 0 for FAT12/16.
11292
u16 wrtTime; // Last (modification) write time.
@@ -115,3 +95,9 @@ typedef struct
11595
u32 fileSize; // File/directory size in bytes.
11696
} FatDir;
11797
static_assert(offsetof(FatDir, fileSize) == 28, "Member fileSize of FatDir not at offsetof 28.");
98+
99+
100+
101+
void calcFormatFat(const u32 totSec, FormatParams &params);
102+
void calcFormatFat32(const u32 totSec, FormatParams &params);
103+
int makeFsFat(const FormatParams &params, BufferedFsWriter &dev, const std::string &label);

include/format.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,22 @@ union ArgFlags
1717
u8 allFlags;
1818
};
1919

20+
typedef struct
21+
{
22+
// TODO: union with exFAT vars.
23+
u64 totSec;
24+
u8 heads;
25+
u8 secPerTrk;
26+
u8 fatBits;
27+
u32 alignment;
28+
u32 secPerClus;
29+
u32 rsvdSecCnt;
30+
u32 secPerFat;
31+
u32 fsAreaSize;
32+
u32 partStart;
33+
u32 maxClus;
34+
} FormatParams;
35+
2036

2137

22-
void setVerboseMode(const bool verbose);
2338
u32 formatSd(const char *const path, const char *const label, const ArgFlags flags, const u64 overrTotSec);

include/mbr.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include "types.h"
5+
#include "format.h"
6+
#include "buffered_fs_writer.h"
7+
8+
9+
typedef struct
10+
{
11+
u8 status; // 0x80 active/bootable, 0x00 inactive.
12+
u8 startCHS[3];
13+
u8 type;
14+
u8 endCHS[3];
15+
u32 startLBA;
16+
u32 sectors;
17+
} __attribute__((packed)) PartEntry;
18+
static_assert(offsetof(PartEntry, sectors) == 12, "Member sectors of PartEntry not at offsetof 12.");
19+
20+
typedef struct
21+
{
22+
u8 bootstrap[440];
23+
u32 diskSig;
24+
u16 reserved; // 0x0000. 0x5A5A for copy protected.
25+
PartEntry partTable[4];
26+
u16 bootSig;
27+
} __attribute__((packed)) Mbr;
28+
static_assert(offsetof(Mbr, bootSig) == 510, "Member bootSig of Mbr not at offsetof 510.");
29+
30+
31+
32+
int createMbrAndPartition(const FormatParams *const params, BufferedFsWriter &dev);

include/privileges.h

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#pragma once
2+
3+
4+
5+
void dropPrivileges(void);

include/verbose_printf.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
4+
5+
void setVerboseMode(const bool verbose);
6+
int verbosePuts(const char *str);
7+
int verbosePrintf(const char *format, ...);

0 commit comments

Comments
 (0)