1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | //***************************************************************************** |
5 | |
6 | // |
7 | // LiteWeightStgdb.cpp |
8 | // |
9 | // This contains definition of class CLiteWeightStgDB. This is light weight |
10 | // read-only implementation for accessing compressed meta data format. |
11 | // |
12 | //***************************************************************************** |
13 | #include "stdafx.h" // Precompiled header. |
14 | |
15 | #include "metamodelrw.h" |
16 | #include "liteweightstgdb.h" |
17 | |
18 | // include stgdatabase.h for GUID_POOL_STREAM definition |
19 | // #include "stgdatabase.h" |
20 | |
21 | // include StgTiggerStorage for TiggerStorage definition |
22 | #include "stgtiggerstorage.h" |
23 | #include "stgio.h" |
24 | #include "pedecoder.h" |
25 | |
26 | #include <log.h> |
27 | |
28 | |
29 | #ifndef TYPELIB_SIG |
30 | #define TYPELIB_SIG_MSFT 0x5446534D // MSFT |
31 | #define TYPELIB_SIG_SLTG 0x47544C53 // SLTG |
32 | #endif |
33 | |
34 | //***************************************************************************** |
35 | // Checks the given storage object to see if it is an NT PE image. |
36 | //***************************************************************************** |
37 | int _IsNTPEImage( // true if file is NT PE image. |
38 | StgIO *pStgIO) // Storage object. |
39 | { |
40 | LONG lfanew=0; // Offset in DOS header to NT header. |
41 | ULONG lSignature=0; // For NT header signature. |
42 | HRESULT hr; |
43 | |
44 | // Read DOS header to find the NT header offset. |
45 | if (FAILED(hr = pStgIO->Seek(60, FILE_BEGIN)) || |
46 | FAILED(hr = pStgIO->Read(&lfanew, sizeof(LONG), 0))) |
47 | { |
48 | return (false); |
49 | } |
50 | |
51 | // Seek to the NT header and read the signature. |
52 | if (FAILED(hr = pStgIO->Seek(VAL32(lfanew), FILE_BEGIN)) || |
53 | FAILED(hr = pStgIO->Read(&lSignature, sizeof(ULONG), 0)) || |
54 | FAILED(hr = pStgIO->Seek(0, FILE_BEGIN))) |
55 | { |
56 | return (false); |
57 | } |
58 | |
59 | // If the signature is a match, then we have a PE format. |
60 | if (lSignature == VAL32(IMAGE_NT_SIGNATURE)) |
61 | return (true); |
62 | else |
63 | return (false); |
64 | } |
65 | |
66 | BOOL _GetFileTypeForPathExt(StgIO * pStgIO, FILETYPE * piType) |
67 | { |
68 | // Avoid confusion. |
69 | *piType = pStgIO->GetFileType(); |
70 | |
71 | // All file types except .obj have a signature built in. You should |
72 | // not get to this code for those file types unless that file is corrupt, |
73 | // or someone has changed a format without updating this code. |
74 | _ASSERTE((*piType == FILETYPE_UNKNOWN) || (*piType == FILETYPE_NTOBJ) || (*piType == FILETYPE_TLB)); |
75 | |
76 | // If we found a type, then you're ok. |
77 | return (*piType != FILETYPE_UNKNOWN); |
78 | } |
79 | |
80 | HRESULT _GetFileTypeForPath(StgIO *pStgIO, FILETYPE *piType) |
81 | { |
82 | ULONG lSignature=0; |
83 | HRESULT hr; |
84 | |
85 | // Assume native file. |
86 | *piType = FILETYPE_CLB; |
87 | |
88 | // Need to read signature to see what type it is. |
89 | if (!(pStgIO->GetFlags() & DBPROP_TMODEF_CREATE)) |
90 | { |
91 | if (FAILED(hr = pStgIO->Read(&lSignature, sizeof(ULONG), 0)) || |
92 | FAILED(hr = pStgIO->Seek(0, FILE_BEGIN))) |
93 | { |
94 | return (hr); |
95 | } |
96 | lSignature = VAL32(lSignature); |
97 | if (lSignature == STORAGE_MAGIC_SIG) |
98 | *piType = FILETYPE_CLB; |
99 | else if ((WORD) lSignature ==IMAGE_DOS_SIGNATURE && _IsNTPEImage(pStgIO)) |
100 | *piType = FILETYPE_NTPE; |
101 | else if (lSignature == TYPELIB_SIG_MSFT || lSignature == TYPELIB_SIG_SLTG) |
102 | *piType = FILETYPE_TLB; |
103 | else if (!_GetFileTypeForPathExt(pStgIO, piType)) |
104 | return CLDB_E_FILE_CORRUPT; |
105 | } |
106 | return S_OK; |
107 | } |
108 | |
109 | //***************************************************************************** |
110 | // Prepare to go away. |
111 | //***************************************************************************** |
112 | CLiteWeightStgdbRW::~CLiteWeightStgdbRW() |
113 | { |
114 | // Free up this stacks reference on the I/O object. |
115 | if (m_pStgIO != NULL) |
116 | { |
117 | m_pStgIO->Release(); |
118 | m_pStgIO = NULL; |
119 | } |
120 | |
121 | if (m_pStreamList != NULL) |
122 | { |
123 | delete m_pStreamList; |
124 | } |
125 | |
126 | if (m_wszFileName != NULL) |
127 | { |
128 | delete [] m_wszFileName; |
129 | } |
130 | } |
131 | |
132 | //***************************************************************************** |
133 | // Open an in-memory metadata section for read |
134 | //***************************************************************************** |
135 | __checkReturn |
136 | HRESULT CLiteWeightStgdbRW::InitOnMem( |
137 | ULONG cbData, // count of bytes in pData |
138 | LPCVOID pData, // points to meta data section in memory |
139 | int bReadOnly) // If true, read-only. |
140 | { |
141 | StgIO *pStgIO = NULL; // For file i/o. |
142 | HRESULT hr = NOERROR; |
143 | |
144 | if ((pStgIO = new (nothrow) StgIO) == 0) |
145 | IfFailGo( E_OUTOFMEMORY); |
146 | |
147 | // Open the storage based on the pbData and cbData |
148 | IfFailGo( pStgIO->Open( |
149 | NULL, // filename |
150 | STGIO_READ, |
151 | pData, |
152 | cbData, |
153 | NULL, // IStream* |
154 | NULL) // LPSecurityAttributes |
155 | ); |
156 | |
157 | IfFailGo( InitFileForRead(pStgIO, bReadOnly) ); |
158 | |
159 | ErrExit: |
160 | if (SUCCEEDED(hr)) |
161 | { |
162 | m_pStgIO = pStgIO; |
163 | } |
164 | else |
165 | { |
166 | if (pStgIO) |
167 | pStgIO->Release(); |
168 | } |
169 | return hr; |
170 | } // CLiteWeightStgdbRW::InitOnMem |
171 | |
172 | |
173 | //***************************************************************************** |
174 | // Given an StgIO, opens compressed streams and do proper initialization. |
175 | // This is a helper for other Init functions. |
176 | //***************************************************************************** |
177 | __checkReturn |
178 | HRESULT |
179 | CLiteWeightStgdbRW::InitFileForRead( |
180 | StgIO * pStgIO, // For file i/o. |
181 | int bReadOnly) // If read-only open. |
182 | { |
183 | TiggerStorage * pStorage = NULL; |
184 | void * pvData; |
185 | ULONG cbData; |
186 | HRESULT hr = NOERROR; |
187 | |
188 | // Allocate a new storage object which has IStorage on it. |
189 | pStorage = new (nothrow) TiggerStorage(); |
190 | IfNullGo(pStorage); |
191 | |
192 | // Init the storage object on the backing storage. |
193 | OptionValue ov; |
194 | IfFailGo(m_MiniMd.GetOption(&ov)); |
195 | IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); |
196 | |
197 | // Save pointers to header structure for version string. |
198 | _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0)); |
199 | IfFailGo(pStorage->GetHeaderPointer(&m_pvMd, &m_cbMd)); |
200 | |
201 | // Check to see if this is a minimal metadata |
202 | if (SUCCEEDED(pStorage->OpenStream(MINIMAL_MD_STREAM, &cbData, &pvData))) |
203 | { |
204 | m_MiniMd.m_fMinimalDelta = TRUE; |
205 | } |
206 | |
207 | // Load the string pool. |
208 | if (SUCCEEDED(hr = pStorage->OpenStream(STRING_POOL_STREAM, &cbData, &pvData))) |
209 | { |
210 | // String pool has to end with a null-terminator, therefore we don't have to check string pool |
211 | // content on access. |
212 | // Shrink size of the pool to the last null-terminator found. |
213 | while (cbData != 0) |
214 | { |
215 | if (((LPBYTE)pvData)[cbData - 1] == 0) |
216 | { // We have found last null terminator |
217 | break; |
218 | } |
219 | // Shrink size of the pool |
220 | cbData--; |
221 | Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap." ); |
222 | } |
223 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, pvData, cbData, bReadOnly)); |
224 | } |
225 | else |
226 | { |
227 | if (hr != STG_E_FILENOTFOUND) |
228 | { |
229 | IfFailGo(hr); |
230 | } |
231 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, NULL, 0, bReadOnly)); |
232 | } |
233 | |
234 | // Load the user string blob pool. |
235 | if (SUCCEEDED(hr = pStorage->OpenStream(US_BLOB_POOL_STREAM, &cbData, &pvData))) |
236 | { |
237 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, pvData, cbData, bReadOnly)); |
238 | } |
239 | else |
240 | { |
241 | if (hr != STG_E_FILENOTFOUND) |
242 | { |
243 | IfFailGo(hr); |
244 | } |
245 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, NULL, 0, bReadOnly)); |
246 | } |
247 | |
248 | // Load the guid pool. |
249 | if (SUCCEEDED(hr = pStorage->OpenStream(GUID_POOL_STREAM, &cbData, &pvData))) |
250 | { |
251 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, pvData, cbData, bReadOnly)); |
252 | } |
253 | else |
254 | { |
255 | if (hr != STG_E_FILENOTFOUND) |
256 | { |
257 | IfFailGo(hr); |
258 | } |
259 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, NULL, 0, bReadOnly)); |
260 | } |
261 | |
262 | // Load the blob pool. |
263 | if (SUCCEEDED(hr = pStorage->OpenStream(BLOB_POOL_STREAM, &cbData, &pvData))) |
264 | { |
265 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, pvData, cbData, bReadOnly)); |
266 | } |
267 | else |
268 | { |
269 | if (hr != STG_E_FILENOTFOUND) |
270 | { |
271 | IfFailGo(hr); |
272 | } |
273 | IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, NULL, 0, bReadOnly)); |
274 | } |
275 | |
276 | // Open the metadata. |
277 | hr = pStorage->OpenStream(COMPRESSED_MODEL_STREAM, &cbData, &pvData); |
278 | if (hr == STG_E_FILENOTFOUND) |
279 | { |
280 | IfFailGo(pStorage->OpenStream(ENC_MODEL_STREAM, &cbData, &pvData)); |
281 | } |
282 | IfFailGo(m_MiniMd.InitOnMem(pvData, cbData, bReadOnly)); |
283 | IfFailGo(m_MiniMd.PostInit(0)); |
284 | |
285 | ErrExit: |
286 | if (pStorage != NULL) |
287 | { |
288 | delete pStorage; |
289 | } |
290 | return hr; |
291 | } // CLiteWeightStgdbRW::InitFileForRead |
292 | |
293 | //***************************************************************************** |
294 | // Open a metadata section for read |
295 | //***************************************************************************** |
296 | __checkReturn |
297 | HRESULT CLiteWeightStgdbRW::OpenForRead( |
298 | LPCWSTR szDatabase, // Name of database. |
299 | void *pbData, // Data to open on top of, 0 default. |
300 | ULONG cbData, // How big is the data. |
301 | DWORD dwFlags) // Flags for the open. |
302 | { |
303 | LPCWSTR pNoFile=W("" ); // Constant for empty file name. |
304 | StgIO *pStgIO = NULL; // For file i/o. |
305 | HRESULT hr; |
306 | |
307 | m_pImage = NULL; |
308 | m_dwImageSize = 0; |
309 | m_eFileType = FILETYPE_UNKNOWN; |
310 | // szDatabase, and pbData are mutually exclusive. Only one may be |
311 | // non-NULL. Having both NULL means empty stream creation. |
312 | // |
313 | _ASSERTE(!(szDatabase && (pbData))); |
314 | _ASSERTE(!(pbData && (szDatabase))); |
315 | |
316 | // Open on memory needs there to be something to work with. |
317 | if (pbData && cbData == 0) |
318 | IfFailGo(CLDB_E_NO_DATA); |
319 | |
320 | // Make sure we have a path to work with. |
321 | if (!szDatabase) |
322 | szDatabase = pNoFile; |
323 | |
324 | // Sanity check the name lentgh. |
325 | if (!IsValidFileNameLength(szDatabase)) |
326 | { |
327 | IfFailGo(E_INVALIDARG); |
328 | } |
329 | |
330 | // If we have storage to work with, init it and get type. |
331 | if (*szDatabase || pbData) |
332 | { |
333 | // Allocate a storage instance to use for i/o. |
334 | if ((pStgIO = new (nothrow) StgIO) == 0) |
335 | IfFailGo( E_OUTOFMEMORY ); |
336 | |
337 | DBPROPMODE dmOpenFlags = DBPROP_TMODEF_READ; |
338 | |
339 | // If we're taking ownership of this memory..... |
340 | if (IsOfTakeOwnership(dwFlags)) |
341 | { |
342 | dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_SHAREDMEM); |
343 | } |
344 | #ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES |
345 | if (IsOfTrustedImage(dwFlags)) |
346 | dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_TRYLOADLIBRARY); |
347 | #endif |
348 | |
349 | // Open the storage so we can read the signature if there is already data. |
350 | IfFailGo( pStgIO->Open(szDatabase, |
351 | dmOpenFlags, |
352 | pbData, |
353 | cbData, |
354 | 0, // IStream* |
355 | NULL) ); |
356 | |
357 | // Determine the type of file we are working with. |
358 | IfFailGo( _GetFileTypeForPath(pStgIO, &m_eFileType) ); |
359 | } |
360 | |
361 | // Check for default type. |
362 | if (m_eFileType == FILETYPE_CLB) |
363 | { |
364 | // If user wanted us to make a local copy of the data, do that now. |
365 | if (IsOfCopyMemory(dwFlags)) |
366 | IfFailGo(pStgIO->LoadFileToMemory()); |
367 | |
368 | // Try the native .clb file. |
369 | IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); |
370 | } |
371 | // PE/COFF executable/object format. This requires us to find the .clb |
372 | // inside the binary before doing the Init. |
373 | else if (m_eFileType == FILETYPE_NTPE || m_eFileType == FILETYPE_NTOBJ) |
374 | { |
375 | //<TODO>@FUTURE: Ideally the FindImageMetaData function |
376 | //@FUTURE: would take the pStgIO and map only the part of the file where |
377 | //@FUTURE: our data lives, leaving the rest alone. This would be smaller |
378 | //@FUTURE: working set for us.</TODO> |
379 | void *ptr; |
380 | ULONG cbSize; |
381 | |
382 | // Map the entire binary for the FindImageMetaData function. |
383 | IfFailGo( pStgIO->MapFileToMem(ptr, &cbSize) ); |
384 | |
385 | // Find the .clb inside of the content. |
386 | if (m_eFileType == FILETYPE_NTPE) |
387 | { |
388 | m_pImage = ptr; |
389 | m_dwImageSize = cbSize; |
390 | hr = FindImageMetaData(ptr, |
391 | cbSize, |
392 | pStgIO->GetMemoryMappedType() == MTYPE_IMAGE, |
393 | &ptr, |
394 | &cbSize); |
395 | } |
396 | else |
397 | { |
398 | _ASSERTE(pStgIO->GetMemoryMappedType() != MTYPE_IMAGE); |
399 | hr = FindObjMetaData(ptr, cbSize, &ptr, &cbSize); |
400 | } |
401 | // Was the metadata found inside the PE file? |
402 | if (FAILED(hr)) |
403 | { |
404 | if (hr == E_OUTOFMEMORY) |
405 | IfFailGo(E_OUTOFMEMORY); |
406 | |
407 | // No clb in the PE, assume it is a type library. |
408 | m_eFileType = FILETYPE_TLB; |
409 | |
410 | // Let the caller deal with a TypeLib. |
411 | IfFailGo(hr); |
412 | } |
413 | else |
414 | { |
415 | // Metadata was found inside the file. |
416 | // Now reset the base of the stg object so that all memory accesses |
417 | // are relative to the .clb content. |
418 | // |
419 | IfFailGo( pStgIO->SetBaseRange(ptr, cbSize) ); |
420 | |
421 | // If user wanted us to make a local copy of the data, do that now. |
422 | if (IsOfCopyMemory(dwFlags)) |
423 | { |
424 | // Cache the PEKind, Machine. |
425 | GetPEKind(pStgIO->GetMemoryMappedType(), NULL, NULL); |
426 | // Copy the file into memory; releases the file. |
427 | IfFailGo(pStgIO->LoadFileToMemory()); |
428 | // No longer have the image. |
429 | m_pImage = NULL; |
430 | m_dwImageSize = 0; |
431 | } |
432 | |
433 | // Defer to the normal lookup. |
434 | IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); |
435 | } |
436 | } |
437 | else if (m_eFileType == FILETYPE_TLB) |
438 | { |
439 | // Let the caller deal with a TypeLib. |
440 | IfFailGo(CLDB_E_NO_DATA); |
441 | } |
442 | // This spells trouble, we need to handle all types we might find. |
443 | else |
444 | { |
445 | _ASSERTE(!"Unknown file type." ); |
446 | IfFailGo( E_FAIL ); |
447 | } |
448 | |
449 | // Save off everything. |
450 | IfFailGo(SetFileName(szDatabase)); |
451 | |
452 | // If this was a file... |
453 | if (pbData == NULL) |
454 | { |
455 | WIN32_FILE_ATTRIBUTE_DATA faData; |
456 | if (!WszGetFileAttributesEx(szDatabase, GetFileExInfoStandard, &faData)) |
457 | IfFailGo(E_FAIL); |
458 | m_dwDatabaseLFS = faData.nFileSizeLow; |
459 | m_dwDatabaseLFT = faData.ftLastWriteTime.dwLowDateTime; |
460 | } |
461 | |
462 | ErrExit: |
463 | if (SUCCEEDED(hr)) |
464 | { |
465 | m_pStgIO = pStgIO; |
466 | } |
467 | else |
468 | { |
469 | if (pStgIO != NULL) |
470 | pStgIO->Release(); |
471 | } |
472 | return hr; |
473 | } |
474 | |
475 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
476 | // Open a metadata section for read/write |
477 | __checkReturn |
478 | HRESULT CLiteWeightStgdbRW::OpenForRead( |
479 | IMDCustomDataSource *pDataSource, // data to open on top of |
480 | DWORD dwFlags) // Flags for the open. |
481 | { |
482 | LPCWSTR pNoFile = W("" ); // Constant for empty file name. |
483 | StgIO *pStgIO = NULL; // For file i/o. |
484 | HRESULT hr; |
485 | |
486 | m_pImage = NULL; |
487 | m_dwImageSize = 0; |
488 | m_eFileType = FILETYPE_UNKNOWN; |
489 | |
490 | IfFailGo(m_MiniMd.InitOnCustomDataSource(pDataSource)); |
491 | IfFailGo(m_MiniMd.PostInit(0)); |
492 | |
493 | // Save off everything. |
494 | IfFailGo(SetFileName(pNoFile)); |
495 | |
496 | ErrExit: |
497 | return hr; |
498 | } |
499 | #endif |
500 | |
501 | // Read/Write versions. |
502 | //***************************************************************************** |
503 | // Init the Stgdb and its subcomponents. |
504 | //***************************************************************************** |
505 | __checkReturn |
506 | HRESULT CLiteWeightStgdbRW::InitNew() |
507 | { |
508 | InitializeLogging(); |
509 | LOG((LF_METADATA, LL_INFO10, "Metadata logging enabled\n" )); |
510 | |
511 | //<TODO>@FUTURE: should probably init the pools here instead of in the MiniMd.</TODO> |
512 | return m_MiniMd.InitNew(); |
513 | } |
514 | |
515 | //***************************************************************************** |
516 | // Determine what the size of the saved data will be. |
517 | //***************************************************************************** |
518 | __checkReturn |
519 | HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error. |
520 | CorSaveSize fSave, // Quick or accurate? |
521 | UINT32 *pcbSaveSize, // Put the size here. |
522 | MetaDataReorderingOptions reorderingOptions, |
523 | CorProfileData *pProfileData) // Profile data for working set optimization |
524 | { |
525 | HRESULT hr = S_OK; // A result. |
526 | UINT32 cbTotal = 0; // The total size. |
527 | UINT32 cbSize = 0; // Size of a component. |
528 | |
529 | m_cbSaveSize = 0; |
530 | |
531 | // Allocate stream list if not already done. |
532 | if (m_pStreamList == NULL) |
533 | { |
534 | IfNullGo(m_pStreamList = new (nothrow) STORAGESTREAMLST); |
535 | } |
536 | else |
537 | { |
538 | m_pStreamList->Clear(); |
539 | } |
540 | |
541 | // Make sure the user string pool is not empty. An empty user string pool causes |
542 | // problems with edit and continue |
543 | |
544 | if (m_MiniMd.m_UserStringHeap.GetUnalignedSize() <= 1) |
545 | { |
546 | if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode) && |
547 | !m_MiniMd.IsMinimalDelta()) |
548 | { |
549 | BYTE rgData[] = {' ', 0, 0}; |
550 | UINT32 nIndex_Ignore; |
551 | IfFailGo(m_MiniMd.PutUserString( |
552 | MetaData::DataBlob(rgData, sizeof(rgData)), |
553 | &nIndex_Ignore)); |
554 | } |
555 | } |
556 | |
557 | // If we're saving a delta metadata, figure out how much space it will take to |
558 | // save the minimal metadata stream (used only to identify that we have a delta |
559 | // metadata... nothing should be in that stream. |
560 | if ((m_MiniMd.m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateDelta) |
561 | { |
562 | IfFailGo(AddStreamToList(0, MINIMAL_MD_STREAM)); |
563 | // Ask the storage system to add stream fixed overhead. |
564 | IfFailGo(TiggerStorage::GetStreamSaveSize(MINIMAL_MD_STREAM, 0, &cbSize)); |
565 | cbTotal += cbSize; |
566 | } |
567 | |
568 | if (reorderingOptions & ReArrangeStringPool) |
569 | { |
570 | if (pProfileData != NULL) |
571 | { |
572 | UINT32 cbHotSize = 0; // Size of pool data. |
573 | UINT32 cbStream; // Size of just the stream. |
574 | DWORD bCompressed; // Will the stream be compressed data? |
575 | |
576 | // Ask the metadata to size its hot data. |
577 | IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); |
578 | cbStream = cbHotSize; |
579 | m_bSaveCompressed = bCompressed; |
580 | |
581 | if (cbHotSize != 0) |
582 | { |
583 | // Add this item to the save list. |
584 | IfFailGo(AddStreamToList(cbHotSize, HOT_MODEL_STREAM)); |
585 | |
586 | // Ask the storage system to add stream fixed overhead. |
587 | IfFailGo(TiggerStorage::GetStreamSaveSize(HOT_MODEL_STREAM, cbHotSize, &cbHotSize)); |
588 | |
589 | // Log the size info. |
590 | LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n" , |
591 | HOT_MODEL_STREAM, cbStream, cbHotSize)); |
592 | |
593 | cbTotal += cbHotSize; |
594 | } |
595 | } |
596 | |
597 | // get string pool save size |
598 | IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); |
599 | cbTotal += cbSize; |
600 | } |
601 | |
602 | // Query the MiniMd for its size. |
603 | IfFailGo(GetTablesSaveSize(fSave, &cbSize, reorderingOptions, pProfileData)); |
604 | cbTotal += cbSize; |
605 | |
606 | // Get the pools' sizes. |
607 | if( !(reorderingOptions & ReArrangeStringPool) ) |
608 | { |
609 | IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); |
610 | cbTotal += cbSize; |
611 | } |
612 | IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize)); |
613 | cbTotal += cbSize; |
614 | IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize)); |
615 | cbTotal += cbSize; |
616 | IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize)); |
617 | cbTotal += cbSize; |
618 | |
619 | // Finally, ask the storage system to add fixed overhead it needs for the |
620 | // file format. The overhead of each stream has already be calculated as |
621 | // part of GetStreamSaveSize. What's left is the signature and header |
622 | // fixed size overhead. |
623 | IfFailGo(TiggerStorage::GetStorageSaveSize((ULONG *)&cbTotal, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion)); |
624 | |
625 | // Log the size info. |
626 | LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n" , cbTotal)); |
627 | |
628 | // The list of streams that will be saved are now in the stream save list. |
629 | // Next step is to walk that list and fill out the correct offsets. This is |
630 | // done here so that the data can be streamed without fixing up the header. |
631 | TiggerStorage::CalcOffsets(m_pStreamList, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion); |
632 | |
633 | if (pcbSaveSize != NULL) |
634 | { |
635 | *pcbSaveSize = cbTotal; |
636 | } |
637 | |
638 | // Don't cache the value for the EnC case |
639 | if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) |
640 | m_cbSaveSize = cbTotal; |
641 | |
642 | ErrExit: |
643 | return hr; |
644 | } // CLiteWeightStgdbRW::GetSaveSize |
645 | |
646 | //***************************************************************************** |
647 | // Get the save size of one of the pools. Also adds the pool's stream to |
648 | // the list of streams to be saved. |
649 | //***************************************************************************** |
650 | __checkReturn |
651 | HRESULT |
652 | CLiteWeightStgdbRW::GetPoolSaveSize( |
653 | LPCWSTR szHeap, // Name of the heap stream. |
654 | int iPool, // The pool of which to get size. |
655 | UINT32 *pcbSaveSize) // Add pool data to this value. |
656 | { |
657 | UINT32 cbSize = 0; // Size of pool data. |
658 | UINT32 cbStream; // Size of just the stream. |
659 | HRESULT hr; |
660 | |
661 | *pcbSaveSize = 0; |
662 | |
663 | // If there is no data, then don't bother. |
664 | if (m_MiniMd.IsPoolEmpty(iPool)) |
665 | return (S_OK); |
666 | |
667 | // Ask the pool to size its data. |
668 | IfFailGo(m_MiniMd.GetPoolSaveSize(iPool, &cbSize)); |
669 | cbStream = cbSize; |
670 | |
671 | // Add this item to the save list. |
672 | IfFailGo(AddStreamToList(cbSize, szHeap)); |
673 | |
674 | |
675 | // Ask the storage system to add stream fixed overhead. |
676 | IfFailGo(TiggerStorage::GetStreamSaveSize(szHeap, cbSize, &cbSize)); |
677 | |
678 | // Log the size info. |
679 | LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n" , |
680 | szHeap, cbStream, cbSize)); |
681 | |
682 | // Give the size of the pool to the caller's total. |
683 | *pcbSaveSize = cbSize; |
684 | |
685 | ErrExit: |
686 | return hr; |
687 | } |
688 | |
689 | //***************************************************************************** |
690 | // Get the save size of the metadata tables. Also adds the tables stream to |
691 | // the list of streams to be saved. |
692 | //***************************************************************************** |
693 | __checkReturn |
694 | HRESULT CLiteWeightStgdbRW::GetTablesSaveSize( |
695 | CorSaveSize fSave, |
696 | UINT32 *pcbSaveSize, |
697 | MetaDataReorderingOptions reorderingOptions, |
698 | CorProfileData *pProfileData) // Add pool data to this value. |
699 | { |
700 | UINT32 cbSize = 0; // Size of pool data. |
701 | UINT32 cbHotSize = 0; // Size of pool data. |
702 | UINT32 cbStream; // Size of just the stream. |
703 | DWORD bCompressed; // Will the stream be compressed data? |
704 | LPCWSTR szName; // What will the name of the pool be? |
705 | HRESULT hr; |
706 | |
707 | *pcbSaveSize = 0; |
708 | |
709 | if( !(reorderingOptions & ReArrangeStringPool) ) |
710 | { |
711 | if (pProfileData != NULL) |
712 | { |
713 | // Ask the metadata to size its hot data. |
714 | IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); |
715 | cbStream = cbHotSize; |
716 | m_bSaveCompressed = bCompressed; |
717 | |
718 | if (cbHotSize != 0) |
719 | { |
720 | szName = HOT_MODEL_STREAM; |
721 | |
722 | // Add this item to the save list. |
723 | IfFailGo(AddStreamToList(cbHotSize, szName)); |
724 | |
725 | // Ask the storage system to add stream fixed overhead. |
726 | IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbHotSize, &cbHotSize)); |
727 | |
728 | // Log the size info. |
729 | LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n" , |
730 | szName, cbStream, cbHotSize)); |
731 | } |
732 | } |
733 | } |
734 | // Ask the metadata to size its data. |
735 | IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbSize, &bCompressed)); |
736 | cbStream = cbSize; |
737 | m_bSaveCompressed = bCompressed; |
738 | szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM; |
739 | |
740 | // Add this item to the save list. |
741 | IfFailGo(AddStreamToList(cbSize, szName)); |
742 | |
743 | // Ask the storage system to add stream fixed overhead. |
744 | IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbSize, &cbSize)); |
745 | |
746 | // Log the size info. |
747 | LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n" , |
748 | szName, cbStream, cbSize)); |
749 | |
750 | // Give the size of the pool to the caller's total. |
751 | *pcbSaveSize = cbHotSize + cbSize; |
752 | |
753 | ErrExit: |
754 | return hr; |
755 | } // CLiteWeightStgdbRW::GetTablesSaveSize |
756 | |
757 | //***************************************************************************** |
758 | // Add a stream, and its size, to the list of streams to be saved. |
759 | //***************************************************************************** |
760 | __checkReturn |
761 | HRESULT CLiteWeightStgdbRW::AddStreamToList( |
762 | UINT32 cbSize, |
763 | LPCWSTR szName) |
764 | { |
765 | HRESULT hr = S_OK; |
766 | PSTORAGESTREAM pItem; // New item to allocate & fill. |
767 | |
768 | // Add a new item to the end of the list. |
769 | IfNullGo(pItem = m_pStreamList->Append()); |
770 | |
771 | // Fill out the data. |
772 | pItem->SetOffset(0); |
773 | pItem->SetSize((ULONG)cbSize); |
774 | pItem->SetName(szName); |
775 | |
776 | ErrExit: |
777 | return hr; |
778 | } |
779 | |
780 | //***************************************************************************** |
781 | // Save the data to a stream. A TiggerStorage sub-allocates streams within |
782 | // the stream. |
783 | //***************************************************************************** |
784 | __checkReturn |
785 | HRESULT CLiteWeightStgdbRW::SaveToStream( |
786 | IStream *pIStream, |
787 | MetaDataReorderingOptions reorderingOptions, |
788 | CorProfileData *pProfileData) |
789 | { |
790 | HRESULT hr = S_OK; // A result. |
791 | StgIO *pStgIO = 0; |
792 | TiggerStorage *pStorage = 0; |
793 | |
794 | // Allocate a storage subsystem and backing store. |
795 | IfNullGo(pStgIO = new (nothrow) StgIO); |
796 | IfNullGo(pStorage = new (nothrow) TiggerStorage); |
797 | |
798 | // Open around this stream for write. |
799 | IfFailGo(pStgIO->Open(W("" ), |
800 | DBPROP_TMODEF_DFTWRITEMASK, |
801 | 0, 0, // pbData, cbData |
802 | pIStream, |
803 | 0)); // LPSecurityAttributes |
804 | OptionValue ov; |
805 | IfFailGo(m_MiniMd.GetOption(&ov)); |
806 | IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); |
807 | |
808 | // Save worker will do tables, pools. |
809 | IfFailGo(SaveToStorage(pStorage, reorderingOptions, pProfileData)); |
810 | |
811 | ErrExit: |
812 | if (pStgIO != NULL) |
813 | pStgIO->Release(); |
814 | if (pStorage != NULL) |
815 | delete pStorage; |
816 | return hr; |
817 | } // CLiteWeightStgdbRW::SaveToStream |
818 | |
819 | //***************************************************************************** |
820 | //***************************************************************************** |
821 | __checkReturn |
822 | HRESULT CLiteWeightStgdbRW::SaveToStorage( |
823 | TiggerStorage *pStorage, |
824 | MetaDataReorderingOptions reorderingOptions, |
825 | CorProfileData *pProfileData) |
826 | { |
827 | HRESULT hr; // A result. |
828 | LPCWSTR szName; // Name of the tables stream. |
829 | IStream *pIStreamTbl = 0; |
830 | UINT32 cb; |
831 | UINT32 cbSaveSize = m_cbSaveSize; |
832 | |
833 | // Must call GetSaveSize to cache the streams up front. |
834 | // Don't trust cached values in the delta case... if there was a previous call to get |
835 | // a non-delta size, it will be incorrect. |
836 | if ((m_cbSaveSize == 0) || IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) |
837 | { |
838 | IfFailGo(GetSaveSize(cssAccurate, &cbSaveSize)); |
839 | } |
840 | |
841 | // Save the header of the data file. |
842 | IfFailGo(pStorage->WriteHeader(m_pStreamList, 0, NULL)); |
843 | |
844 | // If this is a minimal delta, write a stream marker |
845 | if (IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) |
846 | { |
847 | IfFailGo(pStorage->CreateStream(MINIMAL_MD_STREAM, |
848 | STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, |
849 | 0, 0, &pIStreamTbl)); |
850 | pIStreamTbl->Release(); |
851 | pIStreamTbl = 0; |
852 | } |
853 | |
854 | if (pProfileData != NULL) |
855 | { |
856 | DWORD bCompressed; |
857 | UINT32 cbHotSize; |
858 | // Will the stream be compressed data? |
859 | |
860 | // Only create this additional stream if it will be non-empty |
861 | IfFailGo(m_MiniMd.GetSaveSize(cssAccurate, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); |
862 | |
863 | if (cbHotSize > 0) |
864 | { |
865 | // Create a stream and save the hot tables. |
866 | szName = HOT_MODEL_STREAM; |
867 | IfFailGo(pStorage->CreateStream(szName, |
868 | STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, |
869 | 0, 0, &pIStreamTbl)); |
870 | IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, reorderingOptions, pProfileData)); |
871 | pIStreamTbl->Release(); |
872 | pIStreamTbl = 0; |
873 | } |
874 | } |
875 | |
876 | if (reorderingOptions & ReArrangeStringPool) |
877 | { |
878 | // Save the string pool before the tables when we do not have the string pool cache |
879 | IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings)); |
880 | } |
881 | |
882 | // Create a stream and save the tables. |
883 | szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM; |
884 | IfFailGo(pStorage->CreateStream(szName, |
885 | STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, |
886 | 0, 0, &pIStreamTbl)); |
887 | IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, NoReordering, NULL)); |
888 | pIStreamTbl->Release(); |
889 | pIStreamTbl = 0; |
890 | |
891 | // Save the pools. |
892 | if (!(reorderingOptions & ReArrangeStringPool)) |
893 | { |
894 | // string pool must be saved after the tables when we have the string pool cache |
895 | IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings)); |
896 | } |
897 | IfFailGo(SavePool(US_BLOB_POOL_STREAM, pStorage, MDPoolUSBlobs)); |
898 | IfFailGo(SavePool(GUID_POOL_STREAM, pStorage, MDPoolGuids)); |
899 | IfFailGo(SavePool(BLOB_POOL_STREAM, pStorage, MDPoolBlobs)); |
900 | |
901 | // Write the header to disk. |
902 | OptionValue ov; |
903 | IfFailGo(m_MiniMd.GetOption(&ov)); |
904 | |
905 | IfFailGo(pStorage->WriteFinished(m_pStreamList, (ULONG *)&cb, IsENCDelta(ov.m_UpdateMode))); |
906 | |
907 | _ASSERTE(cbSaveSize == cb); |
908 | |
909 | // Let the Storage release some memory. |
910 | pStorage->ResetBackingStore(); |
911 | |
912 | IfFailGo(m_MiniMd.SaveDone()); |
913 | |
914 | ErrExit: |
915 | if (pIStreamTbl != NULL) |
916 | pIStreamTbl->Release(); |
917 | delete m_pStreamList; |
918 | m_pStreamList = 0; |
919 | m_cbSaveSize = 0; |
920 | return hr; |
921 | } // CLiteWeightStgdbRW::SaveToStorage |
922 | |
923 | //***************************************************************************** |
924 | // Save a pool of data out to a stream. |
925 | //***************************************************************************** |
926 | __checkReturn |
927 | HRESULT CLiteWeightStgdbRW::SavePool( // Return code. |
928 | LPCWSTR szName, // Name of stream on disk. |
929 | TiggerStorage *pStorage, // The storage to put data in. |
930 | int iPool) // The pool to save. |
931 | { |
932 | IStream *pIStream=0; // For writing. |
933 | HRESULT hr; |
934 | |
935 | // If there is no data, then don't bother. |
936 | if (m_MiniMd.IsPoolEmpty(iPool)) |
937 | return (S_OK); |
938 | |
939 | // Create the new stream to hold this table and save it. |
940 | IfFailGo(pStorage->CreateStream(szName, |
941 | STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, |
942 | 0, 0, &pIStream)); |
943 | IfFailGo(m_MiniMd.SavePoolToStream(iPool, pIStream)); |
944 | |
945 | ErrExit: |
946 | if (pIStream) |
947 | pIStream->Release(); |
948 | return hr; |
949 | } // CLiteWeightStgdbRW::SavePool |
950 | |
951 | |
952 | //***************************************************************************** |
953 | // Save the metadata to a file. |
954 | //***************************************************************************** |
955 | __checkReturn |
956 | HRESULT CLiteWeightStgdbRW::Save( |
957 | LPCWSTR szDatabase, // Name of file to which to save. |
958 | DWORD dwSaveFlags) // Flags for the save. |
959 | { |
960 | TiggerStorage * pStorage = NULL; // IStorage object. |
961 | StgIO * pStgIO = NULL; // Backing storage. |
962 | HRESULT hr = S_OK; |
963 | |
964 | if (m_wszFileName == NULL) |
965 | { |
966 | if (szDatabase == NULL) |
967 | { |
968 | // Make sure that a NULL is not passed in the first time around. |
969 | _ASSERTE(!"Not allowed to pass a NULL for filename on the first call to Save." ); |
970 | return E_INVALIDARG; |
971 | } |
972 | else |
973 | { |
974 | // Save the file name. |
975 | IfFailGo(SetFileName(szDatabase)); |
976 | } |
977 | } |
978 | else if ((szDatabase != NULL) && (SString::_wcsicmp(szDatabase, m_wszFileName) != 0)) |
979 | { |
980 | // Save the file name. |
981 | IfFailGo(SetFileName(szDatabase)); |
982 | } |
983 | |
984 | // Sanity check the name. |
985 | if (!IsValidFileNameLength(m_wszFileName)) |
986 | { |
987 | IfFailGo(E_INVALIDARG); |
988 | } |
989 | |
990 | m_eFileType = FILETYPE_CLB; |
991 | |
992 | // Allocate a new storage object. |
993 | IfNullGo(pStgIO = new (nothrow) StgIO); |
994 | |
995 | // Create the output file. |
996 | IfFailGo(pStgIO->Open(m_wszFileName, |
997 | DBPROP_TMODEF_DFTWRITEMASK, |
998 | 0,0, // pbData, cbData |
999 | 0, // IStream* |
1000 | 0)); // LPSecurityAttributes |
1001 | |
1002 | // Allocate an IStorage object to use. |
1003 | IfNullGo(pStorage = new (nothrow) TiggerStorage); |
1004 | |
1005 | // Init the storage object on the i/o system. |
1006 | OptionValue ov; |
1007 | IfFailGo(m_MiniMd.GetOption(&ov)); |
1008 | IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); |
1009 | |
1010 | // Save the data. |
1011 | IfFailGo(SaveToStorage(pStorage)); |
1012 | |
1013 | ErrExit: |
1014 | if (pStgIO != NULL) |
1015 | pStgIO->Release(); |
1016 | if (pStorage != NULL) |
1017 | delete pStorage; |
1018 | return hr; |
1019 | } // CLiteWeightStgdbRW::Save |
1020 | |
1021 | //***************************************************************************** |
1022 | // Pull the PEKind and Machine out of PE headers -- if we have PE headers. |
1023 | //***************************************************************************** |
1024 | __checkReturn |
1025 | HRESULT CLiteWeightStgdbRW::GetPEKind( // S_OK or error. |
1026 | MAPPINGTYPE mtMapping, // The type of mapping the image has |
1027 | DWORD *pdwPEKind, // [OUT] The kind of PE (0 - not a PE) |
1028 | DWORD *pdwMachine) // [OUT] Machine as defined in NT header |
1029 | { |
1030 | HRESULT hr = NOERROR; |
1031 | DWORD dwPEKind=0; // Working copy of pe kind. |
1032 | DWORD dwMachine=0; // Working copy of machine. |
1033 | |
1034 | #ifndef DACCESS_COMPILE |
1035 | // Do we already have cached information? |
1036 | if (m_dwPEKind != (DWORD)(-1)) |
1037 | { |
1038 | dwPEKind = m_dwPEKind; |
1039 | dwMachine = m_dwMachine; |
1040 | } |
1041 | else if (m_pImage) |
1042 | { |
1043 | PEDecoder pe; |
1044 | |
1045 | // We need to use different PEDecoder initialization based on the type of data we give it. |
1046 | // We use the one with a 'bool' as the second argument when dealing with a mapped file, |
1047 | // and we use the one that takes a COUNT_T as the second argument when dealing with a |
1048 | // flat file. |
1049 | |
1050 | if (mtMapping == MTYPE_IMAGE) |
1051 | { |
1052 | if (FAILED(pe.Init(m_pImage, false)) || |
1053 | !pe.CheckNTHeaders()) |
1054 | { |
1055 | IfFailRet(COR_E_BADIMAGEFORMAT); |
1056 | } |
1057 | } |
1058 | else |
1059 | { |
1060 | pe.Init(m_pImage, (COUNT_T)(m_dwImageSize)); |
1061 | } |
1062 | |
1063 | if (pe.HasContents() && pe.HasNTHeaders()) |
1064 | { |
1065 | pe.GetPEKindAndMachine(&dwPEKind, &dwMachine); |
1066 | |
1067 | |
1068 | // Cache entries. |
1069 | m_dwPEKind = dwPEKind; |
1070 | m_dwMachine = dwMachine; |
1071 | } |
1072 | else // if (pe.HasContents()... |
1073 | { |
1074 | hr = COR_E_BADIMAGEFORMAT; |
1075 | } |
1076 | } |
1077 | else |
1078 | { |
1079 | hr = S_FALSE; |
1080 | } |
1081 | #endif |
1082 | if (pdwPEKind) |
1083 | *pdwPEKind = dwPEKind; |
1084 | if (pdwMachine) |
1085 | *pdwMachine = dwMachine; |
1086 | |
1087 | return hr; |
1088 | } // CLiteWeightStgdbRW::GetPEKind |
1089 | |
1090 | //***************************************************************************** |
1091 | // Low level access to the data. Intended for metainfo, and such. |
1092 | //***************************************************************************** |
1093 | __checkReturn |
1094 | HRESULT CLiteWeightStgdbRW::GetRawData( |
1095 | const void **ppvMd, // [OUT] put pointer to MD section here (aka, 'BSJB'). |
1096 | ULONG *pcbMd) // [OUT] put size of the stream here. |
1097 | { |
1098 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
1099 | if (m_pStgIO == NULL) |
1100 | return COR_E_NOTSUPPORTED; |
1101 | #endif |
1102 | |
1103 | *ppvMd = (const void*) m_pStgIO->m_pData; |
1104 | *pcbMd = m_pStgIO->m_cbData; |
1105 | return S_OK; |
1106 | } // CLiteWeightStgdbRW::GetRawData |
1107 | |
1108 | //***************************************************************************** |
1109 | // Get info about the MD stream. |
1110 | // Low level access to stream data. Intended for metainfo, and such. |
1111 | //***************************************************************************** |
1112 | __checkReturn |
1113 | STDMETHODIMP |
1114 | CLiteWeightStgdbRW::GetRawStreamInfo( |
1115 | ULONG ix, // [IN] Stream ordinal desired. |
1116 | const char **ppchName, // [OUT] put pointer to stream name here. |
1117 | const void **ppv, // [OUT] put pointer to MD stream here. |
1118 | ULONG *pcb) // [OUT] put size of the stream here. |
1119 | { |
1120 | HRESULT hr = NOERROR; |
1121 | STORAGEHEADER sHdr; // Header for the storage. |
1122 | PSTORAGESTREAM pStream; // Pointer to each stream. |
1123 | ULONG i; // Loop control. |
1124 | void *pData; |
1125 | ULONG cbData; |
1126 | |
1127 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
1128 | if (m_pStgIO == NULL) |
1129 | IfFailGo(COR_E_NOTSUPPORTED); |
1130 | #endif |
1131 | |
1132 | pData = m_pStgIO->m_pData; |
1133 | cbData = m_pStgIO->m_cbData; |
1134 | |
1135 | // Validate the signature of the format, or it isn't ours. |
1136 | IfFailGo(MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData)); |
1137 | |
1138 | // Get back the first stream. |
1139 | pStream = MDFormat::GetFirstStream(&sHdr, pData); |
1140 | if (pStream == NULL) |
1141 | { |
1142 | Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header." ); |
1143 | IfFailGo(CLDB_E_FILE_CORRUPT); |
1144 | } |
1145 | |
1146 | // Check that the requested stream exists. |
1147 | if (ix >= sHdr.GetiStreams()) |
1148 | return S_FALSE; |
1149 | |
1150 | // Skip to the desired stream. |
1151 | for (i = 0; i < ix; i++) |
1152 | { |
1153 | PSTORAGESTREAM pNext = pStream->NextStream(); |
1154 | |
1155 | // Check that stream header is within the buffer. |
1156 | if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || |
1157 | ((LPBYTE)pNext > ((LPBYTE)pData + cbData))) |
1158 | { |
1159 | Debug_ReportError("Stream header is not within MetaData block." ); |
1160 | hr = CLDB_E_FILE_CORRUPT; |
1161 | goto ErrExit; |
1162 | } |
1163 | |
1164 | // Check that the stream data starts and fits within the buffer. |
1165 | // need two checks on size because of wraparound. |
1166 | if ((pStream->GetOffset() > cbData) || |
1167 | (pStream->GetSize() > cbData) || |
1168 | ((pStream->GetSize() + pStream->GetOffset()) > cbData)) |
1169 | { |
1170 | Debug_ReportError("Stream data are not within MetaData block." ); |
1171 | hr = CLDB_E_FILE_CORRUPT; |
1172 | goto ErrExit; |
1173 | } |
1174 | |
1175 | // Pick off the next stream if there is one. |
1176 | pStream = pNext; |
1177 | } |
1178 | |
1179 | if (pStream != NULL) |
1180 | { |
1181 | *ppv = (const void *)((const BYTE *)pData + pStream->GetOffset()); |
1182 | *pcb = pStream->GetSize(); |
1183 | *ppchName = pStream->GetName(); |
1184 | } |
1185 | else |
1186 | { |
1187 | *ppv = NULL; |
1188 | *pcb = 0; |
1189 | *ppchName = NULL; |
1190 | |
1191 | // Invalid input to the method |
1192 | hr = CLDB_E_FILE_CORRUPT; |
1193 | } |
1194 | |
1195 | ErrExit: |
1196 | return hr; |
1197 | } // CLiteWeightStgdbRW::GetRawStreamInfo |
1198 | |
1199 | //======================================================================================= |
1200 | // |
1201 | // Set file name of this database (makes copy of the file name). |
1202 | // |
1203 | // Return value: S_OK or E_OUTOFMEMORY |
1204 | // |
1205 | __checkReturn |
1206 | HRESULT |
1207 | CLiteWeightStgdbRW::SetFileName( |
1208 | const WCHAR * wszFileName) |
1209 | { |
1210 | HRESULT hr = S_OK; |
1211 | |
1212 | if (m_wszFileName != NULL) |
1213 | { |
1214 | delete [] m_wszFileName; |
1215 | m_wszFileName = NULL; |
1216 | } |
1217 | |
1218 | if ((wszFileName == NULL) || (*wszFileName == 0)) |
1219 | { // The new file name is empty |
1220 | _ASSERTE(m_wszFileName == NULL); |
1221 | |
1222 | // No need to allocate anything, NULL means empty name |
1223 | hr = S_OK; |
1224 | goto ErrExit; |
1225 | } |
1226 | |
1227 | // Size of the file name incl. null terminator |
1228 | size_t cchFileName; |
1229 | cchFileName = wcslen(wszFileName) + 1; |
1230 | |
1231 | // Allocate and copy the file name |
1232 | m_wszFileName = new (nothrow) WCHAR[cchFileName]; |
1233 | IfNullGo(m_wszFileName); |
1234 | wcscpy_s(m_wszFileName, cchFileName, wszFileName); |
1235 | |
1236 | ErrExit: |
1237 | return hr; |
1238 | } // CLiteWeightStgdbRW::SetFileName |
1239 | |
1240 | //======================================================================================= |
1241 | // |
1242 | // Returns TRUE if wszFileName has valid path length (MAX_PATH or 32767 if prefixed with \\?\). |
1243 | // |
1244 | //static |
1245 | BOOL |
1246 | CLiteWeightStgdbRW::IsValidFileNameLength( |
1247 | const WCHAR * wszFileName) |
1248 | { |
1249 | return TRUE; |
1250 | } // CLiteWeightStgdbRW::IsValidFileNameLength |
1251 | |