1 // VmdkHandler.cpp
2
3 #include "StdAfx.h"
4
5 // #include <stdio.h>
6
7 #include "../../../C/CpuArch.h"
8
9 #include "../../Common/ComTry.h"
10 #include "../../Common/IntToString.h"
11 #include "../../Common/StringConvert.h"
12 #include "../../Common/StringToInt.h"
13 #include "../../Common/UTFConvert.h"
14
15 #include "../../Windows/PropVariant.h"
16
17 #include "../Common/RegisterArc.h"
18 #include "../Common/StreamObjects.h"
19 #include "../Common/StreamUtils.h"
20
21 #include "../Compress/ZlibDecoder.h"
22
23 #include "HandlerCont.h"
24
25 using namespace NWindows;
26
27 namespace NArchive {
28 namespace NVmdk {
29
30 #define Get16(p) GetUi16(p)
31 #define Get32(p) GetUi32(p)
32 #define Get64(p) GetUi64(p)
33
34 #define LE_16(offs, dest) dest = Get16(p + (offs))
35 #define LE_32(offs, dest) dest = Get32(p + (offs))
36 #define LE_64(offs, dest) dest = Get64(p + (offs))
37
38
39 static const Byte k_Signature[] = { 'K', 'D', 'M', 'V' };
40
41 static const UInt32 k_Flags_NL = (UInt32)1 << 0;
42 // static const UInt32 k_Flags_RGD = (UInt32)1 << 1;
43 static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2;
44 static const UInt32 k_Flags_Compressed = (UInt32)1 << 16;
45 static const UInt32 k_Flags_Marker = (UInt32)1 << 17;
46
47 static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table
48
49 struct CHeader
50 {
51 UInt32 flags;
52 UInt32 version;
53
54 UInt64 capacity;
55 UInt64 grainSize;
56 UInt64 descriptorOffset;
57 UInt64 descriptorSize;
58
59 UInt32 numGTEsPerGT;
60 UInt16 algo;
61 // Byte uncleanShutdown;
62 // UInt64 rgdOffset;
63 UInt64 gdOffset;
64 UInt64 overHead;
65
Is_NLNArchive::NVmdk::CHeader66 bool Is_NL() const { return (flags & k_Flags_NL) != 0; }
Is_ZeroGrainNArchive::NVmdk::CHeader67 bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; }
Is_CompressedNArchive::NVmdk::CHeader68 bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; }
Is_MarkerNArchive::NVmdk::CHeader69 bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; }
70
71 bool Parse(const Byte *p);
72
IsSameImageForNArchive::NVmdk::CHeader73 bool IsSameImageFor(const CHeader &h) const
74 {
75 return flags == h.flags
76 && version == h.version
77 && capacity == h.capacity
78 && grainSize == h.grainSize
79 && algo == h.algo;
80 }
81 };
82
Parse(const Byte * p)83 bool CHeader::Parse(const Byte *p)
84 {
85 if (memcmp(p, k_Signature, sizeof(k_Signature)) != 0)
86 return false;
87
88 LE_32 (0x04, version);
89 LE_32 (0x08, flags);
90 LE_64 (0x0C, capacity);
91 LE_64 (0x14, grainSize);
92 LE_64 (0x1C, descriptorOffset);
93 LE_64 (0x24, descriptorSize);
94 LE_32 (0x2C, numGTEsPerGT);
95 // LE_64 (0x30, rgdOffset);
96 LE_64 (0x38, gdOffset);
97 LE_64 (0x40, overHead);
98 // uncleanShutdown = buf[0x48];
99 LE_16(0x4D, algo);
100
101 if (Is_NL() && Get32(p + 0x49) != 0x0A0D200A) // do we need Is_NL() check here?
102 return false;
103
104 return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3);
105 }
106
107
108 enum
109 {
110 k_Marker_END_OF_STREAM = 0,
111 k_Marker_GRAIN_TABLE = 1,
112 k_Marker_GRAIN_DIR = 2,
113 k_Marker_FOOTER = 3
114 };
115
116 struct CMarker
117 {
118 UInt64 NumSectors;
119 UInt32 SpecSize; // = 0 for metadata sectors
120 UInt32 Type;
121
ParseNArchive::NVmdk::CMarker122 void Parse(const Byte *p)
123 {
124 LE_64 (0, NumSectors);
125 LE_32 (8, SpecSize);
126 LE_32 (12, Type);
127 }
128 };
129
130
Str_to_ValName(const AString & s,AString & name,AString & val)131 static bool Str_to_ValName(const AString &s, AString &name, AString &val)
132 {
133 name.Empty();
134 val.Empty();
135 int qu = s.Find('"');
136 int eq = s.Find('=');
137 if (eq < 0 || (qu >= 0 && eq > qu))
138 return false;
139 name.SetFrom(s.Ptr(), eq);
140 name.Trim();
141 val = s.Ptr(eq + 1);
142 val.Trim();
143 return true;
144 }
145
IsSpaceChar(char c)146 static inline bool IsSpaceChar(char c)
147 {
148 return (c == ' ' || c == '\t');
149 }
150
SkipSpaces(const char * s)151 static const char *SkipSpaces(const char *s)
152 {
153 for (;; s++)
154 {
155 char c = *s;
156 if (c == 0 || !IsSpaceChar(c))
157 return s;
158 }
159 }
160
161 #define SKIP_SPACES(s) s = SkipSpaces(s);
162
GetNextWord(const char * s,AString & dest)163 static const char *GetNextWord(const char *s, AString &dest)
164 {
165 dest.Empty();
166 SKIP_SPACES(s)
167 const char *start = s;
168 for (;; s++)
169 {
170 char c = *s;
171 if (c == 0 || IsSpaceChar(c))
172 {
173 dest.SetFrom(start, (unsigned)(s - start));
174 return s;
175 }
176 }
177 }
178
GetNextNumber(const char * s,UInt64 & val)179 static const char *GetNextNumber(const char *s, UInt64 &val)
180 {
181 SKIP_SPACES(s)
182 if (*s == 0)
183 return s;
184 const char *end;
185 val = ConvertStringToUInt64(s, &end);
186 char c = *end;
187 if (c != 0 && !IsSpaceChar(c))
188 return NULL;
189 return end;
190 }
191
192
193 struct CExtentInfo
194 {
195 AString Access; // RW, RDONLY, or NOACCESS
196 UInt64 NumSectors; // 512 bytes sectors
197 AString Type; // FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW
198 AString FileName;
199 UInt64 StartSector; // used for FLAT
200
201 // for VMWare Player 9:
202 // PartitionUUID
203 // DeviceIdentifier
204
IsType_ZERONArchive::NVmdk::CExtentInfo205 bool IsType_ZERO() const { return Type == "ZERO"; }
206 // bool IsType_FLAT() const { return Type == "FLAT"; }
IsType_FlatNArchive::NVmdk::CExtentInfo207 bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; }
208
209 bool Parse(const char *s);
210 };
211
Parse(const char * s)212 bool CExtentInfo::Parse(const char *s)
213 {
214 NumSectors = 0;
215 StartSector = 0;
216 Access.Empty();
217 Type.Empty();
218 FileName.Empty();
219
220 s = GetNextWord(s, Access);
221 s = GetNextNumber(s, NumSectors);
222 if (!s)
223 return false;
224 s = GetNextWord(s, Type);
225
226 if (Type.IsEmpty())
227 return false;
228
229 SKIP_SPACES(s)
230
231 if (IsType_ZERO())
232 return (*s == 0);
233
234 if (*s != '\"')
235 return false;
236 s++;
237 {
238 const char *s2 = strchr(s, '\"');
239 if (!s2)
240 return false;
241 FileName.SetFrom(s, (unsigned)(s2 - s));
242 s = s2 + 1;
243 }
244 SKIP_SPACES(s)
245 if (*s == 0)
246 return true;
247
248 s = GetNextNumber(s, StartSector);
249 if (!s)
250 return false;
251 return true;
252 // SKIP_SPACES(s);
253 // return (*s == 0);
254 }
255
256
257 struct CDescriptor
258 {
259 AString CID;
260 AString parentCID;
261 AString createType;
262 // AString encoding; // UTF-8, windows-1252 - default is UTF-8
263
264 CObjectVector<CExtentInfo> Extents;
265
GetUnicodeNameNArchive::NVmdk::CDescriptor266 static void GetUnicodeName(const AString &s, UString &res)
267 {
268 if (!ConvertUTF8ToUnicode(s, res))
269 MultiByteToUnicodeString2(res, s);
270 }
271
ClearNArchive::NVmdk::CDescriptor272 void Clear()
273 {
274 CID.Empty();
275 parentCID.Empty();
276 createType.Empty();
277 Extents.Clear();
278 }
279
IsThere_ParentNArchive::NVmdk::CDescriptor280 bool IsThere_Parent() const
281 {
282 return !parentCID.IsEmpty() && !parentCID.IsEqualTo_Ascii_NoCase("ffffffff");
283 }
284
285 bool Parse(const Byte *p, size_t size);
286 };
287
288
Parse(const Byte * p,size_t size)289 bool CDescriptor::Parse(const Byte *p, size_t size)
290 {
291 Clear();
292
293 AString s;
294 AString name;
295 AString val;
296
297 for (;;)
298 {
299 Byte c = 0;
300 if (size != 0)
301 {
302 size--;
303 c = *p++;
304 }
305 if (c == 0 || c == 0xA || c == 0xD)
306 {
307 if (!s.IsEmpty() && s[0] != '#')
308 {
309 if (Str_to_ValName(s, name, val))
310 {
311 if (name.IsEqualTo_Ascii_NoCase("CID"))
312 CID = val;
313 else if (name.IsEqualTo_Ascii_NoCase("parentCID"))
314 parentCID = val;
315 else if (name.IsEqualTo_Ascii_NoCase("createType"))
316 createType = val;
317 }
318 else
319 {
320 CExtentInfo ei;
321 if (!ei.Parse(s))
322 return false;
323 Extents.Add(ei);
324 }
325 }
326
327 s.Empty();
328 if (c == 0)
329 return true;
330 }
331 else
332 s += (char)c;
333 }
334 }
335
336
337 struct CExtent
338 {
339 bool IsOK;
340 bool IsArc;
341 bool NeedDeflate;
342 bool Unsupported;
343 bool IsZero;
344 bool IsFlat;
345 bool DescriptorOK;
346 bool HeadersError;
347
348 unsigned ClusterBits;
349 UInt32 ZeroSector;
350
351 CObjectVector<CByteBuffer> Tables;
352
353 CMyComPtr<IInStream> Stream;
354 UInt64 PosInArc;
355
356 UInt64 PhySize;
357 UInt64 VirtSize; // from vmdk header of volume
358
359 UInt64 StartOffset; // virtual offset of this extent
360 UInt64 NumBytes; // from main descriptor, if multi-vol
361 UInt64 FlatOffset; // in Stream
362
363 CByteBuffer DescriptorBuf;
364 CDescriptor Descriptor;
365
366 CHeader h;
367
GetEndOffsetNArchive::NVmdk::CExtent368 UInt64 GetEndOffset() const { return StartOffset + NumBytes; }
369
IsVmdkNArchive::NVmdk::CExtent370 bool IsVmdk() const { return !IsZero && !IsFlat; }
371 // if (IsOK && IsVmdk()), then VMDK header of this extent was read
372
CExtentNArchive::NVmdk::CExtent373 CExtent():
374 IsOK(false),
375 IsArc(false),
376 NeedDeflate(false),
377 Unsupported(false),
378 IsZero(false),
379 IsFlat(false),
380 DescriptorOK(false),
381 HeadersError(false),
382
383 ClusterBits(0),
384 ZeroSector(0),
385
386 PosInArc(0),
387
388 PhySize(0),
389 VirtSize(0),
390
391 StartOffset(0),
392 NumBytes(0),
393 FlatOffset(0)
394 {}
395
396
397 HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors);
398 HRESULT Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
399 unsigned numVols, unsigned volIndex, UInt64 &complexity);
400
SeekNArchive::NVmdk::CExtent401 HRESULT Seek(UInt64 offset)
402 {
403 PosInArc = offset;
404 return InStream_SeekSet(Stream, offset);
405 }
406
InitAndSeekNArchive::NVmdk::CExtent407 HRESULT InitAndSeek()
408 {
409 if (Stream)
410 return Seek(0);
411 return S_OK;
412 }
413
ReadNArchive::NVmdk::CExtent414 HRESULT Read(void *data, size_t *size)
415 {
416 HRESULT res = ReadStream(Stream, data, size);
417 PosInArc += *size;
418 return res;
419 }
420 };
421
422
423 Z7_class_CHandler_final: public CHandlerImg
424 {
425 bool _isArc;
426 bool _unsupported;
427 bool _unsupportedSome;
428 bool _headerError;
429 bool _missingVol;
430 bool _isMultiVol;
431 bool _needDeflate;
432
433 UInt64 _cacheCluster;
434 unsigned _cacheExtent;
435 CByteBuffer _cache;
436 CByteBuffer _cacheCompressed;
437
438 unsigned _clusterBitsMax;
439 UInt64 _phySize;
440
441 CObjectVector<CExtent> _extents;
442
443 CBufInStream *_bufInStreamSpec;
444 CMyComPtr<ISequentialInStream> _bufInStream;
445
446 CBufPtrSeqOutStream *_bufOutStreamSpec;
447 CMyComPtr<ISequentialOutStream> _bufOutStream;
448
449 NCompress::NZlib::CDecoder *_zlibDecoderSpec;
450 CMyComPtr<ICompressCoder> _zlibDecoder;
451
452 CByteBuffer _descriptorBuf;
453 CDescriptor _descriptor;
454
455 UString _missingVolName;
456
457 void InitAndSeekMain()
458 {
459 _virtPos = 0;
460 }
461
462 virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
463 virtual void CloseAtError() Z7_override;
464 public:
465 Z7_IFACE_COM7_IMP(IInArchive_Img)
466
467 Z7_IFACE_COM7_IMP(IInArchiveGetStream)
468 Z7_IFACE_COM7_IMP(ISequentialInStream)
469 };
470
471
472 Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
473 {
474 if (processedSize)
475 *processedSize = 0;
476 if (_virtPos >= _size)
477 return S_OK;
478 {
479 UInt64 rem = _size - _virtPos;
480 if (size > rem)
481 size = (UInt32)rem;
482 if (size == 0)
483 return S_OK;
484 }
485
486 unsigned extentIndex;
487 {
488 unsigned left = 0, right = _extents.Size();
489 for (;;)
490 {
491 unsigned mid = (left + right) / 2;
492 if (mid == left)
493 break;
494 if (_virtPos < _extents[mid].StartOffset)
495 right = mid;
496 else
497 left = mid;
498 }
499 extentIndex = left;
500 }
501
502 CExtent &extent = _extents[extentIndex];
503
504 {
505 const UInt64 vir = _virtPos - extent.StartOffset;
506 if (vir >= extent.NumBytes)
507 {
508 return E_FAIL;
509 /*
510 if (vir > extent.NumBytes)
511 _stream_dataError = true;
512 memset(data, 0, size);
513 _virtPos += size;
514 if (processedSize)
515 *processedSize = size;
516 return S_OK;
517 */
518 }
519
520 {
521 const UInt64 rem = extent.NumBytes - vir;
522 if (size > rem)
523 size = (UInt32)rem;
524 }
525
526 if (vir >= extent.VirtSize)
527 {
528 // if vmdk's VirtSize is smaller than VirtSize from main multi-volume descriptor
529 _stream_dataError = true;
530 return S_FALSE;
531 /*
532 memset(data, 0, size);
533 _virtPos += size;
534 if (processedSize)
535 *processedSize = size;
536 return S_OK;
537 */
538 }
539
540 {
541 const UInt64 rem = extent.VirtSize - vir;
542 if (size > rem)
543 size = (UInt32)rem;
544 }
545
546 if (extent.IsZero || !extent.IsOK || !extent.Stream || extent.Unsupported)
547 {
548 if (extent.Unsupported)
549 {
550 _stream_unsupportedMethod = true;
551 return S_FALSE;
552 }
553 if (!extent.IsOK || !extent.Stream)
554 {
555 _stream_unavailData = true;
556 return S_FALSE;
557 }
558 memset(data, 0, size);
559 _virtPos += size;
560 if (processedSize)
561 *processedSize = size;
562 return S_OK;
563 }
564
565 if (extent.IsFlat)
566 {
567 UInt64 offset = extent.FlatOffset + vir;
568 if (offset != extent.PosInArc)
569 {
570 RINOK(extent.Seek(offset))
571 }
572 UInt32 size2 = 0;
573 HRESULT res = extent.Stream->Read(data, size, &size2);
574 if (res == S_OK && size2 == 0)
575 {
576 _stream_unavailData = true;
577 /*
578 memset(data, 0, size);
579 _virtPos += size;
580 if (processedSize)
581 *processedSize = size;
582 return S_OK;
583 */
584 }
585 // _stream_PackSize += size2;
586 extent.PosInArc += size2;
587 _virtPos += size2;
588 if (processedSize)
589 *processedSize = size2;
590 return res;
591 }
592 }
593
594
595 for (;;)
596 {
597 const UInt64 vir = _virtPos - extent.StartOffset;
598 const unsigned clusterBits = extent.ClusterBits;
599 const UInt64 cluster = vir >> clusterBits;
600 const size_t clusterSize = (size_t)1 << clusterBits;
601 const size_t lowBits = (size_t)vir & (clusterSize - 1);
602 {
603 size_t rem = clusterSize - lowBits;
604 if (size > rem)
605 size = (UInt32)rem;
606 }
607
608 if (extentIndex == _cacheExtent && cluster == _cacheCluster)
609 {
610 memcpy(data, _cache + lowBits, size);
611 _virtPos += size;
612 if (processedSize)
613 *processedSize = size;
614 return S_OK;
615 }
616
617 const UInt64 high = cluster >> k_NumMidBits;
618
619 if (high < extent.Tables.Size())
620 {
621 const CByteBuffer &table = extent.Tables[(unsigned)high];
622
623 if (table.Size() != 0)
624 {
625 const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1);
626 const Byte *p = (const Byte *)table + (midBits << 2);
627 const UInt32 v = Get32(p);
628
629 if (v != 0 && v != extent.ZeroSector)
630 {
631 UInt64 offset = (UInt64)v << 9;
632 if (extent.NeedDeflate)
633 {
634 if (offset != extent.PosInArc)
635 {
636 // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
637 RINOK(extent.Seek(offset))
638 }
639
640 const size_t kStartSize = 1 << 9;
641 {
642 size_t curSize = kStartSize;
643 RINOK(extent.Read(_cacheCompressed, &curSize))
644 // _stream_PackSize += curSize;
645 if (curSize != kStartSize)
646 return S_FALSE;
647 }
648
649 if (Get64(_cacheCompressed) != (cluster << (clusterBits - 9)))
650 return S_FALSE;
651
652 UInt32 dataSize = Get32(_cacheCompressed + 8);
653 if (dataSize > ((UInt32)1 << 31))
654 return S_FALSE;
655
656 size_t dataSize2 = (size_t)dataSize + 12;
657
658 if (dataSize2 > kStartSize)
659 {
660 dataSize2 = (dataSize2 + 511) & ~(size_t)511;
661 if (dataSize2 > _cacheCompressed.Size())
662 return S_FALSE;
663 size_t curSize = dataSize2 - kStartSize;
664 const size_t curSize2 = curSize;
665 RINOK(extent.Read(_cacheCompressed + kStartSize, &curSize))
666 // _stream_PackSize += curSize;
667 if (curSize != curSize2)
668 return S_FALSE;
669 }
670
671 _bufInStreamSpec->Init(_cacheCompressed + 12, dataSize);
672
673 _cacheCluster = (UInt64)(Int64)-1;
674 _cacheExtent = (unsigned)(int)-1;
675
676 if (_cache.Size() < clusterSize)
677 return E_FAIL;
678 _bufOutStreamSpec->Init(_cache, clusterSize);
679
680 // Do we need to use smaller block than clusterSize for last cluster?
681 const UInt64 blockSize64 = clusterSize;
682 HRESULT res = _zlibDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
683
684 /*
685 if (_bufOutStreamSpec->GetPos() != clusterSize)
686 {
687 _stream_dataError = true;
688 memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
689 }
690 */
691
692 if (_bufOutStreamSpec->GetPos() != clusterSize
693 || _zlibDecoderSpec->GetInputProcessedSize() != dataSize)
694 {
695 _stream_dataError = true;
696 if (res == S_OK)
697 res = S_FALSE;
698 }
699
700 RINOK(res)
701
702 _cacheCluster = cluster;
703 _cacheExtent = extentIndex;
704
705 continue;
706 /*
707 memcpy(data, _cache + lowBits, size);
708 _virtPos += size;
709 if (processedSize)
710 *processedSize = size;
711 return S_OK;
712 */
713 }
714 {
715 offset += lowBits;
716 if (offset != extent.PosInArc)
717 {
718 // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
719 RINOK(extent.Seek(offset))
720 }
721 UInt32 size2 = 0;
722 HRESULT res = extent.Stream->Read(data, size, &size2);
723 if (res == S_OK && size2 == 0)
724 {
725 _stream_unavailData = true;
726 /*
727 memset(data, 0, size);
728 _virtPos += size;
729 if (processedSize)
730 *processedSize = size;
731 return S_OK;
732 */
733 }
734 extent.PosInArc += size2;
735 // _stream_PackSize += size2;
736 _virtPos += size2;
737 if (processedSize)
738 *processedSize = size2;
739 return res;
740 }
741 }
742 }
743 }
744
745 memset(data, 0, size);
746 _virtPos += size;
747 if (processedSize)
748 *processedSize = size;
749 return S_OK;
750 }
751 }
752
753
754 static const Byte kProps[] =
755 {
756 kpidSize,
757 kpidPackSize
758 };
759
760 static const Byte kArcProps[] =
761 {
762 kpidNumVolumes,
763 kpidTotalPhySize,
764 kpidMethod,
765 kpidClusterSize,
766 kpidHeadersSize,
767 kpidId,
768 kpidName,
769 kpidComment
770 };
771
772 IMP_IInArchive_Props
773 IMP_IInArchive_ArcProps
774
775
776 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
777 {
778 COM_TRY_BEGIN
779 NCOM::CPropVariant prop;
780
781 const CExtent *e = NULL;
782 const CDescriptor *desc = NULL;
783
784 if (_isMultiVol)
785 desc = &_descriptor;
786 else if (_extents.Size() == 1)
787 {
788 e = &_extents[0];
789 desc = &e->Descriptor;
790 }
791
792 switch (propID)
793 {
794 case kpidMainSubfile: prop = (UInt32)0; break;
795 case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
796 case kpidTotalPhySize:
797 {
798 UInt64 sum = _phySize;
799 if (_isMultiVol)
800 {
801 FOR_VECTOR (i, _extents)
802 sum += _extents[i].PhySize;
803 }
804 prop = sum;
805 break;
806 }
807 case kpidClusterSize: prop = (UInt32)((UInt32)1 << _clusterBitsMax); break;
808 case kpidHeadersSize: if (e) prop = (e->h.overHead << 9); break;
809 case kpidMethod:
810 {
811 AString s;
812
813 if (desc && !desc->createType.IsEmpty())
814 s = desc->createType;
815
816 bool zlib = false;
817 bool marker = false;
818 Int32 algo = -1;
819
820 FOR_VECTOR (i, _extents)
821 {
822 const CExtent &extent = _extents[i];
823 if (!extent.IsOK || !extent.IsVmdk())
824 continue;
825
826 const CHeader &h = extent.h;
827
828 if (h.algo != 0)
829 {
830 if (h.algo == 1)
831 zlib = true;
832 else if (algo != h.algo)
833 {
834 s.Add_Space_if_NotEmpty();
835 s.Add_UInt32(h.algo);
836 algo = h.algo;
837 }
838 }
839
840 if (h.Is_Marker())
841 marker = true;
842 }
843
844 if (zlib)
845 s.Add_OptSpaced("zlib");
846
847 if (marker)
848 s.Add_OptSpaced("Marker");
849
850 if (!s.IsEmpty())
851 prop = s;
852 break;
853 }
854
855 case kpidComment:
856 {
857 if (e && e->DescriptorBuf.Size() != 0)
858 {
859 AString s;
860 s.SetFrom_CalcLen((const char *)(const Byte *)e->DescriptorBuf, (unsigned)e->DescriptorBuf.Size());
861 if (!s.IsEmpty() && s.Len() <= (1 << 16))
862 prop = s;
863 }
864 break;
865 }
866
867 case kpidId:
868 {
869 if (desc && !desc->CID.IsEmpty())
870 {
871 prop = desc->CID;
872 }
873 break;
874 }
875
876 case kpidName:
877 {
878 if (!_isMultiVol && desc && desc->Extents.Size() == 1)
879 {
880 const CExtentInfo &ei = desc->Extents[0];
881 if (!ei.FileName.IsEmpty())
882 {
883 UString u;
884 CDescriptor::GetUnicodeName(ei.FileName, u);
885 if (!u.IsEmpty())
886 prop = u;
887 }
888 }
889 break;
890 }
891
892 case kpidNumVolumes: if (_isMultiVol) prop = (UInt32)_extents.Size(); break;
893
894 case kpidError:
895 {
896 if (_missingVol || !_missingVolName.IsEmpty())
897 {
898 UString s ("Missing volume : ");
899 if (!_missingVolName.IsEmpty())
900 s += _missingVolName;
901 prop = s;
902 }
903 break;
904 }
905
906 case kpidErrorFlags:
907 {
908 UInt32 v = 0;
909 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
910 if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
911 if (_unsupportedSome) v |= kpv_ErrorFlags_UnsupportedMethod;
912 if (_headerError) v |= kpv_ErrorFlags_HeadersError;
913 // if (_missingVol) v |= kpv_ErrorFlags_UnexpectedEnd;
914 if (v != 0)
915 prop = v;
916 break;
917 }
918 }
919
920 prop.Detach(value);
921 return S_OK;
922 COM_TRY_END
923 }
924
925
926 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
927 {
928 COM_TRY_BEGIN
929 NCOM::CPropVariant prop;
930
931 switch (propID)
932 {
933 case kpidSize: prop = _size; break;
934 case kpidPackSize:
935 {
936 UInt64 packSize = 0;
937 FOR_VECTOR (i, _extents)
938 {
939 const CExtent &e = _extents[i];
940 if (!e.IsOK)
941 continue;
942 if (e.IsVmdk() && !_isMultiVol)
943 {
944 UInt64 ov = (e.h.overHead << 9);
945 if (e.PhySize >= ov)
946 packSize += e.PhySize - ov;
947 }
948 else
949 packSize += e.PhySize;
950 }
951 prop = packSize;
952 break;
953 }
954 case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
955 }
956
957 prop.Detach(value);
958 return S_OK;
959 COM_TRY_END
960 }
961
962
963 static int inline GetLog(UInt64 num)
964 {
965 for (int i = 0; i < 64; i++)
966 if (((UInt64)1 << i) == num)
967 return i;
968 return -1;
969 }
970
971
972 HRESULT CExtent::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors)
973 {
974 sector <<= 9;
975 RINOK(InStream_SeekSet(stream, sector))
976 size_t size = numSectors << 9;
977 RINOK(ReadStream_FALSE(stream, data, size))
978 UInt64 end = sector + size;
979 if (PhySize < end)
980 PhySize = end;
981 return S_OK;
982 }
983
984
985 void CHandler::CloseAtError()
986 {
987 _extents.Clear();
988 CHandlerImg::CloseAtError();
989 }
990
991
992 static const char * const kSignature_Descriptor = "# Disk DescriptorFile";
993
994
995 HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
996 {
997 const unsigned kSectoreSize = 512;
998 Byte buf[kSectoreSize];
999 size_t headerSize = kSectoreSize;
1000 RINOK(ReadStream(stream, buf, &headerSize))
1001
1002 if (headerSize < sizeof(k_Signature))
1003 return S_FALSE;
1004
1005 CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
1006
1007 if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
1008 {
1009 const size_t k_SigDesc_Size = strlen(kSignature_Descriptor);
1010 if (headerSize < k_SigDesc_Size)
1011 return S_FALSE;
1012 if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) != 0)
1013 return S_FALSE;
1014
1015 UInt64 endPos;
1016 RINOK(InStream_GetSize_SeekToEnd(stream, endPos))
1017 if (endPos > (1 << 20))
1018 return S_FALSE;
1019 const size_t numBytes = (size_t)endPos;
1020 _descriptorBuf.Alloc(numBytes);
1021 RINOK(InStream_SeekToBegin(stream))
1022 RINOK(ReadStream_FALSE(stream, _descriptorBuf, numBytes))
1023
1024 if (!_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size()))
1025 return S_FALSE;
1026 _isMultiVol = true;
1027 _isArc = true;
1028 _phySize = numBytes;
1029 if (_descriptor.IsThere_Parent())
1030 _unsupported = true;
1031
1032 if (openCallback)
1033 {
1034 openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
1035 }
1036 if (!volumeCallback)
1037 {
1038 _unsupported = true;
1039 return E_NOTIMPL;
1040 }
1041
1042 /*
1043 UInt64 totalVirtSize = 0;
1044 FOR_VECTOR (i, _descriptor.Extents)
1045 {
1046 const CExtentInfo &ei = _descriptor.Extents[i];
1047 if (ei.NumSectors >= ((UInt64)1 << (63 - 9)))
1048 return S_FALSE;
1049 totalVirtSize += ei.NumSectors;
1050 if (totalVirtSize >= ((UInt64)1 << (63 - 9)))
1051 return S_FALSE;
1052 }
1053 totalVirtSize <<= 9;
1054 */
1055
1056 if (_descriptor.Extents.Size() > 1)
1057 {
1058 const UInt64 numFiles = _descriptor.Extents.Size();
1059 RINOK(openCallback->SetTotal(&numFiles, NULL))
1060 }
1061 }
1062
1063 UInt64 complexity = 0;
1064
1065 for (;;)
1066 {
1067 CExtent *e = NULL;
1068 CMyComPtr<IInStream> nextStream;
1069
1070 if (_isMultiVol)
1071 {
1072 const unsigned extentIndex = _extents.Size();
1073 if (extentIndex >= _descriptor.Extents.Size())
1074 break;
1075 const CExtentInfo &ei = _descriptor.Extents[extentIndex];
1076 e = &_extents.AddNew();
1077 e->StartOffset = 0;
1078 if (ei.NumSectors >= ((UInt64)1 << (62 - 9)) ||
1079 ei.StartSector >= ((UInt64)1 << (62 - 9)))
1080 return S_FALSE;
1081 e->NumBytes = ei.NumSectors << 9;
1082 e->IsZero = ei.IsType_ZERO();
1083 if (extentIndex != 0)
1084 e->StartOffset = _extents[extentIndex - 1].GetEndOffset();
1085 if (e->GetEndOffset() < e->StartOffset)
1086 return S_FALSE;
1087
1088 e->VirtSize = e->NumBytes;
1089 if (e->IsZero)
1090 {
1091 e->IsOK = true;
1092 continue;
1093 }
1094
1095 e->IsFlat = ei.IsType_Flat();
1096 e->FlatOffset = ei.StartSector << 9;
1097
1098 UString u;
1099 CDescriptor::GetUnicodeName(ei.FileName, u);
1100 if (u.IsEmpty())
1101 {
1102 _missingVol = true;
1103 continue;
1104 }
1105
1106 HRESULT result = volumeCallback->GetStream(u, &nextStream);
1107
1108 if (result != S_OK && result != S_FALSE)
1109 return result;
1110
1111 if (!nextStream || result != S_OK)
1112 {
1113 if (_missingVolName.IsEmpty())
1114 _missingVolName = u;
1115 _missingVol = true;
1116 continue;
1117 }
1118
1119 if (e->IsFlat)
1120 {
1121 e->IsOK = true;
1122 e->Stream = nextStream;
1123 e->PhySize = e->NumBytes;
1124 continue;
1125 }
1126
1127 stream = nextStream;
1128
1129 headerSize = kSectoreSize;
1130 RINOK(ReadStream(stream, buf, &headerSize))
1131
1132 if (headerSize != kSectoreSize)
1133 continue;
1134 if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
1135 continue;
1136 }
1137 else
1138 {
1139 if (headerSize != kSectoreSize)
1140 return S_FALSE;
1141 e = &_extents.AddNew();
1142 e->StartOffset = 0;
1143 }
1144
1145 HRESULT res = S_FALSE;
1146 if (e->h.Parse(buf))
1147 res = e->Open3(stream, openCallback, _isMultiVol ? _descriptor.Extents.Size() : 1, _extents.Size() - 1, complexity);
1148
1149 if (!_isMultiVol)
1150 {
1151 _isArc = e->IsArc;
1152 _phySize = e->PhySize;
1153 _unsupported = e->Unsupported;
1154 }
1155
1156 if (e->Unsupported)
1157 _unsupportedSome = true;
1158 if (e->HeadersError)
1159 _headerError = true;
1160
1161 if (res != S_OK)
1162 {
1163 if (res != S_FALSE)
1164 return res;
1165 if (!_isMultiVol)
1166 return res;
1167 continue;
1168 }
1169
1170 e->Stream = stream;
1171 e->IsOK = true;
1172
1173 if (!_isMultiVol)
1174 {
1175 e->NumBytes = e->VirtSize;
1176 break;
1177 }
1178
1179 if (e->NumBytes != e->VirtSize)
1180 _headerError = true;
1181 }
1182
1183 if (!_extents.IsEmpty())
1184 _size = _extents.Back().GetEndOffset();
1185
1186 _needDeflate = false;
1187 _clusterBitsMax = 0;
1188
1189 // unsigned numOKs = 0;
1190 unsigned numUnsupported = 0;
1191
1192 FOR_VECTOR (i, _extents)
1193 {
1194 const CExtent &e = _extents[i];
1195 if (e.Unsupported)
1196 numUnsupported++;
1197 if (!e.IsOK)
1198 continue;
1199 // numOKs++;
1200 if (e.IsVmdk())
1201 {
1202 if (e.NeedDeflate)
1203 _needDeflate = true;
1204 if (_clusterBitsMax < e.ClusterBits)
1205 _clusterBitsMax = e.ClusterBits;
1206 }
1207 }
1208
1209 if (numUnsupported != 0 && numUnsupported == _extents.Size())
1210 _unsupported = true;
1211
1212 return S_OK;
1213 }
1214
1215
1216 HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
1217 unsigned numVols, unsigned volIndex, UInt64 &complexity)
1218 {
1219 if (h.descriptorSize != 0)
1220 {
1221 if (h.descriptorOffset == 0 ||
1222 h.descriptorSize > (1 << 10))
1223 return S_FALSE;
1224 DescriptorBuf.Alloc((size_t)h.descriptorSize << 9);
1225 RINOK(ReadForHeader(stream, h.descriptorOffset, DescriptorBuf, (size_t)h.descriptorSize))
1226 if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(DescriptorBuf) == 0)
1227 {
1228 // We check data as end marker.
1229 // and if probably it's footer's copy of header, we don't want to open it.
1230 return S_FALSE;
1231 }
1232
1233 DescriptorOK = Descriptor.Parse(DescriptorBuf, DescriptorBuf.Size());
1234 if (!DescriptorOK)
1235 HeadersError = true;
1236 if (Descriptor.IsThere_Parent())
1237 Unsupported = true;
1238 }
1239
1240 if (h.gdOffset == (UInt64)(Int64)-1)
1241 {
1242 // Grain Dir is at end of file
1243 UInt64 endPos;
1244 RINOK(InStream_GetSize_SeekToEnd(stream, endPos))
1245 if ((endPos & 511) != 0)
1246 return S_FALSE;
1247
1248 const size_t kEndSize = 512 * 3;
1249 Byte buf2[kEndSize];
1250 if (endPos < kEndSize)
1251 return S_FALSE;
1252 RINOK(InStream_SeekSet(stream, endPos - kEndSize))
1253 RINOK(ReadStream_FALSE(stream, buf2, kEndSize))
1254
1255 CHeader h2;
1256 if (!h2.Parse(buf2 + 512))
1257 return S_FALSE;
1258 if (!h.IsSameImageFor(h2))
1259 return S_FALSE;
1260
1261 h = h2;
1262
1263 CMarker m;
1264 m.Parse(buf2);
1265 if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER)
1266 return S_FALSE;
1267 m.Parse(buf2 + 512 * 2);
1268 if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM)
1269 return S_FALSE;
1270 PhySize = endPos;
1271 }
1272
1273 const int grainSize_Log = GetLog(h.grainSize);
1274 if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB
1275 return S_FALSE;
1276 if (h.capacity >= ((UInt64)1 << (63 - 9)))
1277 return S_FALSE;
1278 if (h.overHead >= ((UInt64)1 << (63 - 9)))
1279 return S_FALSE;
1280
1281 IsArc = true;
1282 ClusterBits = (9 + (unsigned)grainSize_Log);
1283 VirtSize = h.capacity << 9;
1284 NeedDeflate = (h.algo >= 1);
1285
1286 if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0))
1287 {
1288 Unsupported = true;
1289 PhySize = 0;
1290 return S_FALSE;
1291 }
1292
1293 {
1294 const UInt64 overHeadBytes = h.overHead << 9;
1295 if (PhySize < overHeadBytes)
1296 PhySize = overHeadBytes;
1297 }
1298
1299 ZeroSector = 0;
1300 if (h.Is_ZeroGrain())
1301 ZeroSector = 1;
1302
1303 const UInt64 numSectorsPerGde = (UInt64)1 << ((unsigned)grainSize_Log + k_NumMidBits);
1304 const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> ((unsigned)grainSize_Log + k_NumMidBits);
1305 CByteBuffer table;
1306
1307 if (numGdeEntries != 0)
1308 {
1309 if (h.gdOffset == 0)
1310 return S_FALSE;
1311
1312 size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2));
1313 size_t t1SizeBytes = numSectors << 9;
1314 if ((t1SizeBytes >> 2) < numGdeEntries)
1315 return S_FALSE;
1316 table.Alloc(t1SizeBytes);
1317
1318 if (h.Is_Marker())
1319 {
1320 Byte buf2[1 << 9];
1321 if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK)
1322 return S_FALSE;
1323 {
1324 CMarker m;
1325 m.Parse(buf2);
1326 if (m.Type != k_Marker_GRAIN_DIR
1327 || m.NumSectors != numSectors
1328 || m.SpecSize != 0)
1329 return S_FALSE;
1330 }
1331 }
1332
1333 RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors))
1334 }
1335
1336 const size_t clusterSize = (size_t)1 << ClusterBits;
1337
1338 const UInt64 complexityStart = complexity;
1339
1340 if (openCallback)
1341 {
1342 complexity += (UInt64)numGdeEntries << (k_NumMidBits + 2);
1343 {
1344 const UInt64 numVols2 = numVols;
1345 RINOK(openCallback->SetTotal((numVols == 1) ? NULL : &numVols2, &complexity))
1346 }
1347 if (numVols != 1)
1348 {
1349 const UInt64 volIndex2 = volIndex;
1350 RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &complexityStart))
1351 }
1352 }
1353
1354 UInt64 lastSector = 0;
1355 UInt64 lastVirtCluster = 0;
1356 size_t numProcessed_Prev = 0;
1357
1358 for (size_t i = 0; i < numGdeEntries; i++)
1359 {
1360 const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2);
1361 const size_t k_NumMidItems = (size_t)1 << k_NumMidBits;
1362
1363 CByteBuffer &buf = Tables.AddNew();
1364
1365 {
1366 const UInt32 v = Get32((const Byte *)table + (size_t)i * 4);
1367 if (v == 0 || v == ZeroSector)
1368 continue;
1369 if (openCallback && (i - numProcessed_Prev) >= 1024)
1370 {
1371 const UInt64 comp = complexityStart + ((UInt64)i << (k_NumMidBits + 2));
1372 const UInt64 volIndex2 = volIndex;
1373 RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &comp))
1374 numProcessed_Prev = i;
1375 }
1376
1377 if (h.Is_Marker())
1378 {
1379 Byte buf2[1 << 9];
1380 if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK)
1381 return S_FALSE;
1382 {
1383 CMarker m;
1384 m.Parse(buf2);
1385 if (m.Type != k_Marker_GRAIN_TABLE
1386 || m.NumSectors != k_NumSectors
1387 || m.SpecSize != 0)
1388 return S_FALSE;
1389 }
1390 }
1391
1392 buf.Alloc(k_NumMidItems * 4);
1393 RINOK(ReadForHeader(stream, v, buf, k_NumSectors))
1394 }
1395
1396 for (size_t k = 0; k < k_NumMidItems; k++)
1397 {
1398 const UInt32 v = Get32((const Byte *)buf + (size_t)k * 4);
1399 if (v == 0 || v == ZeroSector)
1400 continue;
1401 if (v < h.overHead)
1402 return S_FALSE;
1403 if (lastSector < v)
1404 {
1405 lastSector = v;
1406 if (NeedDeflate)
1407 lastVirtCluster = ((UInt64)i << k_NumMidBits) + k;
1408 }
1409 }
1410 }
1411
1412 if (!NeedDeflate)
1413 {
1414 UInt64 end = ((UInt64)lastSector << 9) + clusterSize;
1415 if (PhySize < end)
1416 PhySize = end;
1417 }
1418 else if (lastSector != 0)
1419 {
1420 Byte buf[1 << 9];
1421 if (ReadForHeader(stream, lastSector, buf, 1) == S_OK)
1422 {
1423 UInt64 lba = Get64(buf);
1424 if (lba == (lastVirtCluster << (ClusterBits - 9)))
1425 {
1426 UInt32 dataSize = Get32(buf + 8);
1427 size_t dataSize2 = (size_t)dataSize + 12;
1428 dataSize2 = (dataSize2 + 511) & ~(size_t)511;
1429 UInt64 end = ((UInt64)lastSector << 9) + dataSize2;
1430 if (PhySize < end)
1431 PhySize = end;
1432 }
1433 }
1434 }
1435
1436 return S_OK;
1437 }
1438
1439
1440 Z7_COM7F_IMF(CHandler::Close())
1441 {
1442 _phySize = 0;
1443
1444 _cacheCluster = (UInt64)(Int64)-1;
1445 _cacheExtent = (unsigned)(int)-1;
1446
1447 _clusterBitsMax = 0;
1448
1449 _isArc = false;
1450 _unsupported = false;
1451 _unsupportedSome = false;
1452 _headerError = false;
1453 _missingVol = false;
1454 _isMultiVol = false;
1455 _needDeflate = false;
1456
1457 _missingVolName.Empty();
1458
1459 _descriptorBuf.Free();
1460 _descriptor.Clear();
1461
1462 // CHandlerImg:
1463 Clear_HandlerImg_Vars();
1464 Stream.Release();
1465
1466 _extents.Clear();
1467 return S_OK;
1468 }
1469
1470
1471 Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
1472 {
1473 COM_TRY_BEGIN
1474 *stream = NULL;
1475
1476 if (_unsupported)
1477 return S_FALSE;
1478
1479 ClearStreamVars();
1480 // _stream_UsePackSize = true;
1481
1482 if (_needDeflate)
1483 {
1484 if (!_bufInStream)
1485 {
1486 _bufInStreamSpec = new CBufInStream;
1487 _bufInStream = _bufInStreamSpec;
1488 }
1489
1490 if (!_bufOutStream)
1491 {
1492 _bufOutStreamSpec = new CBufPtrSeqOutStream();
1493 _bufOutStream = _bufOutStreamSpec;
1494 }
1495
1496 if (!_zlibDecoder)
1497 {
1498 _zlibDecoderSpec = new NCompress::NZlib::CDecoder;
1499 _zlibDecoder = _zlibDecoderSpec;
1500 }
1501
1502 const size_t clusterSize = (size_t)1 << _clusterBitsMax;
1503 _cache.AllocAtLeast(clusterSize);
1504 _cacheCompressed.AllocAtLeast(clusterSize * 2);
1505 }
1506
1507 FOR_VECTOR (i, _extents)
1508 {
1509 RINOK(_extents[i].InitAndSeek())
1510 }
1511
1512 CMyComPtr<ISequentialInStream> streamTemp = this;
1513 InitAndSeekMain();
1514 *stream = streamTemp.Detach();
1515 return S_OK;
1516 COM_TRY_END
1517 }
1518
1519
1520 REGISTER_ARC_I(
1521 "VMDK", "vmdk", NULL, 0xC8,
1522 k_Signature,
1523 0,
1524 0,
1525 NULL)
1526
1527 }}
1528