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:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2015-10-05 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:56 +0300
commit6543c280208393fa32cb0094f770d14c1cfb13b2 (patch)
treebeb90f5e81e85e7957463ee5ad89cab0b3566560 /CPP/7zip/Archive
parentf6444c32568553e0261ca0105083658f12be6284 (diff)
15.0815.08
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r--CPP/7zip/Archive/7z/7zIn.cpp4
-rw-r--r--CPP/7zip/Archive/7z/7zProperties.cpp18
-rw-r--r--CPP/7zip/Archive/Chm/ChmHandler.cpp4
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp6
-rw-r--r--CPP/7zip/Archive/Common/MultiStream.cpp6
-rw-r--r--CPP/7zip/Archive/CpioHandler.cpp3
-rw-r--r--CPP/7zip/Archive/CramfsHandler.cpp22
-rw-r--r--CPP/7zip/Archive/ElfHandler.cpp6
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp2610
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp14
-rw-r--r--CPP/7zip/Archive/FlvHandler.cpp6
-rw-r--r--CPP/7zip/Archive/HandlerCont.cpp26
-rw-r--r--CPP/7zip/Archive/HandlerCont.h3
-rw-r--r--CPP/7zip/Archive/IArchive.h24
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.cpp22
-rw-r--r--CPP/7zip/Archive/MbrHandler.cpp8
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp28
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp50
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp11
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp31
-rw-r--r--CPP/7zip/Archive/SquashfsHandler.cpp39
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.cpp1
-rw-r--r--CPP/7zip/Archive/Tar/TarHandlerOut.cpp7
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.cpp2
-rw-r--r--CPP/7zip/Archive/UefiHandler.cpp6
-rw-r--r--CPP/7zip/Archive/VhdHandler.cpp6
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.cpp6
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.cpp2
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.h5
-rw-r--r--CPP/7zip/Archive/XarHandler.cpp9
-rw-r--r--CPP/7zip/Archive/Zip/ZipAddCommon.cpp2
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Zip/ZipHeader.h31
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp2
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.cpp13
35 files changed, 2824 insertions, 211 deletions
diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp
index bd6c4d95..fc527be6 100644
--- a/CPP/7zip/Archive/7z/7zIn.cpp
+++ b/CPP/7zip/Archive/7z/7zIn.cpp
@@ -1180,7 +1180,7 @@ HRESULT CInArchive::ReadHeader(
bool isKnownType = true;
if (type > ((UInt32)1 << 30))
isKnownType = false;
- else switch((UInt32)type)
+ else switch ((UInt32)type)
{
case NID::kName:
{
@@ -1338,7 +1338,7 @@ HRESULT CInArchive::ReadHeader(
db.UnsupportedFeatureWarning = true;
_inByteBack->SkipRem();
}
- // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02)
+ // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02)
if (_inByteBack->GetRem() != 0)
ThrowIncorrect();
}
diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp
index a2c9bf31..4cb5a5e6 100644
--- a/CPP/7zip/Archive/7z/7zProperties.cpp
+++ b/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -14,7 +14,7 @@ namespace N7z {
struct CPropMap
{
UInt32 FilePropID;
- STATPROPSTG StatPROPSTG;
+ CStatProp StatProp;
};
static const CPropMap kPropMap[] =
@@ -24,11 +24,11 @@ static const CPropMap kPropMap[] =
{ NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
#ifdef _MULTI_PACK
- { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } },
- { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
- { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
- { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
- { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } },
+ { 100, { "Pack0", kpidPackedSize0, VT_UI8 } },
+ { 101, { "Pack1", kpidPackedSize1, VT_UI8 } },
+ { 102, { "Pack2", kpidPackedSize2, VT_UI8 } },
+ { 103, { "Pack3", kpidPackedSize3, VT_UI8 } },
+ { 104, { "Pack4", kpidPackedSize4, VT_UI8 } },
#endif
{ NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
@@ -90,7 +90,7 @@ void CHandler::FillPopIDs()
_fileInfoPopIDs.Clear();
#ifdef _7Z_VOL
- if(_volumes.Size() < 1)
+ if (_volumes.Size() < 1)
return;
const CVolume &volume = _volumes.Front();
const CArchiveDatabaseEx &_db = volume.Database;
@@ -156,8 +156,8 @@ STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID,
const CPropMap &pr = kPropMap[i];
if (pr.FilePropID == id)
{
- const STATPROPSTG &st = pr.StatPROPSTG;
- *propID = st.propid;
+ const CStatProp &st = pr.StatProp;
+ *propID = st.PropID;
*varType = st.vt;
/*
if (st.lpwstrName)
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
index b1ab2996..3e29fd00 100644
--- a/CPP/7zip/Archive/Chm/ChmHandler.cpp
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -103,7 +103,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NCOM::CPropVariant prop;
if (m_Database.NewFormat)
{
- switch(propID)
+ switch (propID)
{
case kpidSize:
prop = (UInt64)m_Database.NewFormatString.Len();
@@ -318,7 +318,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce
if (processedSize)
*processedSize = 0;
- while(size != 0)
+ while (size != 0)
{
if (m_FileIsOpen)
{
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index 9cfd40cc..e24074a5 100644
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -592,13 +592,13 @@ HRESULT CDatabase::Open(IInStream *inStream)
MainSubfile = -1;
{
- FOR_VECTOR(t, Items)
+ FOR_VECTOR (t, Items)
{
Update_PhySize_WithItem(t);
}
}
{
- FOR_VECTOR(t, Items)
+ FOR_VECTOR (t, Items)
{
const CItem &item = Items[t];
@@ -739,7 +739,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
return S_OK;
UInt32 i;
UInt64 totalSize = 0;
- for(i = 0; i < numItems; i++)
+ for (i = 0; i < numItems; i++)
{
const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
if (!item.IsDir())
diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp
index 5bf0bef9..1de74afe 100644
--- a/CPP/7zip/Archive/Common/MultiStream.cpp
+++ b/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -119,9 +119,9 @@ HRESULT COutVolumeStream::Flush()
/*
STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
- if(processedSize != NULL)
+ if (processedSize)
*processedSize = 0;
- while(size > 0)
+ while (size > 0)
{
if (_streamIndex >= Streams.Size())
{
@@ -157,7 +157,7 @@ STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *proce
_absPos += realProcessed;
if (_absPos > _length)
_length = _absPos;
- if(processedSize != NULL)
+ if (processedSize)
*processedSize += realProcessed;
if (subStream.Pos == subStream.Size)
{
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index 2436fb5e..e8898cac 100644
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -5,6 +5,7 @@
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
#include "../../Common/StringConvert.h"
#include "../../Common/StringToInt.h"
#include "../../Common/UTFConvert.h"
@@ -121,7 +122,7 @@ struct CItem
bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; }
bool IsCrcFormat() const { return Type == k_Type_HexCrc; }
- bool IsDir() const { return (Mode & 0170000) == 0040000; }
+ bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
};
diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp
index e776b3c7..020f84b7 100644
--- a/CPP/7zip/Archive/CramfsHandler.cpp
+++ b/CPP/7zip/Archive/CramfsHandler.cpp
@@ -8,6 +8,7 @@
#include "../../../C/LzmaDec.h"
#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
#include "../../Common/StringConvert.h"
#include "../../Windows/PropVariantUtils.h"
@@ -98,7 +99,7 @@ struct CNode
#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
-static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; }
+static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); }
static UInt32 GetSize(const Byte *p, bool be)
{
@@ -146,7 +147,7 @@ struct CHeader
{
if (memcmp(p + 16, kSignature, ARRAY_SIZE(kSignature)) != 0)
return false;
- switch(GetUi32(p))
+ switch (GetUi32(p))
{
case 0x28CD3D45: be = false; break;
case 0x453DCD28: be = true; break;
@@ -354,7 +355,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (!_h.IsVer2())
{
- FOR_VECTOR(i, _items)
+ FOR_VECTOR (i, _items)
{
const CItem &item = _items[i];
const Byte *p = _data + item.Offset;
@@ -530,7 +531,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
const Byte *p = _data + item.Offset;
bool be = _h.be;
bool isDir = IsDir(p, be);
- switch(propID)
+ switch (propID)
{
case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
case kpidIsDir: prop = isDir; break;
@@ -660,10 +661,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- CMyComPtr<ISequentialInStream> inStream(streamSpec);
- streamSpec->SetStream(_stream);
-
for (i = 0; i < numItems; i++)
{
lps->InSize = totalPackSize;
@@ -701,20 +698,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
int res = NExtract::NOperationResult::kDataError;
{
CMyComPtr<ISequentialInStream> inSeqStream;
- CMyComPtr<IInStream> inStream;
HRESULT hres = GetStream(index, &inSeqStream);
- if (inSeqStream)
- inSeqStream.QueryInterface(IID_IInStream, &inStream);
if (hres == E_OUTOFMEMORY)
return E_OUTOFMEMORY;
- if (hres == S_FALSE || !inStream)
+ if (hres == S_FALSE || !inSeqStream)
res = NExtract::NOperationResult::kUnsupportedMethod;
else
{
RINOK(hres);
- if (inStream)
{
- HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ HRESULT hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
if (hres == S_OK)
{
if (copyCoderSpec->TotalSize == curSize)
@@ -729,6 +722,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
RINOK(extractCallback->SetOperationResult(res));
}
+
return S_OK;
COM_TRY_END
}
diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp
index beca8036..1c3c7c45 100644
--- a/CPP/7zip/Archive/ElfHandler.cpp
+++ b/CPP/7zip/Archive/ElfHandler.cpp
@@ -632,7 +632,7 @@ enum
kpidInfoSection
};
-static const STATPROPSTG kProps[] =
+static const CStatProp kProps[] =
{
{ NULL, kpidPath, VT_BSTR },
{ NULL, kpidSize, VT_UI8 },
@@ -641,8 +641,8 @@ static const STATPROPSTG kProps[] =
{ NULL, kpidVa, VT_UI8 },
{ NULL, kpidType, VT_BSTR },
{ NULL, kpidCharacts, VT_BSTR }
- , { (LPOLESTR)L"Link Section", kpidLinkSection, VT_BSTR}
- , { (LPOLESTR)L"Info Section", kpidInfoSection, VT_BSTR}
+ , { "Link Section", kpidLinkSection, VT_BSTR}
+ , { "Info Section", kpidInfoSection, VT_BSTR}
};
IMP_IInArchive_Props_WITH_NAME
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
new file mode 100644
index 00000000..6d8101f5
--- /dev/null
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -0,0 +1,2610 @@
+// ExtHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NExt {
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define LE_16(offs, dest) dest = Get16(p + (offs));
+#define LE_32(offs, dest) dest = Get32(p + (offs));
+#define LE_64(offs, dest) dest = Get64(p + (offs));
+
+#define HI_16(offs, dest) dest |= (((UInt32)Get16(p + (offs))) << 16);
+#define HI_32(offs, dest) dest |= (((UInt64)Get32(p + (offs))) << 32);
+
+/*
+static UInt32 g_Crc32CTable[256];
+
+static struct CInitCrc32C
+{
+ CInitCrc32C()
+ {
+ for (unsigned i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (0x82F63B78 & ~((r & 1) - 1));
+ g_Crc32CTable[i] = r;
+ }
+ }
+} g_InitCrc32C;
+
+#define CRC32C_INIT_VAL 0xFFFFFFFF
+#define CRC32C_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC32C_UPDATE_BYTE(crc, b) (g_Crc32CTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+static UInt32 Crc32C_Update(UInt32 crc, Byte const *data, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ crc = CRC32C_UPDATE_BYTE(crc, data[i]);
+ return crc;
+}
+
+static UInt32 Crc32C_Calc(Byte const *data, size_t size)
+{
+ return Crc32C_Update(CRC32C_INIT_VAL, data, size);
+}
+*/
+
+
+// CRC-16-ANSI. The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
+static UInt16 g_Crc16Table[256];
+
+static struct CInitCrc16
+{
+ CInitCrc16()
+ {
+ for (unsigned i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (0xA001 & ~((r & 1) - 1));
+ g_Crc16Table[i] = (UInt16)r;
+ }
+ }
+} g_InitCrc16;
+
+#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+#define CRC16_INIT_VAL 0xFFFF
+
+static UInt32 Crc16Update(UInt32 crc, Byte const *data, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ crc = CRC16_UPDATE_BYTE(crc, data[i]);
+ return crc;
+}
+
+static UInt32 Crc16Calc(Byte const *data, size_t size)
+{
+ return Crc16Update(CRC16_INIT_VAL, data, size);
+}
+
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+// inodes numbers
+
+// #define k_INODE_BAD 1 // Bad blocks
+#define k_INODE_ROOT 2 // Root dir
+// #define k_INODE_USR_QUOTA 3 // User quota
+// #define k_INODE_GRP_QUOTA 4 // Group quota
+// #define k_INODE_BOOT_LOADER 5 // Boot loader
+// #define k_INODE_UNDEL_DIR 6 // Undelete dir
+#define k_INODE_RESIZE 7 // Reserved group descriptors
+// #define k_INODE_JOURNAL 8 // Journal
+
+// First non-reserved inode for old ext4 filesystems
+#define k_INODE_GOOD_OLD_FIRST 11
+
+static const char * const k_SysInode_Names[] =
+{
+ "0"
+ , "Bad"
+ , "Root"
+ , "UserQuota"
+ , "GroupQuota"
+ , "BootLoader"
+ , "Undelete"
+ , "Resize"
+ , "Journal"
+ , "Exclude"
+ , "Replica"
+};
+
+static const char * const kHostOS[] =
+{
+ "Linux"
+ , "Hurd"
+ , "Masix"
+ , "FreeBSD"
+ , "Lites"
+};
+
+static const CUInt32PCharPair g_FeatureCompat_Flags[] =
+{
+ { 0, "DIR_PREALLOC" },
+ { 1, "IMAGIC_INODES" },
+ { 2, "HAS_JOURNAL" },
+ { 3, "EXT_ATTR" },
+ { 4, "RESIZE_INODE" },
+ { 5, "DIR_INDEX" },
+ { 6, "LAZY_BG" }, // not in Linux
+ // { 7, "EXCLUDE_INODE" }, // not used
+ // { 8, "EXCLUDE_BITMAP" }, // not in kernel
+ { 9, "SPARSE_SUPER2" }
+};
+
+
+#define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1)
+#define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7)
+
+static const CUInt32PCharPair g_FeatureIncompat_Flags[] =
+{
+ { 0, "COMPRESSION" },
+ { 1, "FILETYPE" },
+ { 2, "RECOVER" }, /* Needs recovery */
+ { 3, "JOURNAL_DEV" }, /* Journal device */
+ { 4, "META_BG" },
+
+ { 6, "EXTENTS" }, /* extents support */
+ { 7, "64BIT" },
+ { 8, "MMP" },
+ { 9, "FLEX_BG" },
+ { 10, "EA_INODE" }, /* EA in inode */
+
+ { 12, "DIRDATA" }, /* data in dirent */
+ { 13, "BG_USE_META_CSUM" }, /* use crc32c for bg */
+ { 14, "LARGEDIR" }, /* >2GB or 3-lvl htree */
+ { 15, "INLINE_DATA" }, /* data in inode */
+ { 16, "ENCRYPT" }
+};
+
+
+static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4;
+static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10;
+
+static const CUInt32PCharPair g_FeatureRoCompat_Flags[] =
+{
+ { 0, "SPARSE_SUPER" },
+ { 1, "LARGE_FILE" },
+ { 2, "BTREE_DIR" },
+ { 3, "HUGE_FILE" },
+ { 4, "GDT_CSUM" },
+ { 5, "DIR_NLINK" },
+ { 6, "EXTRA_ISIZE" },
+ { 7, "HAS_SNAPSHOT" },
+ { 8, "QUOTA" },
+ { 9, "BIGALLOC" },
+ { 10, "METADATA_CSUM" },
+ { 11, "REPLICA" },
+ { 12, "READONLY" }
+};
+
+
+
+static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18;
+static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19;
+
+
+static const CUInt32PCharPair g_NodeFlags[] =
+{
+ { 0, "SECRM" },
+ { 1, "UNRM" },
+ { 2, "COMPR" },
+ { 3, "SYNC" },
+ { 4, "IMMUTABLE" },
+ { 5, "APPEND" },
+ { 6, "NODUMP" },
+ { 7, "NOATIME" },
+ { 8, "DIRTY" },
+ { 9, "COMPRBLK" },
+ { 10, "NOCOMPR" },
+ { 11, "ENCRYPT" },
+ { 12, "INDEX" },
+ { 13, "IMAGIC" },
+ { 14, "JOURNAL_DATA" },
+ { 15, "NOTAIL" },
+ { 16, "DIRSYNC" },
+ { 17, "TOPDIR" },
+ { 18, "HUGE_FILE" },
+ { 19, "EXTENTS" },
+
+ { 21, "EA_INODE" },
+ { 22, "EOFBLOCKS" },
+
+ { 28, "INLINE_DATA" }
+};
+
+
+static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
+
+static inline void PrintHex(unsigned v, char *s)
+{
+ s[0] = GetHex((v >> 4) & 0xF);
+ s[1] = GetHex(v & 0xF);
+}
+
+
+enum
+{
+ k_Type_UNKNOWN,
+ k_Type_REG_FILE,
+ k_Type_DIR,
+ k_Type_CHRDEV,
+ k_Type_BLKDEV,
+ k_Type_FIFO,
+ k_Type_SOCK,
+ k_Type_SYMLINK
+};
+
+static const UInt16 k_TypeToMode[] =
+{
+ 0,
+ MY_LIN_S_IFREG,
+ MY_LIN_S_IFDIR,
+ MY_LIN_S_IFCHR,
+ MY_LIN_S_IFBLK,
+ MY_LIN_S_IFIFO,
+ MY_LIN_S_IFSOCK,
+ MY_LIN_S_IFLNK
+};
+
+
+#define EXT4_GOOD_OLD_REV 0 // old (original) format
+// #define EXT4_DYNAMIC_REV 1 // V2 format with dynamic inode sizes
+
+struct CHeader
+{
+ unsigned BlockBits;
+ unsigned ClusterBits;
+
+ UInt32 NumInodes;
+ UInt64 NumBlocks;
+ // UInt64 NumBlocksSuper;
+ UInt64 NumFreeBlocks;
+ UInt32 NumFreeInodes;
+ UInt32 FirstDataBlock;
+
+ UInt32 BlocksPerGroup;
+ UInt32 ClustersPerGroup;
+ UInt32 InodesPerGroup;
+
+ UInt32 MountTime;
+ UInt32 WriteTime;
+
+ // UInt16 NumMounts;
+ // UInt16 NumMountsMax;
+
+ // UInt16 State;
+ // UInt16 Errors;
+ // UInt16 MinorRevLevel;
+
+ UInt32 LastCheckTime;
+ // UInt32 CheckInterval;
+ UInt32 CreatorOs;
+ UInt32 RevLevel;
+
+ // UInt16 DefResUid;
+ // UInt16 DefResGid;
+
+ UInt32 FirstInode;
+ UInt16 InodeSize;
+ UInt16 BlockGroupNr;
+ UInt32 FeatureCompat;
+ UInt32 FeatureIncompat;
+ UInt32 FeatureRoCompat;
+ Byte Uuid[16];
+ char VolName[16];
+ char LastMount[64];
+ // UInt32 BitmapAlgo;
+
+ UInt32 JournalInode;
+ UInt16 GdSize; // = 64 if 64-bit();
+ UInt32 CTime;
+ UInt16 MinExtraISize;
+ // UInt16 WantExtraISize;
+ // UInt32 Flags;
+ // Byte LogGroupsPerFlex;
+ // Byte ChecksumType;
+
+ UInt64 WrittenKB;
+
+ bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; }
+
+ UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; }
+
+ bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; }
+ bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; }
+ bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
+ bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
+
+ bool Parse(const Byte *p);
+};
+
+
+static int inline GetLog(UInt32 num)
+{
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (GetUi16(p + 0x38) != 0xEF53)
+ return false;
+
+ LE_32 (0x18, BlockBits);
+ LE_32 (0x1C, ClusterBits);
+
+ if (ClusterBits != 0 && BlockBits != ClusterBits)
+ return false;
+
+ if (BlockBits > 16 - 10) return false;
+ BlockBits += 10;
+ if (ClusterBits > 16) return false;
+
+ LE_32 (0x00, NumInodes);
+ LE_32 (0x04, NumBlocks);
+ // LE_32 (0x08, NumBlocksSuper);
+ LE_32 (0x0C, NumFreeBlocks);
+ LE_32 (0x10, NumFreeInodes);
+ LE_32 (0x14, FirstDataBlock);
+
+ if (FirstDataBlock != 0)
+ return false;
+
+ LE_32 (0x20, BlocksPerGroup);
+ LE_32 (0x24, ClustersPerGroup);
+
+ if (BlocksPerGroup != ClustersPerGroup)
+ return false;
+ if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3)))
+ return false;
+
+ LE_32 (0x28, InodesPerGroup);
+
+ LE_32 (0x2C, MountTime);
+ LE_32 (0x30, WriteTime);
+
+ // LE_16 (0x34, NumMounts);
+ // LE_16 (0x36, NumMountsMax);
+
+ // LE_16 (0x3A, State);
+ // LE_16 (0x3C, Errors);
+ // LE_16 (0x3E, MinorRevLevel);
+
+ LE_32 (0x40, LastCheckTime);
+ // LE_32 (0x44, CheckInterval);
+ LE_32 (0x48, CreatorOs);
+ LE_32 (0x4C, RevLevel);
+
+ // LE_16 (0x50, DefResUid);
+ // LE_16 (0x52, DefResGid);
+
+ FirstInode = k_INODE_GOOD_OLD_FIRST;
+ InodeSize = EXT4_GOOD_OLD_INODE_SIZE;
+
+ if (!IsOldRev())
+ {
+ LE_32 (0x54, FirstInode);
+ LE_16 (0x58, InodeSize);
+ if (FirstInode < k_INODE_GOOD_OLD_FIRST)
+ return false;
+ if (InodeSize > (UInt32)1 << BlockBits)
+ return false;
+ if (GetLog(InodeSize) < 0)
+ return false;
+ }
+
+ LE_16 (0x5A, BlockGroupNr);
+ LE_32 (0x5C, FeatureCompat);
+ LE_32 (0x60, FeatureIncompat);
+ LE_32 (0x64, FeatureRoCompat);
+
+ memcpy(Uuid, p + 0x68, sizeof(Uuid));
+ memcpy(VolName, p + 0x78, sizeof(VolName));
+ memcpy(LastMount, p + 0x88, sizeof(LastMount));
+
+ // LE_32 (0xC8, BitmapAlgo);
+
+ LE_32 (0xE0, JournalInode);
+
+ LE_16 (0xFE, GdSize);
+
+ LE_32 (0x108, CTime);
+
+ if (Is64Bit())
+ {
+ HI_32(150, NumBlocks);
+ // HI_32(154, NumBlocksSuper);
+ HI_32(0x158, NumFreeBlocks);
+ }
+
+ if (NumBlocks >= (UInt64)1 << (63 - BlockBits))
+ return false;
+
+
+ LE_16(0x15C, MinExtraISize);
+ // LE_16(0x15E, WantExtraISize);
+ // LE_32(0x160, Flags);
+ // LE_16(0x164, RaidStride);
+ // LE_16(0x166, MmpInterval);
+ // LE_64(0x168, MmpBlock);
+
+ // LogGroupsPerFlex = p[0x174];
+ // ChecksumType = p[0x175];
+
+ LE_64 (0x178, WrittenKB);
+
+ // LE_32(0x194, ErrorCount);
+ // LE_32(0x198, ErrorTime);
+ // LE_32(0x19C, ErrorINode);
+ // LE_32(0x1A0, ErrorBlock);
+
+ if (NumBlocks < 1)
+ return false;
+ if (NumFreeBlocks > NumBlocks)
+ return false;
+
+ return true;
+}
+
+
+struct CGroupDescriptor
+{
+ UInt64 BlockBitmap;
+ UInt64 InodeBitmap;
+ UInt64 InodeTable;
+ UInt32 NumFreeBlocks;
+ UInt32 NumFreeInodes;
+ UInt32 DirCount;
+
+ UInt16 Flags;
+
+ UInt64 ExcludeBitmap;
+ UInt32 BlockBitmap_Checksum;
+ UInt32 InodeBitmap_Checksum;
+ UInt32 UnusedCount;
+ UInt16 Checksum;
+
+ void Parse(const Byte *p, unsigned size);
+};
+
+void CGroupDescriptor::Parse(const Byte *p, unsigned size)
+{
+ LE_32 (0x00, BlockBitmap);
+ LE_32 (0x04, InodeBitmap);
+ LE_32 (0x08, InodeTable);
+ LE_16 (0x0C, NumFreeBlocks);
+ LE_16 (0x0E, NumFreeInodes);
+ LE_16 (0x10, DirCount);
+ LE_16 (0x12, Flags);
+ LE_32 (0x14, ExcludeBitmap);
+ LE_16 (0x18, BlockBitmap_Checksum);
+ LE_16 (0x1A, InodeBitmap_Checksum);
+ LE_16 (0x1C, UnusedCount);
+ LE_16 (0x1E, Checksum);
+
+ if (size >= 64)
+ {
+ p += 0x20;
+ HI_32 (0x00, BlockBitmap);
+ HI_32 (0x04, InodeBitmap);
+ HI_32 (0x08, InodeTable);
+ HI_16 (0x0C, NumFreeBlocks);
+ HI_16 (0x0E, NumFreeInodes);
+ HI_16 (0x10, DirCount);
+ HI_16 (0x12, UnusedCount); // instead of Flags
+ HI_32 (0x14, ExcludeBitmap);
+ HI_16 (0x18, BlockBitmap_Checksum);
+ HI_16 (0x1A, InodeBitmap_Checksum);
+ // HI_16 (0x1C, Reserved);
+ }
+}
+
+
+static const unsigned kNodeBlockFieldSize = 60;
+
+struct CExtentTreeHeader
+{
+ UInt16 NumEntries;
+ UInt16 MaxEntries;
+ UInt16 Depth;
+ // UInt32 Generation;
+
+ bool Parse(const Byte *p)
+ {
+ LE_16 (0x02, NumEntries);
+ LE_16 (0x04, MaxEntries);
+ LE_16 (0x06, Depth);
+ // LE_32 (0x08, Generation);
+ return Get16(p) == 0xF30A; // magic
+ }
+};
+
+struct CExtentIndexNode
+{
+ UInt32 VirtBlock;
+ UInt64 PhyLeaf;
+
+ void Parse(const Byte *p)
+ {
+ LE_32 (0x00, VirtBlock);
+ LE_32 (0x04, PhyLeaf);
+ PhyLeaf |= (((UInt64)Get16(p + 8)) << 32);
+ // unused 16-bit field (at offset 0x0A) can be not zero in some cases. Why?
+ }
+};
+
+struct CExtent
+{
+ UInt32 VirtBlock;
+ UInt16 Len;
+ bool IsInited;
+ UInt64 PhyStart;
+
+ UInt32 GetVirtEnd() const { return VirtBlock + Len; }
+ bool IsLenOK() const { return VirtBlock + Len >= VirtBlock; }
+
+ void Parse(const Byte *p)
+ {
+ LE_32 (0x00, VirtBlock);
+ LE_16 (0x04, Len);
+ IsInited = true;
+ if (Len > (UInt32)0x8000)
+ {
+ IsInited = false;
+ Len -= (UInt32)0x8000;
+ }
+ LE_32 (0x08, PhyStart);
+ UInt16 hi;
+ LE_16 (0x06, hi);
+ PhyStart |= ((UInt64)hi << 32);
+ }
+};
+
+
+
+struct CExtTime
+{
+ UInt32 Val;
+ UInt32 Extra;
+};
+
+struct CNode
+{
+ Int32 ParentNode; // in _nodes[], -1 if not dir
+ int ItemIndex; // in _items[]
+ int SymLinkIndex; // in _symLinks[]
+ int DirIndex; // in _dirs[]
+
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt16 Gid;
+ // UInt16 Checksum;
+ bool IsEmpty;
+
+ UInt64 FileSize;
+ CExtTime MTime;
+ CExtTime ATime;
+ CExtTime CTime;
+ // CExtTime InodeChangeTime;
+ // CExtTime DTime;
+
+ UInt64 NumBlocks;
+ UInt32 NumLinks;
+ UInt32 Flags;
+
+ UInt32 NumLinksCalced;
+
+ Byte Block[kNodeBlockFieldSize];
+
+ CNode():
+ ParentNode(-1),
+ ItemIndex(-1),
+ SymLinkIndex(-1),
+ DirIndex(0),
+ NumLinksCalced(0)
+ {}
+
+ bool IsFlags_HUGE() const { return (Flags & k_NodeFlags_HUGE) != 0; }
+ bool IsFlags_EXTENTS() const { return (Flags & k_NodeFlags_EXTENTS) != 0; }
+
+ bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
+ bool IsRegular() const { return MY_LIN_S_ISREG(Mode); }
+ bool IsLink() const { return MY_LIN_S_ISLNK(Mode); }
+
+ bool Parse(const Byte *p, const CHeader &_h);
+};
+
+
+bool CNode::Parse(const Byte *p, const CHeader &_h)
+{
+ MTime.Extra = 0;
+ ATime.Extra = 0;
+ CTime.Extra = 0;
+ // InodeChangeTime.Extra = 0;
+ // DTime.Extra = 0;
+
+ LE_16 (0x00, Mode);
+ LE_16 (0x02, Uid);
+ LE_32 (0x04, FileSize);
+ LE_32 (0x08, ATime.Val);
+ // LE_32 (0x0C, InodeChangeTime.Val);
+ LE_32 (0x10, MTime.Val);
+ // LE_32 (0x14, DTime.Val);
+ LE_16 (0x18, Gid);
+ LE_16 (0x1A, NumLinks);
+
+ LE_32 (0x1C, NumBlocks);
+ LE_32 (0x20, Flags);
+ // LE_32 (0x24, Union osd1);
+
+ memcpy(Block, p + 0x28, kNodeBlockFieldSize);
+
+ // LE_32 (0x64, Generation); // File version (for NFS)
+ // LE_32 (0x68, ACL);
+
+ {
+ UInt32 highSize;
+ LE_32 (0x6C, highSize); // In ext2/3 this field was named i_dir_acl
+
+ if (IsRegular()) // do we need that check ?
+ FileSize |= ((UInt64)highSize << 32);
+ }
+
+ // LE_32 (0x70, fragmentAddress);
+
+ // osd2
+ {
+ // Linux;
+ UInt32 numBlocksHigh;
+ LE_16 (0x74, numBlocksHigh);
+ NumBlocks |= (UInt64)numBlocksHigh << 32;
+ HI_16 (0x74 + 4, Uid);
+ HI_16 (0x74 + 6, Gid);
+ /*
+ UInt32 checksum;
+ LE_16 (0x74 + 8, checksum);
+ checksum = checksum;
+ */
+ }
+
+ // 0x74: Byte Union osd2[12];
+
+ if (_h.InodeSize > 128)
+ {
+ UInt16 extra_isize;
+ LE_16 (0x80, extra_isize);
+ if (128 + extra_isize > _h.InodeSize)
+ return false;
+ if (extra_isize >= 0x1C)
+ {
+ // UInt16 checksumUpper;
+ // LE_16 (0x82, checksumUpper);
+ // LE_32 (0x84, InodeChangeTime.Extra);
+ LE_32 (0x88, MTime.Extra);
+ LE_32 (0x8C, ATime.Extra);
+ LE_32 (0x90, CTime.Val);
+ LE_32 (0x94, CTime.Extra);
+ // LE_32 (0x98, VersionHi);
+ }
+ }
+
+ PRF(printf("size = %5d", (unsigned)FileSize));
+
+ return true;
+}
+
+
+struct CItem
+{
+ unsigned Node; // in _nodes[]
+ int ParentNode; // in _nodes[]
+ int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir
+ Byte Type;
+
+ AString Name;
+
+ CItem():
+ Node(0),
+ ParentNode(-1),
+ SymLinkItemIndex(-1),
+ Type(k_Type_UNKNOWN)
+ {}
+
+ void Clear()
+ {
+ Node = 0;
+ ParentNode = -1;
+ SymLinkItemIndex = -1;
+ Type = k_Type_UNKNOWN;
+ Name.Empty();
+ }
+
+ bool IsDir() const { return Type == k_Type_DIR; }
+ // bool IsNotDir() const { return Type != k_Type_DIR && Type != k_Type_UNKNOWN; }
+
+};
+
+
+
+static const unsigned kNumTreeLevelsMax = 6; // must be >= 3
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CObjectVector<CItem> _items;
+ CRecordVector<CNode> _nodes;
+ CObjectVector<CUIntVector> _dirs; // each CUIntVector contains indexes in _items[] only for dir items;
+ AStringVector _symLinks;
+ AStringVector _auxItems;
+ int _auxSysIndex;
+ int _auxUnknownIndex;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ bool _isArc;
+ bool _headersError;
+ bool _linksError;
+
+ bool _isUTF;
+
+ CHeader _h;
+
+ IArchiveOpenCallback *_openCallback;
+ UInt64 _totalRead;
+ UInt64 _totalReadPrev;
+
+ CByteBuffer _tempBufs[kNumTreeLevelsMax];
+
+
+ HRESULT CheckProgress2()
+ {
+ const UInt64 numFiles = _items.Size();
+ return _openCallback->SetCompleted(&numFiles, &_totalRead);
+ }
+
+ HRESULT CheckProgress()
+ {
+ HRESULT res = S_OK;
+ if (_openCallback)
+ {
+ if (_totalRead - _totalReadPrev >= ((UInt32)1 << 20))
+ {
+ _totalReadPrev = _totalRead;
+ res = CheckProgress2();
+ }
+ }
+ return res;
+ }
+
+
+ const int GetParentAux(const CItem &item) const
+ {
+ if (item.Node < _h.FirstInode && _auxSysIndex >= 0)
+ return _auxSysIndex;
+ return _auxUnknownIndex;
+ }
+
+ HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size);
+ HRESULT ParseDir(const Byte *data, size_t size, unsigned nodeIndex);
+ int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const;
+
+ HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks);
+ HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks);
+ HRESULT FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth);
+
+ HRESULT GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream);
+ HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data);
+
+ void ClearRefs();
+ HRESULT Open2(IInStream *inStream);
+
+ void GetPath(unsigned index, AString &s) const;
+ bool GetPackSize(unsigned index, UInt64 &res) const;
+
+public:
+ CHandler() {}
+ ~CHandler() {}
+
+ MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IArchiveGetRawProps(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+
+
+HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
+{
+ bool isThereSelfLink = false;
+
+ PRF(printf("\n\n========= node = %5d size = %5d", nodeIndex, size));
+
+ CNode &nodeDir = _nodes[nodeIndex];
+ nodeDir.DirIndex = _dirs.Size();
+ CUIntVector &dir = _dirs.AddNew();
+ int parentNode = -1;
+
+ CItem item;
+
+ for (;;)
+ {
+ if (size == 0)
+ break;
+ if (size < 8)
+ return S_FALSE;
+ UInt32 iNode;
+ LE_32 (0x00, iNode);
+ unsigned recLen;
+ LE_16 (0x04, recLen);
+ unsigned nameLen = p[6];
+ Byte type = p[7];
+
+ if (recLen > size)
+ return S_FALSE;
+ if (nameLen + 8 > recLen)
+ return S_FALSE;
+
+ if (iNode >= _nodes.Size())
+ return S_FALSE;
+
+ item.Clear();
+
+ if (_h.IsThereFileType())
+ item.Type = type;
+ else if (type != 0)
+ return S_FALSE;
+
+ item.ParentNode = nodeIndex;
+ item.Node = iNode;
+ item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen);
+
+ p += recLen;
+ size -= recLen;
+
+ if (item.Name.Len() != nameLen)
+ return S_FALSE;
+
+ if (_isUTF)
+ _isUTF = CheckUTF8(item.Name);
+
+ if (iNode == 0)
+ {
+ /*
+ ext3 deleted??
+ if (item.Name.Len() != 0)
+ return S_FALSE;
+ */
+
+ PRF(printf("\n EMPTY %6d %d %s", recLen, type, (const char *)item.Name));
+ if (type == 0xDE)
+ {
+ // checksum
+ }
+ continue;
+ }
+
+ CNode &node = _nodes[iNode];
+ if (node.IsEmpty)
+ return S_FALSE;
+
+ if (_h.IsThereFileType() && type != 0)
+ {
+ if (type >= ARRAY_SIZE(k_TypeToMode))
+ return S_FALSE;
+ if (k_TypeToMode[type] != (node.Mode & MY_LIN_S_IFMT))
+ return S_FALSE;
+ }
+
+ node.NumLinksCalced++;
+
+ PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", item.Node, (const char *)item.Name));
+
+ if (item.Name[0] == '.')
+ {
+ if (item.Name[1] == 0)
+ {
+ if (isThereSelfLink)
+ return S_FALSE;
+ isThereSelfLink = true;
+ if (nodeIndex != nodeIndex)
+ return S_FALSE;
+ continue;
+ }
+
+ if (item.Name[1] == '.' && item.Name[2] == 0)
+ {
+ if (parentNode >= 0)
+ return S_FALSE;
+ if (!node.IsDir())
+ return S_FALSE;
+ if (iNode == nodeIndex && iNode != k_INODE_ROOT)
+ return S_FALSE;
+
+ parentNode = iNode;
+
+ if (nodeDir.ParentNode < 0)
+ nodeDir.ParentNode = iNode;
+ else if ((unsigned)nodeDir.ParentNode != iNode)
+ return S_FALSE;
+
+ continue;
+ }
+ }
+
+ if (iNode == nodeIndex)
+ return S_FALSE;
+
+ if (parentNode < 0)
+ return S_FALSE;
+
+ if (node.IsDir())
+ {
+ if (node.ParentNode < 0)
+ node.ParentNode = nodeIndex;
+ else if ((unsigned)node.ParentNode != nodeIndex)
+ return S_FALSE;
+ const unsigned itemIndex = _items.Size();
+ dir.Add(itemIndex);
+ node.ItemIndex = itemIndex;
+ }
+
+ _items.Add(item);
+ }
+
+ if (parentNode < 0 || !isThereSelfLink)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path) const
+{
+ unsigned pos = 0;
+
+ if (path.IsEmpty())
+ return -1;
+
+ if (path[0] == '/')
+ {
+ nodeIndex = k_INODE_ROOT;
+ if (nodeIndex >= _nodes.Size())
+ return -1;
+ pos = 1;
+ }
+
+ AString s;
+
+ while (pos != path.Len())
+ {
+ const CNode &node = _nodes[nodeIndex];
+ int slash = path.Find('/', pos);
+
+ if (slash < 0)
+ {
+ s = path.Ptr(pos);
+ pos = path.Len();
+ }
+ else
+ {
+ s.SetFrom(path.Ptr(pos), slash - pos);
+ pos = slash + 1;
+ }
+
+ if (s[0] == '.')
+ {
+ if (s[1] == 0)
+ continue;
+ else if (s[1] == '.' && s[2] == 0)
+ {
+ if (node.ParentNode < 0)
+ return -1;
+ if (nodeIndex == k_INODE_ROOT)
+ return -1;
+ nodeIndex = node.ParentNode;
+ continue;
+ }
+ }
+
+ if (node.DirIndex < 0)
+ return -1;
+
+ const CUIntVector &dir = _dirs[node.DirIndex];
+
+ for (unsigned i = 0;; i++)
+ {
+ if (i >= dir.Size())
+ return -1;
+ const CItem &item = _items[dir[i]];
+ if (item.Name == s)
+ {
+ nodeIndex = item.Node;
+ break;
+ }
+ }
+ }
+
+ return _nodes[nodeIndex].ItemIndex;
+}
+
+
+HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size)
+{
+ if (block == 0 || block >= _h.NumBlocks)
+ return S_FALSE;
+ if (((size + (1 << _h.BlockBits) + 1) >> _h.BlockBits) > _h.NumBlocks - block)
+ return S_FALSE;
+ RINOK(inStream->Seek((UInt64)block << _h.BlockBits, STREAM_SEEK_SET, NULL));
+ _totalRead += size;
+ return ReadStream_FALSE(inStream, data, size);
+}
+
+
+static const unsigned kHeaderSize = 2 * 1024;
+static const unsigned kHeaderDataOffset = 1024;
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ {
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ if (!_h.Parse(buf + kHeaderDataOffset))
+ return S_FALSE;
+ if (_h.BlockGroupNr != 0)
+ return S_FALSE; // it's just copy of super block
+ }
+
+ {
+ // ---------- Read groups and nodes ----------
+
+ unsigned numGroups;
+ {
+ UInt64 numGroups64 = _h.GetNumGroups();
+ if (numGroups64 > (UInt32)1 << 31)
+ return S_FALSE;
+ numGroups = (unsigned)numGroups64;
+ }
+
+ unsigned gdBits = 5;
+ if (_h.Is64Bit())
+ {
+ if (_h.GdSize != 64)
+ return S_FALSE;
+ gdBits = 6;
+ }
+
+ _isArc = true;
+ _phySize = _h.NumBlocks << _h.BlockBits;
+
+ if (_openCallback)
+ {
+ RINOK(_openCallback->SetTotal(NULL, &_phySize));
+ }
+
+ CRecordVector<CGroupDescriptor> groups;
+
+ {
+ // ---------- Read groups ----------
+
+ CByteBuffer gdBuf;
+ size_t gdBufSize = (size_t)numGroups << gdBits;
+ if ((gdBufSize >> gdBits) != numGroups)
+ return S_FALSE;
+ gdBuf.Alloc(gdBufSize);
+ RINOK(SeekAndRead(inStream, (_h.BlockBits <= 10 ? 2 : 1), gdBuf, gdBufSize));
+
+ for (unsigned i = 0; i < numGroups; i++)
+ {
+ CGroupDescriptor gd;
+
+ const Byte *p = gdBuf + ((size_t)i << gdBits);
+ unsigned gd_Size = (unsigned)1 << gdBits;
+ gd.Parse(p, gd_Size);
+
+ if (_h.UseMetadataChecksum())
+ {
+ // use CRC32c
+ }
+ else if (_h.UseGdtChecksum())
+ {
+ UInt32 crc = Crc16Calc(_h.Uuid, sizeof(_h.Uuid));
+ Byte i_le[4];
+ SetUi32(i_le, i);
+ crc = Crc16Update(crc, i_le, 4);
+ crc = Crc16Update(crc, p, 32 - 2);
+ if (gd_Size != 32)
+ crc = Crc16Update(crc, p + 32, gd_Size - 32);
+ if (crc != gd.Checksum)
+ return S_FALSE;
+ }
+
+ groups.Add(gd);
+ }
+ }
+
+ {
+ // ---------- Read nodes ----------
+
+ if (_h.NumInodes < _h.NumFreeInodes)
+ return S_FALSE;
+
+ UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1;
+ // numReserveInodes = _h.NumInodes + 1;
+ if (numReserveInodes != 0)
+ _nodes.Reserve(numReserveInodes);
+
+ UInt32 numNodes = _h.InodesPerGroup;
+ if (numNodes > _h.NumInodes)
+ numNodes = _h.NumInodes;
+ size_t nodesDataSize = numNodes * _h.InodeSize;
+ if (nodesDataSize / _h.InodeSize != numNodes)
+ return S_FALSE;
+
+ CByteBuffer nodesData;
+ nodesData.Alloc(nodesDataSize);
+
+ CByteBuffer nodesMap;
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ nodesMap.Alloc(blockSize);
+
+ unsigned globalNodeIndex = 0;
+
+ FOR_VECTOR (gi, groups)
+ {
+ if (globalNodeIndex >= _h.NumInodes)
+ break;
+
+ const CGroupDescriptor &gd = groups[gi];
+
+ PRF(printf("\n\ng%6d block = %6x\n", gi, gd.InodeTable));
+
+ RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize));
+ RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize));
+
+ for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++)
+ {
+ if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0)
+ continue;
+
+ const Byte *p = nodesData + (size_t)n * _h.InodeSize;
+ unsigned j = 0;
+ for (j = 0; j < _h.InodeSize; j++)
+ if (p[j] != 0)
+ break;
+
+ if (j == _h.InodeSize)
+ {
+ if (_nodes.Size() >= _h.FirstInode)
+ {
+ // return S_FALSE;
+ }
+ continue;
+ }
+
+ CNode node;
+ node.IsEmpty = false;
+
+ PRF(printf("\nnode = %5d ", (unsigned)n));
+
+ if (!node.Parse(p, _h))
+ return S_FALSE;
+
+ // PRF(printf("\n %6d", n));
+ /*
+ SetUi32(p + 0x7C, 0)
+ SetUi32(p + 0x82, 0)
+
+ UInt32 crc = Crc32C_Calc(_h.Uuid, sizeof(_h.Uuid));
+ Byte i_le[4];
+ SetUi32(i_le, n);
+ crc = Crc32C_Update(crc, i_le, 4);
+ crc = Crc32C_Update(crc, p, _h.InodeSize);
+ if (crc != node.Checksum) return S_FALSE;
+ */
+
+ while (_nodes.Size() < globalNodeIndex + 1)
+ {
+ CNode node2;
+ node2.IsEmpty = true;
+ _nodes.Add(node2);
+ }
+
+ _nodes.Add(node);
+ }
+ }
+
+ if (_nodes.Size() <= k_INODE_ROOT)
+ return S_FALSE;
+ }
+ }
+
+ _stream = inStream; // we need stream for dir nodes
+
+ {
+ // ---------- Read Dirs ----------
+
+ CByteBuffer dataBuf;
+
+ FOR_VECTOR (i, _nodes)
+ {
+ {
+ const CNode &node = _nodes[i];
+ if (node.IsEmpty || !node.IsDir())
+ continue;
+ }
+ RINOK(ExtractNode(i, dataBuf));
+ if (dataBuf.Size() == 0)
+ {
+ // _headersError = true;
+ return S_FALSE;
+ }
+ else
+ {
+ RINOK(ParseDir(dataBuf, dataBuf.Size(), i));
+ }
+ RINOK(CheckProgress());
+ }
+
+ if (_nodes[k_INODE_ROOT].ParentNode != k_INODE_ROOT)
+ return S_FALSE;
+ }
+
+ {
+ // ---------- Check NumLinks and unreferenced dir nodes ----------
+
+ FOR_VECTOR (i, _nodes)
+ {
+ const CNode &node = _nodes[i];
+ if (node.IsEmpty)
+ continue;
+
+ if (node.NumLinks != node.NumLinksCalced)
+ {
+ if (node.NumLinks != 1 || node.NumLinksCalced != 0
+ // ) && i >= _h.FirstInode
+ )
+ {
+ _linksError = true;
+ // return S_FALSE;
+ }
+ }
+
+ if (!node.IsDir())
+ continue;
+
+ if (node.ParentNode < 0)
+ {
+ if (i >= _h.FirstInode)
+ return S_FALSE;
+ continue;
+ }
+ }
+ }
+
+ {
+ // ---------- Check that there is no loops in parents list ----------
+
+ unsigned numNodes = _nodes.Size();
+ CIntArr UsedByNode(numNodes);
+ {
+ for (unsigned i = 0; i < numNodes; i++)
+ UsedByNode[i] = -1;
+ }
+
+ FOR_VECTOR (i, _nodes)
+ {
+ {
+ CNode &node = _nodes[i];
+ if (node.IsEmpty
+ || node.ParentNode < 0 // not dir
+ || i == k_INODE_ROOT)
+ continue;
+ }
+
+ unsigned c = i;
+
+ for (;;)
+ {
+ CNode &node = _nodes[c];
+ if (node.IsEmpty)
+ return S_FALSE;
+
+ if (UsedByNode[c] != -1)
+ {
+ if ((unsigned)UsedByNode[c] == i)
+ return S_FALSE;
+ break;
+ }
+
+ UsedByNode[c] = i;
+ if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT)
+ break;
+ if ((unsigned)node.ParentNode == i)
+ return S_FALSE;
+ c = node.ParentNode;
+ }
+ }
+ }
+
+ {
+ // ---------- Fill SymLinks data ----------
+
+ AString s;
+ CByteBuffer data;
+
+ unsigned i;
+ for (i = 0; i < _nodes.Size(); i++)
+ {
+ CNode &node = _nodes[i];
+ if (node.IsEmpty || !node.IsLink())
+ continue;
+ if (node.FileSize > ((UInt32)1 << 14))
+ continue;
+ if (ExtractNode(i, data) == S_OK && data.Size() != 0)
+ {
+ s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size());
+ if (s.Len() == data.Size())
+ node.SymLinkIndex = _symLinks.Add(s);
+ RINOK(CheckProgress());
+ }
+ }
+
+ unsigned prev = 0;
+ unsigned complex = 0;
+
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CItem &item = _items[i];
+ int sym = _nodes[item.Node].SymLinkIndex;
+ if (sym >= 0 && item.ParentNode >= 0)
+ {
+ item.SymLinkItemIndex = FindTargetItem_for_SymLink(item.ParentNode, _symLinks[sym]);
+ if (_openCallback)
+ {
+ complex++;
+ if (complex - prev >= (1 << 10))
+ {
+ RINOK(CheckProgress2());
+ prev = complex;
+ }
+ }
+ }
+ }
+ }
+
+ {
+ // ---------- Add items and aux folders for unreferenced files ----------
+
+ bool useSys = false;
+ bool useUnknown = false;
+
+ for (unsigned i = 0; i < _nodes.Size(); i++)
+ {
+ const CNode &node = _nodes[i];
+ if (node.IsEmpty)
+ continue;
+
+ if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug
+ {
+ CItem item;
+ item.Node = i;
+
+ // we don't know how to work with k_INODE_RESIZE node (strange FileSize and Block values).
+ // so we ignore it;
+
+ if (i == k_INODE_RESIZE)
+ continue;
+
+ if (node.FileSize == 0)
+ continue;
+
+ if (i < _h.FirstInode)
+ {
+ if (item.Node < ARRAY_SIZE(k_SysInode_Names))
+ item.Name = k_SysInode_Names[item.Node];
+ useSys = true;
+ }
+ else
+ useUnknown = true;
+
+ if (item.Name.IsEmpty())
+ {
+ char temp[16];
+ ConvertUInt32ToString(item.Node, temp);
+ item.Name = temp;
+ }
+
+ _items.Add(item);
+ }
+ }
+
+ if (useSys)
+ _auxSysIndex = _auxItems.Add("[SYS]");
+ if (useUnknown)
+ _auxUnknownIndex = _auxItems.Add("[UNKNOWN]");
+ }
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ HRESULT res;
+ try
+ {
+ _openCallback = callback;
+ res = Open2(stream);
+ }
+ catch(...)
+ {
+ ClearRefs();
+ throw;
+ }
+
+ if (res != S_OK)
+ {
+ ClearRefs();
+ return res;
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+void CHandler::ClearRefs()
+{
+ _stream.Release();
+ _items.Clear();
+ _nodes.Clear();
+ _auxItems.Clear();
+ _symLinks.Clear();
+ _dirs.Clear();
+ _auxSysIndex = -1;
+ _auxUnknownIndex = -1;
+}
+
+
+STDMETHODIMP CHandler::Close()
+{
+ _totalRead = 0;
+ _totalReadPrev = 0;
+ _phySize = 0;
+ _isArc = false;
+ _headersError = false;
+ _linksError = false;
+ _isUTF = true;
+
+ ClearRefs();
+ return S_OK;
+}
+
+
+void CHandler::GetPath(unsigned index, AString &s) const
+{
+ s.Empty();
+
+ if (index >= _items.Size())
+ {
+ s = _auxItems[index - _items.Size()];
+ return;
+ }
+
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ if (!s.IsEmpty())
+ s.InsertAtFront(CHAR_PATH_SEPARATOR);
+ s.Insert(0, item.Name);
+
+ if (item.ParentNode == k_INODE_ROOT)
+ return;
+
+ if (item.ParentNode < 0)
+ {
+ int aux = GetParentAux(item);
+ if (aux < 0)
+ break;
+ s.InsertAtFront(CHAR_PATH_SEPARATOR);
+ s.Insert(0, _auxItems[aux]);
+ return;
+ }
+
+ const CNode &node = _nodes[item.ParentNode];
+ if (node.ItemIndex < 0)
+ return;
+ index = node.ItemIndex;
+
+ if (s.Len() > ((UInt32)1 << 16))
+ {
+ s.Insert(0, "[LONG]" STRING_PATH_SEPARATOR);
+ return;
+ }
+ }
+}
+
+
+bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const
+{
+ if (index >= _items.Size())
+ {
+ totalPack = 0;
+ return false;
+ }
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+
+ // if (!node.IsFlags_EXTENTS())
+ {
+ totalPack = (UInt64)node.NumBlocks << (node.IsFlags_HUGE() ? _h.BlockBits : 9);
+ return true;
+ }
+
+ /*
+ CExtentTreeHeader eth;
+ if (!eth.Parse(node.Block))
+ return false;
+ if (eth.NumEntries > 3)
+ return false;
+ if (!eth.Depth == 0)
+ return false;
+
+ UInt64 numBlocks = 0;
+ {
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtent e;
+ e.Parse(node.Block + 12 + i * 12);
+ // const CExtent &e = node.leafs[i];
+ if (e.IsInited)
+ numBlocks += e.Len;
+ }
+ }
+
+ totalPack = numBlocks << _h.BlockBits;
+ return true;
+ */
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size() + _auxItems.Size();
+ return S_OK;
+}
+
+enum
+{
+ kpidMountTime = kpidUserDefined,
+ kpidLastCheckTime,
+ kpidRevision,
+ kpidINodeSize,
+ kpidLastMount,
+ kpidFeatureIncompat,
+ kpidFeatureRoCompat,
+ kpidWrittenKB
+
+ // kpidGroupSize,
+
+ // kpidChangeTime = kpidUserDefined + 256,
+ // kpidDTime
+};
+
+static const UInt32 kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidPosixAttrib,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ // kpidChangeTime,
+ // kpidDTime,
+ kpidINode,
+ kpidLinks,
+ kpidSymLink,
+ kpidCharacts,
+ kpidUser,
+ kpidGroup
+};
+
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidHeadersSize, VT_BSTR },
+ // { NULL, kpidFileSystem, VT_BSTR },
+ // kpidMethod,
+ { NULL, kpidClusterSize, VT_UI4 },
+ // { "Group Size", kpidGroupSize, VT_UI8 },
+ { NULL, kpidFreeSpace, VT_UI8 },
+
+ { NULL, kpidMTime, VT_FILETIME },
+ { NULL, kpidCTime, VT_FILETIME },
+ { "Mount Time", kpidMountTime, VT_FILETIME },
+ { "Last Check Time", kpidLastCheckTime, VT_FILETIME },
+
+ { NULL, kpidHostOS, VT_BSTR},
+ { "Revision", kpidRevision, VT_UI4},
+ { "inode Size", kpidINodeSize, VT_UI4},
+ { NULL, kpidCodePage, VT_BSTR},
+ { NULL, kpidVolumeName, VT_BSTR},
+ { "Last Mounted", kpidLastMount, VT_BSTR},
+ { NULL, kpidId, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR },
+ { "Incompatible Features", kpidFeatureIncompat, VT_BSTR },
+ { "Readonly-compatible Features", kpidFeatureRoCompat, VT_BSTR },
+ { "Written KiB", kpidWrittenKB, VT_UI8 }
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVariant &prop)
+{
+ UString u;
+ AString a;
+ a.SetFrom_CalcLen(s, size);
+ if (!isUTF || !ConvertUTF8ToUnicode(a, u))
+ MultiByteToUnicodeString2(u, a);
+ prop = u;
+}
+
+static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
+{
+ if (val != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(val, ft);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ /*
+ case kpidFileSystem:
+ {
+ AString res = "Ext4";
+ prop = res;
+ break;
+ }
+ */
+
+ case kpidIsTree: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ case kpidINode: prop = true; break;
+
+ case kpidClusterSize: prop = (UInt32)1 << _h.BlockBits; break;
+ // case kpidGroupSize: prop = (UInt64)_h.BlocksPerGroup << _h.BlockBits; break;
+
+ case kpidFreeSpace: prop = (UInt64)_h.NumFreeBlocks << _h.BlockBits; break;
+
+ case kpidCTime: UnixTimeToProp(_h.CTime, prop); break;
+ case kpidMTime: UnixTimeToProp(_h.WriteTime, prop); break;
+ case kpidMountTime: UnixTimeToProp(_h.MountTime, prop); break;
+ case kpidLastCheckTime: UnixTimeToProp(_h.LastCheckTime, prop); break;
+
+ case kpidHostOS:
+ {
+ char temp[16];
+ const char *s = NULL;
+ if (_h.CreatorOs < ARRAY_SIZE(kHostOS))
+ s = kHostOS[_h.CreatorOs];
+ else
+ {
+ ConvertUInt32ToString(_h.CreatorOs, temp);
+ s = temp;
+ }
+ prop = s;
+ break;
+ }
+
+ case kpidRevision: prop = _h.RevLevel; break;
+
+ case kpidINodeSize: prop = _h.InodeSize; break;
+
+ case kpidId:
+ {
+ char s[16 * 2 + 2];
+ for (unsigned i = 0; i < 16; i++)
+ PrintHex(_h.Uuid[i], s + i * 2);
+ s[16 * 2] = 0;
+ prop = s;
+ break;
+ }
+
+ case kpidCodePage: if (_isUTF) prop = "UTF-8"; break;
+ case kpidVolumeName: StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break;
+ case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break;
+
+ case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break;
+ case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break;
+ case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break;
+ case kpidWrittenKB: prop = _h.WrittenKB; break;
+
+ case kpidPhySize: prop = _phySize; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
+ if (_linksError) v |= kpv_ErrorFlags_HeadersError;
+ if (_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (!_stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+/*
+static const Byte kRawProps[] =
+{
+ // kpidSha1,
+};
+*/
+
+STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
+{
+ // *numProps = ARRAY_SIZE(kRawProps);
+ *numProps = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
+{
+ // *propID = kRawProps[index];
+ *propID = 0;
+ *name = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+
+ if (index >= _items.Size())
+ return S_OK;
+
+ const CItem &item = _items[index];
+
+ if (item.ParentNode < 0)
+ {
+ int aux = GetParentAux(item);
+ if (aux >= 0)
+ *parent = _items.Size() + aux;
+ }
+ else
+ {
+ int itemIndex = _nodes[item.ParentNode].ItemIndex;
+ if (itemIndex >= 0)
+ *parent = itemIndex;
+ }
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidName && _isUTF)
+ {
+ if (index < _items.Size())
+ {
+ const AString &s = _items[index].Name;
+ if (!s.IsEmpty())
+ {
+ *data = (void *)(const char *)s;
+ *dataSize = (UInt32)s.Len() + 1;
+ *propType = NPropDataType::kUtf8z;
+ }
+ return S_OK;
+ }
+ else
+ {
+ const AString &s = _auxItems[index - _items.Size()];
+ {
+ *data = (void *)(const char *)s;
+ *dataSize = (UInt32)s.Len() + 1;
+ *propType = NPropDataType::kUtf8z;
+ }
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+
+static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
+{
+ /*
+ UInt32 nano = 0;
+ if (t.Extra != 0)
+ {
+ UInt32 mask = t.Extra & 3;
+ if (mask != 0)
+ return;
+ nano = t.Extra >> 2;
+ }
+ UInt64 v;
+ if (t.Val == 0 && nano == 0)
+ return;
+ if (!NTime::UnixTime_to_FileTime64(t.Val, v))
+ return;
+ if (nano != 0)
+ v += nano / 100;
+
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ prop = ft;
+ */
+ if (t.Val == 0)
+ return;
+ if (t.Extra != 0)
+ {
+ UInt32 mask = t.Extra & 3;
+ if (mask != 0)
+ return;
+ }
+ FILETIME ft;
+ if (NTime::UnixTime64ToFileTime(t.Val, ft))
+ prop = ft;
+}
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ if (index >= _items.Size())
+ {
+ switch (propID)
+ {
+ case kpidPath:
+ case kpidName:
+ {
+ AString s = _auxItems[index - _items.Size()];
+ prop = s;
+ break;
+ }
+ case kpidIsDir: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ }
+ }
+ else
+ {
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ bool isDir = node.IsDir();
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString u;
+ {
+ AString s;
+ GetPath(index, s);
+ if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
+ MultiByteToUnicodeString2(u, s);
+ }
+ prop = u;
+ break;
+ }
+
+ case kpidName:
+ {
+ {
+ UString u;
+ {
+ if (!_isUTF || !ConvertUTF8ToUnicode(item.Name, u))
+ MultiByteToUnicodeString2(u, item.Name);
+ }
+ prop = u;
+ }
+ break;
+ }
+
+ case kpidIsDir:
+ {
+ bool isDir2 = isDir;
+ if (item.SymLinkItemIndex >= 0)
+ isDir2 = _nodes[_items[item.SymLinkItemIndex].Node].IsDir();
+ prop = isDir2;
+ break;
+ }
+
+ case kpidSize: if (!isDir) prop = node.FileSize; break;
+
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt64 size;
+ if (GetPackSize(index, size))
+ prop = size;
+ }
+ break;
+
+ case kpidPosixAttrib:
+ {
+ /*
+ if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode))
+ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
+ */
+ prop = (UInt32)(node.Mode);
+ break;
+ }
+
+ case kpidMTime: ExtTimeToProp(node.MTime, prop); break;
+ case kpidCTime: ExtTimeToProp(node.CTime, prop); break;
+ case kpidATime: ExtTimeToProp(node.ATime, prop); break;
+ // case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
+ // case kpidChangeTime: ExtTimeToProp(node.InodeChangeTime, prop); break;
+
+ case kpidUser: prop = (UInt32)node.Uid; break;
+ case kpidGroup: prop = (UInt32)node.Gid; break;
+ case kpidLinks: prop = node.NumLinks; break;
+ case kpidINode: prop = (UInt32)item.Node; break;
+ case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break;
+ case kpidCharacts: FLAGS_TO_PROP(g_NodeFlags, (UInt32)node.Flags, prop); break;
+
+ case kpidSymLink:
+ {
+ if (node.SymLinkIndex >= 0)
+ {
+ UString u;
+ {
+ const AString &s = _symLinks[node.SymLinkIndex];
+ if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
+ MultiByteToUnicodeString2(u, s);
+ }
+ prop = u;
+ }
+ break;
+ }
+ }
+
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+class CExtInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _phyPos;
+public:
+ UInt64 _size;
+ unsigned BlockBits;
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<CExtent> Extents;
+
+ CExtInStream() {}
+
+ HRESULT StartSeek()
+ {
+ _virtPos = 0;
+ _phyPos = 0;
+ return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL);
+ }
+
+ MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ return S_OK;
+ UInt64 rem = _size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+
+ UInt32 blockIndex = (UInt32)(_virtPos >> BlockBits);
+
+ unsigned left = 0, right = Extents.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (blockIndex < Extents[mid].VirtBlock)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ {
+ const CExtent &extent = Extents[left];
+ if (blockIndex < extent.VirtBlock)
+ return E_FAIL;
+ UInt32 bo = blockIndex - extent.VirtBlock;
+ if (bo >= extent.Len)
+ return E_FAIL;
+
+ UInt32 offset = ((UInt32)_virtPos & (((UInt32)1 << BlockBits) - 1));
+ UInt32 remBlocks = extent.Len - bo;
+ UInt64 remBytes = ((UInt64)remBlocks << BlockBits);
+ remBytes -= offset;
+
+ if (size > remBytes)
+ size = (UInt32)remBytes;
+
+ if (!extent.IsInited)
+ {
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ UInt64 phyBlock = extent.PhyStart + bo;
+ UInt64 phy = (phyBlock << BlockBits) + offset;
+
+ if (phy != _phyPos)
+ {
+ RINOK(Stream->Seek(phy, STREAM_SEEK_SET, NULL));
+ _phyPos = phy;
+ }
+
+ UInt32 realProcessSize = 0;
+
+ HRESULT res = Stream->Read(data, size, &realProcessSize);
+
+ _phyPos += realProcessSize;
+ _virtPos += realProcessSize;
+ if (processedSize)
+ *processedSize = realProcessSize;
+ return res;
+ }
+}
+
+
+STDMETHODIMP CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = offset;
+ if (newPosition)
+ *newPosition = offset;
+ return S_OK;
+}
+
+
+
+HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks)
+{
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ CByteBuffer &tempBuf = _tempBufs[level];
+ tempBuf.Alloc(blockSize);
+
+ RINOK(SeekAndRead(_stream, block, tempBuf, blockSize));
+
+ const Byte *p = tempBuf;
+ size_t num = (size_t)1 << (_h.BlockBits - 2);
+
+ for (size_t i = 0; i < num; i++)
+ {
+ if (blocks.Size() == numBlocks)
+ break;
+ UInt32 val = GetUi32(p + 4 * i);
+ if (val == 0 || val >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (level != 0)
+ {
+ RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks));
+ continue;
+ }
+
+ PRF(printf("\n i = %3d, start = %5d ", (unsigned)val));
+
+ blocks.Add(val);
+ }
+
+ return S_OK;
+}
+
+
+static const unsigned kNumDirectNodeBlocks = 12;
+
+HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks)
+{
+ blocks.ClearAndReserve(numBlocks);
+
+ unsigned i;
+
+ for (i = 0; i < kNumDirectNodeBlocks; i++)
+ {
+ if (i == numBlocks)
+ return S_OK;
+ UInt32 val = GetUi32(p + 4 * i);
+ if (val == 0 || val >= _h.NumBlocks)
+ return S_FALSE;
+ blocks.Add(val);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ if (blocks.Size() == numBlocks)
+ break;
+ UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + i));
+ if (val == 0 || val >= _h.NumBlocks)
+ return S_FALSE;
+ RINOK(FillFileBlocks2(val, i, numBlocks, blocks));
+ }
+
+ return S_OK;
+}
+
+
+static void AddSkipExtents(CRecordVector<CExtent> &extents, UInt32 virtBlock, UInt32 numBlocks)
+{
+ while (numBlocks != 0)
+ {
+ UInt32 len = numBlocks;
+ const UInt32 kLenMax = (UInt32)1 << 15;
+ if (len > kLenMax)
+ len = kLenMax;
+ CExtent e;
+ e.VirtBlock = virtBlock;
+ e.Len = (UInt16)len;
+ e.IsInited = false;
+ e.PhyStart = 0;
+ extents.Add(e);
+ virtBlock += len;
+ numBlocks -= len;
+ }
+}
+
+static bool UpdateExtents(CRecordVector<CExtent> &extents, UInt32 block)
+{
+ if (extents.IsEmpty())
+ {
+ if (block == 0)
+ return true;
+ AddSkipExtents(extents, 0, block);
+ return true;
+ }
+
+ const CExtent &prev = extents.Back();
+ if (block < prev.VirtBlock)
+ return false;
+ UInt32 prevEnd = prev.GetVirtEnd();
+ if (block == prevEnd)
+ return true;
+ AddSkipExtents(extents, prevEnd, block - prevEnd);
+ return true;
+}
+
+
+HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth)
+{
+ CExtentTreeHeader eth;
+ if (!eth.Parse(p))
+ return S_FALSE;
+
+ if (parentDepth >= 0 && eth.Depth != parentDepth - 1) // (eth.Depth >= parentDepth)
+ return S_FALSE;
+
+ if (12 + 12 * (size_t)eth.NumEntries > size)
+ return S_FALSE;
+
+ if (eth.Depth >= kNumTreeLevelsMax)
+ return S_FALSE;
+
+ if (eth.Depth == 0)
+ {
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtent e;
+ e.Parse(p + 12 + i * 12);
+ if (e.PhyStart == 0
+ || e.PhyStart > _h.NumBlocks
+ || e.PhyStart + e.Len > _h.NumBlocks
+ || !e.IsLenOK())
+ return S_FALSE;
+ if (!UpdateExtents(extents, e.VirtBlock))
+ return S_FALSE;
+ extents.Add(e);
+ }
+
+ return S_OK;
+ }
+
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ CByteBuffer &tempBuf = _tempBufs[eth.Depth];
+ tempBuf.Alloc(blockSize);
+
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtentIndexNode e;
+ e.Parse(p + 12 + i * 12);
+
+ if (e.PhyLeaf == 0 || e.PhyLeaf >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (!UpdateExtents(extents, e.VirtBlock))
+ return S_FALSE;
+
+ RINOK(SeekAndRead(_stream, e.PhyLeaf, tempBuf, blockSize));
+ RINOK(FillExtents(tempBuf, blockSize, extents, eth.Depth));
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CHandler::GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ *stream = NULL;
+
+ const CNode &node = _nodes[nodeIndex];
+
+ if (!node.IsFlags_EXTENTS())
+ {
+ // maybe sparse file can have NumBlocks == 0 ?
+ if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize)
+ {
+ Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream);
+ return S_OK;
+ }
+ }
+
+ if (node.FileSize >= ((UInt64)1 << 63))
+ return S_FALSE;
+
+ CMyComPtr<IInStream> streamTemp;
+
+ UInt64 numBlocks64 = (node.FileSize + (UInt64)(((UInt32)1 << _h.BlockBits) - 1)) >> _h.BlockBits;
+
+ if (node.IsFlags_EXTENTS())
+ {
+ if ((UInt32)numBlocks64 != numBlocks64)
+ return S_FALSE;
+
+ CExtInStream *streamSpec = new CExtInStream;
+ streamTemp = streamSpec;
+
+ streamSpec->BlockBits = _h.BlockBits;
+ streamSpec->_size = node.FileSize;
+ streamSpec->Stream = _stream;
+
+ RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1));
+
+ UInt32 end = 0;
+ if (!streamSpec->Extents.IsEmpty())
+ end = streamSpec->Extents.Back().GetVirtEnd();
+ if (end < numBlocks64)
+ {
+ AddSkipExtents(streamSpec->Extents, end, (UInt32)(numBlocks64 - end));
+ // return S_FALSE;
+ }
+
+ RINOK(streamSpec->StartSeek());
+ }
+ else
+ {
+ {
+ UInt64 numBlocks2 = numBlocks64;
+
+ if (numBlocks64 > kNumDirectNodeBlocks)
+ {
+ UInt64 rem = numBlocks64 - kNumDirectNodeBlocks;
+ const unsigned refBits = (_h.BlockBits - 2);
+ const size_t numRefsInBlocks = (size_t)1 << refBits;
+ numBlocks2++;
+ if (rem > numRefsInBlocks)
+ {
+ numBlocks2++;
+ const UInt64 numL2 = (rem - 1) >> refBits;
+ numBlocks2 += numL2;
+ if (numL2 > numRefsInBlocks)
+ {
+ numBlocks2++;
+ numBlocks2 += (numL2 - 1) >> refBits;
+ }
+ }
+ }
+
+ const unsigned specBits = (node.IsFlags_HUGE() ? 0 : _h.BlockBits - 9);
+ const UInt32 specMask = ((UInt32)1 << specBits) - 1;;
+ if ((node.NumBlocks & specMask) != 0)
+ return S_FALSE;
+ const UInt64 numBlocks64_from_header = node.NumBlocks >> specBits;
+ if (numBlocks64_from_header < numBlocks2)
+ {
+ // why (numBlocks64_from_header > numBlocks2) in some cases?
+ // return S_FALSE;
+ }
+ }
+
+ unsigned numBlocks = (unsigned)numBlocks64;
+ if (numBlocks != numBlocks64)
+ return S_FALSE;
+
+ CClusterInStream *streamSpec = new CClusterInStream;
+ streamTemp = streamSpec;
+
+ streamSpec->BlockSizeLog = _h.BlockBits;
+ streamSpec->StartOffset = 0;
+ streamSpec->Size = node.FileSize;
+ streamSpec->Stream = _stream;
+
+ RINOK(FillFileBlocks(node.Block, numBlocks, streamSpec->Vector));
+ streamSpec->InitAndSeek();
+ }
+
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::ExtractNode(unsigned nodeIndex, CByteBuffer &data)
+{
+ data.Free();
+ const CNode &node = _nodes[nodeIndex];
+ size_t size = (size_t)node.FileSize;
+ if (size != node.FileSize)
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ RINOK(GetStream_Node(nodeIndex, &inSeqStream));
+ if (!inSeqStream)
+ return S_FALSE;
+ data.Alloc(size);
+ _totalRead += size;
+ return ReadStream_FALSE(inSeqStream, data, size);
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size() + _auxItems.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ if (index >= _items.Size())
+ continue;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ if (!node.IsDir())
+ totalSize += node.FileSize;
+ }
+
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0;; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+
+ if (i == numItems)
+ break;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+
+ if (index >= _items.Size())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+
+ if (node.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ UInt64 unpackSize = node.FileSize;
+ totalSize += unpackSize;
+ UInt64 packSize;
+ if (GetPackSize(index, packSize))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (hres == S_FALSE || !inSeqStream)
+ {
+ if (hres == E_OUTOFMEMORY)
+ return hres;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else
+ {
+ RINOK(hres);
+ {
+ HRESULT hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == unpackSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else if (hres == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else if (hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ if (index >= _items.Size())
+ return S_FALSE;
+ return GetStream_Node(_items[index].Node, stream);
+}
+
+
+API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size)
+{
+ if (size < kHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ CHeader h;
+ if (!h.Parse(p + kHeaderDataOffset))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+static const Byte k_Signature[] = { 0x53, 0xEF };
+
+REGISTER_ARC_I(
+ "Ext", "ext ext3 ext4", 0, 0xC7,
+ k_Signature,
+ 0x438,
+ 0,
+ IsArc_Ext)
+
+}}
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index 649d54bd..e16a8860 100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -805,7 +805,7 @@ enum
// kpidFileSysType
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
{ NULL, kpidFileSystem, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4},
@@ -814,12 +814,12 @@ static const STATPROPSTG kArcProps[] =
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidVolumeName, VT_BSTR},
- { (LPOLESTR)L"FATs", kpidNumFats, VT_UI4},
+ { "FATs", kpidNumFats, VT_UI4},
{ NULL, kpidSectorSize, VT_UI4},
{ NULL, kpidId, VT_UI4},
- // { (LPOLESTR)L"OEM Name", kpidOemName, VT_BSTR},
- // { (LPOLESTR)L"Volume Name", kpidVolName, VT_BSTR},
- // { (LPOLESTR)L"File System Type", kpidFileSysType, VT_BSTR}
+ // { "OEM Name", kpidOemName, VT_BSTR},
+ // { "Volume Name", kpidVolName, VT_BSTR},
+ // { "File System Type", kpidFileSysType, VT_BSTR}
// { NULL, kpidSectorsPerTrack, VT_UI4},
// { NULL, kpidNumHeads, VT_UI4},
// { NULL, kpidHiddenSectors, VT_UI4}
@@ -858,7 +858,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidFileSystem:
{
@@ -897,7 +897,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CItem &item = Items[index];
- switch(propID)
+ switch (propID)
{
case kpidPath: prop = GetItemPath(index); break;
case kpidShortName: prop = item.GetShortName(); break;
diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp
index dafb250b..72ccd993 100644
--- a/CPP/7zip/Archive/FlvHandler.cpp
+++ b/CPP/7zip/Archive/FlvHandler.cpp
@@ -145,7 +145,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
NWindows::NCOM::CPropVariant prop;
const CItem2 &item = _items2[index];
- switch(propID)
+ switch (propID)
{
case kpidExtension:
prop = _isRaw ?
@@ -209,7 +209,7 @@ AString CHandler::GetComment()
Byte type = *p++;
size--;
bool ok = false;
- switch(type)
+ switch (type)
{
case 0:
{
@@ -256,7 +256,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
// COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
// case kpidComment: prop = GetComment(); break;
case kpidPhySize: prop = (UInt64)_phySize; break;
diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp
index 23a184f2..ca9153b8 100644
--- a/CPP/7zip/Archive/HandlerCont.cpp
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -227,4 +227,30 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
+
+HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
+{
+ areThereNonZeros = false;
+ numZeros = 0;
+ const size_t kBufSize = 1 << 11;
+ Byte buf[kBufSize];
+ for (;;)
+ {
+ UInt32 size = 0;
+ HRESULT(stream->Read(buf, kBufSize, &size));
+ if (size == 0)
+ return S_OK;
+ for (UInt32 i = 0; i < size; i++)
+ if (buf[i] != 0)
+ {
+ areThereNonZeros = true;
+ numZeros += i;
+ return S_OK;
+ }
+ numZeros += size;
+ if (numZeros > maxSize)
+ return S_OK;
+ }
+}
+
}
diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
index 603a6511..58b45d54 100644
--- a/CPP/7zip/Archive/HandlerCont.h
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -85,6 +85,9 @@ public:
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
+
+HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize);
+
}
#endif
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 84a4cc4b..0028d762 100644
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -293,12 +293,14 @@ namespace NPropDataType
const UInt32 kMask_ZeroEnd = 1 << 4;
// const UInt32 kMask_BigEndian = 1 << 5;
const UInt32 kMask_Utf = 1 << 6;
- // const UInt32 kMask_Utf8 = kMask_Utf | 0;
+ const UInt32 kMask_Utf8 = kMask_Utf | 0;
const UInt32 kMask_Utf16 = kMask_Utf | 1;
// const UInt32 kMask_Utf32 = kMask_Utf | 2;
const UInt32 kNotDefined = 0;
const UInt32 kRaw = 1;
+
+ const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd;
const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd;
};
@@ -512,12 +514,26 @@ ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05)
{ if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
*propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \
+
+struct CStatProp
+{
+ const char *Name;
+ UInt32 PropID;
+ VARTYPE vt;
+};
+
+namespace NWindows {
+namespace NCOM {
+// PropVariant.cpp
+BSTR AllocBstrFromAscii(const char *s) throw();
+}}
+
#define IMP_IInArchive_GetProp_WITH_NAME(k) \
(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
{ if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
- const STATPROPSTG &srcItem = k[index]; \
- *propID = srcItem.propid; *varType = srcItem.vt; \
- if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
+ const CStatProp &prop = k[index]; \
+ *propID = (PROPID)prop.PropID; *varType = prop.vt; \
+ *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \
#define IMP_IInArchive_Props \
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index b72e8687..39034b63 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -8,6 +8,8 @@
#include "../../Common/StreamUtils.h"
+#include "../HandlerCont.h"
+
#include "IsoIn.h"
namespace NArchive {
@@ -596,7 +598,7 @@ HRESULT CInArchive::Open2()
ReadBootInfo();
{
- FOR_VECTOR(i, Refs)
+ FOR_VECTOR (i, Refs)
{
const CRef &ref = Refs[i];
for (UInt32 j = 0; j < ref.NumExtents; j++)
@@ -608,12 +610,28 @@ HRESULT CInArchive::Open2()
}
}
{
- FOR_VECTOR(i, BootEntries)
+ FOR_VECTOR (i, BootEntries)
{
const CBootInitialEntry &be = BootEntries[i];
UpdatePhySize(be.LoadRBA, GetBootItemSize(i));
}
}
+
+ if (PhySize < _fileSize)
+ {
+ UInt64 rem = _fileSize - PhySize;
+ const UInt64 kRemMax = 1 << 21;
+ if (rem <= kRemMax)
+ {
+ RINOK(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL));
+ bool areThereNonZeros = false;
+ UInt64 numZeros = 0;
+ RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax));
+ if (!areThereNonZeros)
+ PhySize += numZeros;
+ }
+ }
+
return S_OK;
}
diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp
index 5135e5f8..93b615d2 100644
--- a/CPP/7zip/Archive/MbrHandler.cpp
+++ b/CPP/7zip/Archive/MbrHandler.cpp
@@ -332,15 +332,15 @@ enum
kpidEndChs
};
-static const STATPROPSTG kProps[] =
+static const CStatProp kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidFileSystem, VT_BSTR},
{ NULL, kpidOffset, VT_UI8},
- { (LPOLESTR)L"Primary", kpidPrimary, VT_BOOL},
- { (LPOLESTR)L"Begin CHS", kpidBegChs, VT_BSTR},
- { (LPOLESTR)L"End CHS", kpidEndChs, VT_BSTR}
+ { "Primary", kpidPrimary, VT_BOOL},
+ { "Begin CHS", kpidBegChs, VT_BSTR},
+ { "End CHS", kpidEndChs, VT_BSTR}
};
IMP_IInArchive_Props_WITH_NAME
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index 67cd385f..70023fe4 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -519,7 +519,7 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
UInt64 vSize = 0;
{
unsigned i = num;
- do vSize = (vSize << 8) | p[--i]; while(i);
+ do vSize = (vSize << 8) | p[--i]; while (i);
}
if (vSize == 0)
return false;
@@ -1835,7 +1835,7 @@ HRESULT CDatabase::Open()
int indexOfUnnamedStream = -1;
if (!rec.IsDir())
{
- FOR_VECTOR(di, rec.DataRefs)
+ FOR_VECTOR (di, rec.DataRefs)
if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty())
{
indexOfUnnamedStream = di;
@@ -1849,7 +1849,7 @@ HRESULT CDatabase::Open()
if (i < kNumSysRecs)
{
needShow = false;
- FOR_VECTOR(di, rec.DataRefs)
+ FOR_VECTOR (di, rec.DataRefs)
if (rec.GetSize(di) != 0)
{
needShow = true;
@@ -1905,7 +1905,7 @@ HRESULT CDatabase::Open()
unsigned numAltStreams = 0;
- FOR_VECTOR(di, rec.DataRefs)
+ FOR_VECTOR (di, rec.DataRefs)
{
if (!rec.IsDir() && (int)di == indexOfUnnamedStream)
continue;
@@ -2173,7 +2173,7 @@ enum
kpidATime2
};
-static const STATPROPSTG kProps[] =
+static const CStatProp kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidSize, VT_UI8},
@@ -2181,20 +2181,20 @@ static const STATPROPSTG kProps[] =
// { NULL, kpidLink, VT_BSTR},
- // { (LPOLESTR)L"Link 2", kpidLink2, VT_BSTR},
- // { (LPOLESTR)L"Link Type", kpidLinkType, VT_UI2},
+ // { "Link 2", kpidLink2, VT_BSTR},
+ // { "Link Type", kpidLinkType, VT_UI2},
{ NULL, kpidINode, VT_UI8},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME},
- // { (LPOLESTR)L"Record Modified", kpidRecMTime, VT_FILETIME},
+ // { "Record Modified", kpidRecMTime, VT_FILETIME},
- // { (LPOLESTR)L"Modified 2", kpidMTime2, VT_FILETIME},
- // { (LPOLESTR)L"Created 2", kpidCTime2, VT_FILETIME},
- // { (LPOLESTR)L"Accessed 2", kpidATime2, VT_FILETIME},
- // { (LPOLESTR)L"Record Modified 2", kpidRecMTime2, VT_FILETIME},
+ // { "Modified 2", kpidMTime2, VT_FILETIME},
+ // { "Created 2", kpidCTime2, VT_FILETIME},
+ // { "Accessed 2", kpidATime2, VT_FILETIME},
+ // { "Record Modified 2", kpidRecMTime2, VT_FILETIME},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidNumBlocks, VT_UI4},
@@ -2226,13 +2226,13 @@ enum
kpidRecordSize = kpidUserDefined
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
{ NULL, kpidVolumeName, VT_BSTR},
{ NULL, kpidFileSystem, VT_BSTR},
{ NULL, kpidClusterSize, VT_UI4},
{ NULL, kpidSectorSize, VT_UI4},
- { (LPOLESTR)L"Record Size", kpidRecordSize, VT_UI4},
+ { "Record Size", kpidRecordSize, VT_UI4},
{ NULL, kpidHeadersSize, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidId, VT_UI8},
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index 43450e80..9cbc7c3c 100644
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -765,7 +765,7 @@ enum
// kpidBaseOfData32,
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
// { NULL, kpidWarning, VT_BSTR},
{ NULL, kpidCpu, VT_BSTR},
@@ -776,28 +776,28 @@ static const STATPROPSTG kArcProps[] =
{ NULL, kpidChecksum, VT_UI4},
{ NULL, kpidName, VT_BSTR},
- { (LPOLESTR)L"Image Size", kpidImageSize, VT_UI4},
- { (LPOLESTR)L"Section Alignment", kpidSectAlign, VT_UI4},
- { (LPOLESTR)L"File Alignment", kpidFileAlign, VT_UI4},
- { (LPOLESTR)L"Code Size", kpidCodeSize, VT_UI4},
- { (LPOLESTR)L"Initialized Data Size", kpidInitDataSize, VT_UI4},
- { (LPOLESTR)L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
- { (LPOLESTR)L"Linker Version", kpidLinkerVer, VT_BSTR},
- { (LPOLESTR)L"OS Version", kpidOsVer, VT_BSTR},
- { (LPOLESTR)L"Image Version", kpidImageVer, VT_BSTR},
- { (LPOLESTR)L"Subsystem Version", kpidSubsysVer, VT_BSTR},
- { (LPOLESTR)L"Subsystem", kpidSubSystem, VT_BSTR},
- { (LPOLESTR)L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
- { (LPOLESTR)L"Stack Reserve", kpidStackReserve, VT_UI8},
- { (LPOLESTR)L"Stack Commit", kpidStackCommit, VT_UI8},
- { (LPOLESTR)L"Heap Reserve", kpidHeapReserve, VT_UI8},
- { (LPOLESTR)L"Heap Commit", kpidHeapCommit, VT_UI8},
- { (LPOLESTR)L"Image Base", kpidImageBase, VT_UI8},
+ { "Image Size", kpidImageSize, VT_UI4},
+ { "Section Alignment", kpidSectAlign, VT_UI4},
+ { "File Alignment", kpidFileAlign, VT_UI4},
+ { "Code Size", kpidCodeSize, VT_UI4},
+ { "Initialized Data Size", kpidInitDataSize, VT_UI4},
+ { "Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
+ { "Linker Version", kpidLinkerVer, VT_BSTR},
+ { "OS Version", kpidOsVer, VT_BSTR},
+ { "Image Version", kpidImageVer, VT_BSTR},
+ { "Subsystem Version", kpidSubsysVer, VT_BSTR},
+ { "Subsystem", kpidSubSystem, VT_BSTR},
+ { "DLL Characteristics", kpidDllCharacts, VT_BSTR},
+ { "Stack Reserve", kpidStackReserve, VT_UI8},
+ { "Stack Commit", kpidStackCommit, VT_UI8},
+ { "Heap Reserve", kpidHeapReserve, VT_UI8},
+ { "Heap Commit", kpidHeapCommit, VT_UI8},
+ { "Image Base", kpidImageBase, VT_UI8},
{ NULL, kpidComment, VT_BSTR},
- // { (LPOLESTR)L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
- // { (LPOLESTR)L"Base Of Code", kpidBaseOfCode, VT_UI8},
- // { (LPOLESTR)L"Base Of Data", kpidBaseOfData32, VT_UI8},
+ // { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
+ // { "Base Of Code", kpidBaseOfCode, VT_UI8},
+ // { "Base Of Data", kpidBaseOfData32, VT_UI8},
};
static const Byte kProps[] =
@@ -2233,7 +2233,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
sections.Sort();
UInt32 limit = (1 << 12);
unsigned num = 0;
- FOR_VECTOR(i, sections)
+ FOR_VECTOR (i, sections)
{
const CSection &s = sections[i];
if (s.Pa > limit)
@@ -2798,12 +2798,12 @@ enum
// , kpidImageBase
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
// { NULL, kpidHeadersSize, VT_UI4 },
{ NULL, kpidCpu, VT_BSTR},
- { (LPOLESTR)L"Subsystem", kpidSubSystem, VT_BSTR },
- // { (LPOLESTR)L"Image Base", kpidImageBase, VT_UI8 }
+ { "Subsystem", kpidSubSystem, VT_BSTR },
+ // { "Image Base", kpidImageBase, VT_UI8 }
};
IMP_IInArchive_Props
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index 72fe4f68..2cfe805e 100644
--- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -30,6 +30,8 @@
#include "../Common/FindSignature.h"
#include "../Common/ItemNameUtils.h"
+#include "../HandlerCont.h"
+
#include "RarVol.h"
#include "Rar5Handler.h"
@@ -38,13 +40,6 @@ using namespace NWindows;
#define Get32(p) GetUi32(p)
namespace NArchive {
-
-namespace NRar {
-
-HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize);
-
-}
-
namespace NRar5 {
static const unsigned kMarkerSize = 8;
@@ -1938,7 +1933,7 @@ HRESULT CHandler::Open2(IInStream *stream,
bool areThereNonZeros;
UInt64 numZeros;
const UInt64 maxSize = 1 << 12;
- RINOK(NRar::ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize));
+ RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize));
if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize)
arcInfo.EndPos += numZeros;
}
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index d6d894f4..dde15958 100644
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -30,6 +30,8 @@
#include "../Common/ItemNameUtils.h"
#include "../Common/OutStreamWithCRC.h"
+#include "../HandlerCont.h"
+
#include "RarVol.h"
#include "RarHandler.h"
@@ -938,7 +940,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.BaseFileIndex >= 0)
mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex];
*/
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -998,31 +1000,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
-HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
-{
- areThereNonZeros = false;
- numZeros = 0;
- const size_t kBufSize = 1 << 9;
- Byte buf[kBufSize];
- for (;;)
- {
- UInt32 size = 0;
- HRESULT(stream->Read(buf, kBufSize, &size));
- if (size == 0)
- return S_OK;
- for (UInt32 i = 0; i < size; i++)
- if (buf[i] != 0)
- {
- areThereNonZeros = true;
- numZeros += i;
- return S_OK;
- }
- numZeros += size;
- if (numZeros > maxSize)
- return S_OK;
- }
-}
-
HRESULT CHandler::Open2(IInStream *stream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openCallback)
@@ -1593,7 +1570,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ICompressCoder> commonCoder;
- switch(item.Method)
+ switch (item.Method)
{
case '0':
{
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
index c65067af..fc195717 100644
--- a/CPP/7zip/Archive/SquashfsHandler.cpp
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -8,6 +8,7 @@
#include "../../../C/Xz.h"
#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
#include "../../Common/IntToString.h"
#include "../../Common/StringConvert.h"
@@ -76,14 +77,6 @@ static const char * const k_Methods[] =
static const UInt32 kMetadataBlockSizeLog = 13;
static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
-#define MY_S_IFIFO 0x1000
-#define MY_S_IFCHR 0x2000
-#define MY_S_IFDIR 0x4000
-#define MY_S_IFBLK 0x6000
-#define MY_S_IFREG 0x8000
-#define MY_S_IFLNK 0xA000
-#define MY_S_IFSOCK 0xC000
-
enum
{
kType_IPC,
@@ -99,8 +92,8 @@ enum
static const UInt32 k_TypeToMode[] =
{
0,
- MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK,
- MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK
+ MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK,
+ MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK
};
@@ -754,7 +747,7 @@ UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h)
}
unsigned offset = 20;
- switch(Type)
+ switch (Type)
{
case kType_FIFO: case kType_FIFO + 7:
case kType_SOCK: case kType_SOCK + 7:
@@ -939,7 +932,7 @@ static const Byte kArcProps[] =
kpidHeadersSize,
kpidFileSystem,
kpidMethod,
- kpidBlock,
+ kpidClusterSize,
kpidBigEndian,
kpidCTime,
kpidCharacts
@@ -1552,7 +1545,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
const Byte *p = _inodesData.Data + pos;
UInt32 size = totalSize - pos;
- switch(_h.Major)
+ switch (_h.Major)
{
case 1: size = n.Parse1(p, size, _h); break;
case 2: size = n.Parse2(p, size, _h); break;
@@ -1817,7 +1810,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMethod:
{
@@ -1850,7 +1843,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = res;
break;
}
- case kpidBlock: prop = _h.BlockSize; break;
+ case kpidClusterSize: prop = _h.BlockSize; break;
case kpidBigEndian: prop = _h.be; break;
case kpidCTime:
if (_h.CTime != 0)
@@ -1882,7 +1875,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
bool isDir = node.IsDir();
bool be = _h.be;
- switch(propID)
+ switch (propID)
{
case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
case kpidIsDir: prop = isDir; break;
@@ -1899,7 +1892,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime:
{
UInt32 offset = 0;
- switch(_h.Major)
+ switch (_h.Major)
{
case 1:
if (node.Type == kType_FILE)
@@ -2111,11 +2104,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
int res = NExtract::NOperationResult::kDataError;
{
CMyComPtr<ISequentialInStream> inSeqStream;
- CMyComPtr<IInStream> inStream;
HRESULT hres = GetStream(index, &inSeqStream);
- if (inSeqStream)
- inSeqStream.QueryInterface(IID_IInStream, &inStream);
- if (hres == S_FALSE || !inStream)
+ if (hres == S_FALSE || !inSeqStream)
{
if (hres == E_OUTOFMEMORY)
return hres;
@@ -2124,9 +2114,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
else
{
RINOK(hres);
- if (inStream)
{
- HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ HRESULT hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
if (hres == S_OK)
{
if (copyCoderSpec->TotalSize == unpackSize)
@@ -2136,15 +2125,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
res = NExtract::NOperationResult::kUnsupportedMethod;
}
- else if(hres != S_FALSE)
+ else if (hres != S_FALSE)
{
RINOK(hres);
}
}
}
}
+
RINOK(extractCallback->SetOperationResult(res));
}
+
return S_OK;
COM_TRY_END
}
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index d1eec144..14cf3e59 100644
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -639,6 +639,7 @@ void CHandler::Init()
_forceCodePage = false;
// _codePage = CP_OEMCP;
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
+ _thereIsPaxExtendedHeader = false;
}
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
index 8dd99869..429a8afe 100644
--- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -4,6 +4,7 @@
#include "../../../Common/ComTry.h"
#include "../../../Common/Defs.h"
+#include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/UTFConvert.h"
@@ -113,7 +114,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop));
if (prop.vt == VT_EMPTY)
- ui.Mode = 0777 | (ui.IsDir ? 0040000 : 0100000);
+ ui.Mode =
+ MY_LIN_S_IRWXO
+ | MY_LIN_S_IRWXG
+ | MY_LIN_S_IRWXU
+ | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
else if (prop.vt != VT_UI4)
return E_INVALIDARG;
else
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
index d35db9fb..876482d1 100644
--- a/CPP/7zip/Archive/Udf/UdfHandler.cpp
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -58,7 +58,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidPhySize: prop = _archive.PhySize; break;
diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp
index 3de6351a..015a9caa 100644
--- a/CPP/7zip/Archive/UefiHandler.cpp
+++ b/CPP/7zip/Archive/UefiHandler.cpp
@@ -694,7 +694,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NWindows::NCOM::CPropVariant prop;
const CItem2 &item2 = _items2[index];
const CItem &item = _items[item2.MainIndex];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
@@ -754,7 +754,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidMethod:
{
@@ -1039,7 +1039,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p
else
{
bool needAdd = true;
- switch(type)
+ switch (type)
{
case SECTION_RAW:
{
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index d7c3ca95..0459571b 100644
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -599,17 +599,17 @@ enum
kpidSavedState
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidOffset, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidClusterSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR},
- { (LPOLESTR)L"Parent", kpidParent, VT_BSTR},
+ { "Parent", kpidParent, VT_BSTR},
{ NULL, kpidCreatorApp, VT_BSTR},
{ NULL, kpidHostOS, VT_BSTR},
- { (LPOLESTR)L"Saved State", kpidSavedState, VT_BOOL},
+ { "Saved State", kpidSavedState, VT_BOOL},
{ NULL, kpidId, VT_BSTR}
};
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
index 0c635eae..6c07f37c 100644
--- a/CPP/7zip/Archive/Wim/WimHandler.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -56,7 +56,7 @@ enum
kpidBootImage
};
-static const STATPROPSTG kArcProps[] =
+static const CStatProp kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
@@ -69,8 +69,8 @@ static const STATPROPSTG kArcProps[] =
{ NULL, kpidIsVolume, VT_BOOL},
{ NULL, kpidVolume, VT_UI4},
{ NULL, kpidNumVolumes, VT_UI4},
- { (LPOLESTR)L"Images", kpidNumImages, VT_UI4},
- { (LPOLESTR)L"Boot Image", kpidBootImage, VT_UI4}
+ { "Images", kpidNumImages, VT_UI4},
+ { "Boot Image", kpidBootImage, VT_UI4}
};
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
index 2c1ec5de..1da6ca98 100644
--- a/CPP/7zip/Archive/Wim/WimIn.cpp
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -21,7 +21,7 @@
#include "../../Common/StreamObjects.h"
#include "../../Common/StreamUtils.h"
-#include "../../Compress/XPressDecoder.h"
+#include "../../Compress/XpressDecoder.h"
#include "../Common/OutStreamWithSha1.h"
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
index ac4a2bd8..6a387212 100644
--- a/CPP/7zip/Archive/Wim/WimIn.h
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -221,6 +221,7 @@ namespace NHeaderFlags
const UInt32 kXPRESS = (UInt32)1 << 17;
const UInt32 kLZX = (UInt32)1 << 18;
const UInt32 kLZMS = (UInt32)1 << 19;
+ const UInt32 kXPRESS2 = (UInt32)1 << 21; // XPRESS with nonstandard chunk size ?
const UInt32 kMethodMask = 0xFFFE0000;
}
@@ -277,7 +278,8 @@ struct CHeader
return (!IsCompressed()
|| (Flags & NHeaderFlags::kLZX) != 0
|| (Flags & NHeaderFlags::kXPRESS) != 0
- || (Flags & NHeaderFlags::kLZMS) != 0);
+ || (Flags & NHeaderFlags::kLZMS) != 0
+ || (Flags & NHeaderFlags::kXPRESS2) != 0);
}
unsigned GetMethod() const
@@ -289,6 +291,7 @@ struct CHeader
if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS;
if (mask == NHeaderFlags::kLZX) return NMethod::kLZX;
if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS;
+ if (mask == NHeaderFlags::kXPRESS2) return NMethod::kXPRESS;
return mask;
}
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
index 5ef3bdf9..80111b6b 100644
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -5,6 +5,7 @@
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
#include "../../Common/MyXml.h"
#include "../../Common/StringToInt.h"
#include "../../Common/UTFConvert.h"
@@ -360,7 +361,7 @@ HRESULT CHandler::Open2(IInStream *stream)
UInt64 totalPackSize = 0;
unsigned numMainFiles = 0;
- FOR_VECTOR(i, _files)
+ FOR_VECTOR (i, _files)
{
const CFile &file = _files[i];
file.UpdateTotalPackSize(totalPackSize);
@@ -511,10 +512,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.ModeDefined)
{
UInt32 mode = item.Mode;
- const UInt32 k_PosixAttrib_Dir = (1 << 14);
- const UInt32 k_PosixAttrib_RegFile = (1 << 15);
- if ((mode & 0xF000) == 0)
- mode |= (item.IsDir ? k_PosixAttrib_Dir : k_PosixAttrib_RegFile);
+ if ((mode & MY_LIN_S_IFMT) == 0)
+ mode |= (item.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
prop = mode;
}
break;
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
index c9c290aa..06fbe22f 100644
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -271,7 +271,7 @@ HRESULT CAddCommon::Compress(
else
{
CMethodId methodId;
- switch(method)
+ switch (method)
{
case NFileHeader::NCompressionMethod::kBZip2:
methodId = kMethodId_BZip2;
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
index 3e29a880..510ecb41 100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -929,7 +929,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = m_Items.Size();
- if(numItems == 0)
+ if (numItems == 0)
return S_OK;
UInt32 i;
for (i = 0; i < numItems; i++)
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h
index c109992c..18ba064a 100644
--- a/CPP/7zip/Archive/Zip/ZipHeader.h
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -153,36 +153,7 @@ namespace NFileHeader
};
}
- namespace NUnixAttrib
- {
- const UInt32 kIFMT = 0170000; // file type mask
-
- const UInt32 kIFDIR = 0040000; // directory
- const UInt32 kIFREG = 0100000; // regular file
- const UInt32 kIFSOCK = 0140000; // socket (BSD, not SysV or Amiga)
- const UInt32 kIFLNK = 0120000; // symbolic link (not SysV, Amiga)
- const UInt32 kIFBLK = 0060000; // block special (not Amiga)
- const UInt32 kIFCHR = 0020000; // character special (not Amiga)
- const UInt32 kIFIFO = 0010000; // fifo (BCC, not MSC or Amiga)
-
- const UInt32 kISUID = 04000; // set user id on execution
- const UInt32 kISGID = 02000; // set group id on execution
- const UInt32 kISVTX = 01000; // directory permissions control
- const UInt32 kENFMT = kISGID; // record locking enforcement flag
- const UInt32 kIRWXU = 00700; // read, write, execute: owner
- const UInt32 kIRUSR = 00400; // read permission: owner
- const UInt32 kIWUSR = 00200; // write permission: owner
- const UInt32 kIXUSR = 00100; // execute permission: owner
- const UInt32 kIRWXG = 00070; // read, write, execute: group
- const UInt32 kIRGRP = 00040; // read permission: group
- const UInt32 kIWGRP = 00020; // write permission: group
- const UInt32 kIXGRP = 00010; // execute permission: group
- const UInt32 kIRWXO = 00007; // read, write, execute: other
- const UInt32 kIROTH = 00004; // read permission: other
- const UInt32 kIWOTH = 00002; // write permission: other
- const UInt32 kIXOTH = 00001; // execute permission: other
- }
-
+
namespace NAmigaAttrib
{
const UInt32 kIFMT = 06000; // Amiga file type mask
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index 3c466424..f72e7f8c 100644
--- a/CPP/7zip/Archive/Zip/ZipIn.cpp
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -579,7 +579,7 @@ static bool FlagsAreSame(const CItem &i1, const CItem &i2)
if (i1.Flags == i2.Flags)
return true;
UInt32 mask = 0xFFFF;
- switch(i1.Method)
+ switch (i1.Method)
{
case NFileHeader::NCompressionMethod::kDeflated:
mask = 0x7FF9;
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
index f2ccc814..9e1f5e00 100644
--- a/CPP/7zip/Archive/Zip/ZipItem.cpp
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -2,11 +2,14 @@
#include "StdAfx.h"
-#include "ZipHeader.h"
-#include "ZipItem.h"
-#include "../Common/ItemNameUtils.h"
#include "../../../../C/CpuArch.h"
+#include "../../../Common/MyLinux.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "ZipItem.h"
+
namespace NArchive {
namespace NZip {
@@ -114,7 +117,7 @@ bool CItem::IsDir() const
case NHostOS::kMVS:
return false; // change it throw kUnknownAttributes;
case NHostOS::kUnix:
- return ((highAttrib & NUnixAttrib::kIFMT) == NUnixAttrib::kIFDIR);
+ return MY_LIN_S_ISDIR(highAttrib);
default:
return false;
}
@@ -151,7 +154,7 @@ bool CItem::GetPosixAttrib(UInt32 &attrib) const
}
attrib = 0;
if (IsDir())
- attrib = NUnixAttrib::kIFDIR;
+ attrib = MY_LIN_S_IFDIR;
return false;
}