Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/VhdHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/VhdHandler.cpp517
1 files changed, 384 insertions, 133 deletions
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index 9d1c928e..5268bd0b 100755..100644
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -4,12 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
-#include "Common/IntToString.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -22,14 +22,19 @@
#define Get32(p) GetBe32(p)
#define Get64(p) GetBe64(p)
-#define G32(p, dest) dest = Get32(p);
-#define G64(p, dest) dest = Get64(p);
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+#define G64(_offs_, dest) dest = Get64(p + (_offs_));
using namespace NWindows;
namespace NArchive {
namespace NVhd {
+#define SIGNATURE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }
+
+static const unsigned kSignatureSize = 10;
+static const Byte kSignature[kSignatureSize] = SIGNATURE;
+
static const UInt32 kUnusedBlock = 0xFFFFFFFF;
static const UInt32 kDiskType_Fixed = 2;
@@ -38,11 +43,11 @@ static const UInt32 kDiskType_Diff = 4;
static const char *kDiskTypes[] =
{
- "0",
- "1",
- "Fixed",
- "Dynamic",
- "Differencing"
+ "0"
+ , "1"
+ , "Fixed"
+ , "Dynamic"
+ , "Differencing"
};
struct CFooter
@@ -73,7 +78,7 @@ struct CFooter
AString CFooter::GetTypeString() const
{
- if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0]))
+ if (Type < ARRAY_SIZE(kDiskTypes))
return kDiskTypes[Type];
char s[16];
ConvertUInt32ToString(Type, s);
@@ -96,27 +101,35 @@ static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, un
return true;
}
+static const unsigned kSectorSize_Log = 9;
+static const unsigned kSectorSize = 1 << kSectorSize_Log;
+static const unsigned kHeaderSize = 512;
+
bool CFooter::Parse(const Byte *p)
{
- if (memcmp(p, "conectix", 8) != 0)
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return false;
+ // G32(0x08, Features);
+ // G32(0x0C, FormatVersion);
+ G64(0x10, DataOffset);
+ G32(0x18, CTime);
+ G32(0x1C, CreatorApp);
+ G32(0x20, CreatorVersion);
+ G32(0x24, CreatorHostOS);
+ // G64(0x28, OriginalSize);
+ G64(0x30, CurrentSize);
+ G32(0x38, DiskGeometry);
+ G32(0x3C, Type);
+ if (Type < kDiskType_Fixed ||
+ Type > kDiskType_Diff)
return false;
- // G32(p + 0x08, Features);
- // G32(p + 0x0C, FormatVersion);
- G64(p + 0x10, DataOffset);
- G32(p + 0x18, CTime);
- G32(p + 0x1C, CreatorApp);
- G32(p + 0x20, CreatorVersion);
- G32(p + 0x24, CreatorHostOS);
- // G64(p + 0x28, OriginalSize);
- G64(p + 0x30, CurrentSize);
- G32(p + 0x38, DiskGeometry);
- G32(p + 0x3C, Type);
memcpy(Id, p + 0x44, 16);
SavedState = p[0x54];
- return CheckBlock(p, 512, 0x40, 0x55);
+ // if (DataOffset > ((UInt64)1 << 62)) return false;
+ // if (CurrentSize > ((UInt64)1 << 62)) return false;
+ return CheckBlock(p, kHeaderSize, 0x40, 0x55);
}
-/*
struct CParentLocatorEntry
{
UInt32 Code;
@@ -124,17 +137,15 @@ struct CParentLocatorEntry
UInt32 DataLen;
UInt64 DataOffset;
- bool Parse(const Byte *p);
+ bool Parse(const Byte *p)
+ {
+ G32(0x00, Code);
+ G32(0x04, DataSpace);
+ G32(0x08, DataLen);
+ G64(0x10, DataOffset);
+ return Get32(p + 0x0C) == 0; // Reserved
+ }
};
-bool CParentLocatorEntry::Parse(const Byte *p)
-{
- G32(p + 0x00, Code);
- G32(p + 0x04, DataSpace);
- G32(p + 0x08, DataLen);
- G32(p + 0x10, DataOffset);
- return (Get32(p + 0x0C) == 0); // Resrved
-}
-*/
struct CDynHeader
{
@@ -142,56 +153,63 @@ struct CDynHeader
UInt64 TableOffset;
// UInt32 HeaderVersion;
UInt32 NumBlocks;
- int BlockSizeLog;
+ unsigned BlockSizeLog;
UInt32 ParentTime;
Byte ParentId[16];
+ bool RelativeNameWasUsed;
UString ParentName;
- // CParentLocatorEntry ParentLocators[8];
+ UString RelativeParentNameFromLocator;
+ CParentLocatorEntry ParentLocators[8];
bool Parse(const Byte *p);
UInt32 NumBitMapSectors() const
{
- UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9));
- return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8);
+ UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log));
+ return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8);
+ }
+ void Clear()
+ {
+ RelativeNameWasUsed = false;
+ ParentName.Empty();
+ RelativeParentNameFromLocator.Empty();
}
};
-static int GetLog(UInt32 num)
-{
- for (int i = 0; i < 31; i++)
- if (((UInt32)1 << i) == num)
- return i;
- return -1;
-}
-
bool CDynHeader::Parse(const Byte *p)
{
if (memcmp(p, "cxsparse", 8) != 0)
return false;
- // G64(p + 0x08, DataOffset);
- G64(p + 0x10, TableOffset);
- // G32(p + 0x18, HeaderVersion);
- G32(p + 0x1C, NumBlocks);
- BlockSizeLog = GetLog(Get32(p + 0x20));
- if (BlockSizeLog < 9 || BlockSizeLog > 30)
- return false;
- G32(p + 0x38, ParentTime);
+ // G64(0x08, DataOffset);
+ G64(0x10, TableOffset);
+ // G32(0x18, HeaderVersion);
+ G32(0x1C, NumBlocks);
+ {
+ UInt32 blockSize = Get32(p + 0x20);
+ unsigned i;
+ for (i = kSectorSize_Log;; i++)
+ {
+ if (i > 31)
+ return false;
+ if (((UInt32)1 << i) == blockSize)
+ break;
+ }
+ BlockSizeLog = i;
+ }
+ G32(0x38, ParentTime);
if (Get32(p + 0x3C) != 0) // reserved
return false;
memcpy(ParentId, p + 0x28, 16);
{
- const int kNameLength = 256;
- wchar_t *s = ParentName.GetBuffer(kNameLength);
- for (unsigned i = 0; i < kNameLength; i++)
+ const unsigned kNameLen = 256;
+ wchar_t *s = ParentName.GetBuffer(kNameLen);
+ for (unsigned i = 0; i < kNameLen; i++)
s[i] = Get16(p + 0x40 + i * 2);
- s[kNameLength] = 0;
+ s[kNameLen] = 0;
ParentName.ReleaseBuffer();
}
- /*
- for (int i = 0; i < 8; i++)
+ for (unsigned i = 0; i < 8; i++)
if (!ParentLocators[i].Parse(p + 0x240 + i * 24))
return false;
- */
return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24);
}
@@ -202,8 +220,10 @@ class CHandler:
public CMyUnknownImp
{
UInt64 _virtPos;
- UInt64 _phyPos;
- UInt64 _phyLimit;
+ UInt64 _posInArc;
+ UInt64 _posInArcLimit;
+ UInt64 _startOffset;
+ UInt64 _phySize;
CFooter Footer;
CDynHeader Dyn;
@@ -214,7 +234,22 @@ class CHandler:
CMyComPtr<IInStream> Stream;
CMyComPtr<IInStream> ParentStream;
CHandler *Parent;
+ UString _errorMessage;
+ // bool _unexpectedEnd;
+ void AddErrorMessage(const wchar_t *s)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += L'\n';
+ _errorMessage += s;
+ }
+ void UpdatePhySize(UInt64 value)
+ {
+ if (_phySize < value)
+ _phySize = value;
+ }
+
+ void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; }
HRESULT Seek(UInt64 offset);
HRESULT InitAndSeek();
HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size);
@@ -223,7 +258,7 @@ class CHandler:
UInt64 GetPackSize() const
{ return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; }
- UString GetParentName() const
+ UString GetParentSequence() const
{
const CHandler *p = this;
UString res;
@@ -231,26 +266,45 @@ class CHandler:
{
if (!res.IsEmpty())
res += L" -> ";
- res += p->Dyn.ParentName;
+ UString mainName;
+ UString anotherName;
+ if (Dyn.RelativeNameWasUsed)
+ {
+ mainName = p->Dyn.RelativeParentNameFromLocator;
+ anotherName = p->Dyn.ParentName;
+ }
+ else
+ {
+ mainName = p->Dyn.ParentName;
+ anotherName = p->Dyn.RelativeParentNameFromLocator;
+ }
+ res += mainName;
+ if (mainName != anotherName && !anotherName.IsEmpty())
+ {
+ res += L' ';
+ res += L'(';
+ res += anotherName;
+ res += L')';
+ }
p = p->Parent;
}
return res;
}
- bool IsOK() const
+ bool AreParentsOK() const
{
const CHandler *p = this;
while (p->NeedParent())
{
p = p->Parent;
- if (p == 0)
+ if (!p)
return false;
}
return true;
}
HRESULT Open3();
- HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level);
+ HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level);
public:
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
@@ -261,7 +315,7 @@ public:
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
-HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); }
+HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); }
HRESULT CHandler::InitAndSeek()
{
@@ -269,50 +323,122 @@ HRESULT CHandler::InitAndSeek()
{
RINOK(Parent->InitAndSeek());
}
- _virtPos = _phyPos = 0;
+ _virtPos = _posInArc = 0;
BitMapTag = kUnusedBlock;
- BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9);
+ BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log);
return Seek(0);
}
HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size)
{
- if (offset + size > _phyLimit)
+ if (offset + size > _posInArcLimit)
return S_FALSE;
- if (offset != _phyPos)
+ if (offset != _posInArc)
{
- _phyPos = offset;
+ _posInArc = offset;
RINOK(Seek(offset));
}
HRESULT res = ReadStream_FALSE(Stream, data, size);
- _phyPos += size;
+ if (res == S_OK)
+ _posInArc += size;
+ else
+ Reset_PosInArc();
return res;
}
HRESULT CHandler::Open3()
{
- RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos));
- if (_phyPos < 512)
+ // Fixed archive uses only footer
+
+ UInt64 startPos;
+ RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &startPos));
+ _startOffset = startPos;
+ Byte header[kHeaderSize];
+ RINOK(ReadStream_FALSE(Stream, header, kHeaderSize));
+ bool headerIsOK = Footer.Parse(header);
+
+ if (headerIsOK && !Footer.ThereIsDynamic())
+ {
+ // fixed archive
+ if (startPos < Footer.CurrentSize)
+ return S_FALSE;
+ _posInArcLimit = Footer.CurrentSize;
+ _phySize = Footer.CurrentSize + kHeaderSize;
+ _startOffset = startPos - Footer.CurrentSize;
+ _posInArc = _phySize;
+ return S_OK;
+ }
+
+ UInt64 fileSize;
+ RINOK(Stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize < kHeaderSize)
return S_FALSE;
+
const UInt32 kDynSize = 1024;
Byte buf[kDynSize];
- _phyLimit = _phyPos;
- RINOK(ReadPhy(_phyLimit - 512, buf, 512));
- if (!Footer.Parse(buf))
- return S_FALSE;
- _phyLimit -= 512;
+ RINOK(Stream->Seek(fileSize - kHeaderSize, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize));
- if (!Footer.ThereIsDynamic())
+ if (!headerIsOK)
+ {
+ if (!Footer.Parse(buf))
+ return S_FALSE;
+ if (Footer.ThereIsDynamic())
+ return S_FALSE; // we can't open Dynamic Archive backward.
+ _posInArcLimit = Footer.CurrentSize;
+ _phySize = Footer.CurrentSize + kHeaderSize;
+ _startOffset = fileSize - kHeaderSize - Footer.CurrentSize;
+ _posInArc = _phySize;
return S_OK;
+ }
- RINOK(ReadPhy(0, buf + 512, 512));
- if (memcmp(buf, buf + 512, 512) != 0)
- return S_FALSE;
+ _phySize = kHeaderSize;
+ _posInArc = fileSize - startPos;
+ _posInArcLimit = _posInArc - kHeaderSize;
+
+ bool headerAndFooterAreEqual = false;
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ headerAndFooterAreEqual = true;
+ _phySize = fileSize - _startOffset;
+ }
RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize));
if (!Dyn.Parse(buf))
return S_FALSE;
+
+ UpdatePhySize(Footer.DataOffset + kDynSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ const CParentLocatorEntry &locator = Dyn.ParentLocators[i];
+ const UInt32 kNameBufSizeMax = 1024;
+ if (locator.DataLen < kNameBufSizeMax &&
+ locator.DataOffset < _posInArcLimit &&
+ locator.DataOffset + locator.DataLen <= _posInArcLimit)
+ {
+ if (locator.Code == 0x57327275 && (locator.DataLen & 1) == 0)
+ {
+ // "W2ru" locator
+ // Path is encoded as little-endian UTF-16
+ Byte nameBuf[kNameBufSizeMax];
+ UString tempString;
+ unsigned len = (locator.DataLen >> 1);
+ wchar_t *s = tempString.GetBuffer(len);
+ RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen));
+ for (unsigned j = 0; j < len; j++)
+ s[j] = GetUi16(nameBuf + j * 2);
+ s[len] = 0;
+ tempString.ReleaseBuffer();
+ if (tempString[0] == L'.' && tempString[1] == L'\\')
+ tempString.DeleteFrontal(2);
+ Dyn.RelativeParentNameFromLocator = tempString;
+ }
+ }
+ if (locator.DataLen != 0)
+ UpdatePhySize(locator.DataOffset + locator.DataLen);
+ }
if (Dyn.NumBlocks >= (UInt32)1 << 31)
return S_FALSE;
@@ -324,20 +450,69 @@ HRESULT CHandler::Open3()
else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks)
return S_FALSE;
- Bat.Reserve(Dyn.NumBlocks);
+ Bat.ClearAndReserve(Dyn.NumBlocks);
+
+ UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log;
+
while ((UInt32)Bat.Size() < Dyn.NumBlocks)
{
- RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, 512));
- for (UInt32 j = 0; j < 512; j += 4)
+ RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, kSectorSize));
+ UpdatePhySize(Dyn.TableOffset + kSectorSize);
+ for (UInt32 j = 0; j < kSectorSize; j += 4)
{
UInt32 v = Get32(buf + j);
if (v != kUnusedBlock)
+ {
+ UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog;
+ UpdatePhySize(((UInt64)v << kSectorSize_Log) + bitmapSize + blockSize);
NumUsedBlocks++;
- Bat.Add(v);
+ }
+ Bat.AddInReserved(v);
if ((UInt32)Bat.Size() >= Dyn.NumBlocks)
break;
}
}
+
+ if (headerAndFooterAreEqual)
+ return S_OK;
+
+ if (_startOffset + _phySize + kHeaderSize > fileSize)
+ {
+ // _unexpectedEnd = true;
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+
+ RINOK(ReadPhy(_phySize, buf, kHeaderSize));
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+
+ if (_phySize == 0x800)
+ {
+ /* WHY does empty archive contain additional empty sector?
+ We skip that sector and check footer again. */
+ unsigned i;
+ for (i = 0; i < kSectorSize && buf[i] == 0; i++);
+ if (i == kSectorSize)
+ {
+ RINOK(ReadPhy(_phySize + kSectorSize, buf, kHeaderSize));
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ _phySize += kSectorSize;
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+ }
+ }
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ AddErrorMessage(L"Can't find footer");
return S_OK;
}
@@ -371,17 +546,17 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
}
else
{
- UInt64 newPos = (UInt64)blockSectIndex << 9;
+ UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log;
if (BitMapTag != blockIndex)
{
- RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity()));
+ RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size()));
BitMapTag = blockIndex;
}
- RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size));
+ RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size));
for (UInt32 cur = 0; cur < size;)
{
UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur);
- UInt32 bmi = offsetInBlock >> 9;
+ UInt32 bmi = offsetInBlock >> kSectorSize_Log;
if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0)
{
if (ParentStream)
@@ -409,15 +584,18 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
- switch(seekOrigin)
+ switch (seekOrigin)
{
- case STREAM_SEEK_SET: _virtPos = offset; break;
- case STREAM_SEEK_CUR: _virtPos += offset; break;
- case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break;
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Footer.CurrentSize; break;
default: return STG_E_INVALIDFUNCTION;
}
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = offset;
if (newPosition)
- *newPosition = _virtPos;
+ *newPosition = offset;
return S_OK;
}
@@ -427,9 +605,10 @@ enum
kpidSavedState
};
-STATPROPSTG kArcProps[] =
+static const STATPROPSTG kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidClusterSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR},
@@ -440,16 +619,16 @@ STATPROPSTG kArcProps[] =
{ NULL, kpidId, VT_BSTR}
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME}
+ kpidSize,
+ kpidPackSize,
+ kpidCTime
/*
- { NULL, kpidNumCyls, VT_UI4},
- { NULL, kpidNumHeads, VT_UI4},
- { NULL, kpidSectorsPerTrack, VT_UI4}
+ { kpidNumCyls, VT_UI4},
+ { kpidNumHeads, VT_UI4},
+ { kpidSectorsPerTrack, VT_UI4}
*/
};
@@ -470,11 +649,11 @@ static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop)
prop = utc;
}
-static void StringToAString(char *dest, UInt32 s)
+static void StringToAString(char *dest, UInt32 val)
{
for (int i = 24; i >= 0; i -= 8)
{
- Byte b = (Byte)((s >> i) & 0xFF);
+ Byte b = (Byte)((val >> i) & 0xFF);
if (b < 0x20 || b > 0x7F)
break;
*dest++ = b;
@@ -496,11 +675,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMainSubfile: prop = (UInt32)0; break;
case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break;
+ case kpidShortComment:
case kpidMethod:
{
AString s = Footer.GetTypeString();
@@ -535,7 +715,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
case kpidHostOS:
{
- if (Footer.CreatorHostOS == 0x5769326b)
+ if (Footer.CreatorHostOS == 0x5769326B)
prop = "Windows";
else
{
@@ -555,18 +735,32 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
break;
}
case kpidSavedState: prop = Footer.SavedState ? true : false; break;
- case kpidParent: if (NeedParent()) prop = GetParentName(); break;
+ case kpidParent: if (NeedParent()) prop = GetParentSequence(); break;
+ case kpidOffset: prop = _startOffset; break;
+ case kpidPhySize: prop = _phySize; break;
+ /*
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (_unexpectedEnd)
+ flags |= kpv_ErrorFlags_UnexpectedEndOfArc;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ */
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
-HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level)
+HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level)
{
Close();
Stream = stream;
- if (level > 32)
+ if (level > (1 << 12)) // Maybe we need to increase that limit
return S_FALSE;
RINOK(Open3());
if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0)
@@ -575,16 +769,65 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback
return S_OK;
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK)
- return S_FALSE;
+ {
+ // return S_FALSE;
+ }
CMyComPtr<IInStream> nextStream;
- HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
- if (res == S_FALSE)
- return S_OK;
- RINOK(res);
- Parent = new CHandler;
- ParentStream = Parent;
- return Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+ bool useRelative;
+ UString name;
+ if (!Dyn.RelativeParentNameFromLocator.IsEmpty())
+ {
+ useRelative = true;
+ name = Dyn.RelativeParentNameFromLocator;
+ }
+ else
+ {
+ useRelative = false;
+ name = Dyn.ParentName;
+ }
+ Dyn.RelativeNameWasUsed = useRelative;
+
+ if (openVolumeCallback)
+ {
+ HRESULT res = openVolumeCallback->GetStream(name, &nextStream);
+ if (res == S_FALSE)
+ {
+ if (useRelative && Dyn.ParentName != Dyn.RelativeParentNameFromLocator)
+ {
+ res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
+ if (res == S_OK)
+ Dyn.RelativeNameWasUsed = false;
+ }
+ if (res == S_FALSE)
+ return S_OK;
+ }
+ RINOK(res);
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+
+ res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+ if (res == S_FALSE)
+ {
+ Parent = NULL;
+ ParentStream.Release();
+ }
+ }
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (p == 0)
+ {
+ AddErrorMessage(L"Can't open parent VHD file:");
+ AddErrorMessage(Dyn.ParentName);
+ break;
+ }
+ }
+ }
+ return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *stream,
@@ -613,11 +856,15 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
Bat.Clear();
NumUsedBlocks = 0;
Parent = 0;
Stream.Release();
ParentStream.Release();
+ Dyn.Clear();
+ _errorMessage.Empty();
+ // _unexpectedEnd = false;
return S_OK;
}
@@ -629,8 +876,8 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
+ // COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
switch(propID)
{
@@ -645,7 +892,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
}
prop.Detach(value);
return S_OK;
- COM_TRY_END
+ // COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
@@ -654,7 +901,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
RINOK(extractCallback->SetTotal(Footer.CurrentSize));
@@ -678,7 +925,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(0, &inStream);
if (hres == S_FALSE)
- res = NExtract::NOperationResult::kUnSupportedMethod;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
@@ -715,7 +962,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
*stream = streamTemp.Detach();
return S_OK;
}
- if (!Footer.ThereIsDynamic() || !IsOK())
+ if (!Footer.ThereIsDynamic() || !AreParentsOK())
return S_FALSE;
CMyComPtr<ISequentialInStream> streamTemp = this;
RINOK(InitAndSeek());
@@ -724,10 +971,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 };
+ { "VHD", "vhd", ".mbr", 0xDC,
+ kSignatureSize, SIGNATURE,
+ 0,
+ NArcInfoFlags::kUseGlobalOffset,
+ CreateArc };
REGISTER_ARC(Vhd)