1*f6dc9357SAndroid Build Coastguard Worker // VhdxHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
15*f6dc9357SAndroid Build Coastguard Worker
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker
19*f6dc9357SAndroid Build Coastguard Worker #include "HandlerCont.h"
20*f6dc9357SAndroid Build Coastguard Worker
21*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
22*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
23*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
24*f6dc9357SAndroid Build Coastguard Worker
25*f6dc9357SAndroid Build Coastguard Worker #define G32(_offs_, dest) dest = Get32(p + (_offs_))
26*f6dc9357SAndroid Build Coastguard Worker #define G64(_offs_, dest) dest = Get64(p + (_offs_))
27*f6dc9357SAndroid Build Coastguard Worker
28*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
29*f6dc9357SAndroid Build Coastguard Worker
30*f6dc9357SAndroid Build Coastguard Worker
31*f6dc9357SAndroid Build Coastguard Worker EXTERN_C_BEGIN
32*f6dc9357SAndroid Build Coastguard Worker
33*f6dc9357SAndroid Build Coastguard Worker // CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41
34*f6dc9357SAndroid Build Coastguard Worker #define k_Crc32c_Poly 0x82f63b78
35*f6dc9357SAndroid Build Coastguard Worker
36*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN(64)
37*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_Crc32c_Table[256];
38*f6dc9357SAndroid Build Coastguard Worker
Crc32c_GenerateTable()39*f6dc9357SAndroid Build Coastguard Worker static void Z7_FASTCALL Crc32c_GenerateTable()
40*f6dc9357SAndroid Build Coastguard Worker {
41*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
42*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < 256; i++)
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker UInt32 r = i;
45*f6dc9357SAndroid Build Coastguard Worker unsigned j;
46*f6dc9357SAndroid Build Coastguard Worker for (j = 0; j < 8; j++)
47*f6dc9357SAndroid Build Coastguard Worker r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1)));
48*f6dc9357SAndroid Build Coastguard Worker g_Crc32c_Table[i] = r;
49*f6dc9357SAndroid Build Coastguard Worker }
50*f6dc9357SAndroid Build Coastguard Worker }
51*f6dc9357SAndroid Build Coastguard Worker
52*f6dc9357SAndroid Build Coastguard Worker
53*f6dc9357SAndroid Build Coastguard Worker #define CRC32C_INIT_VAL 0xFFFFFFFF
54*f6dc9357SAndroid Build Coastguard Worker
55*f6dc9357SAndroid Build Coastguard Worker #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
56*f6dc9357SAndroid Build Coastguard Worker
57*f6dc9357SAndroid Build Coastguard Worker // UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
CrcUpdateT1_vhdx(UInt32 v,const void * data,size_t size,const UInt32 * table)58*f6dc9357SAndroid Build Coastguard Worker static UInt32 Z7_FASTCALL CrcUpdateT1_vhdx(UInt32 v, const void *data, size_t size, const UInt32 *table)
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)data;
61*f6dc9357SAndroid Build Coastguard Worker const Byte *pEnd = p + size;
62*f6dc9357SAndroid Build Coastguard Worker for (; p != pEnd; p++)
63*f6dc9357SAndroid Build Coastguard Worker v = CRC_UPDATE_BYTE_2(v, *p);
64*f6dc9357SAndroid Build Coastguard Worker return v;
65*f6dc9357SAndroid Build Coastguard Worker }
66*f6dc9357SAndroid Build Coastguard Worker
Crc32c_Calc(const void * data,size_t size)67*f6dc9357SAndroid Build Coastguard Worker static UInt32 Z7_FASTCALL Crc32c_Calc(const void *data, size_t size)
68*f6dc9357SAndroid Build Coastguard Worker {
69*f6dc9357SAndroid Build Coastguard Worker return CrcUpdateT1_vhdx(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL;
70*f6dc9357SAndroid Build Coastguard Worker }
71*f6dc9357SAndroid Build Coastguard Worker
72*f6dc9357SAndroid Build Coastguard Worker EXTERN_C_END
73*f6dc9357SAndroid Build Coastguard Worker
74*f6dc9357SAndroid Build Coastguard Worker
75*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
76*f6dc9357SAndroid Build Coastguard Worker namespace NVhdx {
77*f6dc9357SAndroid Build Coastguard Worker
C_CRC32c_TableInitNArchive::NVhdx::C_CRC32c_TableInit78*f6dc9357SAndroid Build Coastguard Worker static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g_CRC32c_TableInit;
79*f6dc9357SAndroid Build Coastguard Worker
80*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSignatureSize = 8;
81*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature[kSignatureSize] =
82*f6dc9357SAndroid Build Coastguard Worker { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' };
83*f6dc9357SAndroid Build Coastguard Worker
84*f6dc9357SAndroid Build Coastguard Worker static const unsigned kBitmapSize_Log = 20;
85*f6dc9357SAndroid Build Coastguard Worker static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log;
86*f6dc9357SAndroid Build Coastguard Worker
87*f6dc9357SAndroid Build Coastguard Worker
IsZeroArr(const Byte * p,size_t size)88*f6dc9357SAndroid Build Coastguard Worker static bool IsZeroArr(const Byte *p, size_t size)
89*f6dc9357SAndroid Build Coastguard Worker {
90*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < size; i++)
91*f6dc9357SAndroid Build Coastguard Worker if (p[i] != 0)
92*f6dc9357SAndroid Build Coastguard Worker return false;
93*f6dc9357SAndroid Build Coastguard Worker return true;
94*f6dc9357SAndroid Build Coastguard Worker }
95*f6dc9357SAndroid Build Coastguard Worker
96*f6dc9357SAndroid Build Coastguard Worker
97*f6dc9357SAndroid Build Coastguard Worker
98*f6dc9357SAndroid Build Coastguard Worker Z7_FORCE_INLINE
DecodeFrom2HexChars(const wchar_t * s)99*f6dc9357SAndroid Build Coastguard Worker static int DecodeFrom2HexChars(const wchar_t *s)
100*f6dc9357SAndroid Build Coastguard Worker {
101*f6dc9357SAndroid Build Coastguard Worker unsigned v0 = (unsigned)s[0]; Z7_PARSE_HEX_DIGIT(v0, return -1;)
102*f6dc9357SAndroid Build Coastguard Worker unsigned v1 = (unsigned)s[1]; Z7_PARSE_HEX_DIGIT(v1, return -1;)
103*f6dc9357SAndroid Build Coastguard Worker return (int)((v0 << 4) | v1);
104*f6dc9357SAndroid Build Coastguard Worker }
105*f6dc9357SAndroid Build Coastguard Worker
106*f6dc9357SAndroid Build Coastguard Worker
107*f6dc9357SAndroid Build Coastguard Worker struct CGuid
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker Byte Data[16];
110*f6dc9357SAndroid Build Coastguard Worker
IsZeroNArchive::NVhdx::CGuid111*f6dc9357SAndroid Build Coastguard Worker bool IsZero() const { return IsZeroArr(Data, 16); }
IsEqualToNArchive::NVhdx::CGuid112*f6dc9357SAndroid Build Coastguard Worker bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; }
IsEqualToNArchive::NVhdx::CGuid113*f6dc9357SAndroid Build Coastguard Worker bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); }
114*f6dc9357SAndroid Build Coastguard Worker void AddHexToString(UString &s) const;
115*f6dc9357SAndroid Build Coastguard Worker
SetFromNArchive::NVhdx::CGuid116*f6dc9357SAndroid Build Coastguard Worker void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
117*f6dc9357SAndroid Build Coastguard Worker
ParseFromFormatedHexStringNArchive::NVhdx::CGuid118*f6dc9357SAndroid Build Coastguard Worker bool ParseFromFormatedHexString(const UString &s)
119*f6dc9357SAndroid Build Coastguard Worker {
120*f6dc9357SAndroid Build Coastguard Worker const unsigned kLen = 16 * 2 + 4 + 2;
121*f6dc9357SAndroid Build Coastguard Worker if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}')
122*f6dc9357SAndroid Build Coastguard Worker return false;
123*f6dc9357SAndroid Build Coastguard Worker unsigned pos = 0;
124*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 1; i < kLen - 1;)
125*f6dc9357SAndroid Build Coastguard Worker {
126*f6dc9357SAndroid Build Coastguard Worker if (i == 9 || i == 14 || i == 19 || i == 24)
127*f6dc9357SAndroid Build Coastguard Worker {
128*f6dc9357SAndroid Build Coastguard Worker if (s[i] != '-')
129*f6dc9357SAndroid Build Coastguard Worker return false;
130*f6dc9357SAndroid Build Coastguard Worker i++;
131*f6dc9357SAndroid Build Coastguard Worker continue;
132*f6dc9357SAndroid Build Coastguard Worker }
133*f6dc9357SAndroid Build Coastguard Worker const int v = DecodeFrom2HexChars(s.Ptr(i));
134*f6dc9357SAndroid Build Coastguard Worker if (v < 0)
135*f6dc9357SAndroid Build Coastguard Worker return false;
136*f6dc9357SAndroid Build Coastguard Worker unsigned pos2 = pos;
137*f6dc9357SAndroid Build Coastguard Worker if (pos < 8)
138*f6dc9357SAndroid Build Coastguard Worker pos2 ^= (pos < 4 ? 3 : 1);
139*f6dc9357SAndroid Build Coastguard Worker Data[pos2] = (Byte)v;
140*f6dc9357SAndroid Build Coastguard Worker pos++;
141*f6dc9357SAndroid Build Coastguard Worker i += 2;
142*f6dc9357SAndroid Build Coastguard Worker }
143*f6dc9357SAndroid Build Coastguard Worker return true; // pos == 16;
144*f6dc9357SAndroid Build Coastguard Worker }
145*f6dc9357SAndroid Build Coastguard Worker };
146*f6dc9357SAndroid Build Coastguard Worker
AddHexToString(UString & s) const147*f6dc9357SAndroid Build Coastguard Worker void CGuid::AddHexToString(UString &s) const
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker char temp[sizeof(Data) * 2 + 2];
150*f6dc9357SAndroid Build Coastguard Worker ConvertDataToHex_Lower(temp, Data, sizeof(Data));
151*f6dc9357SAndroid Build Coastguard Worker s += temp;
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker
154*f6dc9357SAndroid Build Coastguard Worker
155*f6dc9357SAndroid Build Coastguard Worker #define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0)
156*f6dc9357SAndroid Build Coastguard Worker
157*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_FileWriteGuid = 0;
158*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_DataWriteGuid = 1;
159*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_LogGuid = 2;
160*f6dc9357SAndroid Build Coastguard Worker
161*f6dc9357SAndroid Build Coastguard Worker struct CHeader
162*f6dc9357SAndroid Build Coastguard Worker {
163*f6dc9357SAndroid Build Coastguard Worker UInt64 SequenceNumber;
164*f6dc9357SAndroid Build Coastguard Worker // UInt16 LogVersion;
165*f6dc9357SAndroid Build Coastguard Worker // UInt16 Version;
166*f6dc9357SAndroid Build Coastguard Worker UInt32 LogLength;
167*f6dc9357SAndroid Build Coastguard Worker UInt64 LogOffset;
168*f6dc9357SAndroid Build Coastguard Worker CGuid Guids[3];
169*f6dc9357SAndroid Build Coastguard Worker
IsEqualToNArchive::NVhdx::CHeader170*f6dc9357SAndroid Build Coastguard Worker bool IsEqualTo(const CHeader &h) const
171*f6dc9357SAndroid Build Coastguard Worker {
172*f6dc9357SAndroid Build Coastguard Worker if (SequenceNumber != h.SequenceNumber)
173*f6dc9357SAndroid Build Coastguard Worker return false;
174*f6dc9357SAndroid Build Coastguard Worker if (LogLength != h.LogLength)
175*f6dc9357SAndroid Build Coastguard Worker return false;
176*f6dc9357SAndroid Build Coastguard Worker if (LogOffset != h.LogOffset)
177*f6dc9357SAndroid Build Coastguard Worker return false;
178*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 3; i++)
179*f6dc9357SAndroid Build Coastguard Worker if (!Guids[i].IsEqualTo(h.Guids[i]))
180*f6dc9357SAndroid Build Coastguard Worker return false;
181*f6dc9357SAndroid Build Coastguard Worker return true;
182*f6dc9357SAndroid Build Coastguard Worker }
183*f6dc9357SAndroid Build Coastguard Worker
184*f6dc9357SAndroid Build Coastguard Worker bool Parse(Byte *p);
185*f6dc9357SAndroid Build Coastguard Worker };
186*f6dc9357SAndroid Build Coastguard Worker
187*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader2Size = 1 << 12;
188*f6dc9357SAndroid Build Coastguard Worker
Parse(Byte * p)189*f6dc9357SAndroid Build Coastguard Worker bool CHeader::Parse(Byte *p)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker if (Get32(p) != 0x64616568) // "head"
192*f6dc9357SAndroid Build Coastguard Worker return false;
193*f6dc9357SAndroid Build Coastguard Worker const UInt32 crc = Get32(p + 4);
194*f6dc9357SAndroid Build Coastguard Worker SetUi32(p + 4, 0)
195*f6dc9357SAndroid Build Coastguard Worker if (Crc32c_Calc(p, kHeader2Size) != crc)
196*f6dc9357SAndroid Build Coastguard Worker return false;
197*f6dc9357SAndroid Build Coastguard Worker G64(8, SequenceNumber);
198*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 3; i++)
199*f6dc9357SAndroid Build Coastguard Worker Guids[i].SetFrom(p + 0x10 + 0x10 * i);
200*f6dc9357SAndroid Build Coastguard Worker // LogVersion = Get16(p + 0x40);
201*f6dc9357SAndroid Build Coastguard Worker /* LogVersion MUST be set to zero, for known log format
202*f6dc9357SAndroid Build Coastguard Worker but we don't parse log so we ignore it */
203*f6dc9357SAndroid Build Coastguard Worker G32(0x44, LogLength);
204*f6dc9357SAndroid Build Coastguard Worker G64(0x48, LogOffset);
205*f6dc9357SAndroid Build Coastguard Worker if (Get16(p + 0x42) != 1) // Header format Version
206*f6dc9357SAndroid Build Coastguard Worker return false;
207*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(LogLength))
208*f6dc9357SAndroid Build Coastguard Worker return false;
209*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(LogOffset))
210*f6dc9357SAndroid Build Coastguard Worker return false;
211*f6dc9357SAndroid Build Coastguard Worker return true;
212*f6dc9357SAndroid Build Coastguard Worker // return IsZeroArr(p + 0x50, kHeader2Size - 0x50);
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker
215*f6dc9357SAndroid Build Coastguard Worker
216*f6dc9357SAndroid Build Coastguard Worker
217*f6dc9357SAndroid Build Coastguard Worker static const Byte kBat[16] =
218*f6dc9357SAndroid Build Coastguard Worker { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 };
219*f6dc9357SAndroid Build Coastguard Worker static const Byte kMetadataRegion[16] =
220*f6dc9357SAndroid Build Coastguard Worker { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E };
221*f6dc9357SAndroid Build Coastguard Worker
222*f6dc9357SAndroid Build Coastguard Worker struct CRegionEntry
223*f6dc9357SAndroid Build Coastguard Worker {
224*f6dc9357SAndroid Build Coastguard Worker // CGuid Guid;
225*f6dc9357SAndroid Build Coastguard Worker UInt64 Offset;
226*f6dc9357SAndroid Build Coastguard Worker UInt32 Len;
227*f6dc9357SAndroid Build Coastguard Worker UInt32 Required;
228*f6dc9357SAndroid Build Coastguard Worker
GetEndPosNArchive::NVhdx::CRegionEntry229*f6dc9357SAndroid Build Coastguard Worker UInt64 GetEndPos() const { return Offset + Len; }
230*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p);
231*f6dc9357SAndroid Build Coastguard Worker };
232*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p)233*f6dc9357SAndroid Build Coastguard Worker bool CRegionEntry::Parse(const Byte *p)
234*f6dc9357SAndroid Build Coastguard Worker {
235*f6dc9357SAndroid Build Coastguard Worker // Guid.SetFrom(p);
236*f6dc9357SAndroid Build Coastguard Worker G64(0x10, Offset);
237*f6dc9357SAndroid Build Coastguard Worker G32(0x18, Len);
238*f6dc9357SAndroid Build Coastguard Worker G32(0x1c, Required);
239*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(Offset))
240*f6dc9357SAndroid Build Coastguard Worker return false;
241*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(Len))
242*f6dc9357SAndroid Build Coastguard Worker return false;
243*f6dc9357SAndroid Build Coastguard Worker if (Offset + Len < Offset)
244*f6dc9357SAndroid Build Coastguard Worker return false;
245*f6dc9357SAndroid Build Coastguard Worker return true;
246*f6dc9357SAndroid Build Coastguard Worker }
247*f6dc9357SAndroid Build Coastguard Worker
248*f6dc9357SAndroid Build Coastguard Worker
249*f6dc9357SAndroid Build Coastguard Worker struct CRegion
250*f6dc9357SAndroid Build Coastguard Worker {
251*f6dc9357SAndroid Build Coastguard Worker bool Bat_Defined;
252*f6dc9357SAndroid Build Coastguard Worker bool Meta_Defined;
253*f6dc9357SAndroid Build Coastguard Worker UInt64 EndPos;
254*f6dc9357SAndroid Build Coastguard Worker UInt64 DataSize;
255*f6dc9357SAndroid Build Coastguard Worker
256*f6dc9357SAndroid Build Coastguard Worker CRegionEntry BatEntry;
257*f6dc9357SAndroid Build Coastguard Worker CRegionEntry MetaEntry;
258*f6dc9357SAndroid Build Coastguard Worker
259*f6dc9357SAndroid Build Coastguard Worker bool Parse(Byte *p);
260*f6dc9357SAndroid Build Coastguard Worker };
261*f6dc9357SAndroid Build Coastguard Worker
262*f6dc9357SAndroid Build Coastguard Worker
263*f6dc9357SAndroid Build Coastguard Worker static const size_t kRegionSize = 1 << 16;
264*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumRegionEntriesMax = (1 << 11) - 1;
265*f6dc9357SAndroid Build Coastguard Worker
Parse(Byte * p)266*f6dc9357SAndroid Build Coastguard Worker bool CRegion::Parse(Byte *p)
267*f6dc9357SAndroid Build Coastguard Worker {
268*f6dc9357SAndroid Build Coastguard Worker Bat_Defined = false;
269*f6dc9357SAndroid Build Coastguard Worker Meta_Defined = false;
270*f6dc9357SAndroid Build Coastguard Worker EndPos = 0;
271*f6dc9357SAndroid Build Coastguard Worker DataSize = 0;
272*f6dc9357SAndroid Build Coastguard Worker
273*f6dc9357SAndroid Build Coastguard Worker if (Get32(p) != 0x69676572) // "regi"
274*f6dc9357SAndroid Build Coastguard Worker return false;
275*f6dc9357SAndroid Build Coastguard Worker const UInt32 crc = Get32(p + 4);
276*f6dc9357SAndroid Build Coastguard Worker SetUi32(p + 4, 0)
277*f6dc9357SAndroid Build Coastguard Worker const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize);
278*f6dc9357SAndroid Build Coastguard Worker if (crc_calced != crc)
279*f6dc9357SAndroid Build Coastguard Worker return false;
280*f6dc9357SAndroid Build Coastguard Worker
281*f6dc9357SAndroid Build Coastguard Worker const UInt32 EntryCount = Get32(p + 8);
282*f6dc9357SAndroid Build Coastguard Worker if (Get32(p + 12) != 0) // reserved field must be set to 0.
283*f6dc9357SAndroid Build Coastguard Worker return false;
284*f6dc9357SAndroid Build Coastguard Worker if (EntryCount > kNumRegionEntriesMax)
285*f6dc9357SAndroid Build Coastguard Worker return false;
286*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < EntryCount; i++)
287*f6dc9357SAndroid Build Coastguard Worker {
288*f6dc9357SAndroid Build Coastguard Worker CRegionEntry e;
289*f6dc9357SAndroid Build Coastguard Worker const Byte *p2 = p + 0x10 + 0x20 * (size_t)i;
290*f6dc9357SAndroid Build Coastguard Worker if (!e.Parse(p2))
291*f6dc9357SAndroid Build Coastguard Worker return false;
292*f6dc9357SAndroid Build Coastguard Worker DataSize += e.Len;
293*f6dc9357SAndroid Build Coastguard Worker const UInt64 endPos = e.GetEndPos();
294*f6dc9357SAndroid Build Coastguard Worker if (EndPos < endPos)
295*f6dc9357SAndroid Build Coastguard Worker EndPos = endPos;
296*f6dc9357SAndroid Build Coastguard Worker CGuid Guid;
297*f6dc9357SAndroid Build Coastguard Worker Guid.SetFrom(p2);
298*f6dc9357SAndroid Build Coastguard Worker if (Guid.IsEqualTo(kBat))
299*f6dc9357SAndroid Build Coastguard Worker {
300*f6dc9357SAndroid Build Coastguard Worker if (Bat_Defined)
301*f6dc9357SAndroid Build Coastguard Worker return false;
302*f6dc9357SAndroid Build Coastguard Worker BatEntry = e;
303*f6dc9357SAndroid Build Coastguard Worker Bat_Defined = true;
304*f6dc9357SAndroid Build Coastguard Worker }
305*f6dc9357SAndroid Build Coastguard Worker else if (Guid.IsEqualTo(kMetadataRegion))
306*f6dc9357SAndroid Build Coastguard Worker {
307*f6dc9357SAndroid Build Coastguard Worker if (Meta_Defined)
308*f6dc9357SAndroid Build Coastguard Worker return false;
309*f6dc9357SAndroid Build Coastguard Worker MetaEntry = e;
310*f6dc9357SAndroid Build Coastguard Worker Meta_Defined = true;
311*f6dc9357SAndroid Build Coastguard Worker }
312*f6dc9357SAndroid Build Coastguard Worker else
313*f6dc9357SAndroid Build Coastguard Worker {
314*f6dc9357SAndroid Build Coastguard Worker if (e.Required != 0)
315*f6dc9357SAndroid Build Coastguard Worker return false;
316*f6dc9357SAndroid Build Coastguard Worker // it's allowed to ignore unknown non-required region entries
317*f6dc9357SAndroid Build Coastguard Worker }
318*f6dc9357SAndroid Build Coastguard Worker }
319*f6dc9357SAndroid Build Coastguard Worker /*
320*f6dc9357SAndroid Build Coastguard Worker const size_t k = 0x10 + 0x20 * EntryCount;
321*f6dc9357SAndroid Build Coastguard Worker return IsZeroArr(p + k, kRegionSize - k);
322*f6dc9357SAndroid Build Coastguard Worker */
323*f6dc9357SAndroid Build Coastguard Worker return true;
324*f6dc9357SAndroid Build Coastguard Worker }
325*f6dc9357SAndroid Build Coastguard Worker
326*f6dc9357SAndroid Build Coastguard Worker
327*f6dc9357SAndroid Build Coastguard Worker
328*f6dc9357SAndroid Build Coastguard Worker
329*f6dc9357SAndroid Build Coastguard Worker struct CMetaEntry
330*f6dc9357SAndroid Build Coastguard Worker {
331*f6dc9357SAndroid Build Coastguard Worker CGuid Guid;
332*f6dc9357SAndroid Build Coastguard Worker UInt32 Offset;
333*f6dc9357SAndroid Build Coastguard Worker UInt32 Len;
334*f6dc9357SAndroid Build Coastguard Worker UInt32 Flags0;
335*f6dc9357SAndroid Build Coastguard Worker // UInt32 Flags1;
336*f6dc9357SAndroid Build Coastguard Worker
IsUserNArchive::NVhdx::CMetaEntry337*f6dc9357SAndroid Build Coastguard Worker bool IsUser() const { return (Flags0 & 1) != 0; }
IsVirtualDiskNArchive::NVhdx::CMetaEntry338*f6dc9357SAndroid Build Coastguard Worker bool IsVirtualDisk() const { return (Flags0 & 2) != 0; }
IsRequiredNArchive::NVhdx::CMetaEntry339*f6dc9357SAndroid Build Coastguard Worker bool IsRequired() const { return (Flags0 & 4) != 0; }
340*f6dc9357SAndroid Build Coastguard Worker
CheckLimitNArchive::NVhdx::CMetaEntry341*f6dc9357SAndroid Build Coastguard Worker bool CheckLimit(size_t regionSize) const
342*f6dc9357SAndroid Build Coastguard Worker {
343*f6dc9357SAndroid Build Coastguard Worker return Offset <= regionSize && Len <= regionSize - Offset;
344*f6dc9357SAndroid Build Coastguard Worker }
345*f6dc9357SAndroid Build Coastguard Worker
346*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p);
347*f6dc9357SAndroid Build Coastguard Worker };
348*f6dc9357SAndroid Build Coastguard Worker
349*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p)350*f6dc9357SAndroid Build Coastguard Worker bool CMetaEntry::Parse(const Byte *p)
351*f6dc9357SAndroid Build Coastguard Worker {
352*f6dc9357SAndroid Build Coastguard Worker Guid.SetFrom(p);
353*f6dc9357SAndroid Build Coastguard Worker
354*f6dc9357SAndroid Build Coastguard Worker G32(0x10, Offset);
355*f6dc9357SAndroid Build Coastguard Worker G32(0x14, Len);
356*f6dc9357SAndroid Build Coastguard Worker G32(0x18, Flags0);
357*f6dc9357SAndroid Build Coastguard Worker UInt32 Flags1;
358*f6dc9357SAndroid Build Coastguard Worker G32(0x1C, Flags1);
359*f6dc9357SAndroid Build Coastguard Worker
360*f6dc9357SAndroid Build Coastguard Worker if (Offset != 0 && Offset < (1 << 16))
361*f6dc9357SAndroid Build Coastguard Worker return false;
362*f6dc9357SAndroid Build Coastguard Worker if (Len > (1 << 20))
363*f6dc9357SAndroid Build Coastguard Worker return false;
364*f6dc9357SAndroid Build Coastguard Worker if (Len == 0 && Offset != 0)
365*f6dc9357SAndroid Build Coastguard Worker return false;
366*f6dc9357SAndroid Build Coastguard Worker if ((Flags0 >> 3) != 0) // Reserved
367*f6dc9357SAndroid Build Coastguard Worker return false;
368*f6dc9357SAndroid Build Coastguard Worker if ((Flags1 & 3) != 0) // Reserved2
369*f6dc9357SAndroid Build Coastguard Worker return false;
370*f6dc9357SAndroid Build Coastguard Worker return true;
371*f6dc9357SAndroid Build Coastguard Worker }
372*f6dc9357SAndroid Build Coastguard Worker
373*f6dc9357SAndroid Build Coastguard Worker
374*f6dc9357SAndroid Build Coastguard Worker struct CParentPair
375*f6dc9357SAndroid Build Coastguard Worker {
376*f6dc9357SAndroid Build Coastguard Worker UString Key;
377*f6dc9357SAndroid Build Coastguard Worker UString Value;
378*f6dc9357SAndroid Build Coastguard Worker };
379*f6dc9357SAndroid Build Coastguard Worker
380*f6dc9357SAndroid Build Coastguard Worker
381*f6dc9357SAndroid Build Coastguard Worker struct CMetaHeader
382*f6dc9357SAndroid Build Coastguard Worker {
383*f6dc9357SAndroid Build Coastguard Worker // UInt16 EntryCount;
384*f6dc9357SAndroid Build Coastguard Worker bool Guid_Defined;
385*f6dc9357SAndroid Build Coastguard Worker bool VirtualDiskSize_Defined;
386*f6dc9357SAndroid Build Coastguard Worker bool Locator_Defined;
387*f6dc9357SAndroid Build Coastguard Worker
388*f6dc9357SAndroid Build Coastguard Worker unsigned BlockSize_Log;
389*f6dc9357SAndroid Build Coastguard Worker unsigned LogicalSectorSize_Log;
390*f6dc9357SAndroid Build Coastguard Worker unsigned PhysicalSectorSize_Log;
391*f6dc9357SAndroid Build Coastguard Worker
392*f6dc9357SAndroid Build Coastguard Worker UInt32 Flags;
393*f6dc9357SAndroid Build Coastguard Worker UInt64 VirtualDiskSize;
394*f6dc9357SAndroid Build Coastguard Worker CGuid Guid;
395*f6dc9357SAndroid Build Coastguard Worker // CGuid LocatorType;
396*f6dc9357SAndroid Build Coastguard Worker
397*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CParentPair> ParentPairs;
398*f6dc9357SAndroid Build Coastguard Worker
FindParentKeyNArchive::NVhdx::CMetaHeader399*f6dc9357SAndroid Build Coastguard Worker int FindParentKey(const char *name) const
400*f6dc9357SAndroid Build Coastguard Worker {
401*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, ParentPairs)
402*f6dc9357SAndroid Build Coastguard Worker {
403*f6dc9357SAndroid Build Coastguard Worker const CParentPair &pair = ParentPairs[i];
404*f6dc9357SAndroid Build Coastguard Worker if (pair.Key.IsEqualTo(name))
405*f6dc9357SAndroid Build Coastguard Worker return (int)i;
406*f6dc9357SAndroid Build Coastguard Worker }
407*f6dc9357SAndroid Build Coastguard Worker return -1;
408*f6dc9357SAndroid Build Coastguard Worker }
409*f6dc9357SAndroid Build Coastguard Worker
Is_LeaveBlockAllocatedNArchive::NVhdx::CMetaHeader410*f6dc9357SAndroid Build Coastguard Worker bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; }
Is_HasParentNArchive::NVhdx::CMetaHeader411*f6dc9357SAndroid Build Coastguard Worker bool Is_HasParent() const { return (Flags & 2) != 0; }
412*f6dc9357SAndroid Build Coastguard Worker
ClearNArchive::NVhdx::CMetaHeader413*f6dc9357SAndroid Build Coastguard Worker void Clear()
414*f6dc9357SAndroid Build Coastguard Worker {
415*f6dc9357SAndroid Build Coastguard Worker Guid_Defined = false;
416*f6dc9357SAndroid Build Coastguard Worker VirtualDiskSize_Defined = false;
417*f6dc9357SAndroid Build Coastguard Worker Locator_Defined = false;
418*f6dc9357SAndroid Build Coastguard Worker BlockSize_Log = 0;
419*f6dc9357SAndroid Build Coastguard Worker LogicalSectorSize_Log = 0;
420*f6dc9357SAndroid Build Coastguard Worker PhysicalSectorSize_Log = 0;
421*f6dc9357SAndroid Build Coastguard Worker Flags = 0;
422*f6dc9357SAndroid Build Coastguard Worker VirtualDiskSize = 0;
423*f6dc9357SAndroid Build Coastguard Worker ParentPairs.Clear();
424*f6dc9357SAndroid Build Coastguard Worker }
425*f6dc9357SAndroid Build Coastguard Worker
426*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p, size_t size);
427*f6dc9357SAndroid Build Coastguard Worker };
428*f6dc9357SAndroid Build Coastguard Worker
429*f6dc9357SAndroid Build Coastguard Worker
GetLogSize(UInt32 size)430*f6dc9357SAndroid Build Coastguard Worker static unsigned GetLogSize(UInt32 size)
431*f6dc9357SAndroid Build Coastguard Worker {
432*f6dc9357SAndroid Build Coastguard Worker unsigned k;
433*f6dc9357SAndroid Build Coastguard Worker for (k = 0; k < 32; k++)
434*f6dc9357SAndroid Build Coastguard Worker if (((UInt32)1 << k) == size)
435*f6dc9357SAndroid Build Coastguard Worker return k;
436*f6dc9357SAndroid Build Coastguard Worker return k;
437*f6dc9357SAndroid Build Coastguard Worker }
438*f6dc9357SAndroid Build Coastguard Worker
439*f6dc9357SAndroid Build Coastguard Worker
440*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMetadataSize = 8;
441*f6dc9357SAndroid Build Coastguard Worker static const Byte kMetadata[kMetadataSize] =
442*f6dc9357SAndroid Build Coastguard Worker { 'm','e','t','a','d','a','t','a' };
443*f6dc9357SAndroid Build Coastguard Worker
444*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1;
445*f6dc9357SAndroid Build Coastguard Worker
446*f6dc9357SAndroid Build Coastguard Worker static const Byte kFileParameters[16] =
447*f6dc9357SAndroid Build Coastguard Worker { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b };
448*f6dc9357SAndroid Build Coastguard Worker static const Byte kVirtualDiskSize[16] =
449*f6dc9357SAndroid Build Coastguard Worker { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 };
450*f6dc9357SAndroid Build Coastguard Worker static const Byte kVirtualDiskID[16] =
451*f6dc9357SAndroid Build Coastguard Worker { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 };
452*f6dc9357SAndroid Build Coastguard Worker static const Byte kLogicalSectorSize[16] =
453*f6dc9357SAndroid Build Coastguard Worker { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f };
454*f6dc9357SAndroid Build Coastguard Worker static const Byte kPhysicalSectorSize[16] =
455*f6dc9357SAndroid Build Coastguard Worker { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 };
456*f6dc9357SAndroid Build Coastguard Worker static const Byte kParentLocator[16] =
457*f6dc9357SAndroid Build Coastguard Worker { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c };
458*f6dc9357SAndroid Build Coastguard Worker
GetString16(UString & s,const Byte * p,size_t size)459*f6dc9357SAndroid Build Coastguard Worker static bool GetString16(UString &s, const Byte *p, size_t size)
460*f6dc9357SAndroid Build Coastguard Worker {
461*f6dc9357SAndroid Build Coastguard Worker s.Empty();
462*f6dc9357SAndroid Build Coastguard Worker if (size & 1)
463*f6dc9357SAndroid Build Coastguard Worker return false;
464*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < size; i += 2)
465*f6dc9357SAndroid Build Coastguard Worker {
466*f6dc9357SAndroid Build Coastguard Worker const wchar_t c = Get16(p + i);
467*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
468*f6dc9357SAndroid Build Coastguard Worker return false;
469*f6dc9357SAndroid Build Coastguard Worker s += c;
470*f6dc9357SAndroid Build Coastguard Worker }
471*f6dc9357SAndroid Build Coastguard Worker return true;
472*f6dc9357SAndroid Build Coastguard Worker }
473*f6dc9357SAndroid Build Coastguard Worker
474*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p,size_t size)475*f6dc9357SAndroid Build Coastguard Worker bool CMetaHeader::Parse(const Byte *p, size_t size)
476*f6dc9357SAndroid Build Coastguard Worker {
477*f6dc9357SAndroid Build Coastguard Worker if (memcmp(p, kMetadata, kMetadataSize) != 0)
478*f6dc9357SAndroid Build Coastguard Worker return false;
479*f6dc9357SAndroid Build Coastguard Worker if (Get16(p + 8) != 0) // Reserved
480*f6dc9357SAndroid Build Coastguard Worker return false;
481*f6dc9357SAndroid Build Coastguard Worker const UInt32 EntryCount = Get16(p + 10);
482*f6dc9357SAndroid Build Coastguard Worker if (EntryCount > k_Num_MetaEntries_Max)
483*f6dc9357SAndroid Build Coastguard Worker return false;
484*f6dc9357SAndroid Build Coastguard Worker if (!IsZeroArr(p + 12, 20)) // Reserved
485*f6dc9357SAndroid Build Coastguard Worker return false;
486*f6dc9357SAndroid Build Coastguard Worker
487*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < EntryCount; i++)
488*f6dc9357SAndroid Build Coastguard Worker {
489*f6dc9357SAndroid Build Coastguard Worker CMetaEntry e;
490*f6dc9357SAndroid Build Coastguard Worker if (!e.Parse(p + 32 + 32 * (size_t)i))
491*f6dc9357SAndroid Build Coastguard Worker return false;
492*f6dc9357SAndroid Build Coastguard Worker if (!e.CheckLimit(size))
493*f6dc9357SAndroid Build Coastguard Worker return false;
494*f6dc9357SAndroid Build Coastguard Worker const Byte *p2 = p + e.Offset;
495*f6dc9357SAndroid Build Coastguard Worker
496*f6dc9357SAndroid Build Coastguard Worker if (e.Guid.IsEqualTo(kFileParameters))
497*f6dc9357SAndroid Build Coastguard Worker {
498*f6dc9357SAndroid Build Coastguard Worker if (BlockSize_Log != 0)
499*f6dc9357SAndroid Build Coastguard Worker return false;
500*f6dc9357SAndroid Build Coastguard Worker if (e.Len != 8)
501*f6dc9357SAndroid Build Coastguard Worker return false;
502*f6dc9357SAndroid Build Coastguard Worker const UInt32 v = Get32(p2);
503*f6dc9357SAndroid Build Coastguard Worker Flags = Get32(p2 + 4);
504*f6dc9357SAndroid Build Coastguard Worker BlockSize_Log = GetLogSize(v);
505*f6dc9357SAndroid Build Coastguard Worker if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB
506*f6dc9357SAndroid Build Coastguard Worker return false;
507*f6dc9357SAndroid Build Coastguard Worker if ((Flags >> 2) != 0) // reserved
508*f6dc9357SAndroid Build Coastguard Worker return false;
509*f6dc9357SAndroid Build Coastguard Worker }
510*f6dc9357SAndroid Build Coastguard Worker else if (e.Guid.IsEqualTo(kVirtualDiskSize))
511*f6dc9357SAndroid Build Coastguard Worker {
512*f6dc9357SAndroid Build Coastguard Worker if (VirtualDiskSize_Defined)
513*f6dc9357SAndroid Build Coastguard Worker return false;
514*f6dc9357SAndroid Build Coastguard Worker if (e.Len != 8)
515*f6dc9357SAndroid Build Coastguard Worker return false;
516*f6dc9357SAndroid Build Coastguard Worker VirtualDiskSize = Get64(p2);
517*f6dc9357SAndroid Build Coastguard Worker VirtualDiskSize_Defined = true;
518*f6dc9357SAndroid Build Coastguard Worker }
519*f6dc9357SAndroid Build Coastguard Worker else if (e.Guid.IsEqualTo(kVirtualDiskID))
520*f6dc9357SAndroid Build Coastguard Worker {
521*f6dc9357SAndroid Build Coastguard Worker if (e.Len != 16)
522*f6dc9357SAndroid Build Coastguard Worker return false;
523*f6dc9357SAndroid Build Coastguard Worker Guid.SetFrom(p2);
524*f6dc9357SAndroid Build Coastguard Worker Guid_Defined = true;
525*f6dc9357SAndroid Build Coastguard Worker }
526*f6dc9357SAndroid Build Coastguard Worker else if (e.Guid.IsEqualTo(kLogicalSectorSize))
527*f6dc9357SAndroid Build Coastguard Worker {
528*f6dc9357SAndroid Build Coastguard Worker if (LogicalSectorSize_Log != 0)
529*f6dc9357SAndroid Build Coastguard Worker return false;
530*f6dc9357SAndroid Build Coastguard Worker if (e.Len != 4)
531*f6dc9357SAndroid Build Coastguard Worker return false;
532*f6dc9357SAndroid Build Coastguard Worker const UInt32 v = Get32(p2);
533*f6dc9357SAndroid Build Coastguard Worker LogicalSectorSize_Log = GetLogSize(v);
534*f6dc9357SAndroid Build Coastguard Worker if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12)
535*f6dc9357SAndroid Build Coastguard Worker return false;
536*f6dc9357SAndroid Build Coastguard Worker }
537*f6dc9357SAndroid Build Coastguard Worker else if (e.Guid.IsEqualTo(kPhysicalSectorSize))
538*f6dc9357SAndroid Build Coastguard Worker {
539*f6dc9357SAndroid Build Coastguard Worker if (PhysicalSectorSize_Log != 0)
540*f6dc9357SAndroid Build Coastguard Worker return false;
541*f6dc9357SAndroid Build Coastguard Worker if (e.Len != 4)
542*f6dc9357SAndroid Build Coastguard Worker return false;
543*f6dc9357SAndroid Build Coastguard Worker const UInt32 v = Get32(p2);
544*f6dc9357SAndroid Build Coastguard Worker PhysicalSectorSize_Log = GetLogSize(v);
545*f6dc9357SAndroid Build Coastguard Worker if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12)
546*f6dc9357SAndroid Build Coastguard Worker return false;
547*f6dc9357SAndroid Build Coastguard Worker }
548*f6dc9357SAndroid Build Coastguard Worker else if (e.Guid.IsEqualTo(kParentLocator))
549*f6dc9357SAndroid Build Coastguard Worker {
550*f6dc9357SAndroid Build Coastguard Worker if (Locator_Defined)
551*f6dc9357SAndroid Build Coastguard Worker return false;
552*f6dc9357SAndroid Build Coastguard Worker if (e.Len < 20)
553*f6dc9357SAndroid Build Coastguard Worker return false;
554*f6dc9357SAndroid Build Coastguard Worker // LocatorType.SetFrom(p2);
555*f6dc9357SAndroid Build Coastguard Worker /* Specifies the type of the parent virtual disk.
556*f6dc9357SAndroid Build Coastguard Worker is different for each type: VHDX, VHD or iSCSI.
557*f6dc9357SAndroid Build Coastguard Worker only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now
558*f6dc9357SAndroid Build Coastguard Worker */
559*f6dc9357SAndroid Build Coastguard Worker Locator_Defined = true;
560*f6dc9357SAndroid Build Coastguard Worker if (Get16(p2 + 16) != 0) // reserved
561*f6dc9357SAndroid Build Coastguard Worker return false;
562*f6dc9357SAndroid Build Coastguard Worker const UInt32 KeyValueCount = Get16(p2 + 18);
563*f6dc9357SAndroid Build Coastguard Worker if (20 + (UInt32)KeyValueCount * 12 > e.Len)
564*f6dc9357SAndroid Build Coastguard Worker return false;
565*f6dc9357SAndroid Build Coastguard Worker for (unsigned k = 0; k < KeyValueCount; k++)
566*f6dc9357SAndroid Build Coastguard Worker {
567*f6dc9357SAndroid Build Coastguard Worker const Byte *p3 = p2 + 20 + (size_t)k * 12;
568*f6dc9357SAndroid Build Coastguard Worker const UInt32 KeyOffset = Get32(p3);
569*f6dc9357SAndroid Build Coastguard Worker const UInt32 ValueOffset = Get32(p3 + 4);
570*f6dc9357SAndroid Build Coastguard Worker const UInt32 KeyLength = Get16(p3 + 8);
571*f6dc9357SAndroid Build Coastguard Worker const UInt32 ValueLength = Get16(p3 + 10);
572*f6dc9357SAndroid Build Coastguard Worker if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset)
573*f6dc9357SAndroid Build Coastguard Worker return false;
574*f6dc9357SAndroid Build Coastguard Worker if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset)
575*f6dc9357SAndroid Build Coastguard Worker return false;
576*f6dc9357SAndroid Build Coastguard Worker CParentPair pair;
577*f6dc9357SAndroid Build Coastguard Worker if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength))
578*f6dc9357SAndroid Build Coastguard Worker return false;
579*f6dc9357SAndroid Build Coastguard Worker if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength))
580*f6dc9357SAndroid Build Coastguard Worker return false;
581*f6dc9357SAndroid Build Coastguard Worker ParentPairs.Add(pair);
582*f6dc9357SAndroid Build Coastguard Worker }
583*f6dc9357SAndroid Build Coastguard Worker }
584*f6dc9357SAndroid Build Coastguard Worker else
585*f6dc9357SAndroid Build Coastguard Worker {
586*f6dc9357SAndroid Build Coastguard Worker if (e.IsRequired())
587*f6dc9357SAndroid Build Coastguard Worker return false;
588*f6dc9357SAndroid Build Coastguard Worker // return false; // unknown metadata;
589*f6dc9357SAndroid Build Coastguard Worker }
590*f6dc9357SAndroid Build Coastguard Worker }
591*f6dc9357SAndroid Build Coastguard Worker
592*f6dc9357SAndroid Build Coastguard Worker // some properties are required for correct processing
593*f6dc9357SAndroid Build Coastguard Worker
594*f6dc9357SAndroid Build Coastguard Worker if (BlockSize_Log == 0)
595*f6dc9357SAndroid Build Coastguard Worker return false;
596*f6dc9357SAndroid Build Coastguard Worker if (LogicalSectorSize_Log == 0)
597*f6dc9357SAndroid Build Coastguard Worker return false;
598*f6dc9357SAndroid Build Coastguard Worker if (!VirtualDiskSize_Defined)
599*f6dc9357SAndroid Build Coastguard Worker return false;
600*f6dc9357SAndroid Build Coastguard Worker if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0)
601*f6dc9357SAndroid Build Coastguard Worker return false;
602*f6dc9357SAndroid Build Coastguard Worker
603*f6dc9357SAndroid Build Coastguard Worker // vhdx specification sets limit for 64 TB.
604*f6dc9357SAndroid Build Coastguard Worker // do we need to check over same limit ?
605*f6dc9357SAndroid Build Coastguard Worker const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46;
606*f6dc9357SAndroid Build Coastguard Worker if (VirtualDiskSize > kVirtualDiskSize_Max)
607*f6dc9357SAndroid Build Coastguard Worker return false;
608*f6dc9357SAndroid Build Coastguard Worker
609*f6dc9357SAndroid Build Coastguard Worker return true;
610*f6dc9357SAndroid Build Coastguard Worker }
611*f6dc9357SAndroid Build Coastguard Worker
612*f6dc9357SAndroid Build Coastguard Worker
613*f6dc9357SAndroid Build Coastguard Worker
614*f6dc9357SAndroid Build Coastguard Worker struct CBat
615*f6dc9357SAndroid Build Coastguard Worker {
616*f6dc9357SAndroid Build Coastguard Worker CByteBuffer Data;
617*f6dc9357SAndroid Build Coastguard Worker
ClearNArchive::NVhdx::CBat618*f6dc9357SAndroid Build Coastguard Worker void Clear() { Data.Free(); }
GetItemNArchive::NVhdx::CBat619*f6dc9357SAndroid Build Coastguard Worker UInt64 GetItem(size_t n) const
620*f6dc9357SAndroid Build Coastguard Worker {
621*f6dc9357SAndroid Build Coastguard Worker return Get64(Data + n * 8);
622*f6dc9357SAndroid Build Coastguard Worker }
623*f6dc9357SAndroid Build Coastguard Worker };
624*f6dc9357SAndroid Build Coastguard Worker
625*f6dc9357SAndroid Build Coastguard Worker
626*f6dc9357SAndroid Build Coastguard Worker
627*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final: public CHandlerImg
628*f6dc9357SAndroid Build Coastguard Worker {
629*f6dc9357SAndroid Build Coastguard Worker UInt64 _phySize;
630*f6dc9357SAndroid Build Coastguard Worker
631*f6dc9357SAndroid Build Coastguard Worker CBat Bat;
632*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CByteBuffer> BitMaps;
633*f6dc9357SAndroid Build Coastguard Worker
634*f6dc9357SAndroid Build Coastguard Worker unsigned ChunkRatio_Log;
635*f6dc9357SAndroid Build Coastguard Worker size_t ChunkRatio;
636*f6dc9357SAndroid Build Coastguard Worker size_t TotalBatEntries;
637*f6dc9357SAndroid Build Coastguard Worker
638*f6dc9357SAndroid Build Coastguard Worker CMetaHeader Meta;
639*f6dc9357SAndroid Build Coastguard Worker CHeader Header;
640*f6dc9357SAndroid Build Coastguard Worker
641*f6dc9357SAndroid Build Coastguard Worker UInt32 NumUsedBlocks;
642*f6dc9357SAndroid Build Coastguard Worker UInt32 NumUsedBitMaps;
643*f6dc9357SAndroid Build Coastguard Worker UInt64 HeadersSize;
644*f6dc9357SAndroid Build Coastguard Worker
645*f6dc9357SAndroid Build Coastguard Worker UInt32 NumLevels;
646*f6dc9357SAndroid Build Coastguard Worker UInt64 PackSize_Total;
647*f6dc9357SAndroid Build Coastguard Worker
648*f6dc9357SAndroid Build Coastguard Worker /*
649*f6dc9357SAndroid Build Coastguard Worker UInt64 NumUsed_1MB_Blocks; // data and bitmaps
650*f6dc9357SAndroid Build Coastguard Worker bool NumUsed_1MB_Blocks_Defined;
651*f6dc9357SAndroid Build Coastguard Worker */
652*f6dc9357SAndroid Build Coastguard Worker
653*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<IInStream> ParentStream;
654*f6dc9357SAndroid Build Coastguard Worker CHandler *Parent;
655*f6dc9357SAndroid Build Coastguard Worker UString _errorMessage;
656*f6dc9357SAndroid Build Coastguard Worker UString _creator;
657*f6dc9357SAndroid Build Coastguard Worker
658*f6dc9357SAndroid Build Coastguard Worker bool _nonEmptyLog;
659*f6dc9357SAndroid Build Coastguard Worker bool _isDataContiguous;
660*f6dc9357SAndroid Build Coastguard Worker // bool _batOverlap;
661*f6dc9357SAndroid Build Coastguard Worker
662*f6dc9357SAndroid Build Coastguard Worker CGuid _parentGuid;
663*f6dc9357SAndroid Build Coastguard Worker bool _parentGuid_IsDefined;
664*f6dc9357SAndroid Build Coastguard Worker UStringVector ParentNames;
665*f6dc9357SAndroid Build Coastguard Worker UString ParentName_Used;
666*f6dc9357SAndroid Build Coastguard Worker
667*f6dc9357SAndroid Build Coastguard Worker const CHandler *_child;
668*f6dc9357SAndroid Build Coastguard Worker unsigned _level;
669*f6dc9357SAndroid Build Coastguard Worker bool _isCyclic;
670*f6dc9357SAndroid Build Coastguard Worker bool _isCyclic_or_CyclicParent;
671*f6dc9357SAndroid Build Coastguard Worker
672*f6dc9357SAndroid Build Coastguard Worker void AddErrorMessage(const char *message);
673*f6dc9357SAndroid Build Coastguard Worker void AddErrorMessage(const char *message, const wchar_t *name);
674*f6dc9357SAndroid Build Coastguard Worker
675*f6dc9357SAndroid Build Coastguard Worker void UpdatePhySize(UInt64 value)
676*f6dc9357SAndroid Build Coastguard Worker {
677*f6dc9357SAndroid Build Coastguard Worker if (_phySize < value)
678*f6dc9357SAndroid Build Coastguard Worker _phySize = value;
679*f6dc9357SAndroid Build Coastguard Worker }
680*f6dc9357SAndroid Build Coastguard Worker
681*f6dc9357SAndroid Build Coastguard Worker HRESULT Seek2(UInt64 offset);
682*f6dc9357SAndroid Build Coastguard Worker HRESULT Read_FALSE(Byte *data, size_t size)
683*f6dc9357SAndroid Build Coastguard Worker {
684*f6dc9357SAndroid Build Coastguard Worker return ReadStream_FALSE(Stream, data, size);
685*f6dc9357SAndroid Build Coastguard Worker }
686*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size)
687*f6dc9357SAndroid Build Coastguard Worker {
688*f6dc9357SAndroid Build Coastguard Worker buf.Alloc(size);
689*f6dc9357SAndroid Build Coastguard Worker return ReadStream_FALSE(Stream, buf, size);
690*f6dc9357SAndroid Build Coastguard Worker }
691*f6dc9357SAndroid Build Coastguard Worker
692*f6dc9357SAndroid Build Coastguard Worker void InitSeekPositions();
693*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
694*f6dc9357SAndroid Build Coastguard Worker
695*f6dc9357SAndroid Build Coastguard Worker bool IsDiff() const
696*f6dc9357SAndroid Build Coastguard Worker {
697*f6dc9357SAndroid Build Coastguard Worker // here we suppose that only HasParent() flag is mandatory for Diff archive type
698*f6dc9357SAndroid Build Coastguard Worker return Meta.Is_HasParent();
699*f6dc9357SAndroid Build Coastguard Worker // return _parentGuid_IsDefined;
700*f6dc9357SAndroid Build Coastguard Worker }
701*f6dc9357SAndroid Build Coastguard Worker
702*f6dc9357SAndroid Build Coastguard Worker void AddTypeString(AString &s) const
703*f6dc9357SAndroid Build Coastguard Worker {
704*f6dc9357SAndroid Build Coastguard Worker if (IsDiff())
705*f6dc9357SAndroid Build Coastguard Worker s += "Differencing";
706*f6dc9357SAndroid Build Coastguard Worker else
707*f6dc9357SAndroid Build Coastguard Worker {
708*f6dc9357SAndroid Build Coastguard Worker if (Meta.Is_LeaveBlockAllocated())
709*f6dc9357SAndroid Build Coastguard Worker s += _isDataContiguous ? "fixed" : "fixed-non-cont";
710*f6dc9357SAndroid Build Coastguard Worker else
711*f6dc9357SAndroid Build Coastguard Worker s += "dynamic";
712*f6dc9357SAndroid Build Coastguard Worker }
713*f6dc9357SAndroid Build Coastguard Worker }
714*f6dc9357SAndroid Build Coastguard Worker
715*f6dc9357SAndroid Build Coastguard Worker void AddComment(UString &s) const;
716*f6dc9357SAndroid Build Coastguard Worker
717*f6dc9357SAndroid Build Coastguard Worker UInt64 GetPackSize() const
718*f6dc9357SAndroid Build Coastguard Worker {
719*f6dc9357SAndroid Build Coastguard Worker return (UInt64)NumUsedBlocks << Meta.BlockSize_Log;
720*f6dc9357SAndroid Build Coastguard Worker }
721*f6dc9357SAndroid Build Coastguard Worker
722*f6dc9357SAndroid Build Coastguard Worker UString GetParentSequence() const
723*f6dc9357SAndroid Build Coastguard Worker {
724*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
725*f6dc9357SAndroid Build Coastguard Worker UString res;
726*f6dc9357SAndroid Build Coastguard Worker while (p && p->IsDiff())
727*f6dc9357SAndroid Build Coastguard Worker {
728*f6dc9357SAndroid Build Coastguard Worker if (!res.IsEmpty())
729*f6dc9357SAndroid Build Coastguard Worker res += " -> ";
730*f6dc9357SAndroid Build Coastguard Worker res += ParentName_Used;
731*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
732*f6dc9357SAndroid Build Coastguard Worker }
733*f6dc9357SAndroid Build Coastguard Worker return res;
734*f6dc9357SAndroid Build Coastguard Worker }
735*f6dc9357SAndroid Build Coastguard Worker
736*f6dc9357SAndroid Build Coastguard Worker bool AreParentsOK() const
737*f6dc9357SAndroid Build Coastguard Worker {
738*f6dc9357SAndroid Build Coastguard Worker if (_isCyclic_or_CyclicParent)
739*f6dc9357SAndroid Build Coastguard Worker return false;
740*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
741*f6dc9357SAndroid Build Coastguard Worker while (p->IsDiff())
742*f6dc9357SAndroid Build Coastguard Worker {
743*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
744*f6dc9357SAndroid Build Coastguard Worker if (!p)
745*f6dc9357SAndroid Build Coastguard Worker return false;
746*f6dc9357SAndroid Build Coastguard Worker }
747*f6dc9357SAndroid Build Coastguard Worker return true;
748*f6dc9357SAndroid Build Coastguard Worker }
749*f6dc9357SAndroid Build Coastguard Worker
750*f6dc9357SAndroid Build Coastguard Worker // bool ParseLog(CByteBuffer &log);
751*f6dc9357SAndroid Build Coastguard Worker bool ParseBat();
752*f6dc9357SAndroid Build Coastguard Worker bool CheckBat();
753*f6dc9357SAndroid Build Coastguard Worker
754*f6dc9357SAndroid Build Coastguard Worker HRESULT Open3();
755*f6dc9357SAndroid Build Coastguard Worker HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override;
756*f6dc9357SAndroid Build Coastguard Worker HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen);
757*f6dc9357SAndroid Build Coastguard Worker virtual void CloseAtError() Z7_override;
758*f6dc9357SAndroid Build Coastguard Worker
759*f6dc9357SAndroid Build Coastguard Worker public:
760*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(IInArchive_Img)
761*f6dc9357SAndroid Build Coastguard Worker
762*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(IInArchiveGetStream)
763*f6dc9357SAndroid Build Coastguard Worker Z7_IFACE_COM7_IMP(ISequentialInStream)
764*f6dc9357SAndroid Build Coastguard Worker
765*f6dc9357SAndroid Build Coastguard Worker CHandler():
766*f6dc9357SAndroid Build Coastguard Worker _child(NULL),
767*f6dc9357SAndroid Build Coastguard Worker _level(0),
768*f6dc9357SAndroid Build Coastguard Worker _isCyclic(false),
769*f6dc9357SAndroid Build Coastguard Worker _isCyclic_or_CyclicParent(false)
770*f6dc9357SAndroid Build Coastguard Worker {}
771*f6dc9357SAndroid Build Coastguard Worker };
772*f6dc9357SAndroid Build Coastguard Worker
773*f6dc9357SAndroid Build Coastguard Worker
774*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Seek2(UInt64 offset)
775*f6dc9357SAndroid Build Coastguard Worker {
776*f6dc9357SAndroid Build Coastguard Worker return InStream_SeekSet(Stream, offset);
777*f6dc9357SAndroid Build Coastguard Worker }
778*f6dc9357SAndroid Build Coastguard Worker
779*f6dc9357SAndroid Build Coastguard Worker
780*f6dc9357SAndroid Build Coastguard Worker void CHandler::InitSeekPositions()
781*f6dc9357SAndroid Build Coastguard Worker {
782*f6dc9357SAndroid Build Coastguard Worker /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
783*f6dc9357SAndroid Build Coastguard Worker So we must reset these variables before first call of Read() */
784*f6dc9357SAndroid Build Coastguard Worker Reset_VirtPos();
785*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc();
786*f6dc9357SAndroid Build Coastguard Worker if (ParentStream)
787*f6dc9357SAndroid Build Coastguard Worker Parent->InitSeekPositions();
788*f6dc9357SAndroid Build Coastguard Worker }
789*f6dc9357SAndroid Build Coastguard Worker
790*f6dc9357SAndroid Build Coastguard Worker
791*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
792*f6dc9357SAndroid Build Coastguard Worker {
793*f6dc9357SAndroid Build Coastguard Worker processed = 0;
794*f6dc9357SAndroid Build Coastguard Worker if (offset > _phySize
795*f6dc9357SAndroid Build Coastguard Worker || offset + size > _phySize)
796*f6dc9357SAndroid Build Coastguard Worker {
797*f6dc9357SAndroid Build Coastguard Worker // we don't expect these cases, if (_phySize) was set correctly.
798*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
799*f6dc9357SAndroid Build Coastguard Worker }
800*f6dc9357SAndroid Build Coastguard Worker if (offset != _posInArc)
801*f6dc9357SAndroid Build Coastguard Worker {
802*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = Seek2(offset);
803*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK)
804*f6dc9357SAndroid Build Coastguard Worker {
805*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc(); // we don't trust seek_pos in case of error
806*f6dc9357SAndroid Build Coastguard Worker return res;
807*f6dc9357SAndroid Build Coastguard Worker }
808*f6dc9357SAndroid Build Coastguard Worker _posInArc = offset;
809*f6dc9357SAndroid Build Coastguard Worker }
810*f6dc9357SAndroid Build Coastguard Worker {
811*f6dc9357SAndroid Build Coastguard Worker size_t size2 = size;
812*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = ReadStream(Stream, data, &size2);
813*f6dc9357SAndroid Build Coastguard Worker processed = (UInt32)size2;
814*f6dc9357SAndroid Build Coastguard Worker _posInArc += size2;
815*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK)
816*f6dc9357SAndroid Build Coastguard Worker Reset_PosInArc(); // we don't trust seek_pos in case of reading error
817*f6dc9357SAndroid Build Coastguard Worker return res;
818*f6dc9357SAndroid Build Coastguard Worker }
819*f6dc9357SAndroid Build Coastguard Worker }
820*f6dc9357SAndroid Build Coastguard Worker
821*f6dc9357SAndroid Build Coastguard Worker
822*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_NOT_PRESENT 0
823*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_UNDEFINED 1
824*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_ZERO 2
825*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_UNMAPPED 3
826*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_FULLY_PRESENT 6
827*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
828*f6dc9357SAndroid Build Coastguard Worker
829*f6dc9357SAndroid Build Coastguard Worker #define SB_BLOCK_NOT_PRESENT 0
830*f6dc9357SAndroid Build Coastguard Worker #define SB_BLOCK_PRESENT 6
831*f6dc9357SAndroid Build Coastguard Worker
832*f6dc9357SAndroid Build Coastguard Worker #define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF)
833*f6dc9357SAndroid Build Coastguard Worker #define BAT_GET_STATE(v) ((UInt32)(v) & 7)
834*f6dc9357SAndroid Build Coastguard Worker
835*f6dc9357SAndroid Build Coastguard Worker /* The log contains only updates to metadata, bat and region tables
836*f6dc9357SAndroid Build Coastguard Worker The log doesn't contain updates to start header, and 2 headers (first 192 KB of file).
837*f6dc9357SAndroid Build Coastguard Worker The log is array of 4 KB blocks and each block has 4-byte signature.
838*f6dc9357SAndroid Build Coastguard Worker So it's possible to scan whole log to find the latest entry sequence (and header for replay).
839*f6dc9357SAndroid Build Coastguard Worker */
840*f6dc9357SAndroid Build Coastguard Worker
841*f6dc9357SAndroid Build Coastguard Worker /*
842*f6dc9357SAndroid Build Coastguard Worker struct CLogEntry
843*f6dc9357SAndroid Build Coastguard Worker {
844*f6dc9357SAndroid Build Coastguard Worker UInt32 EntryLength;
845*f6dc9357SAndroid Build Coastguard Worker UInt32 Tail;
846*f6dc9357SAndroid Build Coastguard Worker UInt64 SequenceNumber;
847*f6dc9357SAndroid Build Coastguard Worker CGuid LogGuid;
848*f6dc9357SAndroid Build Coastguard Worker UInt32 DescriptorCount;
849*f6dc9357SAndroid Build Coastguard Worker UInt64 FlushedFileOffset;
850*f6dc9357SAndroid Build Coastguard Worker UInt64 LastFileOffset;
851*f6dc9357SAndroid Build Coastguard Worker
852*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p);
853*f6dc9357SAndroid Build Coastguard Worker };
854*f6dc9357SAndroid Build Coastguard Worker
855*f6dc9357SAndroid Build Coastguard Worker bool CLogEntry::Parse(const Byte *p)
856*f6dc9357SAndroid Build Coastguard Worker {
857*f6dc9357SAndroid Build Coastguard Worker G32 (8, EntryLength);
858*f6dc9357SAndroid Build Coastguard Worker G32 (12,Tail);
859*f6dc9357SAndroid Build Coastguard Worker G64 (16, SequenceNumber);
860*f6dc9357SAndroid Build Coastguard Worker G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit
861*f6dc9357SAndroid Build Coastguard Worker if (Get32(p + 28) != 0) // reserved
862*f6dc9357SAndroid Build Coastguard Worker return false;
863*f6dc9357SAndroid Build Coastguard Worker LogGuid.SetFrom(p + 32);
864*f6dc9357SAndroid Build Coastguard Worker G64 (48, FlushedFileOffset);
865*f6dc9357SAndroid Build Coastguard Worker G64 (56, LastFileOffset);
866*f6dc9357SAndroid Build Coastguard Worker
867*f6dc9357SAndroid Build Coastguard Worker if (SequenceNumber == 0)
868*f6dc9357SAndroid Build Coastguard Worker return false;
869*f6dc9357SAndroid Build Coastguard Worker if ((Tail & 0xfff) != 0)
870*f6dc9357SAndroid Build Coastguard Worker return false;
871*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(FlushedFileOffset))
872*f6dc9357SAndroid Build Coastguard Worker return false;
873*f6dc9357SAndroid Build Coastguard Worker if (IS_NON_ALIGNED(LastFileOffset))
874*f6dc9357SAndroid Build Coastguard Worker return false;
875*f6dc9357SAndroid Build Coastguard Worker return true;
876*f6dc9357SAndroid Build Coastguard Worker }
877*f6dc9357SAndroid Build Coastguard Worker
878*f6dc9357SAndroid Build Coastguard Worker
879*f6dc9357SAndroid Build Coastguard Worker bool CHandler::ParseLog(CByteBuffer &log)
880*f6dc9357SAndroid Build Coastguard Worker {
881*f6dc9357SAndroid Build Coastguard Worker CLogEntry lastEntry;
882*f6dc9357SAndroid Build Coastguard Worker lastEntry.SequenceNumber = 0;
883*f6dc9357SAndroid Build Coastguard Worker bool lastEntry_found = false;
884*f6dc9357SAndroid Build Coastguard Worker size_t lastEntry_Offset = 0;
885*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < log.Size(); i += 1 << 12)
886*f6dc9357SAndroid Build Coastguard Worker {
887*f6dc9357SAndroid Build Coastguard Worker Byte *p = (Byte *)(log + i);
888*f6dc9357SAndroid Build Coastguard Worker
889*f6dc9357SAndroid Build Coastguard Worker if (Get32(p) != 0x65676F6C) // "loge"
890*f6dc9357SAndroid Build Coastguard Worker continue;
891*f6dc9357SAndroid Build Coastguard Worker const UInt32 crc = Get32(p + 4);
892*f6dc9357SAndroid Build Coastguard Worker
893*f6dc9357SAndroid Build Coastguard Worker CLogEntry e;
894*f6dc9357SAndroid Build Coastguard Worker if (!e.Parse(p))
895*f6dc9357SAndroid Build Coastguard Worker {
896*f6dc9357SAndroid Build Coastguard Worker return false;
897*f6dc9357SAndroid Build Coastguard Worker continue;
898*f6dc9357SAndroid Build Coastguard Worker }
899*f6dc9357SAndroid Build Coastguard Worker const UInt32 entryLength = Get32(p + 8);
900*f6dc9357SAndroid Build Coastguard Worker if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0)
901*f6dc9357SAndroid Build Coastguard Worker {
902*f6dc9357SAndroid Build Coastguard Worker return false;
903*f6dc9357SAndroid Build Coastguard Worker continue;
904*f6dc9357SAndroid Build Coastguard Worker }
905*f6dc9357SAndroid Build Coastguard Worker SetUi32(p + 4, 0);
906*f6dc9357SAndroid Build Coastguard Worker const UInt32 crc_calced = Crc32c_Calc(p, entryLength);
907*f6dc9357SAndroid Build Coastguard Worker SetUi32(p + 4, crc); // we must restore crc if we want same data in log
908*f6dc9357SAndroid Build Coastguard Worker if (crc_calced != crc)
909*f6dc9357SAndroid Build Coastguard Worker continue;
910*f6dc9357SAndroid Build Coastguard Worker if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber)
911*f6dc9357SAndroid Build Coastguard Worker {
912*f6dc9357SAndroid Build Coastguard Worker lastEntry = e;
913*f6dc9357SAndroid Build Coastguard Worker lastEntry_found = true;
914*f6dc9357SAndroid Build Coastguard Worker lastEntry_Offset = i;
915*f6dc9357SAndroid Build Coastguard Worker }
916*f6dc9357SAndroid Build Coastguard Worker }
917*f6dc9357SAndroid Build Coastguard Worker
918*f6dc9357SAndroid Build Coastguard Worker return true;
919*f6dc9357SAndroid Build Coastguard Worker }
920*f6dc9357SAndroid Build Coastguard Worker */
921*f6dc9357SAndroid Build Coastguard Worker
922*f6dc9357SAndroid Build Coastguard Worker
923*f6dc9357SAndroid Build Coastguard Worker bool CHandler::ParseBat()
924*f6dc9357SAndroid Build Coastguard Worker {
925*f6dc9357SAndroid Build Coastguard Worker ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log;
926*f6dc9357SAndroid Build Coastguard Worker ChunkRatio = (size_t)1 << (ChunkRatio_Log);
927*f6dc9357SAndroid Build Coastguard Worker
928*f6dc9357SAndroid Build Coastguard Worker UInt64 totalBatEntries64;
929*f6dc9357SAndroid Build Coastguard Worker const bool isDiff = IsDiff();
930*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
931*f6dc9357SAndroid Build Coastguard Worker {
932*f6dc9357SAndroid Build Coastguard Worker const UInt64 up = Meta.VirtualDiskSize + blockSize - 1;
933*f6dc9357SAndroid Build Coastguard Worker if (up < Meta.VirtualDiskSize)
934*f6dc9357SAndroid Build Coastguard Worker return false;
935*f6dc9357SAndroid Build Coastguard Worker const UInt64 numDataBlocks = up >> Meta.BlockSize_Log;
936*f6dc9357SAndroid Build Coastguard Worker
937*f6dc9357SAndroid Build Coastguard Worker if (isDiff)
938*f6dc9357SAndroid Build Coastguard Worker {
939*f6dc9357SAndroid Build Coastguard Worker // differencing table must be finished with bitmap entry
940*f6dc9357SAndroid Build Coastguard Worker const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log;
941*f6dc9357SAndroid Build Coastguard Worker totalBatEntries64 = numBitmaps * (ChunkRatio + 1);
942*f6dc9357SAndroid Build Coastguard Worker }
943*f6dc9357SAndroid Build Coastguard Worker else
944*f6dc9357SAndroid Build Coastguard Worker {
945*f6dc9357SAndroid Build Coastguard Worker // we don't need last Bitmap entry
946*f6dc9357SAndroid Build Coastguard Worker totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log);
947*f6dc9357SAndroid Build Coastguard Worker }
948*f6dc9357SAndroid Build Coastguard Worker }
949*f6dc9357SAndroid Build Coastguard Worker
950*f6dc9357SAndroid Build Coastguard Worker if (totalBatEntries64 > Bat.Data.Size() / 8)
951*f6dc9357SAndroid Build Coastguard Worker return false;
952*f6dc9357SAndroid Build Coastguard Worker
953*f6dc9357SAndroid Build Coastguard Worker const size_t totalBatEntries = (size_t)totalBatEntries64;
954*f6dc9357SAndroid Build Coastguard Worker TotalBatEntries = totalBatEntries;
955*f6dc9357SAndroid Build Coastguard Worker
956*f6dc9357SAndroid Build Coastguard Worker bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated());
957*f6dc9357SAndroid Build Coastguard Worker UInt64 prevBlockOffset = 0;
958*f6dc9357SAndroid Build Coastguard Worker UInt64 maxBlockOffset = 0;
959*f6dc9357SAndroid Build Coastguard Worker
960*f6dc9357SAndroid Build Coastguard Worker size_t remEntries = ChunkRatio + 1;
961*f6dc9357SAndroid Build Coastguard Worker
962*f6dc9357SAndroid Build Coastguard Worker size_t i;
963*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < totalBatEntries; i++)
964*f6dc9357SAndroid Build Coastguard Worker {
965*f6dc9357SAndroid Build Coastguard Worker const UInt64 v = Bat.GetItem(i);
966*f6dc9357SAndroid Build Coastguard Worker if ((v & 0xFFFF8) != 0)
967*f6dc9357SAndroid Build Coastguard Worker return false;
968*f6dc9357SAndroid Build Coastguard Worker const UInt64 offset = BAT_GET_OFFSET(v);
969*f6dc9357SAndroid Build Coastguard Worker const unsigned state = BAT_GET_STATE(v);
970*f6dc9357SAndroid Build Coastguard Worker
971*f6dc9357SAndroid Build Coastguard Worker /*
972*f6dc9357SAndroid Build Coastguard Worker UInt64 index64 = v >> 20;
973*f6dc9357SAndroid Build Coastguard Worker printf("\n%7d", i);
974*f6dc9357SAndroid Build Coastguard Worker printf("%10d, ", (unsigned)index64);
975*f6dc9357SAndroid Build Coastguard Worker printf("%4x, ", (unsigned)state);
976*f6dc9357SAndroid Build Coastguard Worker */
977*f6dc9357SAndroid Build Coastguard Worker
978*f6dc9357SAndroid Build Coastguard Worker remEntries--;
979*f6dc9357SAndroid Build Coastguard Worker if (remEntries == 0)
980*f6dc9357SAndroid Build Coastguard Worker {
981*f6dc9357SAndroid Build Coastguard Worker // printf(" ========");
982*f6dc9357SAndroid Build Coastguard Worker // printf("\n");
983*f6dc9357SAndroid Build Coastguard Worker remEntries = ChunkRatio + 1;
984*f6dc9357SAndroid Build Coastguard Worker if (state == SB_BLOCK_PRESENT)
985*f6dc9357SAndroid Build Coastguard Worker {
986*f6dc9357SAndroid Build Coastguard Worker isCont = false;
987*f6dc9357SAndroid Build Coastguard Worker if (!isDiff)
988*f6dc9357SAndroid Build Coastguard Worker return false;
989*f6dc9357SAndroid Build Coastguard Worker if (offset == 0)
990*f6dc9357SAndroid Build Coastguard Worker return false;
991*f6dc9357SAndroid Build Coastguard Worker const UInt64 lim = offset + kBitmapSize;
992*f6dc9357SAndroid Build Coastguard Worker if (lim < offset)
993*f6dc9357SAndroid Build Coastguard Worker return false;
994*f6dc9357SAndroid Build Coastguard Worker if (_phySize < lim)
995*f6dc9357SAndroid Build Coastguard Worker _phySize = lim;
996*f6dc9357SAndroid Build Coastguard Worker NumUsedBitMaps++;
997*f6dc9357SAndroid Build Coastguard Worker }
998*f6dc9357SAndroid Build Coastguard Worker else if (state != SB_BLOCK_NOT_PRESENT)
999*f6dc9357SAndroid Build Coastguard Worker return false;
1000*f6dc9357SAndroid Build Coastguard Worker }
1001*f6dc9357SAndroid Build Coastguard Worker else
1002*f6dc9357SAndroid Build Coastguard Worker {
1003*f6dc9357SAndroid Build Coastguard Worker if (state == PAYLOAD_BLOCK_FULLY_PRESENT
1004*f6dc9357SAndroid Build Coastguard Worker || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1005*f6dc9357SAndroid Build Coastguard Worker {
1006*f6dc9357SAndroid Build Coastguard Worker if (offset == 0)
1007*f6dc9357SAndroid Build Coastguard Worker return false;
1008*f6dc9357SAndroid Build Coastguard Worker if (maxBlockOffset < offset)
1009*f6dc9357SAndroid Build Coastguard Worker maxBlockOffset = offset;
1010*f6dc9357SAndroid Build Coastguard Worker
1011*f6dc9357SAndroid Build Coastguard Worker if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1012*f6dc9357SAndroid Build Coastguard Worker {
1013*f6dc9357SAndroid Build Coastguard Worker isCont = false;
1014*f6dc9357SAndroid Build Coastguard Worker if (!isDiff)
1015*f6dc9357SAndroid Build Coastguard Worker return false;
1016*f6dc9357SAndroid Build Coastguard Worker }
1017*f6dc9357SAndroid Build Coastguard Worker else if (isCont)
1018*f6dc9357SAndroid Build Coastguard Worker {
1019*f6dc9357SAndroid Build Coastguard Worker if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset)
1020*f6dc9357SAndroid Build Coastguard Worker isCont = false;
1021*f6dc9357SAndroid Build Coastguard Worker else
1022*f6dc9357SAndroid Build Coastguard Worker prevBlockOffset = offset;
1023*f6dc9357SAndroid Build Coastguard Worker }
1024*f6dc9357SAndroid Build Coastguard Worker
1025*f6dc9357SAndroid Build Coastguard Worker NumUsedBlocks++;
1026*f6dc9357SAndroid Build Coastguard Worker }
1027*f6dc9357SAndroid Build Coastguard Worker else if (state == PAYLOAD_BLOCK_UNMAPPED)
1028*f6dc9357SAndroid Build Coastguard Worker {
1029*f6dc9357SAndroid Build Coastguard Worker isCont = false;
1030*f6dc9357SAndroid Build Coastguard Worker // non-empty (offset) is allowed
1031*f6dc9357SAndroid Build Coastguard Worker }
1032*f6dc9357SAndroid Build Coastguard Worker else if (state == PAYLOAD_BLOCK_NOT_PRESENT
1033*f6dc9357SAndroid Build Coastguard Worker || state == PAYLOAD_BLOCK_UNDEFINED
1034*f6dc9357SAndroid Build Coastguard Worker || state == PAYLOAD_BLOCK_ZERO)
1035*f6dc9357SAndroid Build Coastguard Worker {
1036*f6dc9357SAndroid Build Coastguard Worker isCont = false;
1037*f6dc9357SAndroid Build Coastguard Worker /* (offset) is reserved and (offset == 0) is expected here,
1038*f6dc9357SAndroid Build Coastguard Worker but we ignore (offset) here */
1039*f6dc9357SAndroid Build Coastguard Worker // if (offset != 0) return false;
1040*f6dc9357SAndroid Build Coastguard Worker }
1041*f6dc9357SAndroid Build Coastguard Worker else
1042*f6dc9357SAndroid Build Coastguard Worker return false;
1043*f6dc9357SAndroid Build Coastguard Worker }
1044*f6dc9357SAndroid Build Coastguard Worker }
1045*f6dc9357SAndroid Build Coastguard Worker
1046*f6dc9357SAndroid Build Coastguard Worker _isDataContiguous = isCont;
1047*f6dc9357SAndroid Build Coastguard Worker
1048*f6dc9357SAndroid Build Coastguard Worker if (maxBlockOffset != 0)
1049*f6dc9357SAndroid Build Coastguard Worker {
1050*f6dc9357SAndroid Build Coastguard Worker const UInt64 lim = maxBlockOffset + blockSize;
1051*f6dc9357SAndroid Build Coastguard Worker if (lim < maxBlockOffset)
1052*f6dc9357SAndroid Build Coastguard Worker return false;
1053*f6dc9357SAndroid Build Coastguard Worker if (_phySize < lim)
1054*f6dc9357SAndroid Build Coastguard Worker _phySize = lim;
1055*f6dc9357SAndroid Build Coastguard Worker const UInt64 kPhyLimit = (UInt64)1 << 62;
1056*f6dc9357SAndroid Build Coastguard Worker if (maxBlockOffset >= kPhyLimit)
1057*f6dc9357SAndroid Build Coastguard Worker return false;
1058*f6dc9357SAndroid Build Coastguard Worker }
1059*f6dc9357SAndroid Build Coastguard Worker return true;
1060*f6dc9357SAndroid Build Coastguard Worker }
1061*f6dc9357SAndroid Build Coastguard Worker
1062*f6dc9357SAndroid Build Coastguard Worker
1063*f6dc9357SAndroid Build Coastguard Worker bool CHandler::CheckBat()
1064*f6dc9357SAndroid Build Coastguard Worker {
1065*f6dc9357SAndroid Build Coastguard Worker const UInt64 upSize = _phySize + kBitmapSize * 8 - 1;
1066*f6dc9357SAndroid Build Coastguard Worker if (upSize < _phySize)
1067*f6dc9357SAndroid Build Coastguard Worker return false;
1068*f6dc9357SAndroid Build Coastguard Worker const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3);
1069*f6dc9357SAndroid Build Coastguard Worker const size_t useMapSize = (size_t)useMapSize64;
1070*f6dc9357SAndroid Build Coastguard Worker
1071*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log);
1072*f6dc9357SAndroid Build Coastguard Worker
1073*f6dc9357SAndroid Build Coastguard Worker // we don't check useMap, if it's too big.
1074*f6dc9357SAndroid Build Coastguard Worker if (useMapSize != useMapSize64)
1075*f6dc9357SAndroid Build Coastguard Worker return true;
1076*f6dc9357SAndroid Build Coastguard Worker if (useMapSize == 0 || useMapSize > ((size_t)1 << 28))
1077*f6dc9357SAndroid Build Coastguard Worker return true;
1078*f6dc9357SAndroid Build Coastguard Worker
1079*f6dc9357SAndroid Build Coastguard Worker CByteArr useMap;
1080*f6dc9357SAndroid Build Coastguard Worker useMap.Alloc(useMapSize);
1081*f6dc9357SAndroid Build Coastguard Worker memset(useMap, 0, useMapSize);
1082*f6dc9357SAndroid Build Coastguard Worker // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers
1083*f6dc9357SAndroid Build Coastguard Worker // we can also update useMap for log, and region data.
1084*f6dc9357SAndroid Build Coastguard Worker
1085*f6dc9357SAndroid Build Coastguard Worker const size_t totalBatEntries = TotalBatEntries;
1086*f6dc9357SAndroid Build Coastguard Worker size_t remEntries = ChunkRatio + 1;
1087*f6dc9357SAndroid Build Coastguard Worker
1088*f6dc9357SAndroid Build Coastguard Worker size_t i;
1089*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < totalBatEntries; i++)
1090*f6dc9357SAndroid Build Coastguard Worker {
1091*f6dc9357SAndroid Build Coastguard Worker const UInt64 v = Bat.GetItem(i);
1092*f6dc9357SAndroid Build Coastguard Worker const UInt64 offset = BAT_GET_OFFSET(v);
1093*f6dc9357SAndroid Build Coastguard Worker const unsigned state = BAT_GET_STATE(v);
1094*f6dc9357SAndroid Build Coastguard Worker const UInt64 index = offset >> kBitmapSize_Log;
1095*f6dc9357SAndroid Build Coastguard Worker UInt32 numBlocks = 1;
1096*f6dc9357SAndroid Build Coastguard Worker remEntries--;
1097*f6dc9357SAndroid Build Coastguard Worker if (remEntries == 0)
1098*f6dc9357SAndroid Build Coastguard Worker {
1099*f6dc9357SAndroid Build Coastguard Worker remEntries = ChunkRatio + 1;
1100*f6dc9357SAndroid Build Coastguard Worker if (state != SB_BLOCK_PRESENT)
1101*f6dc9357SAndroid Build Coastguard Worker continue;
1102*f6dc9357SAndroid Build Coastguard Worker }
1103*f6dc9357SAndroid Build Coastguard Worker else
1104*f6dc9357SAndroid Build Coastguard Worker {
1105*f6dc9357SAndroid Build Coastguard Worker if (state != PAYLOAD_BLOCK_FULLY_PRESENT &&
1106*f6dc9357SAndroid Build Coastguard Worker state != PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1107*f6dc9357SAndroid Build Coastguard Worker continue;
1108*f6dc9357SAndroid Build Coastguard Worker numBlocks = blockSizeMB;
1109*f6dc9357SAndroid Build Coastguard Worker }
1110*f6dc9357SAndroid Build Coastguard Worker
1111*f6dc9357SAndroid Build Coastguard Worker for (unsigned k = 0; k < numBlocks; k++)
1112*f6dc9357SAndroid Build Coastguard Worker {
1113*f6dc9357SAndroid Build Coastguard Worker const UInt64 index2 = index + k;
1114*f6dc9357SAndroid Build Coastguard Worker const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7);
1115*f6dc9357SAndroid Build Coastguard Worker const size_t byteIndex = (size_t)(index2 >> 3);
1116*f6dc9357SAndroid Build Coastguard Worker if (byteIndex >= useMapSize)
1117*f6dc9357SAndroid Build Coastguard Worker return false;
1118*f6dc9357SAndroid Build Coastguard Worker const unsigned m = useMap[byteIndex];
1119*f6dc9357SAndroid Build Coastguard Worker if (m & flag)
1120*f6dc9357SAndroid Build Coastguard Worker return false;
1121*f6dc9357SAndroid Build Coastguard Worker useMap[byteIndex] = (Byte)(m | flag);
1122*f6dc9357SAndroid Build Coastguard Worker }
1123*f6dc9357SAndroid Build Coastguard Worker }
1124*f6dc9357SAndroid Build Coastguard Worker
1125*f6dc9357SAndroid Build Coastguard Worker /*
1126*f6dc9357SAndroid Build Coastguard Worker UInt64 num = 0;
1127*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < useMapSize; i++)
1128*f6dc9357SAndroid Build Coastguard Worker {
1129*f6dc9357SAndroid Build Coastguard Worker Byte b = useMap[i];
1130*f6dc9357SAndroid Build Coastguard Worker unsigned t = 0;
1131*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1132*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1133*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1134*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1135*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1136*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1137*f6dc9357SAndroid Build Coastguard Worker t += (b & 1); b >>= 1;
1138*f6dc9357SAndroid Build Coastguard Worker t += (b & 1);
1139*f6dc9357SAndroid Build Coastguard Worker num += t;
1140*f6dc9357SAndroid Build Coastguard Worker }
1141*f6dc9357SAndroid Build Coastguard Worker NumUsed_1MB_Blocks = num;
1142*f6dc9357SAndroid Build Coastguard Worker NumUsed_1MB_Blocks_Defined = true;
1143*f6dc9357SAndroid Build Coastguard Worker */
1144*f6dc9357SAndroid Build Coastguard Worker
1145*f6dc9357SAndroid Build Coastguard Worker return true;
1146*f6dc9357SAndroid Build Coastguard Worker }
1147*f6dc9357SAndroid Build Coastguard Worker
1148*f6dc9357SAndroid Build Coastguard Worker
1149*f6dc9357SAndroid Build Coastguard Worker
1150*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open3()
1151*f6dc9357SAndroid Build Coastguard Worker {
1152*f6dc9357SAndroid Build Coastguard Worker {
1153*f6dc9357SAndroid Build Coastguard Worker const unsigned kHeaderSize = 512; // + 8
1154*f6dc9357SAndroid Build Coastguard Worker Byte header[kHeaderSize];
1155*f6dc9357SAndroid Build Coastguard Worker
1156*f6dc9357SAndroid Build Coastguard Worker RINOK(Read_FALSE(header, kHeaderSize))
1157*f6dc9357SAndroid Build Coastguard Worker
1158*f6dc9357SAndroid Build Coastguard Worker if (memcmp(header, kSignature, kSignatureSize) != 0)
1159*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1160*f6dc9357SAndroid Build Coastguard Worker
1161*f6dc9357SAndroid Build Coastguard Worker const Byte *p = &header[0];
1162*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2)
1163*f6dc9357SAndroid Build Coastguard Worker {
1164*f6dc9357SAndroid Build Coastguard Worker const wchar_t c = Get16(p + i);
1165*f6dc9357SAndroid Build Coastguard Worker if (c < 0x20 || c > 0x7F)
1166*f6dc9357SAndroid Build Coastguard Worker break;
1167*f6dc9357SAndroid Build Coastguard Worker _creator += c;
1168*f6dc9357SAndroid Build Coastguard Worker }
1169*f6dc9357SAndroid Build Coastguard Worker }
1170*f6dc9357SAndroid Build Coastguard Worker
1171*f6dc9357SAndroid Build Coastguard Worker HeadersSize = (UInt32)1 << 20;
1172*f6dc9357SAndroid Build Coastguard Worker CHeader headers[2];
1173*f6dc9357SAndroid Build Coastguard Worker {
1174*f6dc9357SAndroid Build Coastguard Worker Byte header[kHeader2Size];
1175*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 2; i++)
1176*f6dc9357SAndroid Build Coastguard Worker {
1177*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2((1 << 16) * (1 + i)))
1178*f6dc9357SAndroid Build Coastguard Worker RINOK(Read_FALSE(header, kHeader2Size))
1179*f6dc9357SAndroid Build Coastguard Worker bool headerIsOK = headers[i].Parse(header);
1180*f6dc9357SAndroid Build Coastguard Worker if (!headerIsOK)
1181*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1182*f6dc9357SAndroid Build Coastguard Worker }
1183*f6dc9357SAndroid Build Coastguard Worker }
1184*f6dc9357SAndroid Build Coastguard Worker unsigned mainIndex;
1185*f6dc9357SAndroid Build Coastguard Worker if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
1186*f6dc9357SAndroid Build Coastguard Worker else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
1187*f6dc9357SAndroid Build Coastguard Worker else
1188*f6dc9357SAndroid Build Coastguard Worker {
1189*f6dc9357SAndroid Build Coastguard Worker /* Disk2vhd v2.02 can create image with 2 full copies of headers.
1190*f6dc9357SAndroid Build Coastguard Worker It's violation of VHDX specification:
1191*f6dc9357SAndroid Build Coastguard Worker "A header is current if it is the only valid header
1192*f6dc9357SAndroid Build Coastguard Worker or if it is valid and its SequenceNumber field is
1193*f6dc9357SAndroid Build Coastguard Worker greater than the other header's SequenceNumber".
1194*f6dc9357SAndroid Build Coastguard Worker but we support such Disk2vhd archives. */
1195*f6dc9357SAndroid Build Coastguard Worker if (!headers[0].IsEqualTo(headers[1]))
1196*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1197*f6dc9357SAndroid Build Coastguard Worker mainIndex = 0;
1198*f6dc9357SAndroid Build Coastguard Worker }
1199*f6dc9357SAndroid Build Coastguard Worker
1200*f6dc9357SAndroid Build Coastguard Worker const CHeader &h = headers[mainIndex];
1201*f6dc9357SAndroid Build Coastguard Worker Header = h;
1202*f6dc9357SAndroid Build Coastguard Worker if (h.LogLength != 0)
1203*f6dc9357SAndroid Build Coastguard Worker {
1204*f6dc9357SAndroid Build Coastguard Worker HeadersSize += h.LogLength;
1205*f6dc9357SAndroid Build Coastguard Worker UpdatePhySize(h.LogOffset + h.LogLength);
1206*f6dc9357SAndroid Build Coastguard Worker if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero())
1207*f6dc9357SAndroid Build Coastguard Worker {
1208*f6dc9357SAndroid Build Coastguard Worker _nonEmptyLog = true;
1209*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("non-empty LOG was not replayed");
1210*f6dc9357SAndroid Build Coastguard Worker /*
1211*f6dc9357SAndroid Build Coastguard Worker if (h.LogVersion != 0)
1212*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("unknown LogVresion");
1213*f6dc9357SAndroid Build Coastguard Worker else
1214*f6dc9357SAndroid Build Coastguard Worker {
1215*f6dc9357SAndroid Build Coastguard Worker CByteBuffer log;
1216*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2(h.LogOffset));
1217*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadToBuf_FALSE(log, h.LogLength));
1218*f6dc9357SAndroid Build Coastguard Worker if (!ParseLog(log))
1219*f6dc9357SAndroid Build Coastguard Worker {
1220*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1221*f6dc9357SAndroid Build Coastguard Worker }
1222*f6dc9357SAndroid Build Coastguard Worker }
1223*f6dc9357SAndroid Build Coastguard Worker */
1224*f6dc9357SAndroid Build Coastguard Worker }
1225*f6dc9357SAndroid Build Coastguard Worker }
1226*f6dc9357SAndroid Build Coastguard Worker CRegion regions[2];
1227*f6dc9357SAndroid Build Coastguard Worker int correctRegionIndex = -1;
1228*f6dc9357SAndroid Build Coastguard Worker
1229*f6dc9357SAndroid Build Coastguard Worker {
1230*f6dc9357SAndroid Build Coastguard Worker CByteBuffer temp;
1231*f6dc9357SAndroid Build Coastguard Worker temp.Alloc(kRegionSize * 2);
1232*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2((1 << 16) * 3))
1233*f6dc9357SAndroid Build Coastguard Worker RINOK(Read_FALSE(temp, kRegionSize * 2))
1234*f6dc9357SAndroid Build Coastguard Worker unsigned numTables = 1;
1235*f6dc9357SAndroid Build Coastguard Worker if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0)
1236*f6dc9357SAndroid Build Coastguard Worker {
1237*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Region tables mismatch");
1238*f6dc9357SAndroid Build Coastguard Worker numTables = 2;
1239*f6dc9357SAndroid Build Coastguard Worker }
1240*f6dc9357SAndroid Build Coastguard Worker
1241*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < numTables; i++)
1242*f6dc9357SAndroid Build Coastguard Worker {
1243*f6dc9357SAndroid Build Coastguard Worker // RINOK(Seek2((1 << 16) * (3 + i)));
1244*f6dc9357SAndroid Build Coastguard Worker // RINOK(Read_FALSE(temp, kRegionSize));
1245*f6dc9357SAndroid Build Coastguard Worker if (regions[i].Parse(temp))
1246*f6dc9357SAndroid Build Coastguard Worker {
1247*f6dc9357SAndroid Build Coastguard Worker if (correctRegionIndex < 0)
1248*f6dc9357SAndroid Build Coastguard Worker correctRegionIndex = (int)i;
1249*f6dc9357SAndroid Build Coastguard Worker }
1250*f6dc9357SAndroid Build Coastguard Worker else
1251*f6dc9357SAndroid Build Coastguard Worker {
1252*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Incorrect region table");
1253*f6dc9357SAndroid Build Coastguard Worker }
1254*f6dc9357SAndroid Build Coastguard Worker }
1255*f6dc9357SAndroid Build Coastguard Worker if (correctRegionIndex < 0)
1256*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1257*f6dc9357SAndroid Build Coastguard Worker /*
1258*f6dc9357SAndroid Build Coastguard Worker if (!regions[0].IsEqualTo(regions[1]))
1259*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1260*f6dc9357SAndroid Build Coastguard Worker */
1261*f6dc9357SAndroid Build Coastguard Worker }
1262*f6dc9357SAndroid Build Coastguard Worker
1263*f6dc9357SAndroid Build Coastguard Worker // UpdatePhySize((1 << 16) * 5);
1264*f6dc9357SAndroid Build Coastguard Worker UpdatePhySize(1 << 20);
1265*f6dc9357SAndroid Build Coastguard Worker
1266*f6dc9357SAndroid Build Coastguard Worker {
1267*f6dc9357SAndroid Build Coastguard Worker const CRegion ®ion = regions[correctRegionIndex];
1268*f6dc9357SAndroid Build Coastguard Worker HeadersSize += region.DataSize;
1269*f6dc9357SAndroid Build Coastguard Worker UpdatePhySize(region.EndPos);
1270*f6dc9357SAndroid Build Coastguard Worker {
1271*f6dc9357SAndroid Build Coastguard Worker if (!region.Meta_Defined)
1272*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1273*f6dc9357SAndroid Build Coastguard Worker const CRegionEntry &e = region.MetaEntry;
1274*f6dc9357SAndroid Build Coastguard Worker if (e.Len == 0)
1275*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1276*f6dc9357SAndroid Build Coastguard Worker {
1277*f6dc9357SAndroid Build Coastguard Worker // static const kMetaTableSize = 1 << 16;
1278*f6dc9357SAndroid Build Coastguard Worker CByteBuffer temp;
1279*f6dc9357SAndroid Build Coastguard Worker {
1280*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2(e.Offset))
1281*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadToBuf_FALSE(temp, e.Len))
1282*f6dc9357SAndroid Build Coastguard Worker }
1283*f6dc9357SAndroid Build Coastguard Worker if (!Meta.Parse(temp, temp.Size()))
1284*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1285*f6dc9357SAndroid Build Coastguard Worker }
1286*f6dc9357SAndroid Build Coastguard Worker // UpdatePhySize(e.GetEndPos());
1287*f6dc9357SAndroid Build Coastguard Worker }
1288*f6dc9357SAndroid Build Coastguard Worker {
1289*f6dc9357SAndroid Build Coastguard Worker if (!region.Bat_Defined)
1290*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1291*f6dc9357SAndroid Build Coastguard Worker const CRegionEntry &e = region.BatEntry;
1292*f6dc9357SAndroid Build Coastguard Worker if (e.Len == 0)
1293*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1294*f6dc9357SAndroid Build Coastguard Worker // UpdatePhySize(e.GetEndPos());
1295*f6dc9357SAndroid Build Coastguard Worker {
1296*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2(e.Offset))
1297*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadToBuf_FALSE(Bat.Data, e.Len))
1298*f6dc9357SAndroid Build Coastguard Worker }
1299*f6dc9357SAndroid Build Coastguard Worker if (!ParseBat())
1300*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1301*f6dc9357SAndroid Build Coastguard Worker if (!CheckBat())
1302*f6dc9357SAndroid Build Coastguard Worker {
1303*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("BAT overlap");
1304*f6dc9357SAndroid Build Coastguard Worker // _batOverlap = true;
1305*f6dc9357SAndroid Build Coastguard Worker // return S_FALSE;
1306*f6dc9357SAndroid Build Coastguard Worker }
1307*f6dc9357SAndroid Build Coastguard Worker }
1308*f6dc9357SAndroid Build Coastguard Worker }
1309*f6dc9357SAndroid Build Coastguard Worker
1310*f6dc9357SAndroid Build Coastguard Worker {
1311*f6dc9357SAndroid Build Coastguard Worker // do we need to check "parent_linkage2" also?
1312*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Meta.ParentPairs)
1313*f6dc9357SAndroid Build Coastguard Worker {
1314*f6dc9357SAndroid Build Coastguard Worker const CParentPair &pair = Meta.ParentPairs[i];
1315*f6dc9357SAndroid Build Coastguard Worker if (pair.Key.IsEqualTo("parent_linkage"))
1316*f6dc9357SAndroid Build Coastguard Worker {
1317*f6dc9357SAndroid Build Coastguard Worker _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value);
1318*f6dc9357SAndroid Build Coastguard Worker break;
1319*f6dc9357SAndroid Build Coastguard Worker }
1320*f6dc9357SAndroid Build Coastguard Worker }
1321*f6dc9357SAndroid Build Coastguard Worker }
1322*f6dc9357SAndroid Build Coastguard Worker
1323*f6dc9357SAndroid Build Coastguard Worker {
1324*f6dc9357SAndroid Build Coastguard Worker // absolute paths for parent stream can be rejected later in client callback
1325*f6dc9357SAndroid Build Coastguard Worker // the order of check by specification:
1326*f6dc9357SAndroid Build Coastguard Worker const char * const g_ParentKeys[] =
1327*f6dc9357SAndroid Build Coastguard Worker {
1328*f6dc9357SAndroid Build Coastguard Worker "relative_path" // "..\..\path2\sub3\parent.vhdx"
1329*f6dc9357SAndroid Build Coastguard Worker , "volume_path" // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx")
1330*f6dc9357SAndroid Build Coastguard Worker , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx"
1331*f6dc9357SAndroid Build Coastguard Worker };
1332*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ParentKeys); i++)
1333*f6dc9357SAndroid Build Coastguard Worker {
1334*f6dc9357SAndroid Build Coastguard Worker const int index = Meta.FindParentKey(g_ParentKeys[i]);
1335*f6dc9357SAndroid Build Coastguard Worker if (index < 0)
1336*f6dc9357SAndroid Build Coastguard Worker continue;
1337*f6dc9357SAndroid Build Coastguard Worker ParentNames.Add(Meta.ParentPairs[index].Value);
1338*f6dc9357SAndroid Build Coastguard Worker }
1339*f6dc9357SAndroid Build Coastguard Worker }
1340*f6dc9357SAndroid Build Coastguard Worker
1341*f6dc9357SAndroid Build Coastguard Worker if (Meta.Is_HasParent())
1342*f6dc9357SAndroid Build Coastguard Worker {
1343*f6dc9357SAndroid Build Coastguard Worker if (!Meta.Locator_Defined)
1344*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Parent locator is not defined");
1345*f6dc9357SAndroid Build Coastguard Worker else
1346*f6dc9357SAndroid Build Coastguard Worker {
1347*f6dc9357SAndroid Build Coastguard Worker if (!_parentGuid_IsDefined)
1348*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Parent GUID is not defined");
1349*f6dc9357SAndroid Build Coastguard Worker if (ParentNames.IsEmpty())
1350*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Parent VHDX file name is not defined");
1351*f6dc9357SAndroid Build Coastguard Worker }
1352*f6dc9357SAndroid Build Coastguard Worker }
1353*f6dc9357SAndroid Build Coastguard Worker else
1354*f6dc9357SAndroid Build Coastguard Worker {
1355*f6dc9357SAndroid Build Coastguard Worker if (Meta.Locator_Defined)
1356*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Unexpected parent locator");
1357*f6dc9357SAndroid Build Coastguard Worker }
1358*f6dc9357SAndroid Build Coastguard Worker
1359*f6dc9357SAndroid Build Coastguard Worker // here we suppose that and locator can be used only with HasParent flag
1360*f6dc9357SAndroid Build Coastguard Worker
1361*f6dc9357SAndroid Build Coastguard Worker // return S_FALSE;
1362*f6dc9357SAndroid Build Coastguard Worker
1363*f6dc9357SAndroid Build Coastguard Worker _size = Meta.VirtualDiskSize; // CHandlerImg
1364*f6dc9357SAndroid Build Coastguard Worker
1365*f6dc9357SAndroid Build Coastguard Worker // _posInArc = 0;
1366*f6dc9357SAndroid Build Coastguard Worker // Reset_PosInArc();
1367*f6dc9357SAndroid Build Coastguard Worker // RINOK(InStream_SeekToBegin(Stream))
1368*f6dc9357SAndroid Build Coastguard Worker
1369*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1370*f6dc9357SAndroid Build Coastguard Worker }
1371*f6dc9357SAndroid Build Coastguard Worker
1372*f6dc9357SAndroid Build Coastguard Worker
1373*f6dc9357SAndroid Build Coastguard Worker /*
1374*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_NumCalls = 0;
1375*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_NumCalls2 = 0;
1376*f6dc9357SAndroid Build Coastguard Worker static struct CCounter { ~CCounter()
1377*f6dc9357SAndroid Build Coastguard Worker {
1378*f6dc9357SAndroid Build Coastguard Worker printf("\nNumCalls = %10u\n", g_NumCalls);
1379*f6dc9357SAndroid Build Coastguard Worker printf("NumCalls2 = %10u\n", g_NumCalls2);
1380*f6dc9357SAndroid Build Coastguard Worker } } g_Counter;
1381*f6dc9357SAndroid Build Coastguard Worker */
1382*f6dc9357SAndroid Build Coastguard Worker
1383*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
1384*f6dc9357SAndroid Build Coastguard Worker {
1385*f6dc9357SAndroid Build Coastguard Worker // g_NumCalls++;
1386*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
1387*f6dc9357SAndroid Build Coastguard Worker *processedSize = 0;
1388*f6dc9357SAndroid Build Coastguard Worker if (_virtPos >= Meta.VirtualDiskSize)
1389*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1390*f6dc9357SAndroid Build Coastguard Worker {
1391*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = Meta.VirtualDiskSize - _virtPos;
1392*f6dc9357SAndroid Build Coastguard Worker if (size > rem)
1393*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem;
1394*f6dc9357SAndroid Build Coastguard Worker }
1395*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
1396*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1397*f6dc9357SAndroid Build Coastguard Worker const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log);
1398*f6dc9357SAndroid Build Coastguard Worker const size_t chunkIndex = blockIndex >> ChunkRatio_Log;
1399*f6dc9357SAndroid Build Coastguard Worker const size_t chunkRatio = (size_t)1 << ChunkRatio_Log;
1400*f6dc9357SAndroid Build Coastguard Worker const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1));
1401*f6dc9357SAndroid Build Coastguard Worker const UInt64 blockSectVal = Bat.GetItem(blockIndex2);
1402*f6dc9357SAndroid Build Coastguard Worker const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal);
1403*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockState = BAT_GET_STATE(blockSectVal);
1404*f6dc9357SAndroid Build Coastguard Worker
1405*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
1406*f6dc9357SAndroid Build Coastguard Worker const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
1407*f6dc9357SAndroid Build Coastguard Worker size = MyMin(blockSize - offsetInBlock, size);
1408*f6dc9357SAndroid Build Coastguard Worker
1409*f6dc9357SAndroid Build Coastguard Worker bool needParent = false;
1410*f6dc9357SAndroid Build Coastguard Worker bool needRead = false;
1411*f6dc9357SAndroid Build Coastguard Worker
1412*f6dc9357SAndroid Build Coastguard Worker if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT)
1413*f6dc9357SAndroid Build Coastguard Worker needRead = true;
1414*f6dc9357SAndroid Build Coastguard Worker else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT)
1415*f6dc9357SAndroid Build Coastguard Worker {
1416*f6dc9357SAndroid Build Coastguard Worker /* for a differencing VHDX: parent virtual disk SHOULD be
1417*f6dc9357SAndroid Build Coastguard Worker inspected to determine the associated contents (SPECIFICATION).
1418*f6dc9357SAndroid Build Coastguard Worker we suppose that we should not check BitMap.
1419*f6dc9357SAndroid Build Coastguard Worker for fixed or dynamic VHDX files: the block contents are undefined and
1420*f6dc9357SAndroid Build Coastguard Worker can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */
1421*f6dc9357SAndroid Build Coastguard Worker if (IsDiff())
1422*f6dc9357SAndroid Build Coastguard Worker needParent = true;
1423*f6dc9357SAndroid Build Coastguard Worker }
1424*f6dc9357SAndroid Build Coastguard Worker else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1425*f6dc9357SAndroid Build Coastguard Worker {
1426*f6dc9357SAndroid Build Coastguard Worker // only allowed for differencing VHDX files.
1427*f6dc9357SAndroid Build Coastguard Worker // associated sector bitmap block MUST be valid
1428*f6dc9357SAndroid Build Coastguard Worker if (chunkIndex >= BitMaps.Size())
1429*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1430*f6dc9357SAndroid Build Coastguard Worker // else
1431*f6dc9357SAndroid Build Coastguard Worker {
1432*f6dc9357SAndroid Build Coastguard Worker const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex];
1433*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)bitmap;
1434*f6dc9357SAndroid Build Coastguard Worker if (!p)
1435*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1436*f6dc9357SAndroid Build Coastguard Worker // else
1437*f6dc9357SAndroid Build Coastguard Worker {
1438*f6dc9357SAndroid Build Coastguard Worker // g_NumCalls2++;
1439*f6dc9357SAndroid Build Coastguard Worker const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log;
1440*f6dc9357SAndroid Build Coastguard Worker
1441*f6dc9357SAndroid Build Coastguard Worker #define BIT_MAP_UNIT_LOG 3 // it's for small block (4 KB)
1442*f6dc9357SAndroid Build Coastguard Worker // #define BIT_MAP_UNIT_LOG 5 // speed optimization for large blocks (16 KB)
1443*f6dc9357SAndroid Build Coastguard Worker
1444*f6dc9357SAndroid Build Coastguard Worker const size_t offs = (size_t)(sectorIndex >> 3) &
1445*f6dc9357SAndroid Build Coastguard Worker (
1446*f6dc9357SAndroid Build Coastguard Worker (kBitmapSize - 1)
1447*f6dc9357SAndroid Build Coastguard Worker & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1)
1448*f6dc9357SAndroid Build Coastguard Worker );
1449*f6dc9357SAndroid Build Coastguard Worker
1450*f6dc9357SAndroid Build Coastguard Worker unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1);
1451*f6dc9357SAndroid Build Coastguard Worker #if BIT_MAP_UNIT_LOG == 5
1452*f6dc9357SAndroid Build Coastguard Worker UInt32 v = GetUi32(p + offs) >> sector2;
1453*f6dc9357SAndroid Build Coastguard Worker #else
1454*f6dc9357SAndroid Build Coastguard Worker unsigned v = (unsigned)p[offs] >> sector2;
1455*f6dc9357SAndroid Build Coastguard Worker #endif
1456*f6dc9357SAndroid Build Coastguard Worker // UInt32 v = GetUi32(p + offs) >> sector2;
1457*f6dc9357SAndroid Build Coastguard Worker const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log;
1458*f6dc9357SAndroid Build Coastguard Worker const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1);
1459*f6dc9357SAndroid Build Coastguard Worker const unsigned bit = (unsigned)(v & 1);
1460*f6dc9357SAndroid Build Coastguard Worker if (bit)
1461*f6dc9357SAndroid Build Coastguard Worker needRead = true;
1462*f6dc9357SAndroid Build Coastguard Worker else
1463*f6dc9357SAndroid Build Coastguard Worker needParent = true; // zero - from the parent VHDX file
1464*f6dc9357SAndroid Build Coastguard Worker UInt32 rem = sectorSize - offsetInSector;
1465*f6dc9357SAndroid Build Coastguard Worker for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++)
1466*f6dc9357SAndroid Build Coastguard Worker {
1467*f6dc9357SAndroid Build Coastguard Worker v >>= 1;
1468*f6dc9357SAndroid Build Coastguard Worker if (bit != (v & 1))
1469*f6dc9357SAndroid Build Coastguard Worker break;
1470*f6dc9357SAndroid Build Coastguard Worker rem += sectorSize;
1471*f6dc9357SAndroid Build Coastguard Worker }
1472*f6dc9357SAndroid Build Coastguard Worker if (size > rem)
1473*f6dc9357SAndroid Build Coastguard Worker size = rem;
1474*f6dc9357SAndroid Build Coastguard Worker }
1475*f6dc9357SAndroid Build Coastguard Worker }
1476*f6dc9357SAndroid Build Coastguard Worker }
1477*f6dc9357SAndroid Build Coastguard Worker
1478*f6dc9357SAndroid Build Coastguard Worker bool needZero = true;
1479*f6dc9357SAndroid Build Coastguard Worker
1480*f6dc9357SAndroid Build Coastguard Worker HRESULT res = S_OK;
1481*f6dc9357SAndroid Build Coastguard Worker
1482*f6dc9357SAndroid Build Coastguard Worker if (needParent)
1483*f6dc9357SAndroid Build Coastguard Worker {
1484*f6dc9357SAndroid Build Coastguard Worker if (!ParentStream)
1485*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1486*f6dc9357SAndroid Build Coastguard Worker // if (ParentStream)
1487*f6dc9357SAndroid Build Coastguard Worker {
1488*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(ParentStream, _virtPos))
1489*f6dc9357SAndroid Build Coastguard Worker size_t processed = size;
1490*f6dc9357SAndroid Build Coastguard Worker res = ReadStream(ParentStream, (Byte *)data, &processed);
1491*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)processed;
1492*f6dc9357SAndroid Build Coastguard Worker needZero = false;
1493*f6dc9357SAndroid Build Coastguard Worker }
1494*f6dc9357SAndroid Build Coastguard Worker }
1495*f6dc9357SAndroid Build Coastguard Worker else if (needRead)
1496*f6dc9357SAndroid Build Coastguard Worker {
1497*f6dc9357SAndroid Build Coastguard Worker UInt32 processed = 0;
1498*f6dc9357SAndroid Build Coastguard Worker res = ReadPhy(blockOffset + offsetInBlock, data, size, processed);
1499*f6dc9357SAndroid Build Coastguard Worker size = processed;
1500*f6dc9357SAndroid Build Coastguard Worker needZero = false;
1501*f6dc9357SAndroid Build Coastguard Worker }
1502*f6dc9357SAndroid Build Coastguard Worker
1503*f6dc9357SAndroid Build Coastguard Worker if (needZero)
1504*f6dc9357SAndroid Build Coastguard Worker memset(data, 0, size);
1505*f6dc9357SAndroid Build Coastguard Worker
1506*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
1507*f6dc9357SAndroid Build Coastguard Worker *processedSize = size;
1508*f6dc9357SAndroid Build Coastguard Worker
1509*f6dc9357SAndroid Build Coastguard Worker _virtPos += size;
1510*f6dc9357SAndroid Build Coastguard Worker return res;
1511*f6dc9357SAndroid Build Coastguard Worker }
1512*f6dc9357SAndroid Build Coastguard Worker
1513*f6dc9357SAndroid Build Coastguard Worker
1514*f6dc9357SAndroid Build Coastguard Worker enum
1515*f6dc9357SAndroid Build Coastguard Worker {
1516*f6dc9357SAndroid Build Coastguard Worker kpidParent = kpidUserDefined
1517*f6dc9357SAndroid Build Coastguard Worker };
1518*f6dc9357SAndroid Build Coastguard Worker
1519*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kArcProps[] =
1520*f6dc9357SAndroid Build Coastguard Worker {
1521*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidClusterSize, VT_UI4},
1522*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidSectorSize, VT_UI4},
1523*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidMethod, VT_BSTR},
1524*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidNumVolumes, VT_UI4},
1525*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidTotalPhySize, VT_UI8},
1526*f6dc9357SAndroid Build Coastguard Worker { "Parent", kpidParent, VT_BSTR},
1527*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidCreatorApp, VT_BSTR},
1528*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidComment, VT_BSTR},
1529*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidId, VT_BSTR}
1530*f6dc9357SAndroid Build Coastguard Worker };
1531*f6dc9357SAndroid Build Coastguard Worker
1532*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
1533*f6dc9357SAndroid Build Coastguard Worker {
1534*f6dc9357SAndroid Build Coastguard Worker kpidSize,
1535*f6dc9357SAndroid Build Coastguard Worker kpidPackSize
1536*f6dc9357SAndroid Build Coastguard Worker };
1537*f6dc9357SAndroid Build Coastguard Worker
1538*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
1539*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_WITH_NAME
1540*f6dc9357SAndroid Build Coastguard Worker
1541*f6dc9357SAndroid Build Coastguard Worker
1542*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddErrorMessage(const char *message)
1543*f6dc9357SAndroid Build Coastguard Worker {
1544*f6dc9357SAndroid Build Coastguard Worker if (!_errorMessage.IsEmpty())
1545*f6dc9357SAndroid Build Coastguard Worker _errorMessage.Add_LF();
1546*f6dc9357SAndroid Build Coastguard Worker _errorMessage += message;
1547*f6dc9357SAndroid Build Coastguard Worker }
1548*f6dc9357SAndroid Build Coastguard Worker
1549*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddErrorMessage(const char *message, const wchar_t *name)
1550*f6dc9357SAndroid Build Coastguard Worker {
1551*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage(message);
1552*f6dc9357SAndroid Build Coastguard Worker _errorMessage += name;
1553*f6dc9357SAndroid Build Coastguard Worker }
1554*f6dc9357SAndroid Build Coastguard Worker
1555*f6dc9357SAndroid Build Coastguard Worker
1556*f6dc9357SAndroid Build Coastguard Worker static void AddComment_Name(UString &s, const char *name)
1557*f6dc9357SAndroid Build Coastguard Worker {
1558*f6dc9357SAndroid Build Coastguard Worker s += name;
1559*f6dc9357SAndroid Build Coastguard Worker s += ": ";
1560*f6dc9357SAndroid Build Coastguard Worker }
1561*f6dc9357SAndroid Build Coastguard Worker
1562*f6dc9357SAndroid Build Coastguard Worker static void AddComment_Bool(UString &s, const char *name, bool val)
1563*f6dc9357SAndroid Build Coastguard Worker {
1564*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, name);
1565*f6dc9357SAndroid Build Coastguard Worker s.Add_Char(val ? '+' : '-');
1566*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1567*f6dc9357SAndroid Build Coastguard Worker }
1568*f6dc9357SAndroid Build Coastguard Worker
1569*f6dc9357SAndroid Build Coastguard Worker static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false)
1570*f6dc9357SAndroid Build Coastguard Worker {
1571*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, name);
1572*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt64(v);
1573*f6dc9357SAndroid Build Coastguard Worker if (showMB)
1574*f6dc9357SAndroid Build Coastguard Worker {
1575*f6dc9357SAndroid Build Coastguard Worker s += " (";
1576*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt64(v >> 20);
1577*f6dc9357SAndroid Build Coastguard Worker s += " MiB)";
1578*f6dc9357SAndroid Build Coastguard Worker }
1579*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1580*f6dc9357SAndroid Build Coastguard Worker }
1581*f6dc9357SAndroid Build Coastguard Worker
1582*f6dc9357SAndroid Build Coastguard Worker static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
1583*f6dc9357SAndroid Build Coastguard Worker {
1584*f6dc9357SAndroid Build Coastguard Worker if (logSize != 0)
1585*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, name, ((UInt64)1 << logSize));
1586*f6dc9357SAndroid Build Coastguard Worker }
1587*f6dc9357SAndroid Build Coastguard Worker
1588*f6dc9357SAndroid Build Coastguard Worker
1589*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddComment(UString &s) const
1590*f6dc9357SAndroid Build Coastguard Worker {
1591*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
1592*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "PhysicalSize", _phySize);
1593*f6dc9357SAndroid Build Coastguard Worker
1594*f6dc9357SAndroid Build Coastguard Worker if (!_errorMessage.IsEmpty())
1595*f6dc9357SAndroid Build Coastguard Worker {
1596*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, "Error");
1597*f6dc9357SAndroid Build Coastguard Worker s += _errorMessage;
1598*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1599*f6dc9357SAndroid Build Coastguard Worker }
1600*f6dc9357SAndroid Build Coastguard Worker
1601*f6dc9357SAndroid Build Coastguard Worker if (Meta.Guid_Defined)
1602*f6dc9357SAndroid Build Coastguard Worker {
1603*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, "Id");
1604*f6dc9357SAndroid Build Coastguard Worker Meta.Guid.AddHexToString(s);
1605*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1606*f6dc9357SAndroid Build Coastguard Worker }
1607*f6dc9357SAndroid Build Coastguard Worker
1608*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber);
1609*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "LogLength", Header.LogLength, true);
1610*f6dc9357SAndroid Build Coastguard Worker
1611*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 3; i++)
1612*f6dc9357SAndroid Build Coastguard Worker {
1613*f6dc9357SAndroid Build Coastguard Worker const CGuid &g = Header.Guids[i];
1614*f6dc9357SAndroid Build Coastguard Worker if (g.IsZero())
1615*f6dc9357SAndroid Build Coastguard Worker continue;
1616*f6dc9357SAndroid Build Coastguard Worker if (i == 0)
1617*f6dc9357SAndroid Build Coastguard Worker s += "FileWrite";
1618*f6dc9357SAndroid Build Coastguard Worker else if (i == 1)
1619*f6dc9357SAndroid Build Coastguard Worker s += "DataWrite";
1620*f6dc9357SAndroid Build Coastguard Worker else
1621*f6dc9357SAndroid Build Coastguard Worker s += "Log";
1622*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, "Guid");
1623*f6dc9357SAndroid Build Coastguard Worker g.AddHexToString(s);
1624*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1625*f6dc9357SAndroid Build Coastguard Worker }
1626*f6dc9357SAndroid Build Coastguard Worker
1627*f6dc9357SAndroid Build Coastguard Worker AddComment_Bool(s, "HasParent", Meta.Is_HasParent());
1628*f6dc9357SAndroid Build Coastguard Worker AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated());
1629*f6dc9357SAndroid Build Coastguard Worker if (Meta.Is_LeaveBlockAllocated())
1630*f6dc9357SAndroid Build Coastguard Worker AddComment_Bool(s, "DataContiguous", _isDataContiguous);
1631*f6dc9357SAndroid Build Coastguard Worker
1632*f6dc9357SAndroid Build Coastguard Worker AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log);
1633*f6dc9357SAndroid Build Coastguard Worker AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log);
1634*f6dc9357SAndroid Build Coastguard Worker AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log);
1635*f6dc9357SAndroid Build Coastguard Worker
1636*f6dc9357SAndroid Build Coastguard Worker {
1637*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize = GetPackSize();
1638*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "PackSize", packSize, true);
1639*f6dc9357SAndroid Build Coastguard Worker const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log);
1640*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "HeadersSize", headersSize, true);
1641*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true);
1642*f6dc9357SAndroid Build Coastguard Worker /*
1643*f6dc9357SAndroid Build Coastguard Worker if (NumUsed_1MB_Blocks_Defined)
1644*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20));
1645*f6dc9357SAndroid Build Coastguard Worker */
1646*f6dc9357SAndroid Build Coastguard Worker }
1647*f6dc9357SAndroid Build Coastguard Worker
1648*f6dc9357SAndroid Build Coastguard Worker if (Meta.ParentPairs.Size() != 0)
1649*f6dc9357SAndroid Build Coastguard Worker {
1650*f6dc9357SAndroid Build Coastguard Worker s += "Parent:";
1651*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1652*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR(i, Meta.ParentPairs)
1653*f6dc9357SAndroid Build Coastguard Worker {
1654*f6dc9357SAndroid Build Coastguard Worker const CParentPair &pair = Meta.ParentPairs[i];
1655*f6dc9357SAndroid Build Coastguard Worker s += " ";
1656*f6dc9357SAndroid Build Coastguard Worker s += pair.Key;
1657*f6dc9357SAndroid Build Coastguard Worker s += ": ";
1658*f6dc9357SAndroid Build Coastguard Worker s += pair.Value;
1659*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1660*f6dc9357SAndroid Build Coastguard Worker }
1661*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1662*f6dc9357SAndroid Build Coastguard Worker }
1663*f6dc9357SAndroid Build Coastguard Worker }
1664*f6dc9357SAndroid Build Coastguard Worker
1665*f6dc9357SAndroid Build Coastguard Worker
1666*f6dc9357SAndroid Build Coastguard Worker
1667*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1668*f6dc9357SAndroid Build Coastguard Worker {
1669*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
1670*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop;
1671*f6dc9357SAndroid Build Coastguard Worker switch (propID)
1672*f6dc9357SAndroid Build Coastguard Worker {
1673*f6dc9357SAndroid Build Coastguard Worker case kpidMainSubfile: prop = (UInt32)0; break;
1674*f6dc9357SAndroid Build Coastguard Worker case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break;
1675*f6dc9357SAndroid Build Coastguard Worker case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break;
1676*f6dc9357SAndroid Build Coastguard Worker case kpidShortComment:
1677*f6dc9357SAndroid Build Coastguard Worker case kpidMethod:
1678*f6dc9357SAndroid Build Coastguard Worker {
1679*f6dc9357SAndroid Build Coastguard Worker AString s;
1680*f6dc9357SAndroid Build Coastguard Worker AddTypeString(s);
1681*f6dc9357SAndroid Build Coastguard Worker if (IsDiff())
1682*f6dc9357SAndroid Build Coastguard Worker {
1683*f6dc9357SAndroid Build Coastguard Worker s += " -> ";
1684*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
1685*f6dc9357SAndroid Build Coastguard Worker while (p && p->IsDiff())
1686*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
1687*f6dc9357SAndroid Build Coastguard Worker if (!p)
1688*f6dc9357SAndroid Build Coastguard Worker s += '?';
1689*f6dc9357SAndroid Build Coastguard Worker else
1690*f6dc9357SAndroid Build Coastguard Worker p->AddTypeString(s);
1691*f6dc9357SAndroid Build Coastguard Worker }
1692*f6dc9357SAndroid Build Coastguard Worker prop = s;
1693*f6dc9357SAndroid Build Coastguard Worker break;
1694*f6dc9357SAndroid Build Coastguard Worker }
1695*f6dc9357SAndroid Build Coastguard Worker case kpidComment:
1696*f6dc9357SAndroid Build Coastguard Worker {
1697*f6dc9357SAndroid Build Coastguard Worker UString s;
1698*f6dc9357SAndroid Build Coastguard Worker {
1699*f6dc9357SAndroid Build Coastguard Worker if (NumLevels > 1)
1700*f6dc9357SAndroid Build Coastguard Worker {
1701*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "NumVolumeLevels", NumLevels);
1702*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true);
1703*f6dc9357SAndroid Build Coastguard Worker s += "----";
1704*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1705*f6dc9357SAndroid Build Coastguard Worker }
1706*f6dc9357SAndroid Build Coastguard Worker
1707*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
1708*f6dc9357SAndroid Build Coastguard Worker for (;;)
1709*f6dc9357SAndroid Build Coastguard Worker {
1710*f6dc9357SAndroid Build Coastguard Worker if (p->_level != 0 || p->Parent)
1711*f6dc9357SAndroid Build Coastguard Worker AddComment_UInt64(s, "VolumeLevel", p->_level + 1);
1712*f6dc9357SAndroid Build Coastguard Worker p->AddComment(s);
1713*f6dc9357SAndroid Build Coastguard Worker if (!p->Parent)
1714*f6dc9357SAndroid Build Coastguard Worker break;
1715*f6dc9357SAndroid Build Coastguard Worker s += "----";
1716*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1717*f6dc9357SAndroid Build Coastguard Worker {
1718*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1719*f6dc9357SAndroid Build Coastguard Worker if (!p->ParentName_Used.IsEmpty())
1720*f6dc9357SAndroid Build Coastguard Worker {
1721*f6dc9357SAndroid Build Coastguard Worker AddComment_Name(s, "Name");
1722*f6dc9357SAndroid Build Coastguard Worker s += p->ParentName_Used;
1723*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1724*f6dc9357SAndroid Build Coastguard Worker }
1725*f6dc9357SAndroid Build Coastguard Worker }
1726*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
1727*f6dc9357SAndroid Build Coastguard Worker }
1728*f6dc9357SAndroid Build Coastguard Worker }
1729*f6dc9357SAndroid Build Coastguard Worker prop = s;
1730*f6dc9357SAndroid Build Coastguard Worker break;
1731*f6dc9357SAndroid Build Coastguard Worker }
1732*f6dc9357SAndroid Build Coastguard Worker case kpidCreatorApp:
1733*f6dc9357SAndroid Build Coastguard Worker {
1734*f6dc9357SAndroid Build Coastguard Worker if (!_creator.IsEmpty())
1735*f6dc9357SAndroid Build Coastguard Worker prop = _creator;
1736*f6dc9357SAndroid Build Coastguard Worker break;
1737*f6dc9357SAndroid Build Coastguard Worker }
1738*f6dc9357SAndroid Build Coastguard Worker case kpidId:
1739*f6dc9357SAndroid Build Coastguard Worker {
1740*f6dc9357SAndroid Build Coastguard Worker if (Meta.Guid_Defined)
1741*f6dc9357SAndroid Build Coastguard Worker {
1742*f6dc9357SAndroid Build Coastguard Worker UString s;
1743*f6dc9357SAndroid Build Coastguard Worker Meta.Guid.AddHexToString(s);
1744*f6dc9357SAndroid Build Coastguard Worker prop = s;
1745*f6dc9357SAndroid Build Coastguard Worker }
1746*f6dc9357SAndroid Build Coastguard Worker break;
1747*f6dc9357SAndroid Build Coastguard Worker }
1748*f6dc9357SAndroid Build Coastguard Worker case kpidName:
1749*f6dc9357SAndroid Build Coastguard Worker {
1750*f6dc9357SAndroid Build Coastguard Worker if (Meta.Guid_Defined)
1751*f6dc9357SAndroid Build Coastguard Worker {
1752*f6dc9357SAndroid Build Coastguard Worker UString s;
1753*f6dc9357SAndroid Build Coastguard Worker Meta.Guid.AddHexToString(s);
1754*f6dc9357SAndroid Build Coastguard Worker s += ".vhdx";
1755*f6dc9357SAndroid Build Coastguard Worker prop = s;
1756*f6dc9357SAndroid Build Coastguard Worker }
1757*f6dc9357SAndroid Build Coastguard Worker break;
1758*f6dc9357SAndroid Build Coastguard Worker }
1759*f6dc9357SAndroid Build Coastguard Worker case kpidParent: if (IsDiff()) prop = GetParentSequence(); break;
1760*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize: prop = _phySize; break;
1761*f6dc9357SAndroid Build Coastguard Worker case kpidTotalPhySize:
1762*f6dc9357SAndroid Build Coastguard Worker {
1763*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
1764*f6dc9357SAndroid Build Coastguard Worker UInt64 sum = 0;
1765*f6dc9357SAndroid Build Coastguard Worker do
1766*f6dc9357SAndroid Build Coastguard Worker {
1767*f6dc9357SAndroid Build Coastguard Worker sum += p->_phySize;
1768*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
1769*f6dc9357SAndroid Build Coastguard Worker }
1770*f6dc9357SAndroid Build Coastguard Worker while (p);
1771*f6dc9357SAndroid Build Coastguard Worker prop = sum;
1772*f6dc9357SAndroid Build Coastguard Worker break;
1773*f6dc9357SAndroid Build Coastguard Worker }
1774*f6dc9357SAndroid Build Coastguard Worker case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break;
1775*f6dc9357SAndroid Build Coastguard Worker case kpidError:
1776*f6dc9357SAndroid Build Coastguard Worker {
1777*f6dc9357SAndroid Build Coastguard Worker UString s;
1778*f6dc9357SAndroid Build Coastguard Worker const CHandler *p = this;
1779*f6dc9357SAndroid Build Coastguard Worker do
1780*f6dc9357SAndroid Build Coastguard Worker {
1781*f6dc9357SAndroid Build Coastguard Worker if (!p->_errorMessage.IsEmpty())
1782*f6dc9357SAndroid Build Coastguard Worker {
1783*f6dc9357SAndroid Build Coastguard Worker if (!s.IsEmpty())
1784*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
1785*f6dc9357SAndroid Build Coastguard Worker s += p->_errorMessage;
1786*f6dc9357SAndroid Build Coastguard Worker }
1787*f6dc9357SAndroid Build Coastguard Worker p = p->Parent;
1788*f6dc9357SAndroid Build Coastguard Worker }
1789*f6dc9357SAndroid Build Coastguard Worker while (p);
1790*f6dc9357SAndroid Build Coastguard Worker if (!s.IsEmpty())
1791*f6dc9357SAndroid Build Coastguard Worker prop = s;
1792*f6dc9357SAndroid Build Coastguard Worker break;
1793*f6dc9357SAndroid Build Coastguard Worker }
1794*f6dc9357SAndroid Build Coastguard Worker }
1795*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
1796*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1797*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
1798*f6dc9357SAndroid Build Coastguard Worker }
1799*f6dc9357SAndroid Build Coastguard Worker
1800*f6dc9357SAndroid Build Coastguard Worker
1801*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback)
1802*f6dc9357SAndroid Build Coastguard Worker {
1803*f6dc9357SAndroid Build Coastguard Worker Stream = stream;
1804*f6dc9357SAndroid Build Coastguard Worker if (_level >= (1 << 20))
1805*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1806*f6dc9357SAndroid Build Coastguard Worker
1807*f6dc9357SAndroid Build Coastguard Worker RINOK(Open3())
1808*f6dc9357SAndroid Build Coastguard Worker
1809*f6dc9357SAndroid Build Coastguard Worker NumLevels = 1;
1810*f6dc9357SAndroid Build Coastguard Worker PackSize_Total = GetPackSize();
1811*f6dc9357SAndroid Build Coastguard Worker
1812*f6dc9357SAndroid Build Coastguard Worker if (_child)
1813*f6dc9357SAndroid Build Coastguard Worker {
1814*f6dc9357SAndroid Build Coastguard Worker if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid]))
1815*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1816*f6dc9357SAndroid Build Coastguard Worker const CHandler *child = _child;
1817*f6dc9357SAndroid Build Coastguard Worker do
1818*f6dc9357SAndroid Build Coastguard Worker {
1819*f6dc9357SAndroid Build Coastguard Worker /* We suppose that only FileWriteGuid is unique.
1820*f6dc9357SAndroid Build Coastguard Worker Another IDs must be identical in in difference and parent archives. */
1821*f6dc9357SAndroid Build Coastguard Worker if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo(
1822*f6dc9357SAndroid Build Coastguard Worker child->Header.Guids[kHeader_GUID_Index_FileWriteGuid])
1823*f6dc9357SAndroid Build Coastguard Worker && _phySize == child->_phySize)
1824*f6dc9357SAndroid Build Coastguard Worker {
1825*f6dc9357SAndroid Build Coastguard Worker _isCyclic = true;
1826*f6dc9357SAndroid Build Coastguard Worker _isCyclic_or_CyclicParent = true;
1827*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Cyclic parent archive was blocked");
1828*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1829*f6dc9357SAndroid Build Coastguard Worker }
1830*f6dc9357SAndroid Build Coastguard Worker child = child->_child;
1831*f6dc9357SAndroid Build Coastguard Worker }
1832*f6dc9357SAndroid Build Coastguard Worker while (child);
1833*f6dc9357SAndroid Build Coastguard Worker }
1834*f6dc9357SAndroid Build Coastguard Worker
1835*f6dc9357SAndroid Build Coastguard Worker if (!Meta.Is_HasParent())
1836*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1837*f6dc9357SAndroid Build Coastguard Worker
1838*f6dc9357SAndroid Build Coastguard Worker if (!Meta.Locator_Defined
1839*f6dc9357SAndroid Build Coastguard Worker || !_parentGuid_IsDefined
1840*f6dc9357SAndroid Build Coastguard Worker || ParentNames.IsEmpty())
1841*f6dc9357SAndroid Build Coastguard Worker {
1842*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1843*f6dc9357SAndroid Build Coastguard Worker }
1844*f6dc9357SAndroid Build Coastguard Worker
1845*f6dc9357SAndroid Build Coastguard Worker ParentName_Used = ParentNames.Front();
1846*f6dc9357SAndroid Build Coastguard Worker
1847*f6dc9357SAndroid Build Coastguard Worker HRESULT res;
1848*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumLevelsMax = (1 << 8); // Maybe we need to increase that limit
1849*f6dc9357SAndroid Build Coastguard Worker if (_level >= kNumLevelsMax - 1)
1850*f6dc9357SAndroid Build Coastguard Worker {
1851*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Too many parent levels");
1852*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1853*f6dc9357SAndroid Build Coastguard Worker }
1854*f6dc9357SAndroid Build Coastguard Worker
1855*f6dc9357SAndroid Build Coastguard Worker bool _parentFileWasOpen = false;
1856*f6dc9357SAndroid Build Coastguard Worker
1857*f6dc9357SAndroid Build Coastguard Worker if (!openArchiveCallback)
1858*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
1859*f6dc9357SAndroid Build Coastguard Worker else
1860*f6dc9357SAndroid Build Coastguard Worker res = OpenParent(openArchiveCallback, _parentFileWasOpen);
1861*f6dc9357SAndroid Build Coastguard Worker
1862*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK)
1863*f6dc9357SAndroid Build Coastguard Worker {
1864*f6dc9357SAndroid Build Coastguard Worker if (res != S_FALSE)
1865*f6dc9357SAndroid Build Coastguard Worker return res;
1866*f6dc9357SAndroid Build Coastguard Worker
1867*f6dc9357SAndroid Build Coastguard Worker if (_parentFileWasOpen)
1868*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used);
1869*f6dc9357SAndroid Build Coastguard Worker else
1870*f6dc9357SAndroid Build Coastguard Worker AddErrorMessage("Missing parent VHDX file : ", ParentName_Used);
1871*f6dc9357SAndroid Build Coastguard Worker }
1872*f6dc9357SAndroid Build Coastguard Worker
1873*f6dc9357SAndroid Build Coastguard Worker
1874*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1875*f6dc9357SAndroid Build Coastguard Worker }
1876*f6dc9357SAndroid Build Coastguard Worker
1877*f6dc9357SAndroid Build Coastguard Worker
1878*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen)
1879*f6dc9357SAndroid Build Coastguard Worker {
1880*f6dc9357SAndroid Build Coastguard Worker _parentFileWasOpen = false;
1881*f6dc9357SAndroid Build Coastguard Worker Z7_DECL_CMyComPtr_QI_FROM(
1882*f6dc9357SAndroid Build Coastguard Worker IArchiveOpenVolumeCallback,
1883*f6dc9357SAndroid Build Coastguard Worker openVolumeCallback, openArchiveCallback)
1884*f6dc9357SAndroid Build Coastguard Worker if (!openVolumeCallback)
1885*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1886*f6dc9357SAndroid Build Coastguard Worker {
1887*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<IInStream> nextStream;
1888*f6dc9357SAndroid Build Coastguard Worker HRESULT res = S_FALSE;
1889*f6dc9357SAndroid Build Coastguard Worker UString name;
1890*f6dc9357SAndroid Build Coastguard Worker
1891*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, ParentNames)
1892*f6dc9357SAndroid Build Coastguard Worker {
1893*f6dc9357SAndroid Build Coastguard Worker name = ParentNames[i];
1894*f6dc9357SAndroid Build Coastguard Worker
1895*f6dc9357SAndroid Build Coastguard Worker // we remove prefix ".\\', but client already can support any variant
1896*f6dc9357SAndroid Build Coastguard Worker if (name[0] == L'.' && name[1] == L'\\')
1897*f6dc9357SAndroid Build Coastguard Worker name.DeleteFrontal(2);
1898*f6dc9357SAndroid Build Coastguard Worker
1899*f6dc9357SAndroid Build Coastguard Worker res = openVolumeCallback->GetStream(name, &nextStream);
1900*f6dc9357SAndroid Build Coastguard Worker
1901*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK && nextStream)
1902*f6dc9357SAndroid Build Coastguard Worker break;
1903*f6dc9357SAndroid Build Coastguard Worker
1904*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK && res != S_FALSE)
1905*f6dc9357SAndroid Build Coastguard Worker return res;
1906*f6dc9357SAndroid Build Coastguard Worker }
1907*f6dc9357SAndroid Build Coastguard Worker
1908*f6dc9357SAndroid Build Coastguard Worker if (res == S_FALSE || !nextStream)
1909*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1910*f6dc9357SAndroid Build Coastguard Worker
1911*f6dc9357SAndroid Build Coastguard Worker ParentName_Used = name;
1912*f6dc9357SAndroid Build Coastguard Worker _parentFileWasOpen = true;
1913*f6dc9357SAndroid Build Coastguard Worker
1914*f6dc9357SAndroid Build Coastguard Worker Parent = new CHandler;
1915*f6dc9357SAndroid Build Coastguard Worker ParentStream = Parent;
1916*f6dc9357SAndroid Build Coastguard Worker
1917*f6dc9357SAndroid Build Coastguard Worker try
1918*f6dc9357SAndroid Build Coastguard Worker {
1919*f6dc9357SAndroid Build Coastguard Worker Parent->_level = _level + 1;
1920*f6dc9357SAndroid Build Coastguard Worker Parent->_child = this;
1921*f6dc9357SAndroid Build Coastguard Worker /* we could call CHandlerImg::Open() here.
1922*f6dc9357SAndroid Build Coastguard Worker but we don't need (_imgExt) in (Parent). So we call Open2() here */
1923*f6dc9357SAndroid Build Coastguard Worker Parent->Close();
1924*f6dc9357SAndroid Build Coastguard Worker res = Parent->Open2(nextStream, openArchiveCallback);
1925*f6dc9357SAndroid Build Coastguard Worker }
1926*f6dc9357SAndroid Build Coastguard Worker catch(...)
1927*f6dc9357SAndroid Build Coastguard Worker {
1928*f6dc9357SAndroid Build Coastguard Worker Parent = NULL;
1929*f6dc9357SAndroid Build Coastguard Worker ParentStream.Release();
1930*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
1931*f6dc9357SAndroid Build Coastguard Worker throw;
1932*f6dc9357SAndroid Build Coastguard Worker }
1933*f6dc9357SAndroid Build Coastguard Worker
1934*f6dc9357SAndroid Build Coastguard Worker if (res != S_OK)
1935*f6dc9357SAndroid Build Coastguard Worker {
1936*f6dc9357SAndroid Build Coastguard Worker Parent = NULL;
1937*f6dc9357SAndroid Build Coastguard Worker ParentStream.Release();
1938*f6dc9357SAndroid Build Coastguard Worker if (res == E_ABORT)
1939*f6dc9357SAndroid Build Coastguard Worker return res;
1940*f6dc9357SAndroid Build Coastguard Worker if (res != S_FALSE)
1941*f6dc9357SAndroid Build Coastguard Worker {
1942*f6dc9357SAndroid Build Coastguard Worker // we must show that error code
1943*f6dc9357SAndroid Build Coastguard Worker }
1944*f6dc9357SAndroid Build Coastguard Worker }
1945*f6dc9357SAndroid Build Coastguard Worker
1946*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
1947*f6dc9357SAndroid Build Coastguard Worker {
1948*f6dc9357SAndroid Build Coastguard Worker if (Parent->_isCyclic_or_CyclicParent)
1949*f6dc9357SAndroid Build Coastguard Worker _isCyclic_or_CyclicParent = true;
1950*f6dc9357SAndroid Build Coastguard Worker
1951*f6dc9357SAndroid Build Coastguard Worker NumLevels = Parent->NumLevels + 1;
1952*f6dc9357SAndroid Build Coastguard Worker PackSize_Total += Parent->GetPackSize();
1953*f6dc9357SAndroid Build Coastguard Worker
1954*f6dc9357SAndroid Build Coastguard Worker // we read BitMaps only if Parent was open
1955*f6dc9357SAndroid Build Coastguard Worker
1956*f6dc9357SAndroid Build Coastguard Worker UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log;
1957*f6dc9357SAndroid Build Coastguard Worker if (openArchiveCallback && numBytes != 0)
1958*f6dc9357SAndroid Build Coastguard Worker {
1959*f6dc9357SAndroid Build Coastguard Worker RINOK(openArchiveCallback->SetTotal(NULL, &numBytes))
1960*f6dc9357SAndroid Build Coastguard Worker }
1961*f6dc9357SAndroid Build Coastguard Worker numBytes = 0;
1962*f6dc9357SAndroid Build Coastguard Worker for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1)
1963*f6dc9357SAndroid Build Coastguard Worker {
1964*f6dc9357SAndroid Build Coastguard Worker const UInt64 v = Bat.GetItem(i);
1965*f6dc9357SAndroid Build Coastguard Worker const UInt64 offset = BAT_GET_OFFSET(v);
1966*f6dc9357SAndroid Build Coastguard Worker const unsigned state = BAT_GET_STATE(v);
1967*f6dc9357SAndroid Build Coastguard Worker
1968*f6dc9357SAndroid Build Coastguard Worker CByteBuffer &buf = BitMaps.AddNew();
1969*f6dc9357SAndroid Build Coastguard Worker if (state == SB_BLOCK_PRESENT)
1970*f6dc9357SAndroid Build Coastguard Worker {
1971*f6dc9357SAndroid Build Coastguard Worker if (openArchiveCallback)
1972*f6dc9357SAndroid Build Coastguard Worker {
1973*f6dc9357SAndroid Build Coastguard Worker RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes))
1974*f6dc9357SAndroid Build Coastguard Worker }
1975*f6dc9357SAndroid Build Coastguard Worker numBytes += kBitmapSize;
1976*f6dc9357SAndroid Build Coastguard Worker buf.Alloc(kBitmapSize);
1977*f6dc9357SAndroid Build Coastguard Worker RINOK(Seek2(offset))
1978*f6dc9357SAndroid Build Coastguard Worker RINOK(Read_FALSE(buf, kBitmapSize))
1979*f6dc9357SAndroid Build Coastguard Worker /*
1980*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < (1 << 20); i+=4)
1981*f6dc9357SAndroid Build Coastguard Worker {
1982*f6dc9357SAndroid Build Coastguard Worker UInt32 v = GetUi32(buf + i);
1983*f6dc9357SAndroid Build Coastguard Worker if (v != 0 && v != (UInt32)(Int32)-1)
1984*f6dc9357SAndroid Build Coastguard Worker printf("\n%7d %8x", i, v);
1985*f6dc9357SAndroid Build Coastguard Worker }
1986*f6dc9357SAndroid Build Coastguard Worker */
1987*f6dc9357SAndroid Build Coastguard Worker }
1988*f6dc9357SAndroid Build Coastguard Worker }
1989*f6dc9357SAndroid Build Coastguard Worker }
1990*f6dc9357SAndroid Build Coastguard Worker }
1991*f6dc9357SAndroid Build Coastguard Worker
1992*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1993*f6dc9357SAndroid Build Coastguard Worker }
1994*f6dc9357SAndroid Build Coastguard Worker
1995*f6dc9357SAndroid Build Coastguard Worker
1996*f6dc9357SAndroid Build Coastguard Worker void CHandler::CloseAtError()
1997*f6dc9357SAndroid Build Coastguard Worker {
1998*f6dc9357SAndroid Build Coastguard Worker // CHandlerImg
1999*f6dc9357SAndroid Build Coastguard Worker Clear_HandlerImg_Vars();
2000*f6dc9357SAndroid Build Coastguard Worker Stream.Release();
2001*f6dc9357SAndroid Build Coastguard Worker
2002*f6dc9357SAndroid Build Coastguard Worker _phySize = 0;
2003*f6dc9357SAndroid Build Coastguard Worker Bat.Clear();
2004*f6dc9357SAndroid Build Coastguard Worker BitMaps.Clear();
2005*f6dc9357SAndroid Build Coastguard Worker NumUsedBlocks = 0;
2006*f6dc9357SAndroid Build Coastguard Worker NumUsedBitMaps = 0;
2007*f6dc9357SAndroid Build Coastguard Worker HeadersSize = 0;
2008*f6dc9357SAndroid Build Coastguard Worker /*
2009*f6dc9357SAndroid Build Coastguard Worker NumUsed_1MB_Blocks = 0;
2010*f6dc9357SAndroid Build Coastguard Worker NumUsed_1MB_Blocks_Defined = false;
2011*f6dc9357SAndroid Build Coastguard Worker */
2012*f6dc9357SAndroid Build Coastguard Worker
2013*f6dc9357SAndroid Build Coastguard Worker Parent = NULL;
2014*f6dc9357SAndroid Build Coastguard Worker ParentStream.Release();
2015*f6dc9357SAndroid Build Coastguard Worker _errorMessage.Empty();
2016*f6dc9357SAndroid Build Coastguard Worker _creator.Empty();
2017*f6dc9357SAndroid Build Coastguard Worker _nonEmptyLog = false;
2018*f6dc9357SAndroid Build Coastguard Worker _parentGuid_IsDefined = false;
2019*f6dc9357SAndroid Build Coastguard Worker _isDataContiguous = false;
2020*f6dc9357SAndroid Build Coastguard Worker // _batOverlap = false;
2021*f6dc9357SAndroid Build Coastguard Worker
2022*f6dc9357SAndroid Build Coastguard Worker ParentNames.Clear();
2023*f6dc9357SAndroid Build Coastguard Worker ParentName_Used.Empty();
2024*f6dc9357SAndroid Build Coastguard Worker
2025*f6dc9357SAndroid Build Coastguard Worker Meta.Clear();
2026*f6dc9357SAndroid Build Coastguard Worker
2027*f6dc9357SAndroid Build Coastguard Worker ChunkRatio_Log = 0;
2028*f6dc9357SAndroid Build Coastguard Worker ChunkRatio = 0;
2029*f6dc9357SAndroid Build Coastguard Worker TotalBatEntries = 0;
2030*f6dc9357SAndroid Build Coastguard Worker NumLevels = 0;
2031*f6dc9357SAndroid Build Coastguard Worker PackSize_Total = 0;
2032*f6dc9357SAndroid Build Coastguard Worker
2033*f6dc9357SAndroid Build Coastguard Worker _isCyclic = false;
2034*f6dc9357SAndroid Build Coastguard Worker _isCyclic_or_CyclicParent = false;
2035*f6dc9357SAndroid Build Coastguard Worker }
2036*f6dc9357SAndroid Build Coastguard Worker
2037*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
2038*f6dc9357SAndroid Build Coastguard Worker {
2039*f6dc9357SAndroid Build Coastguard Worker CloseAtError();
2040*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2041*f6dc9357SAndroid Build Coastguard Worker }
2042*f6dc9357SAndroid Build Coastguard Worker
2043*f6dc9357SAndroid Build Coastguard Worker
2044*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
2045*f6dc9357SAndroid Build Coastguard Worker {
2046*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
2047*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop;
2048*f6dc9357SAndroid Build Coastguard Worker
2049*f6dc9357SAndroid Build Coastguard Worker switch (propID)
2050*f6dc9357SAndroid Build Coastguard Worker {
2051*f6dc9357SAndroid Build Coastguard Worker case kpidSize: prop = Meta.VirtualDiskSize; break;
2052*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize: prop = PackSize_Total; break;
2053*f6dc9357SAndroid Build Coastguard Worker case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
2054*f6dc9357SAndroid Build Coastguard Worker }
2055*f6dc9357SAndroid Build Coastguard Worker
2056*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
2057*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2058*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
2059*f6dc9357SAndroid Build Coastguard Worker }
2060*f6dc9357SAndroid Build Coastguard Worker
2061*f6dc9357SAndroid Build Coastguard Worker
2062*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
2063*f6dc9357SAndroid Build Coastguard Worker {
2064*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
2065*f6dc9357SAndroid Build Coastguard Worker *stream = NULL;
2066*f6dc9357SAndroid Build Coastguard Worker // if some prarent is not OK, we don't create stream
2067*f6dc9357SAndroid Build Coastguard Worker if (!AreParentsOK())
2068*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2069*f6dc9357SAndroid Build Coastguard Worker InitSeekPositions();
2070*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> streamTemp = this;
2071*f6dc9357SAndroid Build Coastguard Worker *stream = streamTemp.Detach();
2072*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2073*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
2074*f6dc9357SAndroid Build Coastguard Worker }
2075*f6dc9357SAndroid Build Coastguard Worker
2076*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2077*f6dc9357SAndroid Build Coastguard Worker "VHDX", "vhdx avhdx", NULL, 0xc4,
2078*f6dc9357SAndroid Build Coastguard Worker kSignature,
2079*f6dc9357SAndroid Build Coastguard Worker 0,
2080*f6dc9357SAndroid Build Coastguard Worker 0,
2081*f6dc9357SAndroid Build Coastguard Worker NULL)
2082*f6dc9357SAndroid Build Coastguard Worker
2083*f6dc9357SAndroid Build Coastguard Worker }}
2084