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
+ };
0 commit comments