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

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/NtfsHandler.cpp')
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp652
1 files changed, 349 insertions, 303 deletions
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index 6661492f..ee630a66 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -22,6 +22,7 @@
#include "../Common/MethodProps.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
@@ -62,6 +63,7 @@ static const wchar_t *kVirtualFolder_Lost_Deleted = L"[UNKNOWN]";
static const unsigned kNumSysRecs = 16;
static const unsigned kRecIndex_Volume = 3;
+static const unsigned kRecIndex_RootDir = 5;
static const unsigned kRecIndex_BadClus = 8;
static const unsigned kRecIndex_Security = 9;
@@ -198,10 +200,18 @@ enum
DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
};
-static const Byte kFileNameType_Posix = 0;
-static const Byte kFileNameType_Win32 = 1;
-static const Byte kFileNameType_Dos = 2;
-static const Byte kFileNameType_Win32Dos = 3;
+
+/* WinXP-64:
+ Probably only one short name (dos name) per record is allowed.
+ There are no short names for hard links.
+ The pair (Win32,Dos) can be in any order.
+ Posix name can be after or before Win32 name
+*/
+
+static const Byte kFileNameType_Posix = 0; // for hard links
+static const Byte kFileNameType_Win32 = 1; // after Dos name
+static const Byte kFileNameType_Dos = 2; // short name
+static const Byte kFileNameType_Win32Dos = 3; // short and full name are same
struct CFileNameAttr
{
@@ -215,21 +225,31 @@ struct CFileNameAttr
// UInt64 AllocatedSize;
// UInt64 DataSize;
// UInt16 PackedEaSize;
- UString Name;
+ UString2 Name;
UInt32 Attrib;
Byte NameType;
bool IsDos() const { return NameType == kFileNameType_Dos; }
+ bool IsWin32() const { return (NameType == kFileNameType_Win32); }
+
bool Parse(const Byte *p, unsigned size);
};
-static void GetString(const Byte *p, unsigned len, UString &res)
+static void GetString(const Byte *p, unsigned len, UString2 &res)
{
- wchar_t *s = res.GetBuffer(len);
- for (unsigned i = 0; i < len; i++)
- s[i] = Get16(p + i * 2);
- s[len] = 0;
- res.ReleaseBuffer();
+ if (len == 0 && res.IsEmpty())
+ return;
+ wchar_t *s = res.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c == 0)
+ break;
+ s[i] = c;
+ }
+ s[i] = 0;
+ res.ReleaseBuf_SetLen(i);
}
bool CFileNameAttr::Parse(const Byte *p, unsigned size)
@@ -249,7 +269,8 @@ bool CFileNameAttr::Parse(const Byte *p, unsigned size)
unsigned len = p[0x40];
if (0x42 + len > size)
return false;
- GetString(p + 0x42, len, Name);
+ if (len != 0)
+ GetString(p + 0x42, len, Name);
return true;
}
@@ -321,7 +342,7 @@ struct CAttr
{
UInt32 Type;
// UInt32 Len;
- UString Name;
+ UString2 Name;
// UInt16 Flags;
// UInt16 Instance;
CByteBuffer Data;
@@ -364,7 +385,17 @@ static int CompareAttr(void *const *elem1, void *const *elem2, void *)
const CAttr &a1 = *(*((const CAttr **)elem1));
const CAttr &a2 = *(*((const CAttr **)elem2));
RINOZ(MyCompare(a1.Type, a2.Type));
- RINOZ(wcscmp(a1.Name, a2.Name));
+ if (a1.Name.IsEmpty())
+ {
+ if (!a2.Name.IsEmpty())
+ return -1;
+ }
+ else if (a2.Name.IsEmpty())
+ return 1;
+ else
+ {
+ RINOZ(wcscmp(a1.Name.GetRawPtr(), a2.Name.GetRawPtr()));
+ }
return MyCompare(a1.LowVcn, a2.LowVcn);
}
@@ -387,13 +418,13 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
return 0;
NonResident = p[0x08];
{
- unsigned nameLength = p[9];
+ unsigned nameLen = p[9];
UInt32 nameOffset = Get16(p + 0x0A);
- if (nameLength != 0)
+ if (nameLen != 0)
{
- if (nameOffset + nameLength * 2 > len)
+ if (nameOffset + nameLen * 2 > len)
return 0;
- GetString(p + nameOffset, nameLength, Name);
+ GetString(p + nameOffset, nameLen, Name);
PRF(printf(" N="));
PRF_UTF16(Name);
}
@@ -485,10 +516,11 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
if (num == 0 || num > 8 || num > size)
return false;
- int i;
- UInt64 vSize = p[num - 1];
- for (i = (int)num - 2; i >= 0; i--)
- vSize = (vSize << 8) | p[i];
+ UInt64 vSize = 0;
+ {
+ unsigned i = num;
+ do vSize = (vSize << 8) | p[--i]; while(i);
+ }
if (vSize == 0)
return false;
p += num;
@@ -510,8 +542,10 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
else
{
Int64 v = (signed char)p[num - 1];
- for (i = (int)num - 2; i >= 0; i--)
- v = (v << 8) | p[i];
+ {
+ for (unsigned i = num - 1; i != 0;)
+ v = (v << 8) | p[--i];
+ }
p += num;
size -= num;
lcn += v;
@@ -617,7 +651,7 @@ static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte
{
if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0)
return 0;
- int numDistBits = 4;
+ unsigned numDistBits = 4;
UInt32 sbOffset = 0;
UInt32 pos = 0;
@@ -669,7 +703,7 @@ static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte
STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
- if (processedSize != NULL)
+ if (processedSize)
*processedSize = 0;
if (_virtPos >= Size)
return (Size == _virtPos) ? S_OK: E_FAIL;
@@ -830,7 +864,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
res = Stream->Read(data, size, &size);
_physPos += size;
}
- if (processedSize != NULL)
+ if (processedSize)
*processedSize = size;
_virtPos += size;
_curRem -= size;
@@ -858,54 +892,6 @@ STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPositio
return S_OK;
}
-class CByteBufStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _virtPos;
-public:
- CByteBuffer Buf;
- void Init() { _virtPos = 0; }
-
- MY_UNKNOWN_IMP1(IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize != NULL)
- *processedSize = 0;
- if (_virtPos >= Buf.Size())
- return (_virtPos == Buf.Size()) ? S_OK: E_FAIL;
- UInt64 rem = Buf.Size() - _virtPos;
- if (rem < size)
- size = (UInt32)rem;
- memcpy(data, Buf + (size_t)_virtPos, size);
- if (processedSize != NULL)
- *processedSize = size;
- _virtPos += size;
- return S_OK;
-}
-
-STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += Buf.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;
-}
-
static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs,
unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
{
@@ -966,7 +952,9 @@ struct CMftRec
// UInt16 NextAttrInstance;
CMftRef BaseMftRef;
// UInt32 ThisRecNumber;
+
UInt32 MyNumNameLinks;
+ int MyItemIndex; // index in Items[] of main item for that record, or -1 if there is no item for that record
CObjectVector<CAttr> DataAttrs;
CObjectVector<CFileNameAttr> FileNames;
@@ -977,12 +965,40 @@ struct CMftRec
CByteBuffer ReparseData;
+ int FindWin32Name_for_DosName(unsigned dosNameIndex) const
+ {
+ const CFileNameAttr &cur = FileNames[dosNameIndex];
+ if (cur.IsDos())
+ for (unsigned i = 0; i < FileNames.Size(); i++)
+ {
+ const CFileNameAttr &next = FileNames[i];
+ if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
+ return i;
+ }
+ return -1;
+ }
+
+ int FindDosName(unsigned nameIndex) const
+ {
+ const CFileNameAttr &cur = FileNames[nameIndex];
+ if (cur.IsWin32())
+ for (unsigned i = 0; i < FileNames.Size(); i++)
+ {
+ const CFileNameAttr &next = FileNames[i];
+ if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
+ return i;
+ }
+ return -1;
+ }
+
+ /*
bool IsAltStream(int dataIndex) const
{
return dataIndex >= 0 && (
(IsDir() ||
!DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty()));
}
+ */
void MoveAttrsFrom(CMftRec &src)
{
@@ -1016,7 +1032,7 @@ struct CMftRec
UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
- CMftRec(): MyNumNameLinks(0) {}
+ CMftRec(): MyNumNameLinks(0), MyItemIndex(-1) {}
};
void CMftRec::ParseDataNames()
@@ -1040,12 +1056,10 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
{
*destStream = 0;
- CByteBufStream *streamSpec = new CByteBufStream;
+ CBufferInStream *streamSpec = new CBufferInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
- if (dataIndex < 0)
- return E_FAIL;
-
+ if (dataIndex >= 0)
if ((unsigned)dataIndex < DataRefs.Size())
{
const CDataRef &ref = DataRefs[dataIndex];
@@ -1231,26 +1245,42 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r
return true;
}
+/*
+ NTFS probably creates empty DATA_ATTRIBUTE for empty file,
+ But it doesn't do it for
+ $Secure (:$SDS),
+ $Extend\$Quota
+ $Extend\$ObjId
+ $Extend\$Reparse
+*/
+
+static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream
+static const int k_Item_DataIndex_IsDir = -2;
+
+// static const int k_ParentFolderIndex_Root = -1;
+static const int k_ParentFolderIndex_Lost = -2;
+static const int k_ParentFolderIndex_Deleted = -3;
+
struct CItem
{
unsigned RecIndex; // index in Recs array
unsigned NameIndex; // index in CMftRec::FileNames
int DataIndex; /* index in CMftRec::DataRefs
- -1: for folders
- -1: for files that have no DATA_ATRIBUTE */
+ -1: file without unnamed data stream
+ -2: for directories */
int ParentFolder; /* index in Items array
-1: for root items
-2: [LOST] folder
-3: [UNKNOWN] folder (deleted lost) */
int ParentHost; /* index in Items array, if it's AltStream
- -1: if it's not AltStream
- -1: if there is no Host item */
+ -1: if it's not AltStream */
- CItem(): DataIndex(-1), ParentFolder(-1), ParentHost(-1) {}
+ CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {}
- bool IsDir() const { return DataIndex < 0; }
+ bool IsAltStream() const { return ParentHost != -1; }
+ bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; }
// check it !!!
// probably NTFS for empty file still creates empty DATA_ATTRIBUTE
// But it doesn't do it for $Secure:$SDS
@@ -1276,7 +1306,9 @@ struct CDatabase
bool _showSystemFiles;
bool _showDeletedFiles;
- UStringVector VirtFolderNames;
+ CObjectVector<UString2> VirtFolderNames;
+ UString EmptyString;
+
int _systemFolderIndex;
int _lostFolderIndex_Normal;
int _lostFolderIndex_Deleted;
@@ -1311,6 +1343,8 @@ struct CDatabase
const CMftRec &rec = Recs[(unsigned)recIndex];
if (!rec.IsDir())
return -1;
+ return rec.MyItemIndex;
+ /*
unsigned left = 0, right = Items.Size();
while (left != right)
{
@@ -1319,9 +1353,9 @@ struct CDatabase
UInt64 midValue = item.RecIndex;
if (recIndex == midValue)
{
- // if (!item.IsAltStream)
- // if (!rec.IsAltStream(item.DataIndex))
- if (item.DataIndex < 0)
+ // if item is not dir (file or alt stream we don't return it)
+ // if (item.DataIndex < 0)
+ if (item.IsDir())
return mid;
right = mid;
}
@@ -1331,6 +1365,7 @@ struct CDatabase
left = mid + 1;
}
return -1;
+ */
}
bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const;
@@ -1374,8 +1409,6 @@ void CDatabase::ClearAndClose()
InStream.Release();
}
-#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR
-
void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
{
const CItem *item = &Items[index];
@@ -1383,22 +1416,24 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
const CMftRec &rec = Recs[item->RecIndex];
size += rec.FileNames[item->NameIndex].Name.Len();
- bool isAltStream = rec.IsAltStream(item->DataIndex);
+ bool isAltStream = item->IsAltStream();
+
if (isAltStream)
{
const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start];
+ if (item->RecIndex == kRecIndex_RootDir)
+ {
+ wchar_t *s = path.AllocBstr(data.Name.Len() + 1);
+ s[0] = L':';
+ if (!data.Name.IsEmpty())
+ MyStringCopy(s + 1, data.Name.GetRawPtr());
+ return;
+ }
+
size += data.Name.Len();
size++;
}
- /*
- if (item->ParentHost >= 0)
- {
- item = &Items[item->ParentHost];
- size += item->Name.Len() + 1;
- }
- */
-
for (unsigned i = 0;; i++)
{
if (i > 256)
@@ -1407,7 +1442,8 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
return;
}
const wchar_t *servName;
- if (item->RecIndex < kNumSysRecs)
+ if (item->RecIndex < kNumSysRecs
+ /* && item->RecIndex != kRecIndex_RootDir */)
servName = kVirtualFolder_System;
else
{
@@ -1420,7 +1456,7 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
}
if (index2 == -1)
break;
- servName = (index2 == -2) ?
+ servName = (index2 == k_ParentFolderIndex_Lost) ?
kVirtualFolder_Lost_Normal :
kVirtualFolder_Lost_Deleted;
}
@@ -1435,47 +1471,31 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
bool needColon = false;
if (isAltStream)
{
- const UString &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name;
- size -= name.Len();
- MyStringCopy(s + size, (const wchar_t *)name);
+ const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name;
+ if (!name.IsEmpty())
+ {
+ size -= name.Len();
+ MyStringCopy(s + size, name.GetRawPtr());
+ }
s[--size] = ':';
needColon = true;
}
{
- const UString &name = rec.FileNames[item->NameIndex].Name;
+ const UString2 &name = rec.FileNames[item->NameIndex].Name;
unsigned len = name.Len();
- MyStringCopy(s + size - len, (const wchar_t *)name);
+ if (len != 0)
+ MyStringCopy(s + size - len, name.GetRawPtr());
if (needColon)
s[size] = ':';
size -= len;
}
- /*
- {
- unsigned len = item->Name.Len();
- size -= len;
- MyStringCopy(s + size, (const wchar_t *)item->Name);
- }
- */
-
-
- /*
- if (item->ParentHost >= 0)
- {
- item = &Items[item->ParentHost];
- unsigned len = item->Name.Len();
- size--;
- size -= len;
- MyStringCopy(s + size, (const wchar_t *)item->Name);
- s[size + len] = ':';
- }
- */
-
for (;;)
{
const wchar_t *servName;
- if (item->RecIndex < kNumSysRecs)
+ if (item->RecIndex < kNumSysRecs
+ /* && && item->RecIndex != kRecIndex_RootDir */)
servName = kVirtualFolder_System;
else
{
@@ -1483,17 +1503,20 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
if (index2 >= 0)
{
item = &Items[index2];
- const UString &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name;
+ const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name;
unsigned len = name.Len();
size--;
- size -= len;
- MyStringCopy(s + size, (const wchar_t *)name);
+ if (len != 0)
+ {
+ size -= len;
+ MyStringCopy(s + size, name.GetRawPtr());
+ }
s[size + len] = WCHAR_PATH_SEPARATOR;
continue;
}
if (index2 == -1)
break;
- servName = (index2 == -2) ?
+ servName = (index2 == k_ParentFolderIndex_Lost) ?
kVirtualFolder_Lost_Normal :
kVirtualFolder_Lost_Deleted;
}
@@ -1800,120 +1823,110 @@ HRESULT CDatabase::Open()
if (!rec.InUse() && !_showDeletedFiles)
continue;
- unsigned numNames = 0;
+ rec.MyNumNameLinks = rec.FileNames.Size();
+
// printf("\n%4d: ", i);
- FOR_VECTOR (t, rec.FileNames)
- {
- const CFileNameAttr &fna = rec.FileNames[t];
- // PRF(printf("%4d ", (int)fna.NameType));
- // PRF_UTF16(fna.Name)
- // PRF(printf(" | "));
- if (fna.IsDos())
- continue;
- unsigned numDatas = rec.DataRefs.Size();
-
- /*
- // we can use that code to reduce the number of alt streams
- // For hard linked files we show alt streams only for first Name.
- if (numDatas > 1 && numNames > 0)
- numDatas = 1;
- */
+
+ /* Actually DataAttrs / DataRefs are sorted by name.
+ It can not be more than one unnamed stream in DataRefs
+ And indexOfUnnamedStream <= 0.
+ */
- numNames++;
+ int indexOfUnnamedStream = -1;
+ if (!rec.IsDir())
+ {
+ FOR_VECTOR(di, rec.DataRefs)
+ if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty())
+ {
+ indexOfUnnamedStream = di;
+ break;
+ }
+ }
- // here we suppose that first stream is main stream (unnamed stream).
- // IS IT SO ????
- int hostIndex = -1;
- if (rec.IsDir())
+ if (rec.FileNames.IsEmpty())
+ {
+ bool needShow = true;
+ if (i < kNumSysRecs)
{
- CItem item;
- item.NameIndex = t;
- item.RecIndex = i;
- // item.ParentRef = fna.ParentDirRef;
- // item.Attrib = rec.SiAttr.Attrib | 0x10;
- // item.Attrib = fna.Attrib;
- hostIndex = Items.Add(item);
+ needShow = false;
+ FOR_VECTOR(di, rec.DataRefs)
+ if (rec.GetSize(di) != 0)
+ {
+ needShow = true;
+ break;
+ }
}
- else
+ if (needShow)
{
-
- // probably NTFS for empty file still creates empty DATA_ATTRIBUTE
- // But it doesn't do it for $Secure:$SDS
- if (rec.DataRefs.IsEmpty() ||
- !rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty())
- {
- CItem item;
- item.NameIndex = t;
- item.RecIndex = i;
- // item.ParentRef = fna.ParentDirRef;
- // item.Attrib = rec.SiAttr.Attrib;
- hostIndex = Items.Add(item);
- }
+ CFileNameAttr &fna = rec.FileNames.AddNew();
+ // we set incorrect ParentDirRef, that will place item to [LOST] folder
+ fna.ParentDirRef.Val = (UInt64)(Int64)-1;
+ char s[16 + 16];
+ ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-"));
+ fna.Name.SetFromAscii(s);
+ fna.NameType = kFileNameType_Win32Dos;
+ fna.Attrib = 0;
}
+ }
+
+ // bool isMainName = true;
+
+ FOR_VECTOR (t, rec.FileNames)
+ {
+ #ifdef SHOW_DEBUG_INFO
+ const CFileNameAttr &fna = rec.FileNames[t];
+ #endif
+ PRF(printf("\n %4d ", (int)fna.NameType));
+ PRF_UTF16(fna.Name);
+ // PRF(printf(" | "));
+ if (rec.FindWin32Name_for_DosName(t) >= 0)
{
- bool isThereUnNamedStream = false;
- for (unsigned di = 0; di < numDatas; di++)
- {
- const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
- if (subName.IsEmpty())
- isThereUnNamedStream = true;
- }
- if (!rec.IsDir() && !isThereUnNamedStream)
- {
- // return S_FALSE;
- }
+ rec.MyNumNameLinks--;
+ continue;
}
+
+ CItem item;
+ item.NameIndex = t;
+ item.RecIndex = i;
+ item.DataIndex = rec.IsDir() ?
+ k_Item_DataIndex_IsDir :
+ (indexOfUnnamedStream < 0 ?
+ k_Item_DataIndex_IsEmptyFile :
+ indexOfUnnamedStream);
+
+ if (rec.MyItemIndex < 0)
+ rec.MyItemIndex = Items.Size();
+ item.ParentHost = Items.Add(item);
+
+ /* we can use that code to reduce the number of alt streams:
+ it will not show how alt streams for hard links. */
+ // if (!isMainName) continue; isMainName = false;
+
+ unsigned numAltStreams = 0;
- for (unsigned di = 0; di < numDatas; di++)
+ FOR_VECTOR(di, rec.DataRefs)
{
- CItem item;
- item.NameIndex = t;
- // item.FileNameAttr = fna;
- // item.Name = fna.Name;
- // item.Attrib = rec.SiAttr.Attrib;
- const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
- if (subName.IsEmpty())
- {
- if (hostIndex >= 0)
- continue;
- hostIndex = Items.Size();
- }
- else
+ if (!rec.IsDir() && (int)di == indexOfUnnamedStream)
+ continue;
+
+ const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
+
+ PRF(printf("\n alt stream: "));
+ PRF_UTF16(subName);
+
{
// $BadClus:$Bad is sparse file for all clusters. So we skip it.
if (i == kRecIndex_BadClus && subName == L"$Bad")
continue;
- if (hostIndex >= 0)
- {
- // item.Name = subName;
- }
- else
- {
- // there is no host file for some streams
- // return E_FAIL;
- // item.Name += L":";
- // item.Name += subName;
- }
- // item.Attrib = fna.Attrib;
- item.ParentHost = hostIndex;
- // item.IsAltStream = true;
- ThereAreAltStreams = true;
}
-
- PRF(printf("\n%3d", i));
- PRF(printf(" attrib=%2x ", rec.SiAttr.Attrib));
- // PRF_UTF16(item.Name);
-
- item.RecIndex = i;
- item.DataIndex = di;
- // item.ParentRef = fna.ParentDirRef;
+ numAltStreams++;
+ ThereAreAltStreams = true;
+ item.DataIndex = di;
Items.Add(item);
- rec.MyNumNameLinks++;
}
}
- // rec.FileNames.ClearAndFree();
}
if (Recs.Size() > kRecIndex_Security)
@@ -1959,7 +1972,7 @@ HRESULT CDatabase::Open()
const CFileNameAttr &fn = rec.FileNames[item.NameIndex];
const CMftRef &parentDirRef = fn.ParentDirRef;
UInt64 refIndex = parentDirRef.GetIndex();
- if (refIndex == 5)
+ if (refIndex == kRecIndex_RootDir)
item.ParentFolder = -1;
else
{
@@ -1970,12 +1983,12 @@ HRESULT CDatabase::Open()
if (Recs[item.RecIndex].InUse())
{
thereAreUnknownFolders_Normal = true;
- index = -2;
+ index = k_ParentFolderIndex_Lost;
}
else
{
thereAreUnknownFolders_Deleted = true;
- index = -3;
+ index = k_ParentFolderIndex_Deleted;
}
}
item.ParentFolder = index;
@@ -2019,7 +2032,7 @@ public:
INTERFACE_IInArchive(;)
INTERFACE_IArchiveGetRawProps(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
- STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
+ STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
};
STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
@@ -2038,29 +2051,30 @@ STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)
STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)
{
*parentType = NParentType::kDir;
- *parent = (UInt32)(Int32)-1;
+ int par = -1;
- if (index >= Items.Size())
- return S_OK;
- const CItem &item = Items[index];
-
- if (item.ParentHost >= 0)
- {
- *parentType = NParentType::kAltStream;
- *parent = (UInt32)(Int32)item.ParentHost;
- return S_OK;
- }
- if (item.RecIndex < kNumSysRecs)
+ if (index < Items.Size())
{
- if (_showSystemFiles)
- *parent = _systemFolderIndex;
- }
- else if (item.ParentFolder >= 0)
- *parent = item.ParentFolder;
- else if (item.ParentFolder == -2)
- *parent = _lostFolderIndex_Normal;
- else if (item.ParentFolder == -3)
- *parent = _lostFolderIndex_Deleted;
+ const CItem &item = Items[index];
+
+ if (item.ParentHost >= 0)
+ {
+ *parentType = NParentType::kAltStream;
+ par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost);
+ }
+ else if (item.RecIndex < kNumSysRecs)
+ {
+ if (_showSystemFiles)
+ par = _systemFolderIndex;
+ }
+ else if (item.ParentFolder >= 0)
+ par = item.ParentFolder;
+ else if (item.ParentFolder == k_ParentFolderIndex_Lost)
+ par = _lostFolderIndex_Normal;
+ else if (item.ParentFolder == k_ParentFolderIndex_Deleted)
+ par = _lostFolderIndex_Deleted;
+ }
+ *parent = (UInt32)(Int32)par;
return S_OK;
}
@@ -2073,30 +2087,22 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
if (propID == kpidName)
{
#ifdef MY_CPU_LE
- const UString *s;
+ const UString2 *s;
if (index >= Items.Size())
s = &VirtFolderNames[index - Items.Size()];
else
{
const CItem &item = Items[index];
const CMftRec &rec = Recs[item.RecIndex];
-
- // fix it for no HOST case !!
- // if (item.IsAltStream && item.DataIndex >= 0)
- if (rec.IsAltStream(item.DataIndex))
- {
- if (item.ParentHost < 0)
- return S_OK;
- const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
- s = &data.Name;
- }
+ if (item.IsAltStream())
+ s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
else
- {
s = &rec.FileNames[item.NameIndex].Name;
- }
- // s = &item.Name;
}
- *data = (const wchar_t *)*s;
+ if (s->IsEmpty())
+ *data = (const wchar_t *)EmptyString;
+ else
+ *data = s->GetRawPtr();
*dataSize = (s->Len() + 1) * sizeof(wchar_t);
*propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE;
#endif
@@ -2209,6 +2215,9 @@ static const Byte kProps[] =
kpidLinks,
kpidINode,
kpidNumBlocks,
+ kpidNumAltStreams,
+ kpidIsAltStream,
+ kpidShortName,
kpidIsDeleted
};
@@ -2293,9 +2302,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
const CAttr &attr = VolAttrs[i];
if (attr.Type == ATTR_TYPE_VOLUME_NAME)
{
- UString name;
+ UString2 name;
GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name);
- prop = name;
+ if (!name.IsEmpty())
+ prop = name.GetRawPtr();
break;
}
}
@@ -2312,7 +2322,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
CVolInfo vi;
if (attr.ParseVolInfo(vi))
{
- s += ' ';
+ s.Add_Space();
char temp[16];
ConvertUInt32ToString(vi.MajorVer, temp);
s += temp;
@@ -2339,6 +2349,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidWarning:
if (_lostFolderIndex_Normal >= 0)
prop = "There are lost files";
+ break;
/*
case kpidWarningFlags:
@@ -2372,7 +2383,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
case kpidName:
case kpidPath:
- prop = VirtFolderNames[index - Items.Size()];
+ prop = VirtFolderNames[index - Items.Size()].GetRawPtr();
break;
case kpidIsDir: prop = true; break;
case kpidIsAux: prop = true; break;
@@ -2433,35 +2444,46 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = item.RecIndex;
break;
}
+ case kpidStreamId:
+ {
+ if (item.DataIndex >= 0)
+ prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex;
+ break;
+ }
case kpidName:
{
- // prop = item.Name;
- const UString *s;
- if (rec.IsAltStream(item.DataIndex))
+ const UString2 *s;
+ if (item.IsAltStream())
+ s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
+ else
+ s = &rec.FileNames[item.NameIndex].Name;
+ if (s->IsEmpty())
+ prop = (const wchar_t *)EmptyString;
+ else
+ prop = s->GetRawPtr();
+ break;
+ }
+
+ case kpidShortName:
+ {
+ if (!item.IsAltStream())
{
- const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
- s = &data.Name;
- if (item.ParentHost < 0)
+ int dosNameIndex = rec.FindDosName(item.NameIndex);
+ if (dosNameIndex >= 0)
{
- UString s2 = rec.FileNames[item.NameIndex].Name;
- s2 += L':';
- s2 += *s;
- prop = s2;
- break;
+ const UString2 &s = rec.FileNames[dosNameIndex].Name;
+ if (s.IsEmpty())
+ prop = (const wchar_t *)EmptyString;
+ else
+ prop = s.GetRawPtr();
}
}
- else
- {
- s = &rec.FileNames[item.NameIndex].Name;
- }
- prop = *s;
-
break;
}
case kpidIsDir: prop = item.IsDir(); break;
- case kpidIsAltStream: prop = rec.IsAltStream(item.DataIndex); break;
+ case kpidIsAltStream: prop = item.IsAltStream(); break;
case kpidIsDeleted: prop = !rec.InUse(); break;
case kpidIsAux: prop = false; break;
@@ -2491,12 +2513,35 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.IsDir())
attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ /* some system entries can contain extra flags (Index View).
+ // 0x10000000 (Directory)
+ // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View)
+ But we don't need them */
+ attrib &= 0xFFFF;
+
prop = attrib;
break;
}
- case kpidLinks: prop = rec.MyNumNameLinks; break;
- case kpidSize: if (data) prop = data->GetSize(); break;
- case kpidPackSize: if (data) prop = data->GetPackSize(); break;
+ case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break;
+
+ case kpidNumAltStreams:
+ {
+ if (!item.IsAltStream())
+ {
+ unsigned num = rec.DataRefs.Size();
+ if (num > 0)
+ {
+ if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty())
+ num--;
+ if (num > 0)
+ prop = num;
+ }
+ }
+ break;
+ }
+
+ case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
+ case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
}
prop.Detach(value);
@@ -2603,7 +2648,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->Init();
const CMftRec &rec = Recs[item.RecIndex];
- const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
int res = NExtract::NOperationResult::kDataError;
{
@@ -2626,8 +2670,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
}
}
- totalPackSize += data.GetPackSize();
- totalSize += data.GetSize();
+ if (item.DataIndex >= 0)
+ {
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+ totalPackSize += data.GetPackSize();
+ totalSize += data.GetSize();
+ }
outStreamSpec->ReleaseStream();
RINOK(extractCallback->SetOperationResult(res));
}
@@ -2641,7 +2689,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-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)
{
InitProps();
@@ -2668,15 +2716,13 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v
return S_OK;
}
-IMP_CreateArcIn
+static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
-static CArcInfo g_ArcInfo =
- { "NTFS", "ntfs img", 0, 0xD9,
- 9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 },
+REGISTER_ARC_I(
+ "NTFS", "ntfs img", 0, 0xD9,
+ k_Signature,
3,
0,
- CreateArc };
-
-REGISTER_ARC(Ntfs)
+ NULL)
}}