blob: cf0ef688b66507db93f65c174a092278adf2695c [file] [log] [blame]
Zachary Turner0a43efe2016-04-25 17:38:08 +00001//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000011
Zachary Turner0a43efe2016-04-25 17:38:08 +000012#include "llvm/ADT/ArrayRef.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000013#include "llvm/DebugInfo/CodeView/StreamArray.h"
Zachary Turnerb84faa82016-06-10 05:10:19 +000014#include "llvm/DebugInfo/CodeView/StreamInterface.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000015#include "llvm/DebugInfo/CodeView/StreamReader.h"
Zachary Turnerab58ae82016-06-30 17:43:00 +000016#include "llvm/DebugInfo/CodeView/StreamWriter.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000017#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Zachary Turnera1657a92016-06-08 17:26:39 +000018#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000019#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000020#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
Zachary Turner3df1bfa2016-06-03 05:52:57 +000021#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
Rui Ueyama1f6b6e22016-05-13 21:21:53 +000022#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000023#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Rui Ueyama0fcd8262016-05-20 19:55:17 +000024#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
Zachary Turnerf5c59652016-05-03 00:28:21 +000025#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
Zachary Turner0a43efe2016-04-25 17:38:08 +000026#include "llvm/Support/Endian.h"
Zachary Turner1dc9fd32016-06-14 20:48:36 +000027#include "llvm/Support/FileOutputBuffer.h"
Zachary Turner0a43efe2016-04-25 17:38:08 +000028#include "llvm/Support/MemoryBuffer.h"
29
30using namespace llvm;
Zachary Turnerb84faa82016-06-10 05:10:19 +000031using namespace llvm::codeview;
Zachary Turner2f09b502016-04-29 17:28:47 +000032using namespace llvm::pdb;
Zachary Turner0a43efe2016-04-25 17:38:08 +000033
34namespace {
Zachary Turnerb84faa82016-06-10 05:10:19 +000035typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
Zachary Turner0a43efe2016-04-25 17:38:08 +000036}
37
Zachary Turnerb84faa82016-06-10 05:10:19 +000038PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer)
39 : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {}
Zachary Turner0a43efe2016-04-25 17:38:08 +000040
41PDBFile::~PDBFile() {}
42
Zachary Turnerb84faa82016-06-10 05:10:19 +000043uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000044
Zachary Turnerb84faa82016-06-10 05:10:19 +000045uint32_t PDBFile::getUnknown0() const { return SB->Unknown0; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000046
Zachary Turnerb84faa82016-06-10 05:10:19 +000047uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000048
Zachary Turnerb84faa82016-06-10 05:10:19 +000049uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000050
Zachary Turnerb84faa82016-06-10 05:10:19 +000051uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000052
Zachary Turnerb84faa82016-06-10 05:10:19 +000053uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000054
55uint32_t PDBFile::getNumDirectoryBlocks() const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000056 return bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
Zachary Turner0a43efe2016-04-25 17:38:08 +000057}
58
59uint64_t PDBFile::getBlockMapOffset() const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000060 return (uint64_t)SB->BlockMapAddr * SB->BlockSize;
Zachary Turner0a43efe2016-04-25 17:38:08 +000061}
62
Zachary Turnerb84faa82016-06-10 05:10:19 +000063uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); }
Zachary Turner0a43efe2016-04-25 17:38:08 +000064
65uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000066 return StreamSizes[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000067}
68
Zachary Turnerd8447992016-06-07 05:28:55 +000069ArrayRef<support::ulittle32_t>
Zachary Turner0a43efe2016-04-25 17:38:08 +000070PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000071 return StreamMap[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000072}
73
Zachary Turner1dc9fd32016-06-14 20:48:36 +000074size_t PDBFile::getFileSize() const { return Buffer->getLength(); }
75
Zachary Turnere6fee882016-06-07 20:38:37 +000076ArrayRef<uint8_t> PDBFile::getBlockData(uint32_t BlockIndex,
77 uint32_t NumBytes) const {
Zachary Turner0a43efe2016-04-25 17:38:08 +000078 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
79
Zachary Turnerb84faa82016-06-10 05:10:19 +000080 ArrayRef<uint8_t> Result;
81 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
82 consumeError(std::move(EC));
83 return Result;
Zachary Turner0a43efe2016-04-25 17:38:08 +000084}
85
Zachary Turner5acb4ac2016-06-10 05:09:12 +000086Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
87 ArrayRef<uint8_t> Data) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000088 if (Offset >= getBlockSize())
89 return make_error<RawError>(
90 raw_error_code::invalid_block_address,
91 "setBlockData attempted to write out of block bounds.");
92 if (Data.size() >= getBlockSize() - Offset)
93 return make_error<RawError>(
94 raw_error_code::invalid_block_address,
95 "setBlockData attempted to write out of block bounds.");
Zachary Turner5acb4ac2016-06-10 05:09:12 +000096
Zachary Turnerb84faa82016-06-10 05:10:19 +000097 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
98 StreamBlockOffset += Offset;
99 return Buffer->writeBytes(StreamBlockOffset, Data);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000100}
101
Zachary Turner819e77d2016-05-06 20:51:57 +0000102Error PDBFile::parseFileHeaders() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000103 StreamReader Reader(*Buffer);
Zachary Turnerc59261c2016-05-25 03:53:16 +0000104
Zachary Turnerb84faa82016-06-10 05:10:19 +0000105 if (auto EC = Reader.readObject(SB)) {
106 consumeError(std::move(EC));
Zachary Turner819e77d2016-05-06 20:51:57 +0000107 return make_error<RawError>(raw_error_code::corrupt_file,
108 "Does not contain superblock");
Zachary Turnerb84faa82016-06-10 05:10:19 +0000109 }
Zachary Turner0a43efe2016-04-25 17:38:08 +0000110
Zachary Turnerab58ae82016-06-30 17:43:00 +0000111 if (auto EC = setSuperBlock(SB))
112 return EC;
Zachary Turner819e77d2016-05-06 20:51:57 +0000113
Zachary Turnerab58ae82016-06-30 17:43:00 +0000114 Reader.setOffset(getBlockMapOffset());
115 if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks()))
116 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000117
Zachary Turner819e77d2016-05-06 20:51:57 +0000118 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000119}
120
Zachary Turner819e77d2016-05-06 20:51:57 +0000121Error PDBFile::parseStreamData() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000122 assert(SB);
Zachary Turnerd8447992016-06-07 05:28:55 +0000123 if (DirectoryStream)
124 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000125
Zachary Turner0a43efe2016-04-25 17:38:08 +0000126 uint32_t NumStreams = 0;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000127
Zachary Turnerd8447992016-06-07 05:28:55 +0000128 // Normally you can't use a MappedBlockStream without having fully parsed the
129 // PDB file, because it accesses the directory and various other things, which
130 // is exactly what we are attempting to parse. By specifying a custom
131 // subclass of IPDBStreamData which only accesses the fields that have already
132 // been parsed, we can avoid this and reuse MappedBlockStream.
Zachary Turnera1657a92016-06-08 17:26:39 +0000133 auto DS = MappedBlockStream::createDirectoryStream(*this);
134 if (!DS)
135 return DS.takeError();
Zachary Turnerb84faa82016-06-10 05:10:19 +0000136 StreamReader Reader(**DS);
Zachary Turnerd8447992016-06-07 05:28:55 +0000137 if (auto EC = Reader.readInteger(NumStreams))
138 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000139
Zachary Turnerb84faa82016-06-10 05:10:19 +0000140 if (auto EC = Reader.readArray(StreamSizes, NumStreams))
Zachary Turnerd8447992016-06-07 05:28:55 +0000141 return EC;
142 for (uint32_t I = 0; I < NumStreams; ++I) {
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000143 uint32_t StreamSize = getStreamByteSize(I);
144 // FIXME: What does StreamSize ~0U mean?
David Majnemer9efba742016-05-27 16:16:48 +0000145 uint64_t NumExpectedStreamBlocks =
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000146 StreamSize == UINT32_MAX ? 0 : bytesToBlocks(StreamSize, SB->BlockSize);
Zachary Turnerb84faa82016-06-10 05:10:19 +0000147
148 // For convenience, we store the block array contiguously. This is because
149 // if someone calls setStreamMap(), it is more convenient to be able to call
150 // it with an ArrayRef instead of setting up a StreamRef. Since the
151 // DirectoryStream is cached in the class and thus lives for the life of the
152 // class, we can be guaranteed that readArray() will return a stable
153 // reference, even if it has to allocate from its internal pool.
154 ArrayRef<support::ulittle32_t> Blocks;
Zachary Turnerd8447992016-06-07 05:28:55 +0000155 if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
156 return EC;
Zachary Turnerb84faa82016-06-10 05:10:19 +0000157 StreamMap.push_back(Blocks);
David Majnemer9efba742016-05-27 16:16:48 +0000158 }
159
Zachary Turner0a43efe2016-04-25 17:38:08 +0000160 // We should have read exactly SB->NumDirectoryBytes bytes.
Zachary Turnerd8447992016-06-07 05:28:55 +0000161 assert(Reader.bytesRemaining() == 0);
Zachary Turnera1657a92016-06-08 17:26:39 +0000162 DirectoryStream = std::move(*DS);
Zachary Turner819e77d2016-05-06 20:51:57 +0000163 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000164}
165
Zachary Turnerd8447992016-06-07 05:28:55 +0000166llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000167 return DirectoryBlocks;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000168}
Zachary Turner53a65ba2016-04-26 18:42:34 +0000169
Zachary Turner819e77d2016-05-06 20:51:57 +0000170Expected<InfoStream &> PDBFile::getPDBInfoStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000171 if (!Info) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000172 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
173 if (!InfoS)
174 return InfoS.takeError();
175 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
176 if (auto EC = TempInfo->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000177 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000178 Info = std::move(TempInfo);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000179 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000180 return *Info;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000181}
182
Zachary Turner819e77d2016-05-06 20:51:57 +0000183Expected<DbiStream &> PDBFile::getPDBDbiStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000184 if (!Dbi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000185 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
186 if (!DbiS)
187 return DbiS.takeError();
188 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
189 if (auto EC = TempDbi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000190 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000191 Dbi = std::move(TempDbi);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000192 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000193 return *Dbi;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000194}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000195
Zachary Turner819e77d2016-05-06 20:51:57 +0000196Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Zachary Turnerf5c59652016-05-03 00:28:21 +0000197 if (!Tpi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000198 auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
199 if (!TpiS)
200 return TpiS.takeError();
201 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
202 if (auto EC = TempTpi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000203 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000204 Tpi = std::move(TempTpi);
Zachary Turnerf5c59652016-05-03 00:28:21 +0000205 }
206 return *Tpi;
207}
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000208
Zachary Turnerc9972c62016-05-25 04:35:22 +0000209Expected<TpiStream &> PDBFile::getPDBIpiStream() {
210 if (!Ipi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000211 auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
212 if (!IpiS)
213 return IpiS.takeError();
214 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
215 if (auto EC = TempIpi->reload())
Zachary Turnerc9972c62016-05-25 04:35:22 +0000216 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000217 Ipi = std::move(TempIpi);
Zachary Turnerc9972c62016-05-25 04:35:22 +0000218 }
219 return *Ipi;
220}
221
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000222Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
223 if (!Publics) {
224 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000225 if (!DbiS)
226 return DbiS.takeError();
227
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000228 uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
229
Zachary Turnera1657a92016-06-08 17:26:39 +0000230 auto PublicS =
231 MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
232 if (!PublicS)
233 return PublicS.takeError();
234 auto TempPublics =
235 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
236 if (auto EC = TempPublics->reload())
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000237 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000238 Publics = std::move(TempPublics);
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000239 }
240 return *Publics;
241}
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000242
243Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
244 if (!Symbols) {
245 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000246 if (!DbiS)
247 return DbiS.takeError();
248
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000249 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
250
Zachary Turnera1657a92016-06-08 17:26:39 +0000251 auto SymbolS =
252 MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
253 if (!SymbolS)
254 return SymbolS.takeError();
255 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
256 if (auto EC = TempSymbols->reload())
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000257 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000258 Symbols = std::move(TempSymbols);
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000259 }
260 return *Symbols;
261}
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000262
263Expected<NameHashTable &> PDBFile::getStringTable() {
264 if (!StringTable || !StringTableStream) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000265 auto IS = getPDBInfoStream();
266 if (!IS)
267 return IS.takeError();
268
269 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000270
271 if (NameStreamIndex == 0)
272 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000273 if (NameStreamIndex >= getNumStreams())
274 return make_error<RawError>(raw_error_code::no_stream);
275
Zachary Turnera1657a92016-06-08 17:26:39 +0000276 auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
277 if (!NS)
278 return NS.takeError();
279
Zachary Turnerb84faa82016-06-10 05:10:19 +0000280 StreamReader Reader(**NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000281 auto N = llvm::make_unique<NameHashTable>();
282 if (auto EC = N->load(Reader))
283 return std::move(EC);
284 StringTable = std::move(N);
Zachary Turnera1657a92016-06-08 17:26:39 +0000285 StringTableStream = std::move(*NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000286 }
287 return *StringTable;
288}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000289
Zachary Turnerab58ae82016-06-30 17:43:00 +0000290Error PDBFile::setSuperBlock(const SuperBlock *Block) {
291 SB = Block;
292
293 // Check the magic bytes.
294 if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0)
295 return make_error<RawError>(raw_error_code::corrupt_file,
296 "MSF magic header doesn't match");
297
298 // We don't support blocksizes which aren't a multiple of four bytes.
299 if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
300 return make_error<RawError>(raw_error_code::corrupt_file,
301 "Block size is not multiple of 4.");
302
303 switch (SB->BlockSize) {
304 case 512:
305 case 1024:
306 case 2048:
307 case 4096:
308 break;
309 default:
310 // An invalid block size suggests a corrupt PDB file.
311 return make_error<RawError>(raw_error_code::corrupt_file,
312 "Unsupported block size.");
313 }
314
315 if (Buffer->getLength() % SB->BlockSize != 0)
316 return make_error<RawError>(raw_error_code::corrupt_file,
317 "File size is not a multiple of block size");
318
319 // We don't support directories whose sizes aren't a multiple of four bytes.
320 if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
321 return make_error<RawError>(raw_error_code::corrupt_file,
322 "Directory size is not multiple of 4.");
323
324 // The number of blocks which comprise the directory is a simple function of
325 // the number of bytes it contains.
326 uint64_t NumDirectoryBlocks = getNumDirectoryBlocks();
327
328 // The directory, as we understand it, is a block which consists of a list of
329 // block numbers. It is unclear what would happen if the number of blocks
330 // couldn't fit on a single block.
331 if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
332 return make_error<RawError>(raw_error_code::corrupt_file,
333 "Too many directory blocks.");
334
335 return Error::success();
336}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000337
338void PDBFile::setStreamSizes(ArrayRef<support::ulittle32_t> Sizes) {
339 StreamSizes = Sizes;
340}
341
Zachary Turnerab58ae82016-06-30 17:43:00 +0000342void PDBFile::setStreamMap(
343 ArrayRef<support::ulittle32_t> Directory,
344 std::vector<ArrayRef<support::ulittle32_t>> &Streams) {
345 DirectoryBlocks = Directory;
346 StreamMap = Streams;
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000347}
348
Zachary Turnerab58ae82016-06-30 17:43:00 +0000349Error PDBFile::commit() {
350 StreamWriter Writer(*Buffer);
351
352 if (auto EC = Writer.writeObject(*SB))
353 return EC;
354 Writer.setOffset(getBlockMapOffset());
355 if (auto EC = Writer.writeArray(DirectoryBlocks))
356 return EC;
357
358 auto DS = MappedBlockStream::createDirectoryStream(*this);
359 if (!DS)
360 return DS.takeError();
361 auto DirStream = std::move(*DS);
362 StreamWriter DW(*DirStream);
363 if (auto EC = DW.writeInteger(this->getNumStreams()))
364 return EC;
365
366 if (auto EC = DW.writeArray(StreamSizes))
367 return EC;
368
369 for (const auto &Blocks : StreamMap) {
370 if (auto EC = DW.writeArray(Blocks))
371 return EC;
372 }
373
374 return Buffer->commit();
375}