This commit is contained in:
Igor Pavlov
2015-06-15 00:00:00 +00:00
committed by Kornel Lesiński
parent 0713a3ab80
commit 54490d51d5
591 changed files with 34932 additions and 16390 deletions

View File

@@ -37,7 +37,9 @@ static const Byte kProps[] =
kpidMethod,
kpidShortName,
kpidINode,
kpidLinks
kpidLinks,
kpidIsAltStream,
kpidNumAltStreams,
#ifdef WIM_DETAILS
, kpidVolume
@@ -269,14 +271,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
res = kMethodLZX;
if (xpress)
{
if (!res.IsEmpty())
res += ' ';
res.Add_Space_if_NotEmpty();
res += kMethodXpress;
}
if (copy)
{
if (!res.IsEmpty())
res += ' ';
res.Add_Space_if_NotEmpty();
res += kMethodCopy;
}
prop = res;
@@ -308,6 +308,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
AddErrorMessage(s, "Some files have incorrect reference count");
if (!s.IsEmpty())
prop = s;
break;
}
case kpidReadOnly:
{
bool readOnly = false;
if (ThereIsError())
readOnly = true;
else if (_volumes.Size() != 0)
{
if (_version != kWimVersion
|| _volumes.Size() != 2
|| _volumes[0].Stream
// || _db.Images.Size() > kNumImagesMax
)
readOnly = true;
}
if (readOnly)
prop = readOnly;
break;
}
}
prop.Detach(value);
@@ -397,6 +417,22 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break;
case kpidIsDir: prop = item.IsDir; break;
case kpidIsAltStream: prop = item.IsAltStream; break;
case kpidNumAltStreams:
{
if (!item.IsAltStream && mainItem->HasMetadata())
{
UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6);
if (numAltStreams != 0)
{
if (!item.IsDir)
numAltStreams--;
prop = numAltStreams;
}
}
break;
}
case kpidAttrib:
if (!item.IsAltStream && mainItem->ImageIndex >= 0)
{
@@ -481,7 +517,7 @@ STDMETHODIMP CHandler::GetRootProp(PROPID propID, PROPVARIANT *value)
{
// COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (_db.Images.Size() != 0 && _db.NumExludededItems != 0)
if (_db.Images.Size() != 0 && _db.NumExcludededItems != 0)
{
const CImage &image = _db.Images[_db.IndexOfUserImage];
const CItem &item = _db.Items[image.StartItem];
@@ -532,7 +568,7 @@ STDMETHODIMP CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *
*data = 0;
*dataSize = 0;
*propType = 0;
if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExludededItems != 0)
if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExcludededItems != 0)
{
const CImage &image = _db.Images[_db.IndexOfUserImage];
const CItem &item = _db.Items[image.StartItem];
@@ -705,7 +741,7 @@ class CVolumeName
public:
void InitName(const UString &name)
{
int dotPos = name.ReverseFind('.');
int dotPos = name.ReverseFind_Dot();
if (dotPos < 0)
dotPos = name.Len();
_before = name.Left(dotPos);
@@ -798,11 +834,11 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data)
{
wchar_t sz[16];
char sz[16];
ConvertUInt32ToString(xml.VolIndex, sz);
xml.FileName = L'[';
xml.FileName += sz;
xml.FileName += L"].xml";
xml.FileName.AddAscii(sz);
xml.FileName.AddAscii("].xml");
_xmls.Add(xml);
}
@@ -957,11 +993,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
int streamIndex = item.StreamIndex;
if (streamIndex < 0)
{
if (!testMode && !realOutStream)
continue;
if (!item.IsDir)
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(_db.ItemHasStream(item) ?
RINOK(extractCallback->SetOperationResult(!item.IsDir && _db.ItemHasStream(item) ?
NExtract::NOperationResult::kDataError :
NExtract::NOperationResult::kOK));
continue;
@@ -1016,7 +1053,7 @@ CHandler::CHandler()
_xmlError = false;
}
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
InitDefaults();

View File

@@ -70,7 +70,7 @@ public:
INTERFACE_IInArchive(;)
INTERFACE_IArchiveGetRawProps(;)
INTERFACE_IArchiveGetRootProps(;)
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
STDMETHOD(KeepModeForNextOpen)();
INTERFACE_IOutArchive(;)
};

View File

@@ -21,7 +21,7 @@
#include "../../Common/UniqBlocks.h"
#include "../../Crypto/RandGen.h"
#include "../../Crypto/Sha1.h"
#include "../../Crypto/Sha1Cls.h"
#include "WimHandler.h"
@@ -676,6 +676,8 @@ static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaI
trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri);
}
#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
@@ -789,7 +791,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
unsigned imageIndex = (unsigned)val - 1;
if (imageIndex < _db.Images.Size())
isChangedImage[imageIndex] = true;
if (_defaultImageNumber > 0 && val != _defaultImageNumber)
if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber)
return E_INVALIDARG;
}
}
@@ -1065,9 +1067,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
int colonPos = fileName.Find(L':');
if (colonPos < 0)
return E_INVALIDARG;
// we want to support cases of c::substream, where c: is drive name
if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0]))
colonPos = 2;
const UString mainName = fileName.Left(colonPos);
unsigned indexOfDir;
if (curItem->FindDir(db.MetaItems, mainName, indexOfDir))
if (mainName.IsEmpty())
ui.MetaIndex = curItem->MetaIndex;
else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir))
ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex;
else
{
@@ -1082,6 +1091,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
}
}
}
if (ui.MetaIndex >= 0)
{
CAltStream ss;
@@ -1126,7 +1136,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
NCOM::CPropVariant prop;
RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop));
if (prop.vt == VT_BSTR)
mi.ShortName = prop.bstrVal;
mi.ShortName.SetFromBstr(prop.bstrVal);
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
}
@@ -1235,7 +1245,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
const CItem &item = _db.Items[k];
if (item.StreamIndex >= 0)
streamsRefs[item.StreamIndex]++;
streamsRefs[(unsigned)item.StreamIndex]++;
}
}
@@ -1250,7 +1260,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
continue;
const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
if (item.StreamIndex >= 0)
streamsRefs[item.StreamIndex]++;
streamsRefs[(unsigned)item.StreamIndex]++;
}
else
{
@@ -1614,7 +1624,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
db.DefaultDirItem = ri;
pos += db.WriteTree_Dummy(tree);
CByteBuffer meta(pos);
CByteArr meta(pos);
Set32((Byte *)meta + 4, secBufs.Size()); // num security entries
pos = kSecuritySize;
@@ -1637,8 +1647,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
{
const CByteBuffer &buf = secBufs[i];
size_t size = buf.Size();
memcpy(meta + pos, buf, size);
pos += size;
if (size != 0)
{
memcpy(meta + pos, buf, size);
pos += size;
}
}
while ((pos & 7) != 0)
meta[pos++] = 0;
@@ -1740,15 +1753,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu
size_t xmlSize;
{
UString utf16String;
if (!ConvertUTF8ToUnicode(xml, utf16String))
UString utf16;
if (!ConvertUTF8ToUnicode(xml, utf16))
return S_FALSE;
xmlSize = (utf16String.Len() + 1) * 2;
xmlSize = (utf16.Len() + 1) * 2;
CByteBuffer xmlBuf(xmlSize);
CByteArr xmlBuf(xmlSize);
Set16((Byte *)xmlBuf, 0xFEFF);
for (i = 0; i < (unsigned)utf16String.Len(); i++)
Set16((Byte *)xmlBuf + 2 + i * 2, utf16String[i]);
for (i = 0; i < (unsigned)utf16.Len(); i++)
Set16((Byte *)xmlBuf + 2 + i * 2, utf16[i]);
RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize));
}

View File

@@ -325,10 +325,13 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
{
unsigned size = 0;
int index = index1;
unsigned newLevel;
int imageIndex = Items[index].ImageIndex;
const CImage &image = Images[imageIndex];
for (newLevel = 0;;)
unsigned newLevel = 0;
bool needColon = false;
for (;;)
{
const CItem &item = Items[index];
index = item.Parent;
@@ -338,10 +341,11 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
meta += item.IsAltStream ?
(IsOldVersion ? 0x10 : 0x24) :
(IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
needColon = item.IsAltStream;
size += Get16(meta) / 2;
size += newLevel;
newLevel = 1;
if ((UInt32)size >= ((UInt32)1 << 15))
if (size >= ((UInt32)1 << 15))
{
path = kLongPath;
return;
@@ -356,7 +360,9 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
size += image.RootName.Len();
size += newLevel;
}
else if (needColon)
size++;
wchar_t *s = path.AllocBstr(size);
s[size] = 0;
@@ -364,28 +370,31 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
{
MyStringCopy(s, (const wchar_t *)image.RootName);
if (newLevel)
s[image.RootName.Len()] = WCHAR_PATH_SEPARATOR;
s[image.RootName.Len()] = (wchar_t)(needColon ? L':' : WCHAR_PATH_SEPARATOR);
}
else if (needColon)
s[0] = L':';
index = index1;
wchar_t separator = 0;
for (;;)
{
const CItem &item = Items[index];
index = item.Parent;
if (index >= 0 || image.NumEmptyRootItems == 0)
{
if (separator)
if (separator != 0)
s[--size] = separator;
const Byte *meta = image.Meta + item.Offset;
meta += (item.IsAltStream) ?
(IsOldVersion ? 0x10: 0x24) :
(IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
UInt32 len = Get16(meta) / 2;
unsigned len = Get16(meta) / 2;
size -= len;
wchar_t *dest = s + size;
meta += 2;
for (UInt32 i = 0; i < len; i++)
for (unsigned i = 0; i < len; i++)
dest[i] = Get16(meta + i * 2);
}
if (index < 0)
@@ -394,6 +403,14 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
}
}
static bool IsEmptySha(const Byte *data)
{
for (unsigned i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
// Root folders in OLD archives (ver = 1.10) conatin real items.
// Root folders in NEW archives (ver > 1.11) contain only one folder with empty name.
@@ -472,6 +489,8 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
pos += (size_t)len;
unsigned numItems2 = Items.Size();
for (UInt32 i = 0; i < numAltStreams; i++)
{
size_t rem = DirSize - pos;
@@ -522,7 +541,13 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
return S_FALSE;
}
if (fileNameLen == 0)
/* wim uses alt sreams list, if there is at least one alt stream.
And alt stream without name is main stream. */
if (fileNameLen == 0 &&
(attrib & FILE_ATTRIBUTE_REPARSE_POINT
|| !item.IsDir /* && (IsOldVersion || IsEmptySha(prevMeta + 0x40)) */ ))
{
Byte *prevMeta = DirData + item.Offset;
if (IsOldVersion)
@@ -546,7 +571,7 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir)
{
CImage &image = Images.Back();
image.NumEmptyRootItems = Items.Size() - image.StartItem;
image.NumEmptyRootItems = numItems2 - image.StartItem; // Items.Size()
}
if (item.IsDir && subdirOffset != 0)
@@ -732,14 +757,6 @@ static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
return (i == offsetBuf.Size()) ? S_OK : S_FALSE;
}
static bool IsEmptySha(const Byte *data)
{
for (unsigned i = 0; i < kHashSize; i++)
if (data[i] != 0)
return false;
return true;
}
HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml)
{
return UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL);
@@ -1046,7 +1063,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
SortedItems.Clear();
VirtualRoots.Clear();
IndexOfUserImage = imageIndex;
NumExludededItems = 0;
NumExcludededItems = 0;
ExludedItem = -1;
if (Images.Size() != 1 && imageIndex < 0)
@@ -1054,6 +1071,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
unsigned startItem = 0;
unsigned endItem = 0;
if (imageIndex < 0)
{
endItem = Items.Size();
@@ -1062,7 +1080,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
IndexOfUserImage = 0;
const CImage &image = Images[0];
if (!showImageNumber)
NumExludededItems = image.NumEmptyRootItems;
NumExcludededItems = image.NumEmptyRootItems;
}
}
else if ((unsigned)imageIndex < Images.Size())
@@ -1071,12 +1089,13 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
startItem = image.StartItem;
endItem = startItem + image.NumItems;
if (!showImageNumber)
NumExludededItems = image.NumEmptyRootItems;
NumExcludededItems = image.NumEmptyRootItems;
}
if (NumExludededItems != 0)
if (NumExcludededItems != 0)
{
ExludedItem = startItem;
startItem += NumExludededItems;
startItem += NumExcludededItems;
}
unsigned num = endItem - startItem;
@@ -1205,7 +1224,8 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes,
Byte *dest = (Byte *)reparse;
SetUi32(dest, tag);
SetUi32(dest + 4, (UInt32)buf.Size());
memcpy(dest + 8, buf, buf.Size());
if (buf.Size() != 0)
memcpy(dest + 8, buf, buf.Size());
ItemToReparse[i] = ReparseItems.Size() - 1;
}
@@ -1278,20 +1298,28 @@ void CWimXml::ToUnicode(UString &s)
const Byte *p = Data;
if (Get16(p) != 0xFEFF)
return;
wchar_t *chars = s.GetBuffer((unsigned)size / 2);
wchar_t *chars = s.GetBuf((unsigned)(size / 2));
for (size_t i = 2; i < size; i += 2)
*chars++ = (wchar_t)Get16(p + i);
{
wchar_t c = Get16(p + i);
if (c == 0)
break;
*chars++ = c;
}
*chars = 0;
s.ReleaseBuffer();
s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s));
}
bool CWimXml::Parse()
{
UString s;
ToUnicode(s);
AString utf;
if (!ConvertUnicodeToUTF8(s, utf))
return false;
{
UString s;
ToUnicode(s);
// if (!ConvertUnicodeToUTF8(s, utf)) return false;
ConvertUnicodeToUTF8(s, utf);
}
if (!Xml.Parse(utf))
return false;
if (Xml.Root.Name != "WIM")

View File

@@ -406,7 +406,7 @@ public:
CUIntVector SortedItems;
int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items
unsigned NumExludededItems;
unsigned NumExcludededItems;
int ExludedItem; // -1 : if there are no exclude items
CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives
@@ -418,7 +418,7 @@ public:
return 0;
if (imageIndex >= Images.Size())
return 0;
return Images[imageIndex].NumItems - NumExludededItems;
return Images[imageIndex].NumItems - NumExcludededItems;
}
bool ItemHasStream(const CItem &item) const;

View File

@@ -9,19 +9,14 @@
namespace NArchive {
namespace NWim {
IMP_CreateArcIn
IMP_CreateArcOut
static CArcInfo g_ArcInfo =
{ "wim", "wim swm", 0, 0xE6,
8, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 },
REGISTER_ARC_IO(
"wim", "wim swm", 0, 0xE6,
kSignature,
0,
NArcInfoFlags::kAltStreams |
NArcInfoFlags::kNtSecure |
NArcInfoFlags::kSymLinks |
NArcInfoFlags::kHardLinks
, REF_CreateArc_Pair };
REGISTER_ARC(Wim)
, NULL)
}}