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