diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-06-15 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:54 +0300 |
commit | 54490d51d5c6b0d794dcbad2d634d4c95fc25b6c (patch) | |
tree | c3c413656432c0ef87b2841c80e42b55ad17d4e8 /CPP/7zip/Archive/Wim | |
parent | 0713a3ab803e57401f18432148b4139e5fe6e5dd (diff) |
15.0515.05
Diffstat (limited to 'CPP/7zip/Archive/Wim')
-rw-r--r-- | CPP/7zip/Archive/Wim/WimHandler.cpp | 67 | ||||
-rw-r--r-- | CPP/7zip/Archive/Wim/WimHandler.h | 2 | ||||
-rw-r--r-- | CPP/7zip/Archive/Wim/WimHandlerOut.cpp | 43 | ||||
-rw-r--r-- | CPP/7zip/Archive/Wim/WimIn.cpp | 90 | ||||
-rw-r--r-- | CPP/7zip/Archive/Wim/WimIn.h | 4 | ||||
-rw-r--r-- | CPP/7zip/Archive/Wim/WimRegister.cpp | 13 |
6 files changed, 146 insertions, 73 deletions
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 886d8d77..bca551a6 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -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(); diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 416e11ca..00de1b87 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -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(;) }; diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 149989d1..145ede42 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -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)); } diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index cec037cc..12b8525c 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -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") diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index 4b7c6d95..c3b93a8d 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -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; diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 35d78314..3063dec4 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -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) }} |