diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp | 1764 |
1 files changed, 0 insertions, 1764 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp deleted file mode 100644 index 505486fc5..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp +++ /dev/null @@ -1,1764 +0,0 @@ -// NtfsHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO -// #define SHOW_DEBUG_INFO2 - -#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2) -#include <stdio.h> -#endif - -#include "../../../C/CpuArch.h" - -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyCom.h" -#include "Common/StringConvert.h" - -#include "Windows/PropVariant.h" -#include "Windows/Time.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#ifdef SHOW_DEBUG_INFO2 -#define PRF2(x) x -#else -#define PRF2(x) -#endif - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(p, dest) dest = Get16(p); -#define G32(p, dest) dest = Get32(p); -#define G64(p, dest) dest = Get64(p); - -namespace NArchive { -namespace Ntfs { - -static const UInt32 kNumSysRecs = 16; -static const UInt32 kRecIndex_Volume = 3; -static const UInt32 kRecIndex_BadClus = 8; - -struct CHeader -{ - Byte SectorSizeLog; - Byte ClusterSizeLog; - // Byte MediaType; - UInt32 NumHiddenSectors; - UInt64 NumClusters; - UInt64 MftCluster; - UInt64 SerialNumber; - UInt16 SectorsPerTrack; - UInt16 NumHeads; - - UInt64 GetPhySize() const { return NumClusters << ClusterSizeLog; } - UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } - bool Parse(const Byte *p); -}; - -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -bool CHeader::Parse(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - - int codeOffset = 0; - switch (p[0]) - { - case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break; - case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break; - default: return false; - } - Byte sectorsPerClusterLog; - - if (memcmp(p + 3, "NTFS ", 8) != 0) - return false; - { - int s = GetLog(Get16(p + 11)); - if (s < 9 || s > 12) - return false; - SectorSizeLog = (Byte)s; - s = GetLog(p[13]); - if (s < 0) - return false; - sectorsPerClusterLog = (Byte)s; - ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog; - } - - for (int i = 14; i < 21; i++) - if (p[i] != 0) - return false; - - // MediaType = p[21]; - if (Get16(p + 22) != 0) // NumFatSectors - return false; - G16(p + 24, SectorsPerTrack); - G16(p + 26, NumHeads); - G32(p + 28, NumHiddenSectors); - if (Get32(p + 32) != 0) // NumSectors32 - return false; - - // DriveNumber = p[0x24]; - if (p[0x25] != 0) // CurrentHead - return false; - /* - NTFS-HDD: p[0x26] = 0x80 - NTFS-FLASH: p[0x26] = 0 - */ - if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig - return false; - if (p[0x27] != 0) // reserved - return false; - UInt64 numSectors = Get64(p + 0x28); - NumClusters = numSectors >> sectorsPerClusterLog; - - G64(p + 0x30, MftCluster); - // G64(p + 0x38, Mft2Cluster); - G64(p + 0x48, SerialNumber); - UInt32 numClustersInMftRec; - UInt32 numClustersInIndexBlock; - G32(p + 0x40, numClustersInMftRec); - G32(p + 0x44, numClustersInIndexBlock); - return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256); -} - -struct CMftRef -{ - UInt64 Val; - UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); } - UInt16 GetNumber() const { return (UInt16)(Val >> 48); } - bool IsBaseItself() const { return Val == 0; } -}; - -#define ATNAME(n) ATTR_TYPE_ ## n -#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v - -enum -{ - DEF_ATTR_TYPE(0x00, UNUSED), - DEF_ATTR_TYPE(0x10, STANDARD_INFO), - DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST), - DEF_ATTR_TYPE(0x30, FILE_NAME), - DEF_ATTR_TYPE(0x40, OBJECT_ID), - DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR), - DEF_ATTR_TYPE(0x60, VOLUME_NAME), - DEF_ATTR_TYPE(0x70, VOLUME_INFO), - DEF_ATTR_TYPE(0x80, DATA), - DEF_ATTR_TYPE(0x90, INDEX_ROOT), - DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION), - DEF_ATTR_TYPE(0xB0, BITMAP), - DEF_ATTR_TYPE(0xC0, REPARSE_POINT), - DEF_ATTR_TYPE(0xD0, EA_INFO), - DEF_ATTR_TYPE(0xE0, EA), - DEF_ATTR_TYPE(0xF0, PROPERTY_SET), - DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM), - DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE) -}; - -static const Byte kFileNameType_Posix = 0; -static const Byte kFileNameType_Win32 = 1; -static const Byte kFileNameType_Dos = 2; -static const Byte kFileNameType_Win32Dos = 3; - -struct CFileNameAttr -{ - CMftRef ParentDirRef; - // UInt64 CTime; - // UInt64 MTime; - // UInt64 ThisRecMTime; - // UInt64 ATime; - // UInt64 AllocatedSize; - // UInt64 DataSize; - // UInt16 PackedEaSize; - UString Name; - UInt32 Attrib; - Byte NameType; - - bool IsDos() const { return NameType == kFileNameType_Dos; } - bool Parse(const Byte *p, unsigned size); -}; - -static void GetString(const Byte *p, unsigned length, UString &res) -{ - wchar_t *s = res.GetBuffer(length); - for (unsigned i = 0; i < length; i++) - s[i] = Get16(p + i * 2); - s[length] = 0; - res.ReleaseBuffer(); -} - -bool CFileNameAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 0x42) - return false; - G64(p + 0x00, ParentDirRef.Val); - // G64(p + 0x08, CTime); - // G64(p + 0x10, MTime); - // G64(p + 0x18, ThisRecMTime); - // G64(p + 0x20, ATime); - // G64(p + 0x28, AllocatedSize); - // G64(p + 0x30, DataSize); - G32(p + 0x38, Attrib); - // G16(p + 0x3C, PackedEaSize); - NameType = p[0x41]; - unsigned length = p[0x40]; - if (0x42 + length > size) - return false; - GetString(p + 0x42, length, Name); - return true; -} - -struct CSiAttr -{ - UInt64 CTime; - UInt64 MTime; - // UInt64 ThisRecMTime; - UInt64 ATime; - UInt32 Attrib; - - /* - UInt32 MaxVersions; - UInt32 Version; - UInt32 ClassId; - UInt32 OwnerId; - UInt32 SecurityId; - UInt64 QuotaCharged; - */ - - bool Parse(const Byte *p, unsigned size); -}; - -bool CSiAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 0x24) - return false; - G64(p + 0x00, CTime); - G64(p + 0x08, MTime); - // G64(p + 0x10, ThisRecMTime); - G64(p + 0x18, ATime); - G32(p + 0x20, Attrib); - return true; -} - -static const UInt64 kEmptyExtent = (UInt64)(Int64)-1; - -struct CExtent -{ - UInt64 Virt; - UInt64 Phy; - - bool IsEmpty() const { return Phy == kEmptyExtent; } -}; - -struct CVolInfo -{ - Byte MajorVer; - Byte MinorVer; - // UInt16 Flags; - - bool Parse(const Byte *p, unsigned size); -}; - -bool CVolInfo::Parse(const Byte *p, unsigned size) -{ - if (size < 12) - return false; - MajorVer = p[8]; - MinorVer = p[9]; - // Flags = Get16(p + 10); - return true; -} - -struct CAttr -{ - UInt32 Type; - // UInt32 Length; - UString Name; - // UInt16 Flags; - // UInt16 Instance; - CByteBuffer Data; - Byte NonResident; - - // Non-Resident - Byte CompressionUnit; - UInt64 LowVcn; - UInt64 HighVcn; - UInt64 AllocatedSize; - UInt64 Size; - UInt64 PackSize; - UInt64 InitializedSize; - - // Resident - // UInt16 ResidentFlags; - - bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; } - - UInt32 Parse(const Byte *p, unsigned size); - bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const; - UInt64 GetSize() const { return NonResident ? Size : Data.GetCapacity(); } - UInt64 GetPackSize() const - { - if (!NonResident) - return Data.GetCapacity(); - if (CompressionUnit != 0) - return PackSize; - return AllocatedSize; - } -}; - -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } - -static int CompareAttr(void *const *elem1, void *const *elem2, void *) -{ - const CAttr &a1 = *(*((const CAttr **)elem1)); - const CAttr &a2 = *(*((const CAttr **)elem2)); - RINOZ(MyCompare(a1.Type, a2.Type)); - RINOZ(MyCompare(a1.Name, a2.Name)); - return MyCompare(a1.LowVcn, a2.LowVcn); -} - -UInt32 CAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 4) - return 0; - G32(p, Type); - if (Type == 0xFFFFFFFF) - return 4; - if (size < 0x18) - return 0; - PRF(printf(" T=%2X", Type)); - - UInt32 length = Get32(p + 0x04); - PRF(printf(" L=%3d", length)); - if (length > size) - return 0; - NonResident = p[0x08]; - { - int nameLength = p[9]; - UInt32 nameOffset = Get16(p + 0x0A); - if (nameLength != 0) - { - if (nameOffset + nameLength * 2 > length) - return 0; - GetString(p + nameOffset, nameLength, Name); - PRF(printf(" N=%S", Name)); - } - } - - // G16(p + 0x0C, Flags); - // G16(p + 0x0E, Instance); - // PRF(printf(" F=%4X", Flags)); - // PRF(printf(" Inst=%d", Instance)); - - UInt32 dataSize; - UInt32 offs; - if (NonResident) - { - if (length < 0x40) - return 0; - PRF(printf(" NR")); - G64(p + 0x10, LowVcn); - G64(p + 0x18, HighVcn); - G64(p + 0x28, AllocatedSize); - G64(p + 0x30, Size); - G64(p + 0x38, InitializedSize); - G16(p + 0x20, offs); - CompressionUnit = p[0x22]; - - PackSize = Size; - if (CompressionUnit != 0) - { - if (length < 0x48) - return 0; - G64(p + 0x40, PackSize); - PRF(printf(" PS=%I64x", PackSize)); - } - - // PRF(printf("\n")); - PRF(printf(" ASize=%4I64d", AllocatedSize)); - PRF(printf(" Size=%I64d", Size)); - PRF(printf(" IS=%I64d", InitializedSize)); - PRF(printf(" Low=%I64d", LowVcn)); - PRF(printf(" High=%I64d", HighVcn)); - PRF(printf(" CU=%d", (int)CompressionUnit)); - dataSize = length - offs; - } - else - { - if (length < 0x18) - return 0; - PRF(printf(" RES")); - dataSize = Get32(p + 0x10); - PRF(printf(" dataSize=%3d", dataSize)); - offs = Get16(p + 0x14); - // G16(p + 0x16, ResidentFlags); - // PRF(printf(" ResFlags=%4X", ResidentFlags)); - } - if (offs > length || dataSize > length || length - dataSize < offs) - return 0; - Data.SetCapacity(dataSize); - memcpy(Data, p + offs, dataSize); - #ifdef SHOW_DEBUG_INFO - PRF(printf(" : ")); - for (unsigned i = 0; i < Data.GetCapacity(); i++) - { - PRF(printf(" %02X", (int)Data[i])); - } - #endif - return length; -} - -bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const -{ - const Byte *p = Data; - unsigned size = (unsigned)Data.GetCapacity(); - UInt64 vcn = LowVcn; - UInt64 lcn = 0; - UInt64 highVcn1 = HighVcn + 1; - if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63) - return false; - - extents.DeleteBack(); - - PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn)); - - while (size > 0) - { - Byte b = *p++; - size--; - if (b == 0) - break; - UInt32 num = b & 0xF; - if (num == 0 || num > 8 || num > size) - return false; - - int i; - UInt64 vSize = p[num - 1]; - for (i = (int)num - 2; i >= 0; i--) - vSize = (vSize << 8) | p[i]; - if (vSize == 0) - return false; - p += num; - size -= num; - if ((highVcn1 - vcn) < vSize) - return false; - - num = (b >> 4) & 0xF; - if (num > 8 || num > size) - return false; - CExtent e; - e.Virt = vcn; - if (num == 0) - { - if (compressionUnit == 0) - return false; - e.Phy = kEmptyExtent; - } - else - { - Int64 v = (signed char)p[num - 1]; - for (i = (int)num - 2; i >= 0; i--) - v = (v << 8) | p[i]; - p += num; - size -= num; - lcn += v; - if (lcn > numClustersMax) - return false; - e.Phy = lcn; - } - extents.Add(e); - vcn += vSize; - } - CExtent e; - e.Phy = kEmptyExtent; - e.Virt = vcn; - extents.Add(e); - return (highVcn1 == vcn); -} - -static const UInt64 kEmptyTag = (UInt64)(Int64)-1; - -static const int kNumCacheChunksLog = 1; -static const UInt32 kNumCacheChunks = (1 << kNumCacheChunksLog); - -class CInStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; - UInt64 _physPos; - UInt64 _curRem; - bool _sparseMode; - size_t _compressedPos; - - UInt64 _tags[kNumCacheChunks]; - int _chunkSizeLog; - CByteBuffer _inBuf; - CByteBuffer _outBuf; -public: - CMyComPtr<IInStream> Stream; - UInt64 Size; - UInt64 InitializedSize; - int BlockSizeLog; - int CompressionUnit; - bool InUse; - CRecordVector<CExtent> Extents; - - HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } - - UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } - HRESULT InitAndSeek(int compressionUnit) - { - CompressionUnit = compressionUnit; - if (compressionUnit != 0) - { - UInt32 cuSize = GetCuSize(); - _inBuf.SetCapacity(cuSize); - _chunkSizeLog = BlockSizeLog + CompressionUnit; - _outBuf.SetCapacity(kNumCacheChunks << _chunkSizeLog); - } - for (int i = 0; i < kNumCacheChunks; i++) - _tags[i] = kEmptyTag; - - _sparseMode = false; - _curRem = 0; - _virtPos = 0; - _physPos = 0; - const CExtent &e = Extents[0]; - if (!e.IsEmpty()) - _physPos = e.Phy << BlockSizeLog; - return SeekToPhys(); - } - - MY_UNKNOWN_IMP1(IInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen) -{ - size_t destSize = 0; - while (destSize < destLen) - { - if (srcLen < 2 || (destSize & 0xFFF) != 0) - break; - UInt32 v = Get16(src); - if (v == 0) - break; - src += 2; - srcLen -= 2; - UInt32 comprSize = (v & 0xFFF) + 1; - if (comprSize > srcLen) - break; - srcLen -= comprSize; - if ((v & 0x8000) == 0) - { - if (comprSize != (1 << 12)) - break; - memcpy(dest + destSize, src, comprSize); - src += comprSize; - destSize += comprSize; - } - else - { - if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0) - return 0; - int numDistBits = 4; - UInt32 sbOffset = 0; - UInt32 pos = 0; - - do - { - comprSize--; - for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1) - { - if ((mask & 1) == 0) - { - if (sbOffset >= (1 << 12)) - return 0; - dest[destSize++] = src[pos++]; - sbOffset++; - comprSize--; - } - else - { - if (comprSize < 2) - return 0; - UInt32 v = Get16(src + pos); - pos += 2; - comprSize -= 2; - - while (((sbOffset - 1) >> numDistBits) != 0) - numDistBits++; - - UInt32 len = (v & (0xFFFF >> numDistBits)) + 3; - if (sbOffset + len > (1 << 12)) - return 0; - UInt32 dist = (v >> (16 - numDistBits)); - if (dist >= sbOffset) - return 0; - Int32 offs = -1 - dist; - Byte *p = dest + destSize; - for (UInt32 t = 0; t < len; t++) - p[t] = p[t + offs]; - destSize += len; - sbOffset += len; - } - } - } - while (comprSize > 0); - src += pos; - } - } - return destSize; -} - -STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize != NULL) - *processedSize = 0; - if (_virtPos >= Size) - return (Size == _virtPos) ? S_OK: E_FAIL; - if (size == 0) - return S_OK; - UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (_virtPos >= InitializedSize) - { - memset((Byte *)data, 0, size); - _virtPos += size; - *processedSize = size; - return S_OK; - } - rem = InitializedSize - _virtPos; - if (size > rem) - size = (UInt32)rem; - - while (_curRem == 0) - { - UInt64 cacheTag = _virtPos >> _chunkSizeLog; - UInt32 cacheIndex = (UInt32)cacheTag & (kNumCacheChunks - 1); - if (_tags[cacheIndex] == cacheTag) - { - UInt32 chunkSize = (UInt32)1 << _chunkSizeLog; - UInt32 offset = (UInt32)_virtPos & (chunkSize - 1); - UInt32 cur = MyMin(chunkSize - offset, size); - memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); - *processedSize = cur; - _virtPos += cur; - return S_OK; - } - - PRF2(printf("\nVirtPos = %6d", _virtPos)); - - UInt32 comprUnitSize = (UInt32)1 << CompressionUnit; - UInt64 virtBlock = _virtPos >> BlockSizeLog; - UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); - - int left = 0, right = Extents.Size(); - for (;;) - { - int mid = (left + right) / 2; - if (mid == left) - break; - if (virtBlock2 < Extents[mid].Virt) - right = mid; - else - left = mid; - } - - bool isCompressed = false; - UInt64 virtBlock2End = virtBlock2 + comprUnitSize; - if (CompressionUnit != 0) - for (int i = left; i < Extents.Size(); i++) - { - const CExtent &e = Extents[i]; - if (e.Virt >= virtBlock2End) - break; - if (e.IsEmpty()) - { - isCompressed = true; - break; - } - } - - int i; - for (i = left; Extents[i + 1].Virt <= virtBlock; i++); - - _sparseMode = false; - if (!isCompressed) - { - const CExtent &e = Extents[i]; - UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog); - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()); - } - UInt64 next = Extents[i + 1].Virt; - if (next > virtBlock2End) - next &= ~((UInt64)comprUnitSize - 1); - next <<= BlockSizeLog; - if (next > Size) - next = Size; - _curRem = next - _virtPos; - break; - } - bool thereArePhy = false; - for (int i2 = left; i2 < Extents.Size(); i2++) - { - const CExtent &e = Extents[i2]; - if (e.Virt >= virtBlock2End) - break; - if (!e.IsEmpty()) - { - thereArePhy = true; - break; - } - } - if (!thereArePhy) - { - _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos; - _sparseMode = true; - break; - } - - size_t offs = 0; - UInt64 curVirt = virtBlock2; - for (i = left; i < Extents.Size(); i++) - { - const CExtent &e = Extents[i]; - if (e.IsEmpty()) - break; - if (e.Virt >= virtBlock2End) - return S_FALSE; - UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()); - } - UInt64 numChunks = Extents[i + 1].Virt - curVirt; - if (curVirt + numChunks > virtBlock2End) - numChunks = virtBlock2End - curVirt; - size_t compressed = (size_t)numChunks << BlockSizeLog; - RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed)); - curVirt += numChunks; - _physPos += compressed; - offs += compressed; - } - size_t destLenMax = GetCuSize(); - size_t destLen = destLenMax; - UInt64 rem = Size - (virtBlock2 << BlockSizeLog); - if (destLen > rem) - destLen = (size_t)rem; - - Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog); - size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs); - _tags[cacheIndex] = cacheTag; - - // some files in Vista have destSize > destLen - if (destSizeRes < destLen) - { - memset(dest, 0, destLenMax); - if (InUse) - return S_FALSE; - } - } - if (size > _curRem) - size = (UInt32)_curRem; - HRESULT res = S_OK; - if (_sparseMode) - memset(data, 0, size); - else - { - res = Stream->Read(data, size, &size); - _physPos += size; - } - if (processedSize != NULL) - *processedSize = size; - _virtPos += size; - _curRem -= size; - return res; -} - -STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - UInt64 newVirtPos = offset; - switch(seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: newVirtPos += _virtPos; break; - case STREAM_SEEK_END: newVirtPos += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (_virtPos != newVirtPos) - _curRem = 0; - _virtPos = newVirtPos; - if (newPosition) - *newPosition = newVirtPos; - return S_OK; -} - -class CByteBufStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; -public: - CByteBuffer Buf; - void Init() { _virtPos = 0; } - - MY_UNKNOWN_IMP1(IInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize != NULL) - *processedSize = 0; - if (_virtPos >= Buf.GetCapacity()) - return (_virtPos == Buf.GetCapacity()) ? S_OK: E_FAIL; - UInt64 rem = Buf.GetCapacity() - _virtPos; - if (rem < size) - size = (UInt32)rem; - memcpy(data, Buf + (size_t)_virtPos, size); - if (processedSize != NULL) - *processedSize = size; - _virtPos += size; - return S_OK; -} - -STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - switch(seekOrigin) - { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = Buf.GetCapacity() + offset; break; - default: return STG_E_INVALIDFUNCTION; - } - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs, - int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents) -{ - CExtent e; - e.Virt = 0; - e.Phy = kEmptyExtent; - Extents.Add(e); - const CAttr &attr0 = attrs[attrIndex]; - - if (attr0.AllocatedSize < attr0.Size || - (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) || - (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0) - return S_FALSE; - - for (int i = attrIndex; i < attrIndexLim; i++) - if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit)) - return S_FALSE; - - UInt64 packSizeCalc = 0; - for (int k = 0; k < Extents.Size(); k++) - { - CExtent &e = Extents[k]; - if (!e.IsEmpty()) - packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog; - PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt)); - PRF2(printf(" Pos = %4I64X", e.Phy)); - } - - if (attr0.CompressionUnit != 0) - { - if (packSizeCalc != attr0.PackSize) - return S_FALSE; - } - else - { - if (packSizeCalc != attr0.AllocatedSize) - return S_FALSE; - } - return S_OK; -} - -struct CDataRef -{ - int Start; - int Num; -}; - -static const UInt32 kMagic_FILE = 0x454c4946; -static const UInt32 kMagic_BAAD = 0x44414142; - -struct CMftRec -{ - UInt32 Magic; - // UInt64 Lsn; - UInt16 SeqNumber; - UInt16 Flags; - // UInt16 LinkCount; - // UInt16 NextAttrInstance; - CMftRef BaseMftRef; - // UInt32 ThisRecNumber; - UInt32 MyNumNameLinks; - - CObjectVector<CAttr> DataAttrs; - CObjectVector<CFileNameAttr> FileNames; - CRecordVector<CDataRef> DataRefs; - - CSiAttr SiAttr; - - void MoveAttrsFrom(CMftRec &src) - { - DataAttrs += src.DataAttrs; - FileNames += src.FileNames; - src.DataAttrs.ClearAndFree(); - src.FileNames.ClearAndFree(); - } - - UInt64 GetPackSize() const - { - UInt64 res = 0; - for (int i = 0; i < DataRefs.Size(); i++) - res += DataAttrs[DataRefs[i].Start].GetPackSize(); - return res; - } - - bool Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs); - - bool IsEmpty() const { return (Magic <= 2); } - bool IsFILE() const { return (Magic == kMagic_FILE); } - bool IsBAAD() const { return (Magic == kMagic_BAAD); } - - bool InUse() const { return (Flags & 1) != 0; } - bool IsDir() const { return (Flags & 2) != 0; } - - void ParseDataNames(); - HRESULT GetStream(IInStream *mainStream, int dataIndex, - int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; - int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const; - - UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } - - CMftRec(): MyNumNameLinks(0) {} -}; - -void CMftRec::ParseDataNames() -{ - DataRefs.Clear(); - DataAttrs.Sort(CompareAttr, 0); - - for (int i = 0; i < DataAttrs.Size();) - { - CDataRef ref; - ref.Start = i; - for (i++; i < DataAttrs.Size(); i++) - if (DataAttrs[ref.Start].Name != DataAttrs[i].Name) - break; - ref.Num = i - ref.Start; - DataRefs.Add(ref); - } -} - -HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, - int clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const -{ - *destStream = 0; - CByteBufStream *streamSpec = new CByteBufStream; - CMyComPtr<IInStream> streamTemp = streamSpec; - - if (dataIndex < 0) - return E_FAIL; - - if (dataIndex < DataRefs.Size()) - { - const CDataRef &ref = DataRefs[dataIndex]; - int numNonResident = 0; - int i; - for (i = ref.Start; i < ref.Start + ref.Num; i++) - if (DataAttrs[i].NonResident) - numNonResident++; - - const CAttr &attr0 = DataAttrs[ref.Start]; - - if (numNonResident != 0 || ref.Num != 1) - { - if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) - return S_FALSE; - CInStream *streamSpec = new CInStream; - CMyComPtr<IInStream> streamTemp = streamSpec; - RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, streamSpec->Extents)); - streamSpec->Size = attr0.Size; - streamSpec->InitializedSize = attr0.InitializedSize; - streamSpec->Stream = mainStream; - streamSpec->BlockSizeLog = clusterSizeLog; - streamSpec->InUse = InUse(); - RINOK(streamSpec->InitAndSeek(attr0.CompressionUnit)); - *destStream = streamTemp.Detach(); - return S_OK; - } - streamSpec->Buf = attr0.Data; - } - streamSpec->Init(); - *destStream = streamTemp.Detach(); - return S_OK; -} - -int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const -{ - if (dataIndex < 0) - return 0; - { - const CDataRef &ref = DataRefs[dataIndex]; - int numNonResident = 0; - int i; - for (i = ref.Start; i < ref.Start + ref.Num; i++) - if (DataAttrs[i].NonResident) - numNonResident++; - - const CAttr &attr0 = DataAttrs[ref.Start]; - - if (numNonResident != 0 || ref.Num != 1) - { - if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) - return 0; // error; - CRecordVector<CExtent> extents; - if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK) - return 0; // error; - return extents.Size() - 1; - } - // if (attr0.Data.GetCapacity() != 0) - // return 1; - return 0; - } -} - -bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, - CObjectVector<CAttr> *attrs) -{ - G32(p, Magic); - if (!IsFILE()) - return IsEmpty() || IsBAAD(); - - UInt32 usaOffset; - UInt32 numUsaItems; - G16(p + 0x04, usaOffset); - G16(p + 0x06, numUsaItems); - - if ((usaOffset & 1) != 0 || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 || - numUsaItems == 0 || numUsaItems - 1 != numSectors) - return false; - - UInt16 usn = Get16(p + usaOffset); - // PRF(printf("\nusn = %d", usn)); - for (UInt32 i = 1; i < numUsaItems; i++) - { - void *pp = p + (i << sectorSizeLog) - 2; - if (Get16(pp) != usn) - return false; - SetUi16(pp, Get16(p + usaOffset + i * 2)); - } - - // G64(p + 0x08, Lsn); - G16(p + 0x10, SeqNumber); - // G16(p + 0x12, LinkCount); - // PRF(printf(" L=%d", LinkCount)); - UInt32 attrOffs = Get16(p + 0x14); - G16(p + 0x16, Flags); - PRF(printf(" F=%4X", Flags)); - - UInt32 bytesInUse = Get32(p + 0x18); - UInt32 bytesAlloc = Get32(p + 0x1C); - G64(p + 0x20, BaseMftRef.Val); - if (BaseMftRef.Val != 0) - { - PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val)); - // return false; // Check it; - } - // G16(p + 0x28, NextAttrInstance); - if (usaOffset >= 0x30) - if (Get32(p + 0x2C) != recNumber) // NTFS 3.1+ - return false; - - UInt32 limit = numSectors << sectorSizeLog; - if (attrOffs >= limit || (attrOffs & 7) != 0 || bytesInUse > limit - || bytesAlloc != limit) - return false; - - - for (UInt32 t = attrOffs; t < limit;) - { - CAttr attr; - // PRF(printf("\n %2d:", Attrs.Size())); - PRF(printf("\n")); - UInt32 length = attr.Parse(p + t, limit - t); - if (length == 0 || limit - t < length) - return false; - t += length; - if (attr.Type == 0xFFFFFFFF) - break; - switch(attr.Type) - { - case ATTR_TYPE_FILE_NAME: - { - CFileNameAttr fna; - if (!attr.ParseFileName(fna)) - return false; - FileNames.Add(fna); - PRF(printf(" flags = %4x", (int)fna.NameType)); - PRF(printf("\n %S", fna.Name)); - break; - } - case ATTR_TYPE_STANDARD_INFO: - if (!attr.ParseSi(SiAttr)) - return false; - break; - case ATTR_TYPE_DATA: - DataAttrs.Add(attr); - break; - default: - if (attrs) - attrs->Add(attr); - break; - } - } - - return true; -} - -struct CItem -{ - int RecIndex; - int DataIndex; - CMftRef ParentRef; - UString Name; - UInt32 Attrib; - - bool IsDir() const { return (DataIndex < 0); } -}; - -struct CDatabase -{ - CHeader Header; - CObjectVector<CItem> Items; - CObjectVector<CMftRec> Recs; - CMyComPtr<IInStream> InStream; - IArchiveOpenCallback *OpenCallback; - - CByteBuffer ByteBuf; - - CObjectVector<CAttr> VolAttrs; - - ~CDatabase() { ClearAndClose(); } - - void Clear(); - void ClearAndClose(); - - UString GetItemPath(Int32 index) const; - HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, int level); - - HRESULT SeekToCluster(UInt64 cluster); - - int FindMtfRec(const CMftRef &ref) const - { - UInt64 val = ref.GetIndex(); - int left = 0, right = Items.Size(); - while (left != right) - { - int mid = (left + right) / 2; - UInt64 midValue = Items[mid].RecIndex; - if (val == midValue) - return mid; - if (val < midValue) - right = mid; - else - left = mid + 1; - } - return -1; - } - -}; - -HRESULT CDatabase::SeekToCluster(UInt64 cluster) -{ - return InStream->Seek(cluster << Header.ClusterSizeLog, STREAM_SEEK_SET, NULL); -} - -void CDatabase::Clear() -{ - Items.Clear(); - Recs.Clear(); -} - -void CDatabase::ClearAndClose() -{ - Clear(); - InStream.Release(); -} - -#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR - -UString CDatabase::GetItemPath(Int32 index) const -{ - const CItem *item = &Items[index]; - UString name = item->Name; - for (int j = 0; j < 256; j++) - { - CMftRef ref = item->ParentRef; - index = FindMtfRec(ref); - if (ref.GetIndex() == 5) - return name; - if (index < 0 || Recs[Items[index].RecIndex].SeqNumber != ref.GetNumber()) - return MY_DIR_PREFIX(L"UNKNOWN") + name; - item = &Items[index]; - name = item->Name + WCHAR_PATH_SEPARATOR + name; - } - return MY_DIR_PREFIX(L"BAD") + name; -} - -HRESULT CDatabase::Open() -{ - Clear(); - - static const UInt32 kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (!Header.Parse(buf)) - return S_FALSE; - UInt64 fileSize; - RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize < Header.GetPhySize()) - return S_FALSE; - - SeekToCluster(Header.MftCluster); - - CMftRec mftRec; - UInt32 numSectorsInRec; - int recSizeLog; - CMyComPtr<IInStream> mftStream; - { - UInt32 blockSize = 1 << 12; - ByteBuf.SetCapacity(blockSize); - RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); - - UInt32 allocSize = Get32(ByteBuf + 0x1C); - recSizeLog = GetLog(allocSize); - if (recSizeLog < Header.SectorSizeLog) - return false; - numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog); - if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0)) - return S_FALSE; - if (!mftRec.IsFILE()) - return S_FALSE; - mftRec.ParseDataNames(); - if (mftRec.DataRefs.IsEmpty()) - return S_FALSE; - RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream)); - if (!mftStream) - return S_FALSE; - } - - UInt64 mftSize = mftRec.DataAttrs[0].Size; - if ((mftSize >> 4) > Header.GetPhySize()) - return S_FALSE; - - UInt64 numFiles = mftSize >> recSizeLog; - if (numFiles > (1 << 30)) - return S_FALSE; - if (OpenCallback) - { - RINOK(OpenCallback->SetTotal(&numFiles, &mftSize)); - } - const UInt32 kBufSize = (1 << 15); - if (kBufSize < (1 << recSizeLog)) - return S_FALSE; - - ByteBuf.SetCapacity((size_t)kBufSize); - Recs.Reserve((int)numFiles); - for (UInt64 pos64 = 0;;) - { - if (OpenCallback) - { - UInt64 numFiles = Recs.Size(); - if ((numFiles & 0x3FF) == 0) - { - RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)); - } - } - UInt32 readSize = kBufSize; - UInt64 rem = mftSize - pos64; - if (readSize > rem) - readSize = (UInt32)rem; - if (readSize < ((UInt32)1 << recSizeLog)) - break; - RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize)); - pos64 += readSize; - for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++) - { - PRF(printf("\n---------------------")); - PRF(printf("\n%5d:", Recs.Size())); - Byte *p = ByteBuf + ((UInt32)i << recSizeLog); - CMftRec rec; - if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), - (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL)) - return S_FALSE; - Recs.Add(rec); - } - } - - int i; - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.BaseMftRef.IsBaseItself()) - { - UInt64 refIndex = rec.BaseMftRef.GetIndex(); - if (refIndex > (UInt32)Recs.Size()) - return S_FALSE; - CMftRec &refRec = Recs[(int)refIndex]; - bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); - if (rec.InUse() && refRec.InUse()) - { - if (!moveAttrs) - return S_FALSE; - } - else if (rec.InUse() || refRec.InUse()) - moveAttrs = false; - if (moveAttrs) - refRec.MoveAttrsFrom(rec); - } - } - - for (i = 0; i < Recs.Size(); i++) - Recs[i].ParseDataNames(); - - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself()) - continue; - int numNames = 0; - // printf("\n%4d: ", i); - for (int t = 0; t < rec.FileNames.Size(); t++) - { - const CFileNameAttr &fna = rec.FileNames[t]; - // printf("%4d %S | ", (int)fna.NameType, fna.Name); - if (fna.IsDos()) - continue; - int numDatas = rec.DataRefs.Size(); - - // For hard linked files we show substreams only for first Name. - if (numDatas > 1 && numNames > 0) - numDatas = 1; - numNames++; - - if (rec.IsDir()) - { - CItem item; - item.Name = fna.Name; - item.RecIndex = i; - item.DataIndex = -1; - item.ParentRef = fna.ParentDirRef; - item.Attrib = rec.SiAttr.Attrib | 0x10; - // item.Attrib = fna.Attrib; - Items.Add(item); - } - for (int di = 0; di < numDatas; di++) - { - CItem item; - item.Name = fna.Name; - item.Attrib = rec.SiAttr.Attrib; - const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; - if (!subName.IsEmpty()) - { - // $BadClus:$Bad is sparse file for all clusters. So we skip it. - if (i == kRecIndex_BadClus && subName == L"$Bad") - continue; - item.Name += L":"; - item.Name += subName; - item.Attrib = fna.Attrib; - } - - PRF(printf("\n%3d", i)); - PRF(printf(" attrib=%2x", rec.SiAttr.Attrib)); - PRF(printf(" %S", item.Name)); - - item.RecIndex = i; - item.DataIndex = di; - item.ParentRef = fna.ParentDirRef; - - Items.Add(item); - rec.MyNumNameLinks++; - } - } - rec.FileNames.ClearAndFree(); - } - - return S_OK; -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp, - CDatabase -{ -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - IInStream *stream2; - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2); - *stream = (ISequentialInStream *)stream2; - return res; - COM_TRY_END -} - -static const STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidLinks, VT_UI4}, - { NULL, kpidNumBlocks, VT_UI4} -}; - -static const STATPROPSTG kArcProps[] = -{ - { NULL, kpidVolumeName, VT_BSTR}, - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - - { NULL, kpidSectorSize, VT_UI4}, - { NULL, kpidId, VT_UI8} - // { NULL, kpidSectorsPerTrack, VT_UI4}, - // { NULL, kpidNumHeads, VT_UI4}, - // { NULL, kpidHiddenSectors, VT_UI4} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop) -{ - FILETIME ft; - ft.dwLowDateTime = (DWORD)t; - ft.dwHighDateTime = (DWORD)(t >> 32); - prop = ft; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - - const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL); - - switch(propID) - { - case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = Header.GetPhySize(); break; - /* - case kpidHeadersSize: - { - UInt64 val = 0; - for (int i = 0; i < kNumSysRecs; i++) - { - printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize()); - if (i == 8) - i = i - val += Recs[i].GetPackSize(); - } - prop = val; - break; - } - */ - case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;break; - case kpidVolumeName: - { - for (int i = 0; i < VolAttrs.Size(); i++) - { - const CAttr &attr = VolAttrs[i]; - if (attr.Type == ATTR_TYPE_VOLUME_NAME) - { - UString name; - GetString(attr.Data, (int)attr.Data.GetCapacity() / 2, name); - prop = name; - break; - } - } - break; - } - case kpidFileSystem: - { - AString s = "NTFS"; - for (int i = 0; i < VolAttrs.Size(); i++) - { - const CAttr &attr = VolAttrs[i]; - if (attr.Type == ATTR_TYPE_VOLUME_INFO) - { - CVolInfo vi; - if (attr.ParseVolInfo(vi)) - { - s += ' '; - char temp[16]; - ConvertUInt32ToString(vi.MajorVer, temp); - s += temp; - s += '.'; - ConvertUInt32ToString(vi.MinorVer, temp); - s += temp; - } - break; - } - } - prop = s; - break; - } - case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; - case kpidId: prop = Header.SerialNumber; break; - // case kpidMediaType: prop = Header.MediaType; break; - // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; - // case kpidNumHeads: prop = Header.NumHeads; break; - // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - - const CAttr *data= NULL; - if (item.DataIndex >= 0) - data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - - switch(propID) - { - case kpidPath: - { - UString name = GetItemPath(index); - const wchar_t *prefix = NULL; - if (!rec.InUse()) - prefix = MY_DIR_PREFIX(L"DELETED"); - else if (item.RecIndex < kNumSysRecs) - prefix = MY_DIR_PREFIX(L"SYSTEM"); - if (prefix) - name = prefix + name; - prop = name; - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; - - case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; - case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; - case kpidAttrib: - prop = item.Attrib; - break; - case kpidLinks: prop = rec.MyNumNameLinks; break; - case kpidSize: if (data) prop = data->GetSize(); break; - case kpidPackSize: if (data) prop = data->GetPackSize(); break; - case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - ClearAndClose(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CItem &item = Items[allFilesMode ? i : indices[i]]; - const CMftRec &rec = Recs[item.RecIndex]; - if (!rec.IsDir()) - totalSize += rec.GetSize(item.DataIndex); - } - RINOK(extractCallback->SetTotal(totalSize)); - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - CByteBuffer buf; - UInt32 clusterSize = Header.ClusterSize(); - buf.SetCapacity(clusterSize); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - const CItem &item = Items[index]; - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - const CMftRec &rec = Recs[item.RecIndex]; - const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr<IInStream> inStream; - HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnSupportedMethod; - else - { - RINOK(hres); - if (inStream) - { - HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres != S_OK && hres != S_FALSE) - { - RINOK(hres); - } - if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK) - res = NExtract::NOperationResult::kOK; - } - } - } - totalPackSize += data.GetPackSize(); - totalSize += data.GetSize(); - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = Items.Size(); - return S_OK; -} - -static IInArchive *CreateArc() { return new CHandler; } - -static CArcInfo g_ArcInfo = - { L"NTFS", L"ntfs img", 0, 0xD9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, 9, false, CreateArc, 0 }; - -REGISTER_ARC(Fat) - -}} |