xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/NtfsHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // NtfsHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO
6*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO2
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2)
9*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
10*f6dc9357SAndroid Build Coastguard Worker #endif
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyCom.h"
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #include "../Common/MethodProps.h"
23*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker #include "Common/DummyOutStream.h"
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
33*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) x
34*f6dc9357SAndroid Build Coastguard Worker #define PRF_UTF16(x) PRF(printf("%S", x))
35*f6dc9357SAndroid Build Coastguard Worker #else
36*f6dc9357SAndroid Build Coastguard Worker #define PRF(x)
37*f6dc9357SAndroid Build Coastguard Worker #define PRF_UTF16(x)
38*f6dc9357SAndroid Build Coastguard Worker #endif
39*f6dc9357SAndroid Build Coastguard Worker 
40*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO2
41*f6dc9357SAndroid Build Coastguard Worker #define PRF2(x) x
42*f6dc9357SAndroid Build Coastguard Worker #else
43*f6dc9357SAndroid Build Coastguard Worker #define PRF2(x)
44*f6dc9357SAndroid Build Coastguard Worker #endif
45*f6dc9357SAndroid Build Coastguard Worker 
46*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
47*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
48*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
49*f6dc9357SAndroid Build Coastguard Worker 
50*f6dc9357SAndroid Build Coastguard Worker #define G16(p, dest) dest = Get16(p)
51*f6dc9357SAndroid Build Coastguard Worker #define G32(p, dest) dest = Get32(p)
52*f6dc9357SAndroid Build Coastguard Worker #define G64(p, dest) dest = Get64(p)
53*f6dc9357SAndroid Build Coastguard Worker 
54*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
57*f6dc9357SAndroid Build Coastguard Worker namespace Ntfs {
58*f6dc9357SAndroid Build Coastguard Worker 
59*f6dc9357SAndroid Build Coastguard Worker static const wchar_t * const kVirtualFolder_System = L"[SYSTEM]";
60*f6dc9357SAndroid Build Coastguard Worker static const wchar_t * const kVirtualFolder_Lost_Normal = L"[LOST]";
61*f6dc9357SAndroid Build Coastguard Worker static const wchar_t * const kVirtualFolder_Lost_Deleted = L"[UNKNOWN]";
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumSysRecs = 16;
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker static const unsigned kRecIndex_Volume    = 3;
66*f6dc9357SAndroid Build Coastguard Worker static const unsigned kRecIndex_RootDir   = 5;
67*f6dc9357SAndroid Build Coastguard Worker static const unsigned kRecIndex_BadClus   = 8;
68*f6dc9357SAndroid Build Coastguard Worker static const unsigned kRecIndex_Security  = 9;
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker struct CHeader
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker   unsigned SectorSizeLog;
73*f6dc9357SAndroid Build Coastguard Worker   unsigned ClusterSizeLog;
74*f6dc9357SAndroid Build Coastguard Worker   unsigned MftRecordSizeLog;
75*f6dc9357SAndroid Build Coastguard Worker   // Byte MediaType;
76*f6dc9357SAndroid Build Coastguard Worker   // UInt32 NumHiddenSectors;
77*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumSectors;
78*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumClusters;
79*f6dc9357SAndroid Build Coastguard Worker   UInt64 MftCluster;
80*f6dc9357SAndroid Build Coastguard Worker   UInt64 SerialNumber;
81*f6dc9357SAndroid Build Coastguard Worker   // UInt16 SectorsPerTrack;
82*f6dc9357SAndroid Build Coastguard Worker   // UInt16 NumHeads;
83*f6dc9357SAndroid Build Coastguard Worker 
GetPhySize_ClustersNArchive::Ntfs::CHeader84*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPhySize_Clusters() const { return NumClusters << ClusterSizeLog; }
GetPhySize_MaxNArchive::Ntfs::CHeader85*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPhySize_Max() const { return (NumSectors + 1) << SectorSizeLog; }
ClusterSizeNArchive::Ntfs::CHeader86*f6dc9357SAndroid Build Coastguard Worker   UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
87*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
88*f6dc9357SAndroid Build Coastguard Worker };
89*f6dc9357SAndroid Build Coastguard Worker 
GetLog(UInt32 num)90*f6dc9357SAndroid Build Coastguard Worker static int GetLog(UInt32 num)
91*f6dc9357SAndroid Build Coastguard Worker {
92*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 31; i++)
93*f6dc9357SAndroid Build Coastguard Worker     if (((UInt32)1 << i) == num)
94*f6dc9357SAndroid Build Coastguard Worker       return i;
95*f6dc9357SAndroid Build Coastguard Worker   return -1;
96*f6dc9357SAndroid Build Coastguard Worker }
97*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)98*f6dc9357SAndroid Build Coastguard Worker bool CHeader::Parse(const Byte *p)
99*f6dc9357SAndroid Build Coastguard Worker {
100*f6dc9357SAndroid Build Coastguard Worker   if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
101*f6dc9357SAndroid Build Coastguard Worker     return false;
102*f6dc9357SAndroid Build Coastguard Worker 
103*f6dc9357SAndroid Build Coastguard Worker   // int codeOffset = 0;
104*f6dc9357SAndroid Build Coastguard Worker   switch (p[0])
105*f6dc9357SAndroid Build Coastguard Worker   {
106*f6dc9357SAndroid Build Coastguard Worker     case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
107*f6dc9357SAndroid Build Coastguard Worker     case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
108*f6dc9357SAndroid Build Coastguard Worker     default: return false;
109*f6dc9357SAndroid Build Coastguard Worker   }
110*f6dc9357SAndroid Build Coastguard Worker   unsigned sectorsPerClusterLog;
111*f6dc9357SAndroid Build Coastguard Worker 
112*f6dc9357SAndroid Build Coastguard Worker   if (memcmp(p + 3, "NTFS    ", 8) != 0)
113*f6dc9357SAndroid Build Coastguard Worker     return false;
114*f6dc9357SAndroid Build Coastguard Worker   {
115*f6dc9357SAndroid Build Coastguard Worker     {
116*f6dc9357SAndroid Build Coastguard Worker       const int t = GetLog(Get16(p + 11));
117*f6dc9357SAndroid Build Coastguard Worker       if (t < 9 || t > 12)
118*f6dc9357SAndroid Build Coastguard Worker         return false;
119*f6dc9357SAndroid Build Coastguard Worker       SectorSizeLog = (unsigned)t;
120*f6dc9357SAndroid Build Coastguard Worker     }
121*f6dc9357SAndroid Build Coastguard Worker     {
122*f6dc9357SAndroid Build Coastguard Worker       const unsigned v = p[13];
123*f6dc9357SAndroid Build Coastguard Worker       if (v <= 0x80)
124*f6dc9357SAndroid Build Coastguard Worker       {
125*f6dc9357SAndroid Build Coastguard Worker         const int t = GetLog(v);
126*f6dc9357SAndroid Build Coastguard Worker         if (t < 0)
127*f6dc9357SAndroid Build Coastguard Worker           return false;
128*f6dc9357SAndroid Build Coastguard Worker         sectorsPerClusterLog = (unsigned)t;
129*f6dc9357SAndroid Build Coastguard Worker       }
130*f6dc9357SAndroid Build Coastguard Worker       else
131*f6dc9357SAndroid Build Coastguard Worker         sectorsPerClusterLog = 0x100 - v;
132*f6dc9357SAndroid Build Coastguard Worker       ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
133*f6dc9357SAndroid Build Coastguard Worker       if (ClusterSizeLog > 30)
134*f6dc9357SAndroid Build Coastguard Worker         return false;
135*f6dc9357SAndroid Build Coastguard Worker     }
136*f6dc9357SAndroid Build Coastguard Worker   }
137*f6dc9357SAndroid Build Coastguard Worker 
138*f6dc9357SAndroid Build Coastguard Worker   for (int i = 14; i < 21; i++)
139*f6dc9357SAndroid Build Coastguard Worker     if (p[i] != 0)
140*f6dc9357SAndroid Build Coastguard Worker       return false;
141*f6dc9357SAndroid Build Coastguard Worker 
142*f6dc9357SAndroid Build Coastguard Worker   // F8 : a hard disk
143*f6dc9357SAndroid Build Coastguard Worker   // F0 : high-density 3.5-inch floppy disk
144*f6dc9357SAndroid Build Coastguard Worker   if (p[21] != 0xF8) // MediaType = Fixed_Disk
145*f6dc9357SAndroid Build Coastguard Worker     return false;
146*f6dc9357SAndroid Build Coastguard Worker   if (Get16(p + 22) != 0) // NumFatSectors
147*f6dc9357SAndroid Build Coastguard Worker     return false;
148*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 24, SectorsPerTrack); // 63 usually
149*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 26, NumHeads); // 255
150*f6dc9357SAndroid Build Coastguard Worker   // G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?)
151*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 32) != 0) // NumSectors32
152*f6dc9357SAndroid Build Coastguard Worker     return false;
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker   // DriveNumber = p[0x24];
155*f6dc9357SAndroid Build Coastguard Worker   if (p[0x25] != 0) // CurrentHead
156*f6dc9357SAndroid Build Coastguard Worker     return false;
157*f6dc9357SAndroid Build Coastguard Worker   /*
158*f6dc9357SAndroid Build Coastguard Worker   NTFS-HDD:   p[0x26] = 0x80
159*f6dc9357SAndroid Build Coastguard Worker   NTFS-FLASH: p[0x26] = 0
160*f6dc9357SAndroid Build Coastguard Worker   */
161*f6dc9357SAndroid Build Coastguard Worker   if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig
162*f6dc9357SAndroid Build Coastguard Worker     return false;
163*f6dc9357SAndroid Build Coastguard Worker   if (p[0x27] != 0) // reserved
164*f6dc9357SAndroid Build Coastguard Worker     return false;
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker   NumSectors = Get64(p + 0x28);
167*f6dc9357SAndroid Build Coastguard Worker   if (NumSectors >= ((UInt64)1 << (62 - SectorSizeLog)))
168*f6dc9357SAndroid Build Coastguard Worker     return false;
169*f6dc9357SAndroid Build Coastguard Worker 
170*f6dc9357SAndroid Build Coastguard Worker   NumClusters = NumSectors >> sectorsPerClusterLog;
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x30, MftCluster);   // $MFT.
173*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x38, Mft2Cluster);
174*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x48, SerialNumber); // $MFTMirr
175*f6dc9357SAndroid Build Coastguard Worker 
176*f6dc9357SAndroid Build Coastguard Worker   /*
177*f6dc9357SAndroid Build Coastguard Worker     numClusters_per_MftRecord:
178*f6dc9357SAndroid Build Coastguard Worker     numClusters_per_IndexBlock:
179*f6dc9357SAndroid Build Coastguard Worker     only low byte from 4 bytes is used. Another 3 high bytes are zeros.
180*f6dc9357SAndroid Build Coastguard Worker       If the number is positive (number < 0x80),
181*f6dc9357SAndroid Build Coastguard Worker           then it represents the number of clusters.
182*f6dc9357SAndroid Build Coastguard Worker       If the number is negative (number >= 0x80),
183*f6dc9357SAndroid Build Coastguard Worker           then the size of the file record is 2 raised to the absolute value of this number.
184*f6dc9357SAndroid Build Coastguard Worker           example: (0xF6 == -10) means 2^10 = 1024 bytes.
185*f6dc9357SAndroid Build Coastguard Worker   */
186*f6dc9357SAndroid Build Coastguard Worker   {
187*f6dc9357SAndroid Build Coastguard Worker     UInt32 numClusters_per_MftRecord;
188*f6dc9357SAndroid Build Coastguard Worker     G32(p + 0x40, numClusters_per_MftRecord);
189*f6dc9357SAndroid Build Coastguard Worker     if (numClusters_per_MftRecord >= 0x100 || numClusters_per_MftRecord == 0)
190*f6dc9357SAndroid Build Coastguard Worker       return false;
191*f6dc9357SAndroid Build Coastguard Worker     if (numClusters_per_MftRecord < 0x80)
192*f6dc9357SAndroid Build Coastguard Worker     {
193*f6dc9357SAndroid Build Coastguard Worker       const int t = GetLog(numClusters_per_MftRecord);
194*f6dc9357SAndroid Build Coastguard Worker       if (t < 0)
195*f6dc9357SAndroid Build Coastguard Worker         return false;
196*f6dc9357SAndroid Build Coastguard Worker       MftRecordSizeLog = (unsigned)t + ClusterSizeLog;
197*f6dc9357SAndroid Build Coastguard Worker     }
198*f6dc9357SAndroid Build Coastguard Worker     else
199*f6dc9357SAndroid Build Coastguard Worker       MftRecordSizeLog = 0x100 - numClusters_per_MftRecord;
200*f6dc9357SAndroid Build Coastguard Worker     // what exact MFT record sizes are possible and supported by Windows?
201*f6dc9357SAndroid Build Coastguard Worker     // do we need to change this limit here?
202*f6dc9357SAndroid Build Coastguard Worker     const unsigned k_MftRecordSizeLog_MAX = 12;
203*f6dc9357SAndroid Build Coastguard Worker     if (MftRecordSizeLog > k_MftRecordSizeLog_MAX)
204*f6dc9357SAndroid Build Coastguard Worker       return false;
205*f6dc9357SAndroid Build Coastguard Worker     if (MftRecordSizeLog < SectorSizeLog)
206*f6dc9357SAndroid Build Coastguard Worker       return false;
207*f6dc9357SAndroid Build Coastguard Worker   }
208*f6dc9357SAndroid Build Coastguard Worker   {
209*f6dc9357SAndroid Build Coastguard Worker     UInt32 numClusters_per_IndexBlock;
210*f6dc9357SAndroid Build Coastguard Worker     G32(p + 0x44, numClusters_per_IndexBlock);
211*f6dc9357SAndroid Build Coastguard Worker     return (numClusters_per_IndexBlock < 0x100);
212*f6dc9357SAndroid Build Coastguard Worker   }
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker 
215*f6dc9357SAndroid Build Coastguard Worker struct CMftRef
216*f6dc9357SAndroid Build Coastguard Worker {
217*f6dc9357SAndroid Build Coastguard Worker   UInt64 Val;
218*f6dc9357SAndroid Build Coastguard Worker 
GetIndexNArchive::Ntfs::CMftRef219*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); }
GetNumberNArchive::Ntfs::CMftRef220*f6dc9357SAndroid Build Coastguard Worker   UInt16 GetNumber() const { return (UInt16)(Val >> 48); }
IsBaseItselfNArchive::Ntfs::CMftRef221*f6dc9357SAndroid Build Coastguard Worker   bool IsBaseItself() const { return Val == 0; }
222*f6dc9357SAndroid Build Coastguard Worker 
CMftRefNArchive::Ntfs::CMftRef223*f6dc9357SAndroid Build Coastguard Worker   CMftRef(): Val(0) {}
224*f6dc9357SAndroid Build Coastguard Worker };
225*f6dc9357SAndroid Build Coastguard Worker 
226*f6dc9357SAndroid Build Coastguard Worker #define ATNAME(n) ATTR_TYPE_ ## n
227*f6dc9357SAndroid Build Coastguard Worker #define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker enum
230*f6dc9357SAndroid Build Coastguard Worker {
231*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x00, UNUSED),
232*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x10, STANDARD_INFO),
233*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST),
234*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x30, FILE_NAME),
235*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x40, OBJECT_ID),
236*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR),
237*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x60, VOLUME_NAME),
238*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x70, VOLUME_INFO),
239*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x80, DATA),
240*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x90, INDEX_ROOT),
241*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION),
242*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xB0, BITMAP),
243*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xC0, REPARSE_POINT),
244*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xD0, EA_INFO),
245*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xE0, EA),
246*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0xF0, PROPERTY_SET),
247*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM),
248*f6dc9357SAndroid Build Coastguard Worker   DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
249*f6dc9357SAndroid Build Coastguard Worker };
250*f6dc9357SAndroid Build Coastguard Worker 
251*f6dc9357SAndroid Build Coastguard Worker 
252*f6dc9357SAndroid Build Coastguard Worker /* WinXP-64:
253*f6dc9357SAndroid Build Coastguard Worker     Probably only one short name (dos name) per record is allowed.
254*f6dc9357SAndroid Build Coastguard Worker     There are no short names for hard links.
255*f6dc9357SAndroid Build Coastguard Worker    The pair (Win32,Dos) can be in any order.
256*f6dc9357SAndroid Build Coastguard Worker    Posix name can be after or before Win32 name
257*f6dc9357SAndroid Build Coastguard Worker */
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker // static const Byte kFileNameType_Posix     = 0; // for hard links
260*f6dc9357SAndroid Build Coastguard Worker static const Byte kFileNameType_Win32     = 1; // after Dos name
261*f6dc9357SAndroid Build Coastguard Worker static const Byte kFileNameType_Dos       = 2; // short name
262*f6dc9357SAndroid Build Coastguard Worker static const Byte kFileNameType_Win32Dos  = 3; // short and full name are same
263*f6dc9357SAndroid Build Coastguard Worker 
264*f6dc9357SAndroid Build Coastguard Worker struct CFileNameAttr
265*f6dc9357SAndroid Build Coastguard Worker {
266*f6dc9357SAndroid Build Coastguard Worker   CMftRef ParentDirRef;
267*f6dc9357SAndroid Build Coastguard Worker 
268*f6dc9357SAndroid Build Coastguard Worker   // Probably these timestamps don't contain some useful timestamps. So we don't use them
269*f6dc9357SAndroid Build Coastguard Worker   // UInt64 CTime;
270*f6dc9357SAndroid Build Coastguard Worker   // UInt64 MTime;
271*f6dc9357SAndroid Build Coastguard Worker   // UInt64 ThisRecMTime;  // xp-64: the time of previous name change (not last name change. why?)
272*f6dc9357SAndroid Build Coastguard Worker   // UInt64 ATime;
273*f6dc9357SAndroid Build Coastguard Worker   // UInt64 AllocatedSize;
274*f6dc9357SAndroid Build Coastguard Worker   // UInt64 DataSize;
275*f6dc9357SAndroid Build Coastguard Worker   // UInt16 PackedEaSize;
276*f6dc9357SAndroid Build Coastguard Worker   UString2 Name;
277*f6dc9357SAndroid Build Coastguard Worker   UInt32 Attrib;
278*f6dc9357SAndroid Build Coastguard Worker   Byte NameType;
279*f6dc9357SAndroid Build Coastguard Worker 
IsDosNArchive::Ntfs::CFileNameAttr280*f6dc9357SAndroid Build Coastguard Worker   bool IsDos() const { return NameType == kFileNameType_Dos; }
IsWin32NArchive::Ntfs::CFileNameAttr281*f6dc9357SAndroid Build Coastguard Worker   bool IsWin32() const { return (NameType == kFileNameType_Win32); }
282*f6dc9357SAndroid Build Coastguard Worker 
283*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p, unsigned size);
284*f6dc9357SAndroid Build Coastguard Worker 
CFileNameAttrNArchive::Ntfs::CFileNameAttr285*f6dc9357SAndroid Build Coastguard Worker   CFileNameAttr():
286*f6dc9357SAndroid Build Coastguard Worker       Attrib(0),
287*f6dc9357SAndroid Build Coastguard Worker       NameType(0)
288*f6dc9357SAndroid Build Coastguard Worker       {}
289*f6dc9357SAndroid Build Coastguard Worker };
290*f6dc9357SAndroid Build Coastguard Worker 
GetString(const Byte * p,const unsigned len,UString2 & res)291*f6dc9357SAndroid Build Coastguard Worker static void GetString(const Byte *p, const unsigned len, UString2 &res)
292*f6dc9357SAndroid Build Coastguard Worker {
293*f6dc9357SAndroid Build Coastguard Worker   if (len == 0 && res.IsEmpty())
294*f6dc9357SAndroid Build Coastguard Worker     return;
295*f6dc9357SAndroid Build Coastguard Worker   wchar_t *s = res.GetBuf(len);
296*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
297*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < len; i++)
298*f6dc9357SAndroid Build Coastguard Worker   {
299*f6dc9357SAndroid Build Coastguard Worker     const wchar_t c = Get16(p + i * 2);
300*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
301*f6dc9357SAndroid Build Coastguard Worker       break;
302*f6dc9357SAndroid Build Coastguard Worker     s[i] = c;
303*f6dc9357SAndroid Build Coastguard Worker   }
304*f6dc9357SAndroid Build Coastguard Worker   s[i] = 0;
305*f6dc9357SAndroid Build Coastguard Worker   res.ReleaseBuf_SetLen(i);
306*f6dc9357SAndroid Build Coastguard Worker }
307*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)308*f6dc9357SAndroid Build Coastguard Worker bool CFileNameAttr::Parse(const Byte *p, unsigned size)
309*f6dc9357SAndroid Build Coastguard Worker {
310*f6dc9357SAndroid Build Coastguard Worker   if (size < 0x42)
311*f6dc9357SAndroid Build Coastguard Worker     return false;
312*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x00, ParentDirRef.Val);
313*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x08, CTime);
314*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x10, MTime);
315*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x18, ThisRecMTime);
316*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x20, ATime);
317*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x28, AllocatedSize);
318*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x30, DataSize);
319*f6dc9357SAndroid Build Coastguard Worker   G32(p + 0x38, Attrib);
320*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 0x3C, PackedEaSize);
321*f6dc9357SAndroid Build Coastguard Worker   NameType = p[0x41];
322*f6dc9357SAndroid Build Coastguard Worker   const unsigned len = p[0x40];
323*f6dc9357SAndroid Build Coastguard Worker   if (0x42 + len * 2 > size)
324*f6dc9357SAndroid Build Coastguard Worker     return false;
325*f6dc9357SAndroid Build Coastguard Worker   if (len != 0)
326*f6dc9357SAndroid Build Coastguard Worker     GetString(p + 0x42, len, Name);
327*f6dc9357SAndroid Build Coastguard Worker   return true;
328*f6dc9357SAndroid Build Coastguard Worker }
329*f6dc9357SAndroid Build Coastguard Worker 
330*f6dc9357SAndroid Build Coastguard Worker struct CSiAttr
331*f6dc9357SAndroid Build Coastguard Worker {
332*f6dc9357SAndroid Build Coastguard Worker   UInt64 CTime;
333*f6dc9357SAndroid Build Coastguard Worker   UInt64 MTime;
334*f6dc9357SAndroid Build Coastguard Worker   UInt64 ThisRecMTime;
335*f6dc9357SAndroid Build Coastguard Worker   UInt64 ATime;
336*f6dc9357SAndroid Build Coastguard Worker   UInt32 Attrib;
337*f6dc9357SAndroid Build Coastguard Worker 
338*f6dc9357SAndroid Build Coastguard Worker   /*
339*f6dc9357SAndroid Build Coastguard Worker   UInt32 MaxVersions;
340*f6dc9357SAndroid Build Coastguard Worker   UInt32 Version;
341*f6dc9357SAndroid Build Coastguard Worker   UInt32 ClassId;
342*f6dc9357SAndroid Build Coastguard Worker   UInt32 OwnerId;
343*f6dc9357SAndroid Build Coastguard Worker   */
344*f6dc9357SAndroid Build Coastguard Worker   UInt32 SecurityId; // SecurityId = 0 is possible ?
345*f6dc9357SAndroid Build Coastguard Worker   // UInt64 QuotaCharged;
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p, unsigned size);
348*f6dc9357SAndroid Build Coastguard Worker 
CSiAttrNArchive::Ntfs::CSiAttr349*f6dc9357SAndroid Build Coastguard Worker   CSiAttr():
350*f6dc9357SAndroid Build Coastguard Worker       CTime(0),
351*f6dc9357SAndroid Build Coastguard Worker       MTime(0),
352*f6dc9357SAndroid Build Coastguard Worker       ThisRecMTime(0),
353*f6dc9357SAndroid Build Coastguard Worker       ATime(0),
354*f6dc9357SAndroid Build Coastguard Worker       Attrib(0),
355*f6dc9357SAndroid Build Coastguard Worker       SecurityId(0)
356*f6dc9357SAndroid Build Coastguard Worker       {}
357*f6dc9357SAndroid Build Coastguard Worker };
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)360*f6dc9357SAndroid Build Coastguard Worker bool CSiAttr::Parse(const Byte *p, unsigned size)
361*f6dc9357SAndroid Build Coastguard Worker {
362*f6dc9357SAndroid Build Coastguard Worker   if (size < 0x24)
363*f6dc9357SAndroid Build Coastguard Worker     return false;
364*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x00, CTime);
365*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x08, MTime);
366*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x10, ThisRecMTime);
367*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x18, ATime);
368*f6dc9357SAndroid Build Coastguard Worker   G32(p + 0x20, Attrib);
369*f6dc9357SAndroid Build Coastguard Worker   SecurityId = 0;
370*f6dc9357SAndroid Build Coastguard Worker   if (size >= 0x38)
371*f6dc9357SAndroid Build Coastguard Worker     G32(p + 0x34, SecurityId);
372*f6dc9357SAndroid Build Coastguard Worker   return true;
373*f6dc9357SAndroid Build Coastguard Worker }
374*f6dc9357SAndroid Build Coastguard Worker 
375*f6dc9357SAndroid Build Coastguard Worker static const UInt64 kEmptyExtent = (UInt64)(Int64)-1;
376*f6dc9357SAndroid Build Coastguard Worker 
377*f6dc9357SAndroid Build Coastguard Worker struct CExtent
378*f6dc9357SAndroid Build Coastguard Worker {
379*f6dc9357SAndroid Build Coastguard Worker   UInt64 Virt;
380*f6dc9357SAndroid Build Coastguard Worker   UInt64 Phy;
381*f6dc9357SAndroid Build Coastguard Worker 
IsEmptyNArchive::Ntfs::CExtent382*f6dc9357SAndroid Build Coastguard Worker   bool IsEmpty() const { return Phy == kEmptyExtent; }
383*f6dc9357SAndroid Build Coastguard Worker };
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker struct CVolInfo
386*f6dc9357SAndroid Build Coastguard Worker {
387*f6dc9357SAndroid Build Coastguard Worker   Byte MajorVer;
388*f6dc9357SAndroid Build Coastguard Worker   Byte MinorVer;
389*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Flags;
390*f6dc9357SAndroid Build Coastguard Worker 
391*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p, unsigned size);
392*f6dc9357SAndroid Build Coastguard Worker };
393*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)394*f6dc9357SAndroid Build Coastguard Worker bool CVolInfo::Parse(const Byte *p, unsigned size)
395*f6dc9357SAndroid Build Coastguard Worker {
396*f6dc9357SAndroid Build Coastguard Worker   if (size < 12)
397*f6dc9357SAndroid Build Coastguard Worker     return false;
398*f6dc9357SAndroid Build Coastguard Worker   MajorVer = p[8];
399*f6dc9357SAndroid Build Coastguard Worker   MinorVer = p[9];
400*f6dc9357SAndroid Build Coastguard Worker   // Flags = Get16(p + 10);
401*f6dc9357SAndroid Build Coastguard Worker   return true;
402*f6dc9357SAndroid Build Coastguard Worker }
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker struct CAttr
405*f6dc9357SAndroid Build Coastguard Worker {
406*f6dc9357SAndroid Build Coastguard Worker   UInt32 Type;
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker   Byte NonResident;
409*f6dc9357SAndroid Build Coastguard Worker 
410*f6dc9357SAndroid Build Coastguard Worker   // Non-Resident
411*f6dc9357SAndroid Build Coastguard Worker   Byte CompressionUnit;
412*f6dc9357SAndroid Build Coastguard Worker 
413*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Len;
414*f6dc9357SAndroid Build Coastguard Worker   UString2 Name;
415*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Flags;
416*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Instance;
417*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
418*f6dc9357SAndroid Build Coastguard Worker 
419*f6dc9357SAndroid Build Coastguard Worker   // Non-Resident
420*f6dc9357SAndroid Build Coastguard Worker   UInt64 LowVcn;
421*f6dc9357SAndroid Build Coastguard Worker   UInt64 HighVcn;
422*f6dc9357SAndroid Build Coastguard Worker   UInt64 AllocatedSize;
423*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
424*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize;
425*f6dc9357SAndroid Build Coastguard Worker   UInt64 InitializedSize;
426*f6dc9357SAndroid Build Coastguard Worker 
427*f6dc9357SAndroid Build Coastguard Worker   // Resident
428*f6dc9357SAndroid Build Coastguard Worker   // UInt16 ResidentFlags;
429*f6dc9357SAndroid Build Coastguard Worker 
IsCompressionUnitSupportedNArchive::Ntfs::CAttr430*f6dc9357SAndroid Build Coastguard Worker   bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; }
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker   UInt32 Parse(const Byte *p, unsigned size);
ParseFileNameNArchive::Ntfs::CAttr433*f6dc9357SAndroid Build Coastguard Worker   bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
ParseSiNArchive::Ntfs::CAttr434*f6dc9357SAndroid Build Coastguard Worker   bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
ParseVolInfoNArchive::Ntfs::CAttr435*f6dc9357SAndroid Build Coastguard Worker   bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
436*f6dc9357SAndroid Build Coastguard Worker   bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const;
GetSizeNArchive::Ntfs::CAttr437*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize() const { return NonResident ? Size : Data.Size(); }
GetPackSizeNArchive::Ntfs::CAttr438*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPackSize() const
439*f6dc9357SAndroid Build Coastguard Worker   {
440*f6dc9357SAndroid Build Coastguard Worker     if (!NonResident)
441*f6dc9357SAndroid Build Coastguard Worker       return Data.Size();
442*f6dc9357SAndroid Build Coastguard Worker     if (CompressionUnit != 0)
443*f6dc9357SAndroid Build Coastguard Worker       return PackSize;
444*f6dc9357SAndroid Build Coastguard Worker     return AllocatedSize;
445*f6dc9357SAndroid Build Coastguard Worker   }
446*f6dc9357SAndroid Build Coastguard Worker };
447*f6dc9357SAndroid Build Coastguard Worker 
448*f6dc9357SAndroid Build Coastguard Worker #define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
449*f6dc9357SAndroid Build Coastguard Worker 
CompareAttr(void * const * elem1,void * const * elem2,void *)450*f6dc9357SAndroid Build Coastguard Worker static int CompareAttr(void *const *elem1, void *const *elem2, void *)
451*f6dc9357SAndroid Build Coastguard Worker {
452*f6dc9357SAndroid Build Coastguard Worker   const CAttr &a1 = *(*((const CAttr *const *)elem1));
453*f6dc9357SAndroid Build Coastguard Worker   const CAttr &a2 = *(*((const CAttr *const *)elem2));
454*f6dc9357SAndroid Build Coastguard Worker   RINOZ(MyCompare(a1.Type, a2.Type))
455*f6dc9357SAndroid Build Coastguard Worker   if (a1.Name.IsEmpty())
456*f6dc9357SAndroid Build Coastguard Worker   {
457*f6dc9357SAndroid Build Coastguard Worker     if (!a2.Name.IsEmpty())
458*f6dc9357SAndroid Build Coastguard Worker       return -1;
459*f6dc9357SAndroid Build Coastguard Worker   }
460*f6dc9357SAndroid Build Coastguard Worker   else if (a2.Name.IsEmpty())
461*f6dc9357SAndroid Build Coastguard Worker     return 1;
462*f6dc9357SAndroid Build Coastguard Worker   else
463*f6dc9357SAndroid Build Coastguard Worker   {
464*f6dc9357SAndroid Build Coastguard Worker     RINOZ(a1.Name.Compare(a2.Name.GetRawPtr()))
465*f6dc9357SAndroid Build Coastguard Worker   }
466*f6dc9357SAndroid Build Coastguard Worker   return MyCompare(a1.LowVcn, a2.LowVcn);
467*f6dc9357SAndroid Build Coastguard Worker }
468*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)469*f6dc9357SAndroid Build Coastguard Worker UInt32 CAttr::Parse(const Byte *p, unsigned size)
470*f6dc9357SAndroid Build Coastguard Worker {
471*f6dc9357SAndroid Build Coastguard Worker   if (size < 4)
472*f6dc9357SAndroid Build Coastguard Worker     return 0;
473*f6dc9357SAndroid Build Coastguard Worker   G32(p, Type);
474*f6dc9357SAndroid Build Coastguard Worker   if (Type == 0xFFFFFFFF)
475*f6dc9357SAndroid Build Coastguard Worker     return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8
476*f6dc9357SAndroid Build Coastguard Worker   if (size < 0x18)
477*f6dc9357SAndroid Build Coastguard Worker     return 0;
478*f6dc9357SAndroid Build Coastguard Worker 
479*f6dc9357SAndroid Build Coastguard Worker   PRF(printf(" T=%2X", Type));
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker   UInt32 len = Get32(p + 4);
482*f6dc9357SAndroid Build Coastguard Worker   PRF(printf(" L=%3d", len));
483*f6dc9357SAndroid Build Coastguard Worker   if (len > size)
484*f6dc9357SAndroid Build Coastguard Worker     return 0;
485*f6dc9357SAndroid Build Coastguard Worker   if ((len & 7) != 0)
486*f6dc9357SAndroid Build Coastguard Worker     return 0;
487*f6dc9357SAndroid Build Coastguard Worker   NonResident = p[8];
488*f6dc9357SAndroid Build Coastguard Worker   {
489*f6dc9357SAndroid Build Coastguard Worker     unsigned nameLen = p[9];
490*f6dc9357SAndroid Build Coastguard Worker     UInt32 nameOffset = Get16(p + 0x0A);
491*f6dc9357SAndroid Build Coastguard Worker     if (nameLen != 0)
492*f6dc9357SAndroid Build Coastguard Worker     {
493*f6dc9357SAndroid Build Coastguard Worker       if (nameOffset + nameLen * 2 > len)
494*f6dc9357SAndroid Build Coastguard Worker         return 0;
495*f6dc9357SAndroid Build Coastguard Worker       GetString(p + nameOffset, nameLen, Name);
496*f6dc9357SAndroid Build Coastguard Worker       PRF(printf(" N="));
497*f6dc9357SAndroid Build Coastguard Worker       PRF_UTF16(Name);
498*f6dc9357SAndroid Build Coastguard Worker     }
499*f6dc9357SAndroid Build Coastguard Worker   }
500*f6dc9357SAndroid Build Coastguard Worker 
501*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 0x0C, Flags);
502*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 0x0E, Instance);
503*f6dc9357SAndroid Build Coastguard Worker   // PRF(printf(" F=%4X", Flags));
504*f6dc9357SAndroid Build Coastguard Worker   // PRF(printf(" Inst=%d", Instance));
505*f6dc9357SAndroid Build Coastguard Worker 
506*f6dc9357SAndroid Build Coastguard Worker   UInt32 dataSize;
507*f6dc9357SAndroid Build Coastguard Worker   UInt32 offs;
508*f6dc9357SAndroid Build Coastguard Worker 
509*f6dc9357SAndroid Build Coastguard Worker   if (NonResident)
510*f6dc9357SAndroid Build Coastguard Worker   {
511*f6dc9357SAndroid Build Coastguard Worker     if (len < 0x40)
512*f6dc9357SAndroid Build Coastguard Worker       return 0;
513*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" NR"));
514*f6dc9357SAndroid Build Coastguard Worker     G64(p + 0x10, LowVcn);
515*f6dc9357SAndroid Build Coastguard Worker     G64(p + 0x18, HighVcn);
516*f6dc9357SAndroid Build Coastguard Worker     G64(p + 0x28, AllocatedSize);
517*f6dc9357SAndroid Build Coastguard Worker     G64(p + 0x30, Size);
518*f6dc9357SAndroid Build Coastguard Worker     G64(p + 0x38, InitializedSize);
519*f6dc9357SAndroid Build Coastguard Worker     G16(p + 0x20, offs);
520*f6dc9357SAndroid Build Coastguard Worker     CompressionUnit = p[0x22];
521*f6dc9357SAndroid Build Coastguard Worker 
522*f6dc9357SAndroid Build Coastguard Worker     PackSize = Size;
523*f6dc9357SAndroid Build Coastguard Worker     if (CompressionUnit != 0)
524*f6dc9357SAndroid Build Coastguard Worker     {
525*f6dc9357SAndroid Build Coastguard Worker       if (len < 0x48)
526*f6dc9357SAndroid Build Coastguard Worker         return 0;
527*f6dc9357SAndroid Build Coastguard Worker       G64(p + 0x40, PackSize);
528*f6dc9357SAndroid Build Coastguard Worker       PRF(printf(" PS=%I64x", PackSize));
529*f6dc9357SAndroid Build Coastguard Worker     }
530*f6dc9357SAndroid Build Coastguard Worker 
531*f6dc9357SAndroid Build Coastguard Worker     // PRF(printf("\n"));
532*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" ASize=%4I64d", AllocatedSize));
533*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" Size=%I64d", Size));
534*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" IS=%I64d", InitializedSize));
535*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" Low=%I64d", LowVcn));
536*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" High=%I64d", HighVcn));
537*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" CU=%d", (unsigned)CompressionUnit));
538*f6dc9357SAndroid Build Coastguard Worker     dataSize = len - offs;
539*f6dc9357SAndroid Build Coastguard Worker   }
540*f6dc9357SAndroid Build Coastguard Worker   else
541*f6dc9357SAndroid Build Coastguard Worker   {
542*f6dc9357SAndroid Build Coastguard Worker     if (len < 0x18)
543*f6dc9357SAndroid Build Coastguard Worker       return 0;
544*f6dc9357SAndroid Build Coastguard Worker     G32(p + 0x10, dataSize);
545*f6dc9357SAndroid Build Coastguard Worker     G16(p + 0x14, offs);
546*f6dc9357SAndroid Build Coastguard Worker     // G16(p + 0x16, ResidentFlags);
547*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" RES"));
548*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" dataSize=%3d", dataSize));
549*f6dc9357SAndroid Build Coastguard Worker     // PRF(printf(" ResFlags=%4X", ResidentFlags));
550*f6dc9357SAndroid Build Coastguard Worker   }
551*f6dc9357SAndroid Build Coastguard Worker 
552*f6dc9357SAndroid Build Coastguard Worker   if (offs > len || dataSize > len || len - dataSize < offs)
553*f6dc9357SAndroid Build Coastguard Worker     return 0;
554*f6dc9357SAndroid Build Coastguard Worker 
555*f6dc9357SAndroid Build Coastguard Worker   Data.CopyFrom(p + offs, dataSize);
556*f6dc9357SAndroid Build Coastguard Worker 
557*f6dc9357SAndroid Build Coastguard Worker   #ifdef SHOW_DEBUG_INFO
558*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("  : "));
559*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Data.Size(); i++)
560*f6dc9357SAndroid Build Coastguard Worker   {
561*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" %02X", (unsigned)Data[i]));
562*f6dc9357SAndroid Build Coastguard Worker   }
563*f6dc9357SAndroid Build Coastguard Worker   #endif
564*f6dc9357SAndroid Build Coastguard Worker 
565*f6dc9357SAndroid Build Coastguard Worker   return len;
566*f6dc9357SAndroid Build Coastguard Worker }
567*f6dc9357SAndroid Build Coastguard Worker 
568*f6dc9357SAndroid Build Coastguard Worker 
ParseExtents(CRecordVector<CExtent> & extents,UInt64 numClustersMax,unsigned compressionUnit) const569*f6dc9357SAndroid Build Coastguard Worker bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const
570*f6dc9357SAndroid Build Coastguard Worker {
571*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = Data;
572*f6dc9357SAndroid Build Coastguard Worker   unsigned size = (unsigned)Data.Size();
573*f6dc9357SAndroid Build Coastguard Worker   UInt64 vcn = LowVcn;
574*f6dc9357SAndroid Build Coastguard Worker   UInt64 lcn = 0;
575*f6dc9357SAndroid Build Coastguard Worker   const UInt64 highVcn1 = HighVcn + 1;
576*f6dc9357SAndroid Build Coastguard Worker 
577*f6dc9357SAndroid Build Coastguard Worker   if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63)
578*f6dc9357SAndroid Build Coastguard Worker     return false;
579*f6dc9357SAndroid Build Coastguard Worker 
580*f6dc9357SAndroid Build Coastguard Worker   extents.DeleteBack();
581*f6dc9357SAndroid Build Coastguard Worker 
582*f6dc9357SAndroid Build Coastguard Worker   PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn));
583*f6dc9357SAndroid Build Coastguard Worker 
584*f6dc9357SAndroid Build Coastguard Worker   while (size > 0)
585*f6dc9357SAndroid Build Coastguard Worker   {
586*f6dc9357SAndroid Build Coastguard Worker     const unsigned b = *p++;
587*f6dc9357SAndroid Build Coastguard Worker     size--;
588*f6dc9357SAndroid Build Coastguard Worker     if (b == 0)
589*f6dc9357SAndroid Build Coastguard Worker       break;
590*f6dc9357SAndroid Build Coastguard Worker     unsigned num = b & 0xF;
591*f6dc9357SAndroid Build Coastguard Worker     if (num == 0 || num > 8 || num > size)
592*f6dc9357SAndroid Build Coastguard Worker       return false;
593*f6dc9357SAndroid Build Coastguard Worker 
594*f6dc9357SAndroid Build Coastguard Worker     UInt64 vSize = 0;
595*f6dc9357SAndroid Build Coastguard Worker     {
596*f6dc9357SAndroid Build Coastguard Worker       unsigned i = num;
597*f6dc9357SAndroid Build Coastguard Worker       do vSize = (vSize << 8) | p[--i]; while (i);
598*f6dc9357SAndroid Build Coastguard Worker     }
599*f6dc9357SAndroid Build Coastguard Worker     if (vSize == 0)
600*f6dc9357SAndroid Build Coastguard Worker       return false;
601*f6dc9357SAndroid Build Coastguard Worker     p += num;
602*f6dc9357SAndroid Build Coastguard Worker     size -= num;
603*f6dc9357SAndroid Build Coastguard Worker     if ((highVcn1 - vcn) < vSize)
604*f6dc9357SAndroid Build Coastguard Worker       return false;
605*f6dc9357SAndroid Build Coastguard Worker 
606*f6dc9357SAndroid Build Coastguard Worker     CExtent e;
607*f6dc9357SAndroid Build Coastguard Worker     e.Virt = vcn;
608*f6dc9357SAndroid Build Coastguard Worker     vcn += vSize;
609*f6dc9357SAndroid Build Coastguard Worker 
610*f6dc9357SAndroid Build Coastguard Worker     num = b >> 4;
611*f6dc9357SAndroid Build Coastguard Worker     if (num > 8 || num > size)
612*f6dc9357SAndroid Build Coastguard Worker       return false;
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker     if (num == 0)
615*f6dc9357SAndroid Build Coastguard Worker     {
616*f6dc9357SAndroid Build Coastguard Worker       // Sparse
617*f6dc9357SAndroid Build Coastguard Worker 
618*f6dc9357SAndroid Build Coastguard Worker       /* if Unit is compressed, it can have many Elements for each compressed Unit:
619*f6dc9357SAndroid Build Coastguard Worker          and last Element for unit MUST be without LCN.
620*f6dc9357SAndroid Build Coastguard Worker            Element 0: numCompressedClusters2, LCN_0
621*f6dc9357SAndroid Build Coastguard Worker            Element 1: numCompressedClusters2, LCN_1
622*f6dc9357SAndroid Build Coastguard Worker            ...
623*f6dc9357SAndroid Build Coastguard Worker            Last Element : (16 - total_clusters_in_previous_elements), no LCN
624*f6dc9357SAndroid Build Coastguard Worker       */
625*f6dc9357SAndroid Build Coastguard Worker 
626*f6dc9357SAndroid Build Coastguard Worker       // sparse is not allowed for (compressionUnit == 0) ? Why ?
627*f6dc9357SAndroid Build Coastguard Worker       if (compressionUnit == 0)
628*f6dc9357SAndroid Build Coastguard Worker         return false;
629*f6dc9357SAndroid Build Coastguard Worker 
630*f6dc9357SAndroid Build Coastguard Worker       e.Phy = kEmptyExtent;
631*f6dc9357SAndroid Build Coastguard Worker     }
632*f6dc9357SAndroid Build Coastguard Worker     else
633*f6dc9357SAndroid Build Coastguard Worker     {
634*f6dc9357SAndroid Build Coastguard Worker       Int64 v = (signed char)p[num - 1];
635*f6dc9357SAndroid Build Coastguard Worker       {
636*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = num - 1; i != 0;)
637*f6dc9357SAndroid Build Coastguard Worker           v = (v << 8) | p[--i];
638*f6dc9357SAndroid Build Coastguard Worker       }
639*f6dc9357SAndroid Build Coastguard Worker       p += num;
640*f6dc9357SAndroid Build Coastguard Worker       size -= num;
641*f6dc9357SAndroid Build Coastguard Worker       lcn = (UInt64)((Int64)lcn + v);
642*f6dc9357SAndroid Build Coastguard Worker       if (lcn > numClustersMax)
643*f6dc9357SAndroid Build Coastguard Worker         return false;
644*f6dc9357SAndroid Build Coastguard Worker       e.Phy = lcn;
645*f6dc9357SAndroid Build Coastguard Worker     }
646*f6dc9357SAndroid Build Coastguard Worker 
647*f6dc9357SAndroid Build Coastguard Worker     extents.Add(e);
648*f6dc9357SAndroid Build Coastguard Worker   }
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker   CExtent e;
651*f6dc9357SAndroid Build Coastguard Worker   e.Phy = kEmptyExtent;
652*f6dc9357SAndroid Build Coastguard Worker   e.Virt = vcn;
653*f6dc9357SAndroid Build Coastguard Worker   extents.Add(e);
654*f6dc9357SAndroid Build Coastguard Worker   return (highVcn1 == vcn);
655*f6dc9357SAndroid Build Coastguard Worker }
656*f6dc9357SAndroid Build Coastguard Worker 
657*f6dc9357SAndroid Build Coastguard Worker 
658*f6dc9357SAndroid Build Coastguard Worker static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
659*f6dc9357SAndroid Build Coastguard Worker 
660*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumCacheChunksLog = 1;
661*f6dc9357SAndroid Build Coastguard Worker static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog;
662*f6dc9357SAndroid Build Coastguard Worker 
663*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_IInStream(
664*f6dc9357SAndroid Build Coastguard Worker   CInStream
665*f6dc9357SAndroid Build Coastguard Worker )
666*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
667*f6dc9357SAndroid Build Coastguard Worker   UInt64 _physPos;
668*f6dc9357SAndroid Build Coastguard Worker   UInt64 _curRem;
669*f6dc9357SAndroid Build Coastguard Worker   bool _sparseMode;
670*f6dc9357SAndroid Build Coastguard Worker public:
671*f6dc9357SAndroid Build Coastguard Worker   bool InUse;
672*f6dc9357SAndroid Build Coastguard Worker private:
673*f6dc9357SAndroid Build Coastguard Worker   unsigned _chunkSizeLog;
674*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _inBuf;
675*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _outBuf;
676*f6dc9357SAndroid Build Coastguard Worker public:
677*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
678*f6dc9357SAndroid Build Coastguard Worker   UInt64 InitializedSize;
679*f6dc9357SAndroid Build Coastguard Worker   unsigned BlockSizeLog;
680*f6dc9357SAndroid Build Coastguard Worker   unsigned CompressionUnit;
681*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CExtent> Extents;
682*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> Stream;
683*f6dc9357SAndroid Build Coastguard Worker private:
684*f6dc9357SAndroid Build Coastguard Worker   UInt64 _tags[kNumCacheChunks];
685*f6dc9357SAndroid Build Coastguard Worker 
686*f6dc9357SAndroid Build Coastguard Worker   HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
687*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); }
688*f6dc9357SAndroid Build Coastguard Worker public:
689*f6dc9357SAndroid Build Coastguard Worker   HRESULT InitAndSeek(unsigned compressionUnit)
690*f6dc9357SAndroid Build Coastguard Worker   {
691*f6dc9357SAndroid Build Coastguard Worker     CompressionUnit = compressionUnit;
692*f6dc9357SAndroid Build Coastguard Worker     _chunkSizeLog = BlockSizeLog + CompressionUnit;
693*f6dc9357SAndroid Build Coastguard Worker     if (compressionUnit != 0)
694*f6dc9357SAndroid Build Coastguard Worker     {
695*f6dc9357SAndroid Build Coastguard Worker       UInt32 cuSize = GetCuSize();
696*f6dc9357SAndroid Build Coastguard Worker       _inBuf.Alloc(cuSize);
697*f6dc9357SAndroid Build Coastguard Worker       _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog);
698*f6dc9357SAndroid Build Coastguard Worker     }
699*f6dc9357SAndroid Build Coastguard Worker     for (size_t i = 0; i < kNumCacheChunks; i++)
700*f6dc9357SAndroid Build Coastguard Worker       _tags[i] = kEmptyTag;
701*f6dc9357SAndroid Build Coastguard Worker 
702*f6dc9357SAndroid Build Coastguard Worker     _sparseMode = false;
703*f6dc9357SAndroid Build Coastguard Worker     _curRem = 0;
704*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
705*f6dc9357SAndroid Build Coastguard Worker     _physPos = 0;
706*f6dc9357SAndroid Build Coastguard Worker     const CExtent &e = Extents[0];
707*f6dc9357SAndroid Build Coastguard Worker     if (!e.IsEmpty())
708*f6dc9357SAndroid Build Coastguard Worker       _physPos = e.Phy << BlockSizeLog;
709*f6dc9357SAndroid Build Coastguard Worker     return SeekToPhys();
710*f6dc9357SAndroid Build Coastguard Worker   }
711*f6dc9357SAndroid Build Coastguard Worker };
712*f6dc9357SAndroid Build Coastguard Worker 
713*f6dc9357SAndroid Build Coastguard Worker static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen)
714*f6dc9357SAndroid Build Coastguard Worker {
715*f6dc9357SAndroid Build Coastguard Worker   size_t destSize = 0;
716*f6dc9357SAndroid Build Coastguard Worker   while (destSize < destLen)
717*f6dc9357SAndroid Build Coastguard Worker   {
718*f6dc9357SAndroid Build Coastguard Worker     if (srcLen < 2 || (destSize & 0xFFF) != 0)
719*f6dc9357SAndroid Build Coastguard Worker       break;
720*f6dc9357SAndroid Build Coastguard Worker     UInt32 comprSize;
721*f6dc9357SAndroid Build Coastguard Worker     {
722*f6dc9357SAndroid Build Coastguard Worker       const UInt32 v = Get16(src);
723*f6dc9357SAndroid Build Coastguard Worker       if (v == 0)
724*f6dc9357SAndroid Build Coastguard Worker         break;
725*f6dc9357SAndroid Build Coastguard Worker       src += 2;
726*f6dc9357SAndroid Build Coastguard Worker       srcLen -= 2;
727*f6dc9357SAndroid Build Coastguard Worker       comprSize = (v & 0xFFF) + 1;
728*f6dc9357SAndroid Build Coastguard Worker       if (comprSize > srcLen)
729*f6dc9357SAndroid Build Coastguard Worker         break;
730*f6dc9357SAndroid Build Coastguard Worker       srcLen -= comprSize;
731*f6dc9357SAndroid Build Coastguard Worker       if ((v & 0x8000) == 0)
732*f6dc9357SAndroid Build Coastguard Worker       {
733*f6dc9357SAndroid Build Coastguard Worker         if (comprSize != (1 << 12))
734*f6dc9357SAndroid Build Coastguard Worker           break;
735*f6dc9357SAndroid Build Coastguard Worker         memcpy(dest + destSize, src, comprSize);
736*f6dc9357SAndroid Build Coastguard Worker         src += comprSize;
737*f6dc9357SAndroid Build Coastguard Worker         destSize += comprSize;
738*f6dc9357SAndroid Build Coastguard Worker         continue;
739*f6dc9357SAndroid Build Coastguard Worker       }
740*f6dc9357SAndroid Build Coastguard Worker     }
741*f6dc9357SAndroid Build Coastguard Worker     {
742*f6dc9357SAndroid Build Coastguard Worker       if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0)
743*f6dc9357SAndroid Build Coastguard Worker         return 0;
744*f6dc9357SAndroid Build Coastguard Worker       unsigned numDistBits = 4;
745*f6dc9357SAndroid Build Coastguard Worker       UInt32 sbOffset = 0;
746*f6dc9357SAndroid Build Coastguard Worker       UInt32 pos = 0;
747*f6dc9357SAndroid Build Coastguard Worker 
748*f6dc9357SAndroid Build Coastguard Worker       do
749*f6dc9357SAndroid Build Coastguard Worker       {
750*f6dc9357SAndroid Build Coastguard Worker         comprSize--;
751*f6dc9357SAndroid Build Coastguard Worker         for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1)
752*f6dc9357SAndroid Build Coastguard Worker         {
753*f6dc9357SAndroid Build Coastguard Worker           if ((mask & 1) == 0)
754*f6dc9357SAndroid Build Coastguard Worker           {
755*f6dc9357SAndroid Build Coastguard Worker             if (sbOffset >= (1 << 12))
756*f6dc9357SAndroid Build Coastguard Worker               return 0;
757*f6dc9357SAndroid Build Coastguard Worker             dest[destSize++] = src[pos++];
758*f6dc9357SAndroid Build Coastguard Worker             sbOffset++;
759*f6dc9357SAndroid Build Coastguard Worker             comprSize--;
760*f6dc9357SAndroid Build Coastguard Worker           }
761*f6dc9357SAndroid Build Coastguard Worker           else
762*f6dc9357SAndroid Build Coastguard Worker           {
763*f6dc9357SAndroid Build Coastguard Worker             if (comprSize < 2)
764*f6dc9357SAndroid Build Coastguard Worker               return 0;
765*f6dc9357SAndroid Build Coastguard Worker             const UInt32 v = Get16(src + pos);
766*f6dc9357SAndroid Build Coastguard Worker             pos += 2;
767*f6dc9357SAndroid Build Coastguard Worker             comprSize -= 2;
768*f6dc9357SAndroid Build Coastguard Worker 
769*f6dc9357SAndroid Build Coastguard Worker             while (((sbOffset - 1) >> numDistBits) != 0)
770*f6dc9357SAndroid Build Coastguard Worker               numDistBits++;
771*f6dc9357SAndroid Build Coastguard Worker 
772*f6dc9357SAndroid Build Coastguard Worker             UInt32 len = (v & (0xFFFF >> numDistBits)) + 3;
773*f6dc9357SAndroid Build Coastguard Worker             if (sbOffset + len > (1 << 12))
774*f6dc9357SAndroid Build Coastguard Worker               return 0;
775*f6dc9357SAndroid Build Coastguard Worker             UInt32 dist = (v >> (16 - numDistBits));
776*f6dc9357SAndroid Build Coastguard Worker             if (dist >= sbOffset)
777*f6dc9357SAndroid Build Coastguard Worker               return 0;
778*f6dc9357SAndroid Build Coastguard Worker             const size_t offs = 1 + dist;
779*f6dc9357SAndroid Build Coastguard Worker             Byte *p = dest + destSize - offs;
780*f6dc9357SAndroid Build Coastguard Worker             destSize += len;
781*f6dc9357SAndroid Build Coastguard Worker             sbOffset += len;
782*f6dc9357SAndroid Build Coastguard Worker             const Byte *lim = p + len;
783*f6dc9357SAndroid Build Coastguard Worker             p[offs] = *p; ++p;
784*f6dc9357SAndroid Build Coastguard Worker             p[offs] = *p; ++p;
785*f6dc9357SAndroid Build Coastguard Worker             do
786*f6dc9357SAndroid Build Coastguard Worker               p[offs] = *p;
787*f6dc9357SAndroid Build Coastguard Worker             while (++p != lim);
788*f6dc9357SAndroid Build Coastguard Worker           }
789*f6dc9357SAndroid Build Coastguard Worker         }
790*f6dc9357SAndroid Build Coastguard Worker       }
791*f6dc9357SAndroid Build Coastguard Worker       while (comprSize > 0);
792*f6dc9357SAndroid Build Coastguard Worker       src += pos;
793*f6dc9357SAndroid Build Coastguard Worker     }
794*f6dc9357SAndroid Build Coastguard Worker   }
795*f6dc9357SAndroid Build Coastguard Worker   return destSize;
796*f6dc9357SAndroid Build Coastguard Worker }
797*f6dc9357SAndroid Build Coastguard Worker 
798*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
799*f6dc9357SAndroid Build Coastguard Worker {
800*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
801*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
802*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= Size)
803*f6dc9357SAndroid Build Coastguard Worker     return (Size == _virtPos) ? S_OK: E_FAIL;
804*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
805*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
806*f6dc9357SAndroid Build Coastguard Worker   {
807*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = Size - _virtPos;
808*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
809*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
810*f6dc9357SAndroid Build Coastguard Worker   }
811*f6dc9357SAndroid Build Coastguard Worker 
812*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= InitializedSize)
813*f6dc9357SAndroid Build Coastguard Worker   {
814*f6dc9357SAndroid Build Coastguard Worker     memset((Byte *)data, 0, size);
815*f6dc9357SAndroid Build Coastguard Worker     _virtPos += size;
816*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
817*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
818*f6dc9357SAndroid Build Coastguard Worker   }
819*f6dc9357SAndroid Build Coastguard Worker 
820*f6dc9357SAndroid Build Coastguard Worker   {
821*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = InitializedSize - _virtPos;
822*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
823*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
824*f6dc9357SAndroid Build Coastguard Worker   }
825*f6dc9357SAndroid Build Coastguard Worker 
826*f6dc9357SAndroid Build Coastguard Worker   while (_curRem == 0)
827*f6dc9357SAndroid Build Coastguard Worker   {
828*f6dc9357SAndroid Build Coastguard Worker     const UInt64 cacheTag = _virtPos >> _chunkSizeLog;
829*f6dc9357SAndroid Build Coastguard Worker     const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1);
830*f6dc9357SAndroid Build Coastguard Worker 
831*f6dc9357SAndroid Build Coastguard Worker     if (_tags[cacheIndex] == cacheTag)
832*f6dc9357SAndroid Build Coastguard Worker     {
833*f6dc9357SAndroid Build Coastguard Worker       const size_t chunkSize = (size_t)1 << _chunkSizeLog;
834*f6dc9357SAndroid Build Coastguard Worker       const size_t offset = (size_t)_virtPos & (chunkSize - 1);
835*f6dc9357SAndroid Build Coastguard Worker       size_t cur = chunkSize - offset;
836*f6dc9357SAndroid Build Coastguard Worker       if (cur > size)
837*f6dc9357SAndroid Build Coastguard Worker         cur = size;
838*f6dc9357SAndroid Build Coastguard Worker       memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
839*f6dc9357SAndroid Build Coastguard Worker       *processedSize = (UInt32)cur;
840*f6dc9357SAndroid Build Coastguard Worker       _virtPos += cur;
841*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
842*f6dc9357SAndroid Build Coastguard Worker     }
843*f6dc9357SAndroid Build Coastguard Worker 
844*f6dc9357SAndroid Build Coastguard Worker     PRF2(printf("\nVirtPos = %6d", _virtPos));
845*f6dc9357SAndroid Build Coastguard Worker 
846*f6dc9357SAndroid Build Coastguard Worker     const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
847*f6dc9357SAndroid Build Coastguard Worker     const UInt64 virtBlock = _virtPos >> BlockSizeLog;
848*f6dc9357SAndroid Build Coastguard Worker     const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
849*f6dc9357SAndroid Build Coastguard Worker 
850*f6dc9357SAndroid Build Coastguard Worker     unsigned left = 0, right = Extents.Size();
851*f6dc9357SAndroid Build Coastguard Worker     for (;;)
852*f6dc9357SAndroid Build Coastguard Worker     {
853*f6dc9357SAndroid Build Coastguard Worker       unsigned mid = (left + right) / 2;
854*f6dc9357SAndroid Build Coastguard Worker       if (mid == left)
855*f6dc9357SAndroid Build Coastguard Worker         break;
856*f6dc9357SAndroid Build Coastguard Worker       if (virtBlock2 < Extents[mid].Virt)
857*f6dc9357SAndroid Build Coastguard Worker         right = mid;
858*f6dc9357SAndroid Build Coastguard Worker       else
859*f6dc9357SAndroid Build Coastguard Worker         left = mid;
860*f6dc9357SAndroid Build Coastguard Worker     }
861*f6dc9357SAndroid Build Coastguard Worker 
862*f6dc9357SAndroid Build Coastguard Worker     bool isCompressed = false;
863*f6dc9357SAndroid Build Coastguard Worker     const UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
864*f6dc9357SAndroid Build Coastguard Worker     if (CompressionUnit != 0)
865*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = left; i < Extents.Size(); i++)
866*f6dc9357SAndroid Build Coastguard Worker       {
867*f6dc9357SAndroid Build Coastguard Worker         const CExtent &e = Extents[i];
868*f6dc9357SAndroid Build Coastguard Worker         if (e.Virt >= virtBlock2End)
869*f6dc9357SAndroid Build Coastguard Worker           break;
870*f6dc9357SAndroid Build Coastguard Worker         if (e.IsEmpty())
871*f6dc9357SAndroid Build Coastguard Worker         {
872*f6dc9357SAndroid Build Coastguard Worker           isCompressed = true;
873*f6dc9357SAndroid Build Coastguard Worker           break;
874*f6dc9357SAndroid Build Coastguard Worker         }
875*f6dc9357SAndroid Build Coastguard Worker       }
876*f6dc9357SAndroid Build Coastguard Worker 
877*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
878*f6dc9357SAndroid Build Coastguard Worker     for (i = left; Extents[i + 1].Virt <= virtBlock; i++);
879*f6dc9357SAndroid Build Coastguard Worker 
880*f6dc9357SAndroid Build Coastguard Worker     _sparseMode = false;
881*f6dc9357SAndroid Build Coastguard Worker     if (!isCompressed)
882*f6dc9357SAndroid Build Coastguard Worker     {
883*f6dc9357SAndroid Build Coastguard Worker       const CExtent &e = Extents[i];
884*f6dc9357SAndroid Build Coastguard Worker       UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog);
885*f6dc9357SAndroid Build Coastguard Worker       if (newPos != _physPos)
886*f6dc9357SAndroid Build Coastguard Worker       {
887*f6dc9357SAndroid Build Coastguard Worker         _physPos = newPos;
888*f6dc9357SAndroid Build Coastguard Worker         RINOK(SeekToPhys())
889*f6dc9357SAndroid Build Coastguard Worker       }
890*f6dc9357SAndroid Build Coastguard Worker       UInt64 next = Extents[i + 1].Virt;
891*f6dc9357SAndroid Build Coastguard Worker       if (next > virtBlock2End)
892*f6dc9357SAndroid Build Coastguard Worker         next &= ~((UInt64)comprUnitSize - 1);
893*f6dc9357SAndroid Build Coastguard Worker       next <<= BlockSizeLog;
894*f6dc9357SAndroid Build Coastguard Worker       if (next > Size)
895*f6dc9357SAndroid Build Coastguard Worker         next = Size;
896*f6dc9357SAndroid Build Coastguard Worker       _curRem = next - _virtPos;
897*f6dc9357SAndroid Build Coastguard Worker       break;
898*f6dc9357SAndroid Build Coastguard Worker     }
899*f6dc9357SAndroid Build Coastguard Worker 
900*f6dc9357SAndroid Build Coastguard Worker     bool thereArePhy = false;
901*f6dc9357SAndroid Build Coastguard Worker 
902*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i2 = left; i2 < Extents.Size(); i2++)
903*f6dc9357SAndroid Build Coastguard Worker     {
904*f6dc9357SAndroid Build Coastguard Worker       const CExtent &e = Extents[i2];
905*f6dc9357SAndroid Build Coastguard Worker       if (e.Virt >= virtBlock2End)
906*f6dc9357SAndroid Build Coastguard Worker         break;
907*f6dc9357SAndroid Build Coastguard Worker       if (!e.IsEmpty())
908*f6dc9357SAndroid Build Coastguard Worker       {
909*f6dc9357SAndroid Build Coastguard Worker         thereArePhy = true;
910*f6dc9357SAndroid Build Coastguard Worker         break;
911*f6dc9357SAndroid Build Coastguard Worker       }
912*f6dc9357SAndroid Build Coastguard Worker     }
913*f6dc9357SAndroid Build Coastguard Worker 
914*f6dc9357SAndroid Build Coastguard Worker     if (!thereArePhy)
915*f6dc9357SAndroid Build Coastguard Worker     {
916*f6dc9357SAndroid Build Coastguard Worker       _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos;
917*f6dc9357SAndroid Build Coastguard Worker       _sparseMode = true;
918*f6dc9357SAndroid Build Coastguard Worker       break;
919*f6dc9357SAndroid Build Coastguard Worker     }
920*f6dc9357SAndroid Build Coastguard Worker 
921*f6dc9357SAndroid Build Coastguard Worker     size_t offs = 0;
922*f6dc9357SAndroid Build Coastguard Worker     UInt64 curVirt = virtBlock2;
923*f6dc9357SAndroid Build Coastguard Worker 
924*f6dc9357SAndroid Build Coastguard Worker     for (i = left; i < Extents.Size(); i++)
925*f6dc9357SAndroid Build Coastguard Worker     {
926*f6dc9357SAndroid Build Coastguard Worker       const CExtent &e = Extents[i];
927*f6dc9357SAndroid Build Coastguard Worker       if (e.IsEmpty())
928*f6dc9357SAndroid Build Coastguard Worker         break;
929*f6dc9357SAndroid Build Coastguard Worker       if (e.Virt >= virtBlock2End)
930*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
931*f6dc9357SAndroid Build Coastguard Worker       const UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog;
932*f6dc9357SAndroid Build Coastguard Worker       if (newPos != _physPos)
933*f6dc9357SAndroid Build Coastguard Worker       {
934*f6dc9357SAndroid Build Coastguard Worker         _physPos = newPos;
935*f6dc9357SAndroid Build Coastguard Worker         RINOK(SeekToPhys())
936*f6dc9357SAndroid Build Coastguard Worker       }
937*f6dc9357SAndroid Build Coastguard Worker       UInt64 numChunks = Extents[i + 1].Virt - curVirt;
938*f6dc9357SAndroid Build Coastguard Worker       if (curVirt + numChunks > virtBlock2End)
939*f6dc9357SAndroid Build Coastguard Worker         numChunks = virtBlock2End - curVirt;
940*f6dc9357SAndroid Build Coastguard Worker       const size_t compressed = (size_t)numChunks << BlockSizeLog;
941*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed))
942*f6dc9357SAndroid Build Coastguard Worker       curVirt += numChunks;
943*f6dc9357SAndroid Build Coastguard Worker       _physPos += compressed;
944*f6dc9357SAndroid Build Coastguard Worker       offs += compressed;
945*f6dc9357SAndroid Build Coastguard Worker     }
946*f6dc9357SAndroid Build Coastguard Worker 
947*f6dc9357SAndroid Build Coastguard Worker     const size_t destLenMax = GetCuSize();
948*f6dc9357SAndroid Build Coastguard Worker     size_t destLen = destLenMax;
949*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = Size - (virtBlock2 << BlockSizeLog);
950*f6dc9357SAndroid Build Coastguard Worker     if (destLen > rem)
951*f6dc9357SAndroid Build Coastguard Worker       destLen = (size_t)rem;
952*f6dc9357SAndroid Build Coastguard Worker 
953*f6dc9357SAndroid Build Coastguard Worker     Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog);
954*f6dc9357SAndroid Build Coastguard Worker     const size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs);
955*f6dc9357SAndroid Build Coastguard Worker     _tags[cacheIndex] = cacheTag;
956*f6dc9357SAndroid Build Coastguard Worker 
957*f6dc9357SAndroid Build Coastguard Worker     // some files in Vista have destSize > destLen
958*f6dc9357SAndroid Build Coastguard Worker     if (destSizeRes < destLen)
959*f6dc9357SAndroid Build Coastguard Worker     {
960*f6dc9357SAndroid Build Coastguard Worker       memset(dest, 0, destLenMax);
961*f6dc9357SAndroid Build Coastguard Worker       if (InUse)
962*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
963*f6dc9357SAndroid Build Coastguard Worker     }
964*f6dc9357SAndroid Build Coastguard Worker   }
965*f6dc9357SAndroid Build Coastguard Worker 
966*f6dc9357SAndroid Build Coastguard Worker   if (size > _curRem)
967*f6dc9357SAndroid Build Coastguard Worker     size = (UInt32)_curRem;
968*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
969*f6dc9357SAndroid Build Coastguard Worker   if (_sparseMode)
970*f6dc9357SAndroid Build Coastguard Worker     memset(data, 0, size);
971*f6dc9357SAndroid Build Coastguard Worker   else
972*f6dc9357SAndroid Build Coastguard Worker   {
973*f6dc9357SAndroid Build Coastguard Worker     res = Stream->Read(data, size, &size);
974*f6dc9357SAndroid Build Coastguard Worker     _physPos += size;
975*f6dc9357SAndroid Build Coastguard Worker   }
976*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
977*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
978*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
979*f6dc9357SAndroid Build Coastguard Worker   _curRem -= size;
980*f6dc9357SAndroid Build Coastguard Worker   return res;
981*f6dc9357SAndroid Build Coastguard Worker }
982*f6dc9357SAndroid Build Coastguard Worker 
983*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
984*f6dc9357SAndroid Build Coastguard Worker {
985*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
986*f6dc9357SAndroid Build Coastguard Worker   {
987*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
988*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
989*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += Size; break;
990*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
991*f6dc9357SAndroid Build Coastguard Worker   }
992*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
993*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
994*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos != (UInt64)offset)
995*f6dc9357SAndroid Build Coastguard Worker   {
996*f6dc9357SAndroid Build Coastguard Worker     _curRem = 0;
997*f6dc9357SAndroid Build Coastguard Worker     _virtPos = (UInt64)offset;
998*f6dc9357SAndroid Build Coastguard Worker   }
999*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
1000*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
1001*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1002*f6dc9357SAndroid Build Coastguard Worker }
1003*f6dc9357SAndroid Build Coastguard Worker 
1004*f6dc9357SAndroid Build Coastguard Worker static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs,
1005*f6dc9357SAndroid Build Coastguard Worker     unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
1006*f6dc9357SAndroid Build Coastguard Worker {
1007*f6dc9357SAndroid Build Coastguard Worker   {
1008*f6dc9357SAndroid Build Coastguard Worker     CExtent e;
1009*f6dc9357SAndroid Build Coastguard Worker     e.Virt = 0;
1010*f6dc9357SAndroid Build Coastguard Worker     e.Phy = kEmptyExtent;
1011*f6dc9357SAndroid Build Coastguard Worker     Extents.Add(e);
1012*f6dc9357SAndroid Build Coastguard Worker   }
1013*f6dc9357SAndroid Build Coastguard Worker 
1014*f6dc9357SAndroid Build Coastguard Worker   const CAttr &attr0 = attrs[attrIndex];
1015*f6dc9357SAndroid Build Coastguard Worker 
1016*f6dc9357SAndroid Build Coastguard Worker   /*
1017*f6dc9357SAndroid Build Coastguard Worker   if (attrs[attrIndexLim - 1].HighVcn + 1 != (attr0.AllocatedSize >> clusterSizeLog))
1018*f6dc9357SAndroid Build Coastguard Worker   {
1019*f6dc9357SAndroid Build Coastguard Worker   }
1020*f6dc9357SAndroid Build Coastguard Worker   */
1021*f6dc9357SAndroid Build Coastguard Worker 
1022*f6dc9357SAndroid Build Coastguard Worker   if (attr0.AllocatedSize < attr0.Size ||
1023*f6dc9357SAndroid Build Coastguard Worker       (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) ||
1024*f6dc9357SAndroid Build Coastguard Worker       (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)
1025*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1026*f6dc9357SAndroid Build Coastguard Worker 
1027*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = attrIndex; i < attrIndexLim; i++)
1028*f6dc9357SAndroid Build Coastguard Worker     if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit))
1029*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1030*f6dc9357SAndroid Build Coastguard Worker 
1031*f6dc9357SAndroid Build Coastguard Worker   UInt64 packSizeCalc = 0;
1032*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (k, Extents)
1033*f6dc9357SAndroid Build Coastguard Worker   {
1034*f6dc9357SAndroid Build Coastguard Worker     CExtent &e = Extents[k];
1035*f6dc9357SAndroid Build Coastguard Worker     if (!e.IsEmpty())
1036*f6dc9357SAndroid Build Coastguard Worker       packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog;
1037*f6dc9357SAndroid Build Coastguard Worker     PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt));
1038*f6dc9357SAndroid Build Coastguard Worker     PRF2(printf("  Pos = %4I64X", e.Phy));
1039*f6dc9357SAndroid Build Coastguard Worker   }
1040*f6dc9357SAndroid Build Coastguard Worker 
1041*f6dc9357SAndroid Build Coastguard Worker   if (attr0.CompressionUnit != 0)
1042*f6dc9357SAndroid Build Coastguard Worker   {
1043*f6dc9357SAndroid Build Coastguard Worker     if (packSizeCalc != attr0.PackSize)
1044*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1045*f6dc9357SAndroid Build Coastguard Worker   }
1046*f6dc9357SAndroid Build Coastguard Worker   else
1047*f6dc9357SAndroid Build Coastguard Worker   {
1048*f6dc9357SAndroid Build Coastguard Worker     if (packSizeCalc != attr0.AllocatedSize)
1049*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1050*f6dc9357SAndroid Build Coastguard Worker   }
1051*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1052*f6dc9357SAndroid Build Coastguard Worker }
1053*f6dc9357SAndroid Build Coastguard Worker 
1054*f6dc9357SAndroid Build Coastguard Worker struct CDataRef
1055*f6dc9357SAndroid Build Coastguard Worker {
1056*f6dc9357SAndroid Build Coastguard Worker   unsigned Start;
1057*f6dc9357SAndroid Build Coastguard Worker   unsigned Num;
1058*f6dc9357SAndroid Build Coastguard Worker };
1059*f6dc9357SAndroid Build Coastguard Worker 
1060*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_FILE = 0x454C4946;
1061*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_BAAD = 0x44414142;
1062*f6dc9357SAndroid Build Coastguard Worker 
1063*f6dc9357SAndroid Build Coastguard Worker // 22.02: we support some rare case magic values:
1064*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_INDX = 0x58444e49;
1065*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_HOLE = 0x454c4f48;
1066*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_RSTR = 0x52545352;
1067*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_RCRD = 0x44524352;
1068*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_CHKD = 0x444b4843;
1069*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMagic_FFFFFFFF = 0xFFFFFFFF;
1070*f6dc9357SAndroid Build Coastguard Worker 
1071*f6dc9357SAndroid Build Coastguard Worker 
1072*f6dc9357SAndroid Build Coastguard Worker struct CMftRec
1073*f6dc9357SAndroid Build Coastguard Worker {
1074*f6dc9357SAndroid Build Coastguard Worker   UInt32 Magic;
1075*f6dc9357SAndroid Build Coastguard Worker   // UInt64 Lsn;
1076*f6dc9357SAndroid Build Coastguard Worker   UInt16 SeqNumber;  // Number of times this mft record has been reused
1077*f6dc9357SAndroid Build Coastguard Worker   UInt16 Flags;
1078*f6dc9357SAndroid Build Coastguard Worker   // UInt16 LinkCount;
1079*f6dc9357SAndroid Build Coastguard Worker   // UInt16 NextAttrInstance;
1080*f6dc9357SAndroid Build Coastguard Worker   CMftRef BaseMftRef;
1081*f6dc9357SAndroid Build Coastguard Worker   // UInt32 ThisRecNumber;
1082*f6dc9357SAndroid Build Coastguard Worker 
1083*f6dc9357SAndroid Build Coastguard Worker   UInt32 MyNumNameLinks;
1084*f6dc9357SAndroid Build Coastguard Worker   int MyItemIndex; // index in Items[] of main item  for that record, or -1 if there is no item for that record
1085*f6dc9357SAndroid Build Coastguard Worker 
1086*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CAttr> DataAttrs;
1087*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CFileNameAttr> FileNames;
1088*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CDataRef> DataRefs;
1089*f6dc9357SAndroid Build Coastguard Worker   // CAttr SecurityAttr;
1090*f6dc9357SAndroid Build Coastguard Worker 
1091*f6dc9357SAndroid Build Coastguard Worker   CSiAttr SiAttr;
1092*f6dc9357SAndroid Build Coastguard Worker 
1093*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer ReparseData;
1094*f6dc9357SAndroid Build Coastguard Worker 
1095*f6dc9357SAndroid Build Coastguard Worker   int FindWin32Name_for_DosName(unsigned dosNameIndex) const
1096*f6dc9357SAndroid Build Coastguard Worker   {
1097*f6dc9357SAndroid Build Coastguard Worker     const CFileNameAttr &cur = FileNames[dosNameIndex];
1098*f6dc9357SAndroid Build Coastguard Worker     if (cur.IsDos())
1099*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < FileNames.Size(); i++)
1100*f6dc9357SAndroid Build Coastguard Worker       {
1101*f6dc9357SAndroid Build Coastguard Worker         const CFileNameAttr &next = FileNames[i];
1102*f6dc9357SAndroid Build Coastguard Worker         if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
1103*f6dc9357SAndroid Build Coastguard Worker           return (int)i;
1104*f6dc9357SAndroid Build Coastguard Worker       }
1105*f6dc9357SAndroid Build Coastguard Worker     return -1;
1106*f6dc9357SAndroid Build Coastguard Worker   }
1107*f6dc9357SAndroid Build Coastguard Worker 
1108*f6dc9357SAndroid Build Coastguard Worker   int FindDosName(unsigned nameIndex) const
1109*f6dc9357SAndroid Build Coastguard Worker   {
1110*f6dc9357SAndroid Build Coastguard Worker     const CFileNameAttr &cur = FileNames[nameIndex];
1111*f6dc9357SAndroid Build Coastguard Worker     if (cur.IsWin32())
1112*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < FileNames.Size(); i++)
1113*f6dc9357SAndroid Build Coastguard Worker       {
1114*f6dc9357SAndroid Build Coastguard Worker         const CFileNameAttr &next = FileNames[i];
1115*f6dc9357SAndroid Build Coastguard Worker         if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
1116*f6dc9357SAndroid Build Coastguard Worker           return (int)i;
1117*f6dc9357SAndroid Build Coastguard Worker       }
1118*f6dc9357SAndroid Build Coastguard Worker     return -1;
1119*f6dc9357SAndroid Build Coastguard Worker   }
1120*f6dc9357SAndroid Build Coastguard Worker 
1121*f6dc9357SAndroid Build Coastguard Worker   /*
1122*f6dc9357SAndroid Build Coastguard Worker   bool IsAltStream(int dataIndex) const
1123*f6dc9357SAndroid Build Coastguard Worker   {
1124*f6dc9357SAndroid Build Coastguard Worker     return dataIndex >= 0 && (
1125*f6dc9357SAndroid Build Coastguard Worker       (IsDir() ||
1126*f6dc9357SAndroid Build Coastguard Worker       !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty()));
1127*f6dc9357SAndroid Build Coastguard Worker   }
1128*f6dc9357SAndroid Build Coastguard Worker   */
1129*f6dc9357SAndroid Build Coastguard Worker 
1130*f6dc9357SAndroid Build Coastguard Worker   void MoveAttrsFrom(CMftRec &src)
1131*f6dc9357SAndroid Build Coastguard Worker   {
1132*f6dc9357SAndroid Build Coastguard Worker     DataAttrs += src.DataAttrs;
1133*f6dc9357SAndroid Build Coastguard Worker     FileNames += src.FileNames;
1134*f6dc9357SAndroid Build Coastguard Worker     src.DataAttrs.ClearAndFree();
1135*f6dc9357SAndroid Build Coastguard Worker     src.FileNames.ClearAndFree();
1136*f6dc9357SAndroid Build Coastguard Worker   }
1137*f6dc9357SAndroid Build Coastguard Worker 
1138*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPackSize() const
1139*f6dc9357SAndroid Build Coastguard Worker   {
1140*f6dc9357SAndroid Build Coastguard Worker     UInt64 res = 0;
1141*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, DataRefs)
1142*f6dc9357SAndroid Build Coastguard Worker       res += DataAttrs[DataRefs[i].Start].GetPackSize();
1143*f6dc9357SAndroid Build Coastguard Worker     return res;
1144*f6dc9357SAndroid Build Coastguard Worker   }
1145*f6dc9357SAndroid Build Coastguard Worker 
1146*f6dc9357SAndroid Build Coastguard Worker   bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
1147*f6dc9357SAndroid Build Coastguard Worker 
1148*f6dc9357SAndroid Build Coastguard Worker   bool Is_Magic_Empty() const
1149*f6dc9357SAndroid Build Coastguard Worker   {
1150*f6dc9357SAndroid Build Coastguard Worker     // what exact Magic values are possible for empty and unused records?
1151*f6dc9357SAndroid Build Coastguard Worker     const UInt32 k_Magic_Unused_MAX = 5; // 22.02
1152*f6dc9357SAndroid Build Coastguard Worker     return (Magic <= k_Magic_Unused_MAX);
1153*f6dc9357SAndroid Build Coastguard Worker   }
1154*f6dc9357SAndroid Build Coastguard Worker   bool Is_Magic_FILE() const { return (Magic == kMagic_FILE); }
1155*f6dc9357SAndroid Build Coastguard Worker   // bool Is_Magic_BAAD() const { return (Magic == kMagic_BAAD); }
1156*f6dc9357SAndroid Build Coastguard Worker   bool Is_Magic_CanIgnore() const
1157*f6dc9357SAndroid Build Coastguard Worker   {
1158*f6dc9357SAndroid Build Coastguard Worker     return Is_Magic_Empty()
1159*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_BAAD
1160*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_INDX
1161*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_HOLE
1162*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_RSTR
1163*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_RCRD
1164*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_CHKD
1165*f6dc9357SAndroid Build Coastguard Worker         || Magic == kMagic_FFFFFFFF;
1166*f6dc9357SAndroid Build Coastguard Worker   }
1167*f6dc9357SAndroid Build Coastguard Worker 
1168*f6dc9357SAndroid Build Coastguard Worker   bool InUse() const { return (Flags & 1) != 0; }
1169*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const { return (Flags & 2) != 0; }
1170*f6dc9357SAndroid Build Coastguard Worker 
1171*f6dc9357SAndroid Build Coastguard Worker   void ParseDataNames();
1172*f6dc9357SAndroid Build Coastguard Worker   HRESULT GetStream(IInStream *mainStream, int dataIndex,
1173*f6dc9357SAndroid Build Coastguard Worker       unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
1174*f6dc9357SAndroid Build Coastguard Worker   unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const;
1175*f6dc9357SAndroid Build Coastguard Worker 
1176*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
1177*f6dc9357SAndroid Build Coastguard Worker 
1178*f6dc9357SAndroid Build Coastguard Worker   CMftRec():
1179*f6dc9357SAndroid Build Coastguard Worker       SeqNumber(0),
1180*f6dc9357SAndroid Build Coastguard Worker       Flags(0),
1181*f6dc9357SAndroid Build Coastguard Worker       MyNumNameLinks(0),
1182*f6dc9357SAndroid Build Coastguard Worker       MyItemIndex(-1) {}
1183*f6dc9357SAndroid Build Coastguard Worker };
1184*f6dc9357SAndroid Build Coastguard Worker 
1185*f6dc9357SAndroid Build Coastguard Worker void CMftRec::ParseDataNames()
1186*f6dc9357SAndroid Build Coastguard Worker {
1187*f6dc9357SAndroid Build Coastguard Worker   DataRefs.Clear();
1188*f6dc9357SAndroid Build Coastguard Worker   DataAttrs.Sort(CompareAttr, NULL);
1189*f6dc9357SAndroid Build Coastguard Worker 
1190*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < DataAttrs.Size();)
1191*f6dc9357SAndroid Build Coastguard Worker   {
1192*f6dc9357SAndroid Build Coastguard Worker     CDataRef ref;
1193*f6dc9357SAndroid Build Coastguard Worker     ref.Start = i;
1194*f6dc9357SAndroid Build Coastguard Worker     for (i++; i < DataAttrs.Size(); i++)
1195*f6dc9357SAndroid Build Coastguard Worker       if (DataAttrs[ref.Start].Name != DataAttrs[i].Name)
1196*f6dc9357SAndroid Build Coastguard Worker         break;
1197*f6dc9357SAndroid Build Coastguard Worker     ref.Num = i - ref.Start;
1198*f6dc9357SAndroid Build Coastguard Worker     DataRefs.Add(ref);
1199*f6dc9357SAndroid Build Coastguard Worker   }
1200*f6dc9357SAndroid Build Coastguard Worker }
1201*f6dc9357SAndroid Build Coastguard Worker 
1202*f6dc9357SAndroid Build Coastguard Worker HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
1203*f6dc9357SAndroid Build Coastguard Worker     unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
1204*f6dc9357SAndroid Build Coastguard Worker {
1205*f6dc9357SAndroid Build Coastguard Worker   *destStream = NULL;
1206*f6dc9357SAndroid Build Coastguard Worker   CBufferInStream *streamSpec = new CBufferInStream;
1207*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> streamTemp = streamSpec;
1208*f6dc9357SAndroid Build Coastguard Worker 
1209*f6dc9357SAndroid Build Coastguard Worker   if (dataIndex >= 0)
1210*f6dc9357SAndroid Build Coastguard Worker   if ((unsigned)dataIndex < DataRefs.Size())
1211*f6dc9357SAndroid Build Coastguard Worker   {
1212*f6dc9357SAndroid Build Coastguard Worker     const CDataRef &ref = DataRefs[dataIndex];
1213*f6dc9357SAndroid Build Coastguard Worker     unsigned numNonResident = 0;
1214*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
1215*f6dc9357SAndroid Build Coastguard Worker     for (i = ref.Start; i < ref.Start + ref.Num; i++)
1216*f6dc9357SAndroid Build Coastguard Worker       if (DataAttrs[i].NonResident)
1217*f6dc9357SAndroid Build Coastguard Worker         numNonResident++;
1218*f6dc9357SAndroid Build Coastguard Worker 
1219*f6dc9357SAndroid Build Coastguard Worker     const CAttr &attr0 = DataAttrs[ref.Start];
1220*f6dc9357SAndroid Build Coastguard Worker 
1221*f6dc9357SAndroid Build Coastguard Worker     if (numNonResident != 0 || ref.Num != 1)
1222*f6dc9357SAndroid Build Coastguard Worker     {
1223*f6dc9357SAndroid Build Coastguard Worker       if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
1224*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1225*f6dc9357SAndroid Build Coastguard Worker       CInStream *ss = new CInStream;
1226*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<IInStream> streamTemp2 = ss;
1227*f6dc9357SAndroid Build Coastguard Worker       RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, ss->Extents))
1228*f6dc9357SAndroid Build Coastguard Worker       ss->Size = attr0.Size;
1229*f6dc9357SAndroid Build Coastguard Worker       ss->InitializedSize = attr0.InitializedSize;
1230*f6dc9357SAndroid Build Coastguard Worker       ss->Stream = mainStream;
1231*f6dc9357SAndroid Build Coastguard Worker       ss->BlockSizeLog = clusterSizeLog;
1232*f6dc9357SAndroid Build Coastguard Worker       ss->InUse = InUse();
1233*f6dc9357SAndroid Build Coastguard Worker       RINOK(ss->InitAndSeek(attr0.CompressionUnit))
1234*f6dc9357SAndroid Build Coastguard Worker       *destStream = streamTemp2.Detach();
1235*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1236*f6dc9357SAndroid Build Coastguard Worker     }
1237*f6dc9357SAndroid Build Coastguard Worker 
1238*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Buf = attr0.Data;
1239*f6dc9357SAndroid Build Coastguard Worker   }
1240*f6dc9357SAndroid Build Coastguard Worker 
1241*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Init();
1242*f6dc9357SAndroid Build Coastguard Worker   *destStream = streamTemp.Detach();
1243*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1244*f6dc9357SAndroid Build Coastguard Worker }
1245*f6dc9357SAndroid Build Coastguard Worker 
1246*f6dc9357SAndroid Build Coastguard Worker unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const
1247*f6dc9357SAndroid Build Coastguard Worker {
1248*f6dc9357SAndroid Build Coastguard Worker   if (dataIndex < 0)
1249*f6dc9357SAndroid Build Coastguard Worker     return 0;
1250*f6dc9357SAndroid Build Coastguard Worker   {
1251*f6dc9357SAndroid Build Coastguard Worker     const CDataRef &ref = DataRefs[dataIndex];
1252*f6dc9357SAndroid Build Coastguard Worker     unsigned numNonResident = 0;
1253*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
1254*f6dc9357SAndroid Build Coastguard Worker     for (i = ref.Start; i < ref.Start + ref.Num; i++)
1255*f6dc9357SAndroid Build Coastguard Worker       if (DataAttrs[i].NonResident)
1256*f6dc9357SAndroid Build Coastguard Worker         numNonResident++;
1257*f6dc9357SAndroid Build Coastguard Worker 
1258*f6dc9357SAndroid Build Coastguard Worker     const CAttr &attr0 = DataAttrs[ref.Start];
1259*f6dc9357SAndroid Build Coastguard Worker 
1260*f6dc9357SAndroid Build Coastguard Worker     if (numNonResident != 0 || ref.Num != 1)
1261*f6dc9357SAndroid Build Coastguard Worker     {
1262*f6dc9357SAndroid Build Coastguard Worker       if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
1263*f6dc9357SAndroid Build Coastguard Worker         return 0; // error;
1264*f6dc9357SAndroid Build Coastguard Worker       CRecordVector<CExtent> extents;
1265*f6dc9357SAndroid Build Coastguard Worker       if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK)
1266*f6dc9357SAndroid Build Coastguard Worker         return 0; // error;
1267*f6dc9357SAndroid Build Coastguard Worker       return extents.Size() - 1;
1268*f6dc9357SAndroid Build Coastguard Worker     }
1269*f6dc9357SAndroid Build Coastguard Worker     // if (attr0.Data.Size() != 0)
1270*f6dc9357SAndroid Build Coastguard Worker     //   return 1;
1271*f6dc9357SAndroid Build Coastguard Worker     return 0;
1272*f6dc9357SAndroid Build Coastguard Worker   }
1273*f6dc9357SAndroid Build Coastguard Worker }
1274*f6dc9357SAndroid Build Coastguard Worker 
1275*f6dc9357SAndroid Build Coastguard Worker bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
1276*f6dc9357SAndroid Build Coastguard Worker     CObjectVector<CAttr> *attrs)
1277*f6dc9357SAndroid Build Coastguard Worker {
1278*f6dc9357SAndroid Build Coastguard Worker   G32(p, Magic);
1279*f6dc9357SAndroid Build Coastguard Worker   if (!Is_Magic_FILE())
1280*f6dc9357SAndroid Build Coastguard Worker     return Is_Magic_CanIgnore();
1281*f6dc9357SAndroid Build Coastguard Worker 
1282*f6dc9357SAndroid Build Coastguard Worker   {
1283*f6dc9357SAndroid Build Coastguard Worker     UInt32 usaOffset;
1284*f6dc9357SAndroid Build Coastguard Worker     UInt32 numUsaItems;
1285*f6dc9357SAndroid Build Coastguard Worker     G16(p + 0x04, usaOffset);
1286*f6dc9357SAndroid Build Coastguard Worker     G16(p + 0x06, numUsaItems);
1287*f6dc9357SAndroid Build Coastguard Worker 
1288*f6dc9357SAndroid Build Coastguard Worker     /* NTFS stores (usn) to 2 last bytes in each sector (before writing record to disk).
1289*f6dc9357SAndroid Build Coastguard Worker        Original values of these two bytes are stored in table.
1290*f6dc9357SAndroid Build Coastguard Worker        So we restore original data from table */
1291*f6dc9357SAndroid Build Coastguard Worker 
1292*f6dc9357SAndroid Build Coastguard Worker     if ((usaOffset & 1) != 0
1293*f6dc9357SAndroid Build Coastguard Worker         || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2
1294*f6dc9357SAndroid Build Coastguard Worker         || numUsaItems == 0
1295*f6dc9357SAndroid Build Coastguard Worker         || numUsaItems - 1 != numSectors)
1296*f6dc9357SAndroid Build Coastguard Worker       return false;
1297*f6dc9357SAndroid Build Coastguard Worker 
1298*f6dc9357SAndroid Build Coastguard Worker     if (usaOffset >= 0x30) // NTFS 3.1+
1299*f6dc9357SAndroid Build Coastguard Worker     {
1300*f6dc9357SAndroid Build Coastguard Worker       UInt32 iii = Get32(p + 0x2C);
1301*f6dc9357SAndroid Build Coastguard Worker       if (iii != recNumber)
1302*f6dc9357SAndroid Build Coastguard Worker       {
1303*f6dc9357SAndroid Build Coastguard Worker         // ntfs-3g probably writes 0 (that probably is incorrect value) to this field for unused records.
1304*f6dc9357SAndroid Build Coastguard Worker         // so we support that "bad" case.
1305*f6dc9357SAndroid Build Coastguard Worker         if (iii != 0)
1306*f6dc9357SAndroid Build Coastguard Worker           return false;
1307*f6dc9357SAndroid Build Coastguard Worker       }
1308*f6dc9357SAndroid Build Coastguard Worker     }
1309*f6dc9357SAndroid Build Coastguard Worker 
1310*f6dc9357SAndroid Build Coastguard Worker     UInt16 usn = Get16(p + usaOffset);
1311*f6dc9357SAndroid Build Coastguard Worker     // PRF(printf("\nusn = %d", usn));
1312*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 1; i < numUsaItems; i++)
1313*f6dc9357SAndroid Build Coastguard Worker     {
1314*f6dc9357SAndroid Build Coastguard Worker       void *pp = p + (i << sectorSizeLog) - 2;
1315*f6dc9357SAndroid Build Coastguard Worker       if (Get16(pp) != usn)
1316*f6dc9357SAndroid Build Coastguard Worker         return false;
1317*f6dc9357SAndroid Build Coastguard Worker       SetUi16(pp, Get16(p + usaOffset + i * 2))
1318*f6dc9357SAndroid Build Coastguard Worker     }
1319*f6dc9357SAndroid Build Coastguard Worker   }
1320*f6dc9357SAndroid Build Coastguard Worker 
1321*f6dc9357SAndroid Build Coastguard Worker   // G64(p + 0x08, Lsn);
1322*f6dc9357SAndroid Build Coastguard Worker   G16(p + 0x10, SeqNumber);
1323*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 0x12, LinkCount);
1324*f6dc9357SAndroid Build Coastguard Worker   // PRF(printf(" L=%d", LinkCount));
1325*f6dc9357SAndroid Build Coastguard Worker   const UInt32 attrOffs = Get16(p + 0x14);
1326*f6dc9357SAndroid Build Coastguard Worker   G16(p + 0x16, Flags);
1327*f6dc9357SAndroid Build Coastguard Worker   PRF(printf(" F=%4X", Flags));
1328*f6dc9357SAndroid Build Coastguard Worker 
1329*f6dc9357SAndroid Build Coastguard Worker   const UInt32 bytesInUse = Get32(p + 0x18);
1330*f6dc9357SAndroid Build Coastguard Worker   const UInt32 bytesAlloc = Get32(p + 0x1C);
1331*f6dc9357SAndroid Build Coastguard Worker   G64(p + 0x20, BaseMftRef.Val);
1332*f6dc9357SAndroid Build Coastguard Worker   if (BaseMftRef.Val != 0)
1333*f6dc9357SAndroid Build Coastguard Worker   {
1334*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("  BaseRef=%d", (int)BaseMftRef.Val));
1335*f6dc9357SAndroid Build Coastguard Worker     // return false; // Check it;
1336*f6dc9357SAndroid Build Coastguard Worker   }
1337*f6dc9357SAndroid Build Coastguard Worker   // G16(p + 0x28, NextAttrInstance);
1338*f6dc9357SAndroid Build Coastguard Worker 
1339*f6dc9357SAndroid Build Coastguard Worker   UInt32 limit = numSectors << sectorSizeLog;
1340*f6dc9357SAndroid Build Coastguard Worker   if (attrOffs >= limit
1341*f6dc9357SAndroid Build Coastguard Worker       || (attrOffs & 7) != 0
1342*f6dc9357SAndroid Build Coastguard Worker       || (bytesInUse & 7) != 0
1343*f6dc9357SAndroid Build Coastguard Worker       || bytesInUse > limit
1344*f6dc9357SAndroid Build Coastguard Worker       || bytesAlloc != limit)
1345*f6dc9357SAndroid Build Coastguard Worker     return false;
1346*f6dc9357SAndroid Build Coastguard Worker 
1347*f6dc9357SAndroid Build Coastguard Worker   limit = bytesInUse;
1348*f6dc9357SAndroid Build Coastguard Worker 
1349*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 t = attrOffs;;)
1350*f6dc9357SAndroid Build Coastguard Worker   {
1351*f6dc9357SAndroid Build Coastguard Worker     if (t >= limit)
1352*f6dc9357SAndroid Build Coastguard Worker       return false;
1353*f6dc9357SAndroid Build Coastguard Worker 
1354*f6dc9357SAndroid Build Coastguard Worker     CAttr attr;
1355*f6dc9357SAndroid Build Coastguard Worker     // PRF(printf("\n  %2d:", Attrs.Size()));
1356*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\n"));
1357*f6dc9357SAndroid Build Coastguard Worker     UInt32 len = attr.Parse(p + t, limit - t);
1358*f6dc9357SAndroid Build Coastguard Worker     if (len == 0 || limit - t < len)
1359*f6dc9357SAndroid Build Coastguard Worker       return false;
1360*f6dc9357SAndroid Build Coastguard Worker     t += len;
1361*f6dc9357SAndroid Build Coastguard Worker     if (attr.Type == 0xFFFFFFFF)
1362*f6dc9357SAndroid Build Coastguard Worker     {
1363*f6dc9357SAndroid Build Coastguard Worker       if (t != limit)
1364*f6dc9357SAndroid Build Coastguard Worker         return false;
1365*f6dc9357SAndroid Build Coastguard Worker       break;
1366*f6dc9357SAndroid Build Coastguard Worker     }
1367*f6dc9357SAndroid Build Coastguard Worker     switch (attr.Type)
1368*f6dc9357SAndroid Build Coastguard Worker     {
1369*f6dc9357SAndroid Build Coastguard Worker       case ATTR_TYPE_FILE_NAME:
1370*f6dc9357SAndroid Build Coastguard Worker       {
1371*f6dc9357SAndroid Build Coastguard Worker         CFileNameAttr fna;
1372*f6dc9357SAndroid Build Coastguard Worker         if (!attr.ParseFileName(fna))
1373*f6dc9357SAndroid Build Coastguard Worker           return false;
1374*f6dc9357SAndroid Build Coastguard Worker         FileNames.Add(fna);
1375*f6dc9357SAndroid Build Coastguard Worker         PRF(printf("  flags = %4x\n  ", (int)fna.NameType));
1376*f6dc9357SAndroid Build Coastguard Worker         PRF_UTF16(fna.Name);
1377*f6dc9357SAndroid Build Coastguard Worker         break;
1378*f6dc9357SAndroid Build Coastguard Worker       }
1379*f6dc9357SAndroid Build Coastguard Worker       case ATTR_TYPE_STANDARD_INFO:
1380*f6dc9357SAndroid Build Coastguard Worker         if (!attr.ParseSi(SiAttr))
1381*f6dc9357SAndroid Build Coastguard Worker           return false;
1382*f6dc9357SAndroid Build Coastguard Worker         break;
1383*f6dc9357SAndroid Build Coastguard Worker       case ATTR_TYPE_DATA:
1384*f6dc9357SAndroid Build Coastguard Worker         DataAttrs.Add(attr);
1385*f6dc9357SAndroid Build Coastguard Worker         break;
1386*f6dc9357SAndroid Build Coastguard Worker       case ATTR_TYPE_REPARSE_POINT:
1387*f6dc9357SAndroid Build Coastguard Worker         ReparseData = attr.Data;
1388*f6dc9357SAndroid Build Coastguard Worker         break;
1389*f6dc9357SAndroid Build Coastguard Worker       /*
1390*f6dc9357SAndroid Build Coastguard Worker       case ATTR_TYPE_SECURITY_DESCRIPTOR:
1391*f6dc9357SAndroid Build Coastguard Worker         SecurityAttr = attr;
1392*f6dc9357SAndroid Build Coastguard Worker         break;
1393*f6dc9357SAndroid Build Coastguard Worker       */
1394*f6dc9357SAndroid Build Coastguard Worker       default:
1395*f6dc9357SAndroid Build Coastguard Worker         if (attrs)
1396*f6dc9357SAndroid Build Coastguard Worker           attrs->Add(attr);
1397*f6dc9357SAndroid Build Coastguard Worker         break;
1398*f6dc9357SAndroid Build Coastguard Worker     }
1399*f6dc9357SAndroid Build Coastguard Worker   }
1400*f6dc9357SAndroid Build Coastguard Worker 
1401*f6dc9357SAndroid Build Coastguard Worker   return true;
1402*f6dc9357SAndroid Build Coastguard Worker }
1403*f6dc9357SAndroid Build Coastguard Worker 
1404*f6dc9357SAndroid Build Coastguard Worker /*
1405*f6dc9357SAndroid Build Coastguard Worker   NTFS probably creates empty DATA_ATTRIBUTE for empty file,
1406*f6dc9357SAndroid Build Coastguard Worker   But it doesn't do it for
1407*f6dc9357SAndroid Build Coastguard Worker     $Secure (:$SDS),
1408*f6dc9357SAndroid Build Coastguard Worker     $Extend\$Quota
1409*f6dc9357SAndroid Build Coastguard Worker     $Extend\$ObjId
1410*f6dc9357SAndroid Build Coastguard Worker     $Extend\$Reparse
1411*f6dc9357SAndroid Build Coastguard Worker */
1412*f6dc9357SAndroid Build Coastguard Worker 
1413*f6dc9357SAndroid Build Coastguard Worker static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream
1414*f6dc9357SAndroid Build Coastguard Worker static const int k_Item_DataIndex_IsDir = -2;
1415*f6dc9357SAndroid Build Coastguard Worker 
1416*f6dc9357SAndroid Build Coastguard Worker // static const int k_ParentFolderIndex_Root = -1;
1417*f6dc9357SAndroid Build Coastguard Worker static const int k_ParentFolderIndex_Lost = -2;
1418*f6dc9357SAndroid Build Coastguard Worker static const int k_ParentFolderIndex_Deleted = -3;
1419*f6dc9357SAndroid Build Coastguard Worker 
1420*f6dc9357SAndroid Build Coastguard Worker struct CItem
1421*f6dc9357SAndroid Build Coastguard Worker {
1422*f6dc9357SAndroid Build Coastguard Worker   unsigned RecIndex;  // index in Recs array
1423*f6dc9357SAndroid Build Coastguard Worker   unsigned NameIndex; // index in CMftRec::FileNames
1424*f6dc9357SAndroid Build Coastguard Worker 
1425*f6dc9357SAndroid Build Coastguard Worker   int DataIndex;      /* index in CMftRec::DataRefs
1426*f6dc9357SAndroid Build Coastguard Worker                          -1: file without unnamed data stream
1427*f6dc9357SAndroid Build Coastguard Worker                          -2: for directories */
1428*f6dc9357SAndroid Build Coastguard Worker 
1429*f6dc9357SAndroid Build Coastguard Worker   int ParentFolder;   /* index in Items array
1430*f6dc9357SAndroid Build Coastguard Worker                          -1: for root items
1431*f6dc9357SAndroid Build Coastguard Worker                          -2: [LOST] folder
1432*f6dc9357SAndroid Build Coastguard Worker                          -3: [UNKNOWN] folder (deleted lost) */
1433*f6dc9357SAndroid Build Coastguard Worker   int ParentHost;     /* index in Items array, if it's AltStream
1434*f6dc9357SAndroid Build Coastguard Worker                          -1: if it's not AltStream */
1435*f6dc9357SAndroid Build Coastguard Worker 
1436*f6dc9357SAndroid Build Coastguard Worker   CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {}
1437*f6dc9357SAndroid Build Coastguard Worker 
1438*f6dc9357SAndroid Build Coastguard Worker   bool IsAltStream() const { return ParentHost != -1; }
1439*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; }
1440*f6dc9357SAndroid Build Coastguard Worker         // check it !!!
1441*f6dc9357SAndroid Build Coastguard Worker         // probably NTFS for empty file still creates empty DATA_ATTRIBUTE
1442*f6dc9357SAndroid Build Coastguard Worker         // But it doesn't do it for $Secure:$SDS
1443*f6dc9357SAndroid Build Coastguard Worker };
1444*f6dc9357SAndroid Build Coastguard Worker 
1445*f6dc9357SAndroid Build Coastguard Worker struct CDatabase
1446*f6dc9357SAndroid Build Coastguard Worker {
1447*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CItem> Items;
1448*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CMftRec> Recs;
1449*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> InStream;
1450*f6dc9357SAndroid Build Coastguard Worker   CHeader Header;
1451*f6dc9357SAndroid Build Coastguard Worker   UInt64 PhySize;
1452*f6dc9357SAndroid Build Coastguard Worker 
1453*f6dc9357SAndroid Build Coastguard Worker   IArchiveOpenCallback *OpenCallback;
1454*f6dc9357SAndroid Build Coastguard Worker 
1455*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer ByteBuf;
1456*f6dc9357SAndroid Build Coastguard Worker 
1457*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CAttr> VolAttrs;
1458*f6dc9357SAndroid Build Coastguard Worker 
1459*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer SecurData;
1460*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<size_t> SecurOffsets;
1461*f6dc9357SAndroid Build Coastguard Worker 
1462*f6dc9357SAndroid Build Coastguard Worker   // bool _headerWarning;
1463*f6dc9357SAndroid Build Coastguard Worker   bool ThereAreAltStreams;
1464*f6dc9357SAndroid Build Coastguard Worker 
1465*f6dc9357SAndroid Build Coastguard Worker   bool _showSystemFiles;
1466*f6dc9357SAndroid Build Coastguard Worker   bool _showDeletedFiles;
1467*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<UString2> VirtFolderNames;
1468*f6dc9357SAndroid Build Coastguard Worker   UString EmptyString;
1469*f6dc9357SAndroid Build Coastguard Worker 
1470*f6dc9357SAndroid Build Coastguard Worker   int _systemFolderIndex;
1471*f6dc9357SAndroid Build Coastguard Worker   int _lostFolderIndex_Normal;
1472*f6dc9357SAndroid Build Coastguard Worker   int _lostFolderIndex_Deleted;
1473*f6dc9357SAndroid Build Coastguard Worker 
1474*f6dc9357SAndroid Build Coastguard Worker   void InitProps()
1475*f6dc9357SAndroid Build Coastguard Worker   {
1476*f6dc9357SAndroid Build Coastguard Worker     _showSystemFiles = true;
1477*f6dc9357SAndroid Build Coastguard Worker     // we show SystemFiles by default since it's difficult to track $Extend\* system files
1478*f6dc9357SAndroid Build Coastguard Worker     // it must be fixed later
1479*f6dc9357SAndroid Build Coastguard Worker     _showDeletedFiles = false;
1480*f6dc9357SAndroid Build Coastguard Worker   }
1481*f6dc9357SAndroid Build Coastguard Worker 
1482*f6dc9357SAndroid Build Coastguard Worker   CDatabase() { InitProps(); }
1483*f6dc9357SAndroid Build Coastguard Worker   ~CDatabase() { ClearAndClose(); }
1484*f6dc9357SAndroid Build Coastguard Worker 
1485*f6dc9357SAndroid Build Coastguard Worker   void Clear();
1486*f6dc9357SAndroid Build Coastguard Worker   void ClearAndClose();
1487*f6dc9357SAndroid Build Coastguard Worker 
1488*f6dc9357SAndroid Build Coastguard Worker   void GetItemPath(unsigned index, NCOM::CPropVariant &path) const;
1489*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open();
1490*f6dc9357SAndroid Build Coastguard Worker 
1491*f6dc9357SAndroid Build Coastguard Worker   HRESULT SeekToCluster(UInt64 cluster);
1492*f6dc9357SAndroid Build Coastguard Worker 
1493*f6dc9357SAndroid Build Coastguard Worker   int Find_DirItem_For_MftRec(UInt64 recIndex) const
1494*f6dc9357SAndroid Build Coastguard Worker   {
1495*f6dc9357SAndroid Build Coastguard Worker     if (recIndex >= Recs.Size())
1496*f6dc9357SAndroid Build Coastguard Worker       return -1;
1497*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[(unsigned)recIndex];
1498*f6dc9357SAndroid Build Coastguard Worker     if (!rec.IsDir())
1499*f6dc9357SAndroid Build Coastguard Worker       return -1;
1500*f6dc9357SAndroid Build Coastguard Worker     return rec.MyItemIndex;
1501*f6dc9357SAndroid Build Coastguard Worker     /*
1502*f6dc9357SAndroid Build Coastguard Worker     unsigned left = 0, right = Items.Size();
1503*f6dc9357SAndroid Build Coastguard Worker     while (left != right)
1504*f6dc9357SAndroid Build Coastguard Worker     {
1505*f6dc9357SAndroid Build Coastguard Worker       unsigned mid = (left + right) / 2;
1506*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = Items[mid];
1507*f6dc9357SAndroid Build Coastguard Worker       UInt64 midValue = item.RecIndex;
1508*f6dc9357SAndroid Build Coastguard Worker       if (recIndex == midValue)
1509*f6dc9357SAndroid Build Coastguard Worker       {
1510*f6dc9357SAndroid Build Coastguard Worker         // if item is not dir (file or alt stream we don't return it)
1511*f6dc9357SAndroid Build Coastguard Worker         // if (item.DataIndex < 0)
1512*f6dc9357SAndroid Build Coastguard Worker         if (item.IsDir())
1513*f6dc9357SAndroid Build Coastguard Worker           return mid;
1514*f6dc9357SAndroid Build Coastguard Worker         right = mid;
1515*f6dc9357SAndroid Build Coastguard Worker       }
1516*f6dc9357SAndroid Build Coastguard Worker       else if (recIndex < midValue)
1517*f6dc9357SAndroid Build Coastguard Worker         right = mid;
1518*f6dc9357SAndroid Build Coastguard Worker       else
1519*f6dc9357SAndroid Build Coastguard Worker         left = mid + 1;
1520*f6dc9357SAndroid Build Coastguard Worker     }
1521*f6dc9357SAndroid Build Coastguard Worker     return -1;
1522*f6dc9357SAndroid Build Coastguard Worker     */
1523*f6dc9357SAndroid Build Coastguard Worker   }
1524*f6dc9357SAndroid Build Coastguard Worker 
1525*f6dc9357SAndroid Build Coastguard Worker   bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const;
1526*f6dc9357SAndroid Build Coastguard Worker 
1527*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseSecuritySDS_2();
1528*f6dc9357SAndroid Build Coastguard Worker   void ParseSecuritySDS()
1529*f6dc9357SAndroid Build Coastguard Worker   {
1530*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = ParseSecuritySDS_2();
1531*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
1532*f6dc9357SAndroid Build Coastguard Worker     {
1533*f6dc9357SAndroid Build Coastguard Worker       SecurOffsets.Clear();
1534*f6dc9357SAndroid Build Coastguard Worker       SecurData.Free();
1535*f6dc9357SAndroid Build Coastguard Worker     }
1536*f6dc9357SAndroid Build Coastguard Worker   }
1537*f6dc9357SAndroid Build Coastguard Worker 
1538*f6dc9357SAndroid Build Coastguard Worker };
1539*f6dc9357SAndroid Build Coastguard Worker 
1540*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::SeekToCluster(UInt64 cluster)
1541*f6dc9357SAndroid Build Coastguard Worker {
1542*f6dc9357SAndroid Build Coastguard Worker   return InStream_SeekSet(InStream, cluster << Header.ClusterSizeLog);
1543*f6dc9357SAndroid Build Coastguard Worker }
1544*f6dc9357SAndroid Build Coastguard Worker 
1545*f6dc9357SAndroid Build Coastguard Worker void CDatabase::Clear()
1546*f6dc9357SAndroid Build Coastguard Worker {
1547*f6dc9357SAndroid Build Coastguard Worker   Items.Clear();
1548*f6dc9357SAndroid Build Coastguard Worker   Recs.Clear();
1549*f6dc9357SAndroid Build Coastguard Worker   SecurOffsets.Clear();
1550*f6dc9357SAndroid Build Coastguard Worker   SecurData.Free();
1551*f6dc9357SAndroid Build Coastguard Worker   VirtFolderNames.Clear();
1552*f6dc9357SAndroid Build Coastguard Worker   _systemFolderIndex = -1;
1553*f6dc9357SAndroid Build Coastguard Worker   _lostFolderIndex_Normal = -1;
1554*f6dc9357SAndroid Build Coastguard Worker   _lostFolderIndex_Deleted = -1;
1555*f6dc9357SAndroid Build Coastguard Worker   ThereAreAltStreams = false;
1556*f6dc9357SAndroid Build Coastguard Worker   // _headerWarning = false;
1557*f6dc9357SAndroid Build Coastguard Worker   PhySize = 0;
1558*f6dc9357SAndroid Build Coastguard Worker }
1559*f6dc9357SAndroid Build Coastguard Worker 
1560*f6dc9357SAndroid Build Coastguard Worker void CDatabase::ClearAndClose()
1561*f6dc9357SAndroid Build Coastguard Worker {
1562*f6dc9357SAndroid Build Coastguard Worker   Clear();
1563*f6dc9357SAndroid Build Coastguard Worker   InStream.Release();
1564*f6dc9357SAndroid Build Coastguard Worker }
1565*f6dc9357SAndroid Build Coastguard Worker 
1566*f6dc9357SAndroid Build Coastguard Worker 
1567*f6dc9357SAndroid Build Coastguard Worker static void CopyName(wchar_t *dest, const wchar_t *src)
1568*f6dc9357SAndroid Build Coastguard Worker {
1569*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1570*f6dc9357SAndroid Build Coastguard Worker   {
1571*f6dc9357SAndroid Build Coastguard Worker     wchar_t c = *src++;
1572*f6dc9357SAndroid Build Coastguard Worker     // 18.06
1573*f6dc9357SAndroid Build Coastguard Worker     if (c == '\\' || c == '/')
1574*f6dc9357SAndroid Build Coastguard Worker       c = '_';
1575*f6dc9357SAndroid Build Coastguard Worker     *dest++ = c;
1576*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
1577*f6dc9357SAndroid Build Coastguard Worker       return;
1578*f6dc9357SAndroid Build Coastguard Worker   }
1579*f6dc9357SAndroid Build Coastguard Worker }
1580*f6dc9357SAndroid Build Coastguard Worker 
1581*f6dc9357SAndroid Build Coastguard Worker void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
1582*f6dc9357SAndroid Build Coastguard Worker {
1583*f6dc9357SAndroid Build Coastguard Worker   const CItem *item = &Items[index];
1584*f6dc9357SAndroid Build Coastguard Worker   unsigned size = 0;
1585*f6dc9357SAndroid Build Coastguard Worker   const CMftRec &rec = Recs[item->RecIndex];
1586*f6dc9357SAndroid Build Coastguard Worker   size += rec.FileNames[item->NameIndex].Name.Len();
1587*f6dc9357SAndroid Build Coastguard Worker 
1588*f6dc9357SAndroid Build Coastguard Worker   bool isAltStream = item->IsAltStream();
1589*f6dc9357SAndroid Build Coastguard Worker 
1590*f6dc9357SAndroid Build Coastguard Worker   if (isAltStream)
1591*f6dc9357SAndroid Build Coastguard Worker   {
1592*f6dc9357SAndroid Build Coastguard Worker     const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start];
1593*f6dc9357SAndroid Build Coastguard Worker     if (item->RecIndex == kRecIndex_RootDir)
1594*f6dc9357SAndroid Build Coastguard Worker     {
1595*f6dc9357SAndroid Build Coastguard Worker       wchar_t *s = path.AllocBstr(data.Name.Len() + 1);
1596*f6dc9357SAndroid Build Coastguard Worker       s[0] = L':';
1597*f6dc9357SAndroid Build Coastguard Worker       if (!data.Name.IsEmpty())
1598*f6dc9357SAndroid Build Coastguard Worker         CopyName(s + 1, data.Name.GetRawPtr());
1599*f6dc9357SAndroid Build Coastguard Worker       return;
1600*f6dc9357SAndroid Build Coastguard Worker     }
1601*f6dc9357SAndroid Build Coastguard Worker 
1602*f6dc9357SAndroid Build Coastguard Worker     size += data.Name.Len();
1603*f6dc9357SAndroid Build Coastguard Worker     size++;
1604*f6dc9357SAndroid Build Coastguard Worker   }
1605*f6dc9357SAndroid Build Coastguard Worker 
1606*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0;; i++)
1607*f6dc9357SAndroid Build Coastguard Worker   {
1608*f6dc9357SAndroid Build Coastguard Worker     if (i > 256)
1609*f6dc9357SAndroid Build Coastguard Worker     {
1610*f6dc9357SAndroid Build Coastguard Worker       path = "[TOO-LONG]";
1611*f6dc9357SAndroid Build Coastguard Worker       return;
1612*f6dc9357SAndroid Build Coastguard Worker     }
1613*f6dc9357SAndroid Build Coastguard Worker     const wchar_t *servName;
1614*f6dc9357SAndroid Build Coastguard Worker     if (item->RecIndex < kNumSysRecs
1615*f6dc9357SAndroid Build Coastguard Worker         /* && item->RecIndex != kRecIndex_RootDir */)
1616*f6dc9357SAndroid Build Coastguard Worker       servName = kVirtualFolder_System;
1617*f6dc9357SAndroid Build Coastguard Worker     else
1618*f6dc9357SAndroid Build Coastguard Worker     {
1619*f6dc9357SAndroid Build Coastguard Worker       int index2 = item->ParentFolder;
1620*f6dc9357SAndroid Build Coastguard Worker       if (index2 >= 0)
1621*f6dc9357SAndroid Build Coastguard Worker       {
1622*f6dc9357SAndroid Build Coastguard Worker         item = &Items[index2];
1623*f6dc9357SAndroid Build Coastguard Worker         size += Recs[item->RecIndex].FileNames[item->NameIndex].Name.Len() + 1;
1624*f6dc9357SAndroid Build Coastguard Worker         continue;
1625*f6dc9357SAndroid Build Coastguard Worker       }
1626*f6dc9357SAndroid Build Coastguard Worker       if (index2 == -1)
1627*f6dc9357SAndroid Build Coastguard Worker         break;
1628*f6dc9357SAndroid Build Coastguard Worker       servName = (index2 == k_ParentFolderIndex_Lost) ?
1629*f6dc9357SAndroid Build Coastguard Worker           kVirtualFolder_Lost_Normal :
1630*f6dc9357SAndroid Build Coastguard Worker           kVirtualFolder_Lost_Deleted;
1631*f6dc9357SAndroid Build Coastguard Worker     }
1632*f6dc9357SAndroid Build Coastguard Worker     size += MyStringLen(servName) + 1;
1633*f6dc9357SAndroid Build Coastguard Worker     break;
1634*f6dc9357SAndroid Build Coastguard Worker   }
1635*f6dc9357SAndroid Build Coastguard Worker 
1636*f6dc9357SAndroid Build Coastguard Worker   wchar_t *s = path.AllocBstr(size);
1637*f6dc9357SAndroid Build Coastguard Worker 
1638*f6dc9357SAndroid Build Coastguard Worker   item = &Items[index];
1639*f6dc9357SAndroid Build Coastguard Worker 
1640*f6dc9357SAndroid Build Coastguard Worker   bool needColon = false;
1641*f6dc9357SAndroid Build Coastguard Worker   if (isAltStream)
1642*f6dc9357SAndroid Build Coastguard Worker   {
1643*f6dc9357SAndroid Build Coastguard Worker     const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name;
1644*f6dc9357SAndroid Build Coastguard Worker     if (!name.IsEmpty())
1645*f6dc9357SAndroid Build Coastguard Worker     {
1646*f6dc9357SAndroid Build Coastguard Worker       size -= name.Len();
1647*f6dc9357SAndroid Build Coastguard Worker       CopyName(s + size, name.GetRawPtr());
1648*f6dc9357SAndroid Build Coastguard Worker     }
1649*f6dc9357SAndroid Build Coastguard Worker     s[--size] = ':';
1650*f6dc9357SAndroid Build Coastguard Worker     needColon = true;
1651*f6dc9357SAndroid Build Coastguard Worker   }
1652*f6dc9357SAndroid Build Coastguard Worker 
1653*f6dc9357SAndroid Build Coastguard Worker   {
1654*f6dc9357SAndroid Build Coastguard Worker     const UString2 &name = rec.FileNames[item->NameIndex].Name;
1655*f6dc9357SAndroid Build Coastguard Worker     unsigned len = name.Len();
1656*f6dc9357SAndroid Build Coastguard Worker     if (len != 0)
1657*f6dc9357SAndroid Build Coastguard Worker       CopyName(s + size - len, name.GetRawPtr());
1658*f6dc9357SAndroid Build Coastguard Worker     if (needColon)
1659*f6dc9357SAndroid Build Coastguard Worker       s[size] =  ':';
1660*f6dc9357SAndroid Build Coastguard Worker     size -= len;
1661*f6dc9357SAndroid Build Coastguard Worker   }
1662*f6dc9357SAndroid Build Coastguard Worker 
1663*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1664*f6dc9357SAndroid Build Coastguard Worker   {
1665*f6dc9357SAndroid Build Coastguard Worker     const wchar_t *servName;
1666*f6dc9357SAndroid Build Coastguard Worker     if (item->RecIndex < kNumSysRecs
1667*f6dc9357SAndroid Build Coastguard Worker         /* && && item->RecIndex != kRecIndex_RootDir */)
1668*f6dc9357SAndroid Build Coastguard Worker       servName = kVirtualFolder_System;
1669*f6dc9357SAndroid Build Coastguard Worker     else
1670*f6dc9357SAndroid Build Coastguard Worker     {
1671*f6dc9357SAndroid Build Coastguard Worker       int index2 = item->ParentFolder;
1672*f6dc9357SAndroid Build Coastguard Worker       if (index2 >= 0)
1673*f6dc9357SAndroid Build Coastguard Worker       {
1674*f6dc9357SAndroid Build Coastguard Worker         item = &Items[index2];
1675*f6dc9357SAndroid Build Coastguard Worker         const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name;
1676*f6dc9357SAndroid Build Coastguard Worker         unsigned len = name.Len();
1677*f6dc9357SAndroid Build Coastguard Worker         size--;
1678*f6dc9357SAndroid Build Coastguard Worker         if (len != 0)
1679*f6dc9357SAndroid Build Coastguard Worker         {
1680*f6dc9357SAndroid Build Coastguard Worker           size -= len;
1681*f6dc9357SAndroid Build Coastguard Worker           CopyName(s + size, name.GetRawPtr());
1682*f6dc9357SAndroid Build Coastguard Worker         }
1683*f6dc9357SAndroid Build Coastguard Worker         s[size + len] = WCHAR_PATH_SEPARATOR;
1684*f6dc9357SAndroid Build Coastguard Worker         continue;
1685*f6dc9357SAndroid Build Coastguard Worker       }
1686*f6dc9357SAndroid Build Coastguard Worker       if (index2 == -1)
1687*f6dc9357SAndroid Build Coastguard Worker         break;
1688*f6dc9357SAndroid Build Coastguard Worker       servName = (index2 == k_ParentFolderIndex_Lost) ?
1689*f6dc9357SAndroid Build Coastguard Worker           kVirtualFolder_Lost_Normal :
1690*f6dc9357SAndroid Build Coastguard Worker           kVirtualFolder_Lost_Deleted;
1691*f6dc9357SAndroid Build Coastguard Worker     }
1692*f6dc9357SAndroid Build Coastguard Worker     MyStringCopy(s, servName);
1693*f6dc9357SAndroid Build Coastguard Worker     s[MyStringLen(servName)] = WCHAR_PATH_SEPARATOR;
1694*f6dc9357SAndroid Build Coastguard Worker     break;
1695*f6dc9357SAndroid Build Coastguard Worker   }
1696*f6dc9357SAndroid Build Coastguard Worker }
1697*f6dc9357SAndroid Build Coastguard Worker 
1698*f6dc9357SAndroid Build Coastguard Worker bool CDatabase::FindSecurityDescritor(UInt32 item, UInt64 &offset, UInt32 &size) const
1699*f6dc9357SAndroid Build Coastguard Worker {
1700*f6dc9357SAndroid Build Coastguard Worker   offset = 0;
1701*f6dc9357SAndroid Build Coastguard Worker   size = 0;
1702*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = SecurOffsets.Size();
1703*f6dc9357SAndroid Build Coastguard Worker   while (left != right)
1704*f6dc9357SAndroid Build Coastguard Worker   {
1705*f6dc9357SAndroid Build Coastguard Worker     unsigned mid = (left + right) / 2;
1706*f6dc9357SAndroid Build Coastguard Worker     size_t offs = SecurOffsets[mid];
1707*f6dc9357SAndroid Build Coastguard Worker     UInt32 midValue = Get32(((const Byte *)SecurData) + offs + 4);
1708*f6dc9357SAndroid Build Coastguard Worker     if (item == midValue)
1709*f6dc9357SAndroid Build Coastguard Worker     {
1710*f6dc9357SAndroid Build Coastguard Worker       offset = Get64((const Byte *)SecurData + offs + 8) + 20;
1711*f6dc9357SAndroid Build Coastguard Worker       size = Get32((const Byte *)SecurData + offs + 16) - 20;
1712*f6dc9357SAndroid Build Coastguard Worker       return true;
1713*f6dc9357SAndroid Build Coastguard Worker     }
1714*f6dc9357SAndroid Build Coastguard Worker     if (item < midValue)
1715*f6dc9357SAndroid Build Coastguard Worker       right = mid;
1716*f6dc9357SAndroid Build Coastguard Worker     else
1717*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
1718*f6dc9357SAndroid Build Coastguard Worker   }
1719*f6dc9357SAndroid Build Coastguard Worker   return false;
1720*f6dc9357SAndroid Build Coastguard Worker }
1721*f6dc9357SAndroid Build Coastguard Worker 
1722*f6dc9357SAndroid Build Coastguard Worker /*
1723*f6dc9357SAndroid Build Coastguard Worker static int CompareIDs(const size_t *p1, const size_t *p2, void *data)
1724*f6dc9357SAndroid Build Coastguard Worker {
1725*f6dc9357SAndroid Build Coastguard Worker   UInt32 id1 = Get32(((const Byte *)data) + *p1 + 4);
1726*f6dc9357SAndroid Build Coastguard Worker   UInt32 id2 = Get32(((const Byte *)data) + *p2 + 4);
1727*f6dc9357SAndroid Build Coastguard Worker   return MyCompare(id1, id2);
1728*f6dc9357SAndroid Build Coastguard Worker }
1729*f6dc9357SAndroid Build Coastguard Worker */
1730*f6dc9357SAndroid Build Coastguard Worker 
1731*f6dc9357SAndroid Build Coastguard Worker // security data contains duplication copy after each 256 KB.
1732*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSecureDuplicateStepBits = 18;
1733*f6dc9357SAndroid Build Coastguard Worker 
1734*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::ParseSecuritySDS_2()
1735*f6dc9357SAndroid Build Coastguard Worker {
1736*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = SecurData;
1737*f6dc9357SAndroid Build Coastguard Worker   size_t size = SecurData.Size();
1738*f6dc9357SAndroid Build Coastguard Worker   const size_t kDuplicateStep = (size_t)1 << kSecureDuplicateStepBits;
1739*f6dc9357SAndroid Build Coastguard Worker   const size_t kDuplicateMask = kDuplicateStep - 1;
1740*f6dc9357SAndroid Build Coastguard Worker   size_t lim = MyMin(size, kDuplicateStep);
1741*f6dc9357SAndroid Build Coastguard Worker   UInt32 idPrev = 0;
1742*f6dc9357SAndroid Build Coastguard Worker   for (size_t pos = 0; pos < size && size - pos >= 20;)
1743*f6dc9357SAndroid Build Coastguard Worker   {
1744*f6dc9357SAndroid Build Coastguard Worker     UInt32 id = Get32(p + pos + 4);
1745*f6dc9357SAndroid Build Coastguard Worker     UInt64 offs = Get64(p + pos + 8);
1746*f6dc9357SAndroid Build Coastguard Worker     UInt32 entrySize = Get32(p + pos + 16);
1747*f6dc9357SAndroid Build Coastguard Worker     if (offs == pos && entrySize >= 20 && lim - pos >= entrySize)
1748*f6dc9357SAndroid Build Coastguard Worker     {
1749*f6dc9357SAndroid Build Coastguard Worker       if (id <= idPrev)
1750*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1751*f6dc9357SAndroid Build Coastguard Worker       idPrev = id;
1752*f6dc9357SAndroid Build Coastguard Worker       SecurOffsets.Add(pos);
1753*f6dc9357SAndroid Build Coastguard Worker       pos += entrySize;
1754*f6dc9357SAndroid Build Coastguard Worker       pos = (pos + 0xF) & ~(size_t)0xF;
1755*f6dc9357SAndroid Build Coastguard Worker       if ((pos & kDuplicateMask) != 0)
1756*f6dc9357SAndroid Build Coastguard Worker         continue;
1757*f6dc9357SAndroid Build Coastguard Worker     }
1758*f6dc9357SAndroid Build Coastguard Worker     else
1759*f6dc9357SAndroid Build Coastguard Worker       pos = (pos + kDuplicateStep) & ~kDuplicateMask;
1760*f6dc9357SAndroid Build Coastguard Worker     pos += kDuplicateStep;
1761*f6dc9357SAndroid Build Coastguard Worker     lim = pos + kDuplicateStep;
1762*f6dc9357SAndroid Build Coastguard Worker     if (lim >= size)
1763*f6dc9357SAndroid Build Coastguard Worker       lim = size;
1764*f6dc9357SAndroid Build Coastguard Worker   }
1765*f6dc9357SAndroid Build Coastguard Worker   // we checked that IDs are sorted, so we don't need Sort
1766*f6dc9357SAndroid Build Coastguard Worker   // SecurOffsets.Sort(CompareIDs, (void *)p);
1767*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1768*f6dc9357SAndroid Build Coastguard Worker }
1769*f6dc9357SAndroid Build Coastguard Worker 
1770*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::Open()
1771*f6dc9357SAndroid Build Coastguard Worker {
1772*f6dc9357SAndroid Build Coastguard Worker   Clear();
1773*f6dc9357SAndroid Build Coastguard Worker 
1774*f6dc9357SAndroid Build Coastguard Worker   /* NTFS layout:
1775*f6dc9357SAndroid Build Coastguard Worker      1) main part (as specified by NumClusters). Only that part is available, if we open "\\.\c:"
1776*f6dc9357SAndroid Build Coastguard Worker      2) additional empty sectors (as specified by NumSectors)
1777*f6dc9357SAndroid Build Coastguard Worker      3) the copy of first sector (boot sector)
1778*f6dc9357SAndroid Build Coastguard Worker 
1779*f6dc9357SAndroid Build Coastguard Worker      We support both cases:
1780*f6dc9357SAndroid Build Coastguard Worker       - the file with only main part
1781*f6dc9357SAndroid Build Coastguard Worker       - full file (as raw data on partition), including the copy
1782*f6dc9357SAndroid Build Coastguard Worker         of first sector (boot sector) at the end of data
1783*f6dc9357SAndroid Build Coastguard Worker 
1784*f6dc9357SAndroid Build Coastguard Worker      We don't support the case, when only the copy of boot sector
1785*f6dc9357SAndroid Build Coastguard Worker      at the end was detected as NTFS signature.
1786*f6dc9357SAndroid Build Coastguard Worker   */
1787*f6dc9357SAndroid Build Coastguard Worker 
1788*f6dc9357SAndroid Build Coastguard Worker   {
1789*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kHeaderSize = 512;
1790*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kHeaderSize];
1791*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
1792*f6dc9357SAndroid Build Coastguard Worker     if (!Header.Parse(buf))
1793*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1794*f6dc9357SAndroid Build Coastguard Worker 
1795*f6dc9357SAndroid Build Coastguard Worker     UInt64 fileSize;
1796*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
1797*f6dc9357SAndroid Build Coastguard Worker     PhySize = Header.GetPhySize_Clusters();
1798*f6dc9357SAndroid Build Coastguard Worker     if (fileSize < PhySize)
1799*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1800*f6dc9357SAndroid Build Coastguard Worker 
1801*f6dc9357SAndroid Build Coastguard Worker     UInt64 phySizeMax = Header.GetPhySize_Max();
1802*f6dc9357SAndroid Build Coastguard Worker     if (fileSize >= phySizeMax)
1803*f6dc9357SAndroid Build Coastguard Worker     {
1804*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(InStream, Header.NumSectors << Header.SectorSizeLog))
1805*f6dc9357SAndroid Build Coastguard Worker       Byte buf2[kHeaderSize];
1806*f6dc9357SAndroid Build Coastguard Worker       if (ReadStream_FALSE(InStream, buf2, kHeaderSize) == S_OK)
1807*f6dc9357SAndroid Build Coastguard Worker       {
1808*f6dc9357SAndroid Build Coastguard Worker         if (memcmp(buf, buf2, kHeaderSize) == 0)
1809*f6dc9357SAndroid Build Coastguard Worker           PhySize = phySizeMax;
1810*f6dc9357SAndroid Build Coastguard Worker         // else _headerWarning = true;
1811*f6dc9357SAndroid Build Coastguard Worker       }
1812*f6dc9357SAndroid Build Coastguard Worker     }
1813*f6dc9357SAndroid Build Coastguard Worker   }
1814*f6dc9357SAndroid Build Coastguard Worker 
1815*f6dc9357SAndroid Build Coastguard Worker   SeekToCluster(Header.MftCluster);
1816*f6dc9357SAndroid Build Coastguard Worker 
1817*f6dc9357SAndroid Build Coastguard Worker   // we use ByteBuf for records reading.
1818*f6dc9357SAndroid Build Coastguard Worker   // so the size of ByteBuf must be >= mftRecordSize
1819*f6dc9357SAndroid Build Coastguard Worker   const size_t recSize = (size_t)1 << Header.MftRecordSizeLog;
1820*f6dc9357SAndroid Build Coastguard Worker   const size_t kBufSize = MyMax((size_t)(1 << 15), recSize);
1821*f6dc9357SAndroid Build Coastguard Worker   ByteBuf.Alloc(kBufSize);
1822*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(InStream, ByteBuf, recSize))
1823*f6dc9357SAndroid Build Coastguard Worker   {
1824*f6dc9357SAndroid Build Coastguard Worker     const UInt32 allocSize = Get32(ByteBuf + 0x1C);
1825*f6dc9357SAndroid Build Coastguard Worker     if (allocSize != recSize)
1826*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1827*f6dc9357SAndroid Build Coastguard Worker   }
1828*f6dc9357SAndroid Build Coastguard Worker   // MftRecordSizeLog >= SectorSizeLog
1829*f6dc9357SAndroid Build Coastguard Worker   const UInt32 numSectorsInRec = 1u << (Header.MftRecordSizeLog - Header.SectorSizeLog);
1830*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> mftStream;
1831*f6dc9357SAndroid Build Coastguard Worker   CMftRec mftRec;
1832*f6dc9357SAndroid Build Coastguard Worker   {
1833*f6dc9357SAndroid Build Coastguard Worker     if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL))
1834*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1835*f6dc9357SAndroid Build Coastguard Worker     if (!mftRec.Is_Magic_FILE())
1836*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1837*f6dc9357SAndroid Build Coastguard Worker     mftRec.ParseDataNames();
1838*f6dc9357SAndroid Build Coastguard Worker     if (mftRec.DataRefs.IsEmpty())
1839*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1840*f6dc9357SAndroid Build Coastguard Worker     RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream))
1841*f6dc9357SAndroid Build Coastguard Worker     if (!mftStream)
1842*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1843*f6dc9357SAndroid Build Coastguard Worker   }
1844*f6dc9357SAndroid Build Coastguard Worker 
1845*f6dc9357SAndroid Build Coastguard Worker   // CObjectVector<CAttr> SecurityAttrs;
1846*f6dc9357SAndroid Build Coastguard Worker 
1847*f6dc9357SAndroid Build Coastguard Worker   const UInt64 mftSize = mftRec.DataAttrs[0].Size;
1848*f6dc9357SAndroid Build Coastguard Worker   if ((mftSize >> 4) > Header.GetPhySize_Clusters())
1849*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1850*f6dc9357SAndroid Build Coastguard Worker 
1851*f6dc9357SAndroid Build Coastguard Worker   {
1852*f6dc9357SAndroid Build Coastguard Worker     const UInt64 numFiles = mftSize >> Header.MftRecordSizeLog;
1853*f6dc9357SAndroid Build Coastguard Worker     if (numFiles > (1 << 30))
1854*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1855*f6dc9357SAndroid Build Coastguard Worker     if (OpenCallback)
1856*f6dc9357SAndroid Build Coastguard Worker     {
1857*f6dc9357SAndroid Build Coastguard Worker       RINOK(OpenCallback->SetTotal(&numFiles, &mftSize))
1858*f6dc9357SAndroid Build Coastguard Worker     }
1859*f6dc9357SAndroid Build Coastguard Worker     Recs.ClearAndReserve((unsigned)numFiles);
1860*f6dc9357SAndroid Build Coastguard Worker   }
1861*f6dc9357SAndroid Build Coastguard Worker 
1862*f6dc9357SAndroid Build Coastguard Worker   for (UInt64 pos64 = 0;;)
1863*f6dc9357SAndroid Build Coastguard Worker   {
1864*f6dc9357SAndroid Build Coastguard Worker     if (OpenCallback)
1865*f6dc9357SAndroid Build Coastguard Worker     {
1866*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles = Recs.Size();
1867*f6dc9357SAndroid Build Coastguard Worker       if ((numFiles & 0x3FFF) == 0)
1868*f6dc9357SAndroid Build Coastguard Worker       {
1869*f6dc9357SAndroid Build Coastguard Worker         RINOK(OpenCallback->SetCompleted(&numFiles, &pos64))
1870*f6dc9357SAndroid Build Coastguard Worker       }
1871*f6dc9357SAndroid Build Coastguard Worker     }
1872*f6dc9357SAndroid Build Coastguard Worker     size_t readSize = kBufSize;
1873*f6dc9357SAndroid Build Coastguard Worker     {
1874*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = mftSize - pos64;
1875*f6dc9357SAndroid Build Coastguard Worker       if (readSize > rem)
1876*f6dc9357SAndroid Build Coastguard Worker         readSize = (size_t)rem;
1877*f6dc9357SAndroid Build Coastguard Worker     }
1878*f6dc9357SAndroid Build Coastguard Worker     if (readSize < recSize)
1879*f6dc9357SAndroid Build Coastguard Worker       break;
1880*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize))
1881*f6dc9357SAndroid Build Coastguard Worker     pos64 += readSize;
1882*f6dc9357SAndroid Build Coastguard Worker 
1883*f6dc9357SAndroid Build Coastguard Worker     for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize)
1884*f6dc9357SAndroid Build Coastguard Worker     {
1885*f6dc9357SAndroid Build Coastguard Worker       PRF(printf("\n---------------------"));
1886*f6dc9357SAndroid Build Coastguard Worker       PRF(printf("\n%5d:", Recs.Size()));
1887*f6dc9357SAndroid Build Coastguard Worker 
1888*f6dc9357SAndroid Build Coastguard Worker       Byte *p = ByteBuf + i;
1889*f6dc9357SAndroid Build Coastguard Worker       CMftRec rec;
1890*f6dc9357SAndroid Build Coastguard Worker 
1891*f6dc9357SAndroid Build Coastguard Worker       CObjectVector<CAttr> *attrs = NULL;
1892*f6dc9357SAndroid Build Coastguard Worker       unsigned recIndex = Recs.Size();
1893*f6dc9357SAndroid Build Coastguard Worker       switch (recIndex)
1894*f6dc9357SAndroid Build Coastguard Worker       {
1895*f6dc9357SAndroid Build Coastguard Worker         case kRecIndex_Volume: attrs = &VolAttrs; break;
1896*f6dc9357SAndroid Build Coastguard Worker         // case kRecIndex_Security: attrs = &SecurityAttrs; break;
1897*f6dc9357SAndroid Build Coastguard Worker       }
1898*f6dc9357SAndroid Build Coastguard Worker 
1899*f6dc9357SAndroid Build Coastguard Worker       if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs))
1900*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1901*f6dc9357SAndroid Build Coastguard Worker       Recs.Add(rec);
1902*f6dc9357SAndroid Build Coastguard Worker     }
1903*f6dc9357SAndroid Build Coastguard Worker   }
1904*f6dc9357SAndroid Build Coastguard Worker 
1905*f6dc9357SAndroid Build Coastguard Worker   /*
1906*f6dc9357SAndroid Build Coastguard Worker   // that code looks too complex. And we can get security info without index parsing
1907*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < SecurityAttrs.Size(); i++)
1908*f6dc9357SAndroid Build Coastguard Worker   {
1909*f6dc9357SAndroid Build Coastguard Worker     const CAttr &attr = SecurityAttrs[i];
1910*f6dc9357SAndroid Build Coastguard Worker     if (attr.Name == L"$SII")
1911*f6dc9357SAndroid Build Coastguard Worker     {
1912*f6dc9357SAndroid Build Coastguard Worker       if (attr.Type == ATTR_TYPE_INDEX_ROOT)
1913*f6dc9357SAndroid Build Coastguard Worker       {
1914*f6dc9357SAndroid Build Coastguard Worker         const Byte *data = attr.Data;
1915*f6dc9357SAndroid Build Coastguard Worker         size_t size = attr.Data.Size();
1916*f6dc9357SAndroid Build Coastguard Worker 
1917*f6dc9357SAndroid Build Coastguard Worker         // Index Root
1918*f6dc9357SAndroid Build Coastguard Worker         UInt32 attrType = Get32(data);
1919*f6dc9357SAndroid Build Coastguard Worker         UInt32 collationRule = Get32(data + 4);
1920*f6dc9357SAndroid Build Coastguard Worker         UInt32 indexAllocationEtrySizeSize = Get32(data + 8);
1921*f6dc9357SAndroid Build Coastguard Worker         UInt32 clustersPerIndexRecord = Get32(data + 0xC);
1922*f6dc9357SAndroid Build Coastguard Worker         data += 0x10;
1923*f6dc9357SAndroid Build Coastguard Worker 
1924*f6dc9357SAndroid Build Coastguard Worker         // Index Header
1925*f6dc9357SAndroid Build Coastguard Worker         UInt32 firstEntryOffset = Get32(data);
1926*f6dc9357SAndroid Build Coastguard Worker         UInt32 totalSize = Get32(data + 4);
1927*f6dc9357SAndroid Build Coastguard Worker         UInt32 allocSize = Get32(data + 8);
1928*f6dc9357SAndroid Build Coastguard Worker         UInt32 flags = Get32(data + 0xC);
1929*f6dc9357SAndroid Build Coastguard Worker 
1930*f6dc9357SAndroid Build Coastguard Worker         int num = 0;
1931*f6dc9357SAndroid Build Coastguard Worker         for (int j = 0 ; j < num; j++)
1932*f6dc9357SAndroid Build Coastguard Worker         {
1933*f6dc9357SAndroid Build Coastguard Worker           if (Get32(data) != 0x1414 || // offset and size
1934*f6dc9357SAndroid Build Coastguard Worker               Get32(data + 4) != 0 ||
1935*f6dc9357SAndroid Build Coastguard Worker               Get32(data + 8) != 0x428) // KeySize / EntrySize
1936*f6dc9357SAndroid Build Coastguard Worker             break;
1937*f6dc9357SAndroid Build Coastguard Worker           UInt32 flags = Get32(data + 12);
1938*f6dc9357SAndroid Build Coastguard Worker           UInt32 id = Get32(data + 0x10);
1939*f6dc9357SAndroid Build Coastguard Worker           if (id = Get32(data + 0x18))
1940*f6dc9357SAndroid Build Coastguard Worker             break;
1941*f6dc9357SAndroid Build Coastguard Worker           UInt32 descriptorOffset = Get64(data + 0x1C);
1942*f6dc9357SAndroid Build Coastguard Worker           UInt32 descriptorSize = Get64(data + 0x24);
1943*f6dc9357SAndroid Build Coastguard Worker           data += 0x28;
1944*f6dc9357SAndroid Build Coastguard Worker         }
1945*f6dc9357SAndroid Build Coastguard Worker         // break;
1946*f6dc9357SAndroid Build Coastguard Worker       }
1947*f6dc9357SAndroid Build Coastguard Worker     }
1948*f6dc9357SAndroid Build Coastguard Worker   }
1949*f6dc9357SAndroid Build Coastguard Worker   */
1950*f6dc9357SAndroid Build Coastguard Worker 
1951*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
1952*f6dc9357SAndroid Build Coastguard Worker 
1953*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Recs.Size(); i++)
1954*f6dc9357SAndroid Build Coastguard Worker   {
1955*f6dc9357SAndroid Build Coastguard Worker     CMftRec &rec = Recs[i];
1956*f6dc9357SAndroid Build Coastguard Worker     if (!rec.Is_Magic_FILE())
1957*f6dc9357SAndroid Build Coastguard Worker       continue;
1958*f6dc9357SAndroid Build Coastguard Worker 
1959*f6dc9357SAndroid Build Coastguard Worker     if (!rec.BaseMftRef.IsBaseItself())
1960*f6dc9357SAndroid Build Coastguard Worker     {
1961*f6dc9357SAndroid Build Coastguard Worker       const UInt64 refIndex = rec.BaseMftRef.GetIndex();
1962*f6dc9357SAndroid Build Coastguard Worker       if (refIndex >= Recs.Size())
1963*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1964*f6dc9357SAndroid Build Coastguard Worker       CMftRec &refRec = Recs[(unsigned)refIndex];
1965*f6dc9357SAndroid Build Coastguard Worker       if (!refRec.Is_Magic_FILE())
1966*f6dc9357SAndroid Build Coastguard Worker         continue;
1967*f6dc9357SAndroid Build Coastguard Worker 
1968*f6dc9357SAndroid Build Coastguard Worker       bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
1969*f6dc9357SAndroid Build Coastguard Worker       if (rec.InUse() && refRec.InUse())
1970*f6dc9357SAndroid Build Coastguard Worker       {
1971*f6dc9357SAndroid Build Coastguard Worker         if (!moveAttrs)
1972*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1973*f6dc9357SAndroid Build Coastguard Worker       }
1974*f6dc9357SAndroid Build Coastguard Worker       else if (rec.InUse() || refRec.InUse())
1975*f6dc9357SAndroid Build Coastguard Worker         moveAttrs = false;
1976*f6dc9357SAndroid Build Coastguard Worker       if (moveAttrs)
1977*f6dc9357SAndroid Build Coastguard Worker         refRec.MoveAttrsFrom(rec);
1978*f6dc9357SAndroid Build Coastguard Worker     }
1979*f6dc9357SAndroid Build Coastguard Worker   }
1980*f6dc9357SAndroid Build Coastguard Worker 
1981*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Recs.Size(); i++)
1982*f6dc9357SAndroid Build Coastguard Worker   {
1983*f6dc9357SAndroid Build Coastguard Worker     CMftRec &rec = Recs[i];
1984*f6dc9357SAndroid Build Coastguard Worker     if (!rec.Is_Magic_FILE())
1985*f6dc9357SAndroid Build Coastguard Worker       continue;
1986*f6dc9357SAndroid Build Coastguard Worker     rec.ParseDataNames();
1987*f6dc9357SAndroid Build Coastguard Worker   }
1988*f6dc9357SAndroid Build Coastguard Worker 
1989*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Recs.Size(); i++)
1990*f6dc9357SAndroid Build Coastguard Worker   {
1991*f6dc9357SAndroid Build Coastguard Worker     CMftRec &rec = Recs[i];
1992*f6dc9357SAndroid Build Coastguard Worker     if (!rec.Is_Magic_FILE() || !rec.BaseMftRef.IsBaseItself())
1993*f6dc9357SAndroid Build Coastguard Worker       continue;
1994*f6dc9357SAndroid Build Coastguard Worker     if (i < kNumSysRecs && !_showSystemFiles)
1995*f6dc9357SAndroid Build Coastguard Worker       continue;
1996*f6dc9357SAndroid Build Coastguard Worker     if (!rec.InUse() && !_showDeletedFiles)
1997*f6dc9357SAndroid Build Coastguard Worker       continue;
1998*f6dc9357SAndroid Build Coastguard Worker 
1999*f6dc9357SAndroid Build Coastguard Worker     rec.MyNumNameLinks = rec.FileNames.Size();
2000*f6dc9357SAndroid Build Coastguard Worker 
2001*f6dc9357SAndroid Build Coastguard Worker     // printf("\n%4d: ", i);
2002*f6dc9357SAndroid Build Coastguard Worker 
2003*f6dc9357SAndroid Build Coastguard Worker     /* Actually DataAttrs / DataRefs are sorted by name.
2004*f6dc9357SAndroid Build Coastguard Worker        It can not be more than one unnamed stream in DataRefs
2005*f6dc9357SAndroid Build Coastguard Worker        And indexOfUnnamedStream <= 0.
2006*f6dc9357SAndroid Build Coastguard Worker     */
2007*f6dc9357SAndroid Build Coastguard Worker 
2008*f6dc9357SAndroid Build Coastguard Worker     int indexOfUnnamedStream = -1;
2009*f6dc9357SAndroid Build Coastguard Worker     if (!rec.IsDir())
2010*f6dc9357SAndroid Build Coastguard Worker     {
2011*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (di, rec.DataRefs)
2012*f6dc9357SAndroid Build Coastguard Worker         if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty())
2013*f6dc9357SAndroid Build Coastguard Worker         {
2014*f6dc9357SAndroid Build Coastguard Worker           indexOfUnnamedStream = (int)di;
2015*f6dc9357SAndroid Build Coastguard Worker           break;
2016*f6dc9357SAndroid Build Coastguard Worker         }
2017*f6dc9357SAndroid Build Coastguard Worker     }
2018*f6dc9357SAndroid Build Coastguard Worker 
2019*f6dc9357SAndroid Build Coastguard Worker     if (rec.FileNames.IsEmpty())
2020*f6dc9357SAndroid Build Coastguard Worker     {
2021*f6dc9357SAndroid Build Coastguard Worker       bool needShow = true;
2022*f6dc9357SAndroid Build Coastguard Worker       if (i < kNumSysRecs)
2023*f6dc9357SAndroid Build Coastguard Worker       {
2024*f6dc9357SAndroid Build Coastguard Worker         needShow = false;
2025*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (di, rec.DataRefs)
2026*f6dc9357SAndroid Build Coastguard Worker           if (rec.GetSize(di) != 0)
2027*f6dc9357SAndroid Build Coastguard Worker           {
2028*f6dc9357SAndroid Build Coastguard Worker             needShow = true;
2029*f6dc9357SAndroid Build Coastguard Worker             break;
2030*f6dc9357SAndroid Build Coastguard Worker           }
2031*f6dc9357SAndroid Build Coastguard Worker       }
2032*f6dc9357SAndroid Build Coastguard Worker       if (needShow)
2033*f6dc9357SAndroid Build Coastguard Worker       {
2034*f6dc9357SAndroid Build Coastguard Worker         CFileNameAttr &fna = rec.FileNames.AddNew();
2035*f6dc9357SAndroid Build Coastguard Worker         // we set incorrect ParentDirRef, that will place item to [LOST] folder
2036*f6dc9357SAndroid Build Coastguard Worker         fna.ParentDirRef.Val = (UInt64)(Int64)-1;
2037*f6dc9357SAndroid Build Coastguard Worker         char s[16 + 16];
2038*f6dc9357SAndroid Build Coastguard Worker         ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-"));
2039*f6dc9357SAndroid Build Coastguard Worker         fna.Name.SetFromAscii(s);
2040*f6dc9357SAndroid Build Coastguard Worker         fna.NameType = kFileNameType_Win32Dos;
2041*f6dc9357SAndroid Build Coastguard Worker         fna.Attrib = 0;
2042*f6dc9357SAndroid Build Coastguard Worker       }
2043*f6dc9357SAndroid Build Coastguard Worker     }
2044*f6dc9357SAndroid Build Coastguard Worker 
2045*f6dc9357SAndroid Build Coastguard Worker     // bool isMainName = true;
2046*f6dc9357SAndroid Build Coastguard Worker 
2047*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (t, rec.FileNames)
2048*f6dc9357SAndroid Build Coastguard Worker     {
2049*f6dc9357SAndroid Build Coastguard Worker       #ifdef SHOW_DEBUG_INFO
2050*f6dc9357SAndroid Build Coastguard Worker       const CFileNameAttr &fna = rec.FileNames[t];
2051*f6dc9357SAndroid Build Coastguard Worker       #endif
2052*f6dc9357SAndroid Build Coastguard Worker       PRF(printf("\n %4d ", (int)fna.NameType));
2053*f6dc9357SAndroid Build Coastguard Worker       PRF_UTF16(fna.Name);
2054*f6dc9357SAndroid Build Coastguard Worker       // PRF(printf("  | "));
2055*f6dc9357SAndroid Build Coastguard Worker 
2056*f6dc9357SAndroid Build Coastguard Worker       if (rec.FindWin32Name_for_DosName(t) >= 0)
2057*f6dc9357SAndroid Build Coastguard Worker       {
2058*f6dc9357SAndroid Build Coastguard Worker         rec.MyNumNameLinks--;
2059*f6dc9357SAndroid Build Coastguard Worker         continue;
2060*f6dc9357SAndroid Build Coastguard Worker       }
2061*f6dc9357SAndroid Build Coastguard Worker 
2062*f6dc9357SAndroid Build Coastguard Worker       CItem item;
2063*f6dc9357SAndroid Build Coastguard Worker       item.NameIndex = t;
2064*f6dc9357SAndroid Build Coastguard Worker       item.RecIndex = i;
2065*f6dc9357SAndroid Build Coastguard Worker       item.DataIndex = rec.IsDir() ?
2066*f6dc9357SAndroid Build Coastguard Worker           k_Item_DataIndex_IsDir :
2067*f6dc9357SAndroid Build Coastguard Worker             (indexOfUnnamedStream < 0 ?
2068*f6dc9357SAndroid Build Coastguard Worker           k_Item_DataIndex_IsEmptyFile :
2069*f6dc9357SAndroid Build Coastguard Worker           indexOfUnnamedStream);
2070*f6dc9357SAndroid Build Coastguard Worker 
2071*f6dc9357SAndroid Build Coastguard Worker       if (rec.MyItemIndex < 0)
2072*f6dc9357SAndroid Build Coastguard Worker         rec.MyItemIndex = (int)Items.Size();
2073*f6dc9357SAndroid Build Coastguard Worker       item.ParentHost = (int)Items.Add(item);
2074*f6dc9357SAndroid Build Coastguard Worker 
2075*f6dc9357SAndroid Build Coastguard Worker       /* we can use that code to reduce the number of alt streams:
2076*f6dc9357SAndroid Build Coastguard Worker          it will not show how alt streams for hard links. */
2077*f6dc9357SAndroid Build Coastguard Worker       // if (!isMainName) continue; isMainName = false;
2078*f6dc9357SAndroid Build Coastguard Worker 
2079*f6dc9357SAndroid Build Coastguard Worker       // unsigned numAltStreams = 0;
2080*f6dc9357SAndroid Build Coastguard Worker 
2081*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (di, rec.DataRefs)
2082*f6dc9357SAndroid Build Coastguard Worker       {
2083*f6dc9357SAndroid Build Coastguard Worker         if (!rec.IsDir() && (int)di == indexOfUnnamedStream)
2084*f6dc9357SAndroid Build Coastguard Worker           continue;
2085*f6dc9357SAndroid Build Coastguard Worker 
2086*f6dc9357SAndroid Build Coastguard Worker         const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
2087*f6dc9357SAndroid Build Coastguard Worker 
2088*f6dc9357SAndroid Build Coastguard Worker         PRF(printf("\n alt stream: "));
2089*f6dc9357SAndroid Build Coastguard Worker         PRF_UTF16(subName);
2090*f6dc9357SAndroid Build Coastguard Worker 
2091*f6dc9357SAndroid Build Coastguard Worker         {
2092*f6dc9357SAndroid Build Coastguard Worker           // $BadClus:$Bad is sparse file for all clusters. So we skip it.
2093*f6dc9357SAndroid Build Coastguard Worker           if (i == kRecIndex_BadClus && subName == L"$Bad")
2094*f6dc9357SAndroid Build Coastguard Worker             continue;
2095*f6dc9357SAndroid Build Coastguard Worker         }
2096*f6dc9357SAndroid Build Coastguard Worker 
2097*f6dc9357SAndroid Build Coastguard Worker         // numAltStreams++;
2098*f6dc9357SAndroid Build Coastguard Worker         ThereAreAltStreams = true;
2099*f6dc9357SAndroid Build Coastguard Worker         item.DataIndex = (int)di;
2100*f6dc9357SAndroid Build Coastguard Worker         Items.Add(item);
2101*f6dc9357SAndroid Build Coastguard Worker       }
2102*f6dc9357SAndroid Build Coastguard Worker     }
2103*f6dc9357SAndroid Build Coastguard Worker   }
2104*f6dc9357SAndroid Build Coastguard Worker 
2105*f6dc9357SAndroid Build Coastguard Worker   if (Recs.Size() > kRecIndex_Security)
2106*f6dc9357SAndroid Build Coastguard Worker   {
2107*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[kRecIndex_Security];
2108*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (di, rec.DataRefs)
2109*f6dc9357SAndroid Build Coastguard Worker     {
2110*f6dc9357SAndroid Build Coastguard Worker       const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start];
2111*f6dc9357SAndroid Build Coastguard Worker       if (attr.Name == L"$SDS")
2112*f6dc9357SAndroid Build Coastguard Worker       {
2113*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<IInStream> sdsStream;
2114*f6dc9357SAndroid Build Coastguard Worker         RINOK(rec.GetStream(InStream, (int)di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream))
2115*f6dc9357SAndroid Build Coastguard Worker         if (sdsStream)
2116*f6dc9357SAndroid Build Coastguard Worker         {
2117*f6dc9357SAndroid Build Coastguard Worker           const UInt64 size64 = attr.GetSize();
2118*f6dc9357SAndroid Build Coastguard Worker           if (size64 < (UInt32)1 << 29)
2119*f6dc9357SAndroid Build Coastguard Worker           {
2120*f6dc9357SAndroid Build Coastguard Worker             size_t size = (size_t)size64;
2121*f6dc9357SAndroid Build Coastguard Worker             if ((((size + 1) >> kSecureDuplicateStepBits) & 1) != 0)
2122*f6dc9357SAndroid Build Coastguard Worker             {
2123*f6dc9357SAndroid Build Coastguard Worker               size -= (1 << kSecureDuplicateStepBits);
2124*f6dc9357SAndroid Build Coastguard Worker               SecurData.Alloc(size);
2125*f6dc9357SAndroid Build Coastguard Worker               if (ReadStream_FALSE(sdsStream, SecurData, size) == S_OK)
2126*f6dc9357SAndroid Build Coastguard Worker               {
2127*f6dc9357SAndroid Build Coastguard Worker                 ParseSecuritySDS();
2128*f6dc9357SAndroid Build Coastguard Worker                 break;
2129*f6dc9357SAndroid Build Coastguard Worker               }
2130*f6dc9357SAndroid Build Coastguard Worker             }
2131*f6dc9357SAndroid Build Coastguard Worker           }
2132*f6dc9357SAndroid Build Coastguard Worker         }
2133*f6dc9357SAndroid Build Coastguard Worker         break;
2134*f6dc9357SAndroid Build Coastguard Worker       }
2135*f6dc9357SAndroid Build Coastguard Worker     }
2136*f6dc9357SAndroid Build Coastguard Worker   }
2137*f6dc9357SAndroid Build Coastguard Worker 
2138*f6dc9357SAndroid Build Coastguard Worker   bool thereAreUnknownFolders_Normal = false;
2139*f6dc9357SAndroid Build Coastguard Worker   bool thereAreUnknownFolders_Deleted = false;
2140*f6dc9357SAndroid Build Coastguard Worker 
2141*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Items.Size(); i++)
2142*f6dc9357SAndroid Build Coastguard Worker   {
2143*f6dc9357SAndroid Build Coastguard Worker     CItem &item = Items[i];
2144*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[item.RecIndex];
2145*f6dc9357SAndroid Build Coastguard Worker     const CFileNameAttr &fn = rec.FileNames[item.NameIndex];
2146*f6dc9357SAndroid Build Coastguard Worker     const CMftRef &parentDirRef = fn.ParentDirRef;
2147*f6dc9357SAndroid Build Coastguard Worker     const UInt64 refIndex = parentDirRef.GetIndex();
2148*f6dc9357SAndroid Build Coastguard Worker     if (refIndex == kRecIndex_RootDir)
2149*f6dc9357SAndroid Build Coastguard Worker       item.ParentFolder = -1;
2150*f6dc9357SAndroid Build Coastguard Worker     else
2151*f6dc9357SAndroid Build Coastguard Worker     {
2152*f6dc9357SAndroid Build Coastguard Worker       int index = Find_DirItem_For_MftRec(refIndex);
2153*f6dc9357SAndroid Build Coastguard Worker       if (index < 0 ||
2154*f6dc9357SAndroid Build Coastguard Worker           Recs[Items[index].RecIndex].SeqNumber != parentDirRef.GetNumber())
2155*f6dc9357SAndroid Build Coastguard Worker       {
2156*f6dc9357SAndroid Build Coastguard Worker         if (Recs[item.RecIndex].InUse())
2157*f6dc9357SAndroid Build Coastguard Worker         {
2158*f6dc9357SAndroid Build Coastguard Worker           thereAreUnknownFolders_Normal = true;
2159*f6dc9357SAndroid Build Coastguard Worker           index = k_ParentFolderIndex_Lost;
2160*f6dc9357SAndroid Build Coastguard Worker         }
2161*f6dc9357SAndroid Build Coastguard Worker         else
2162*f6dc9357SAndroid Build Coastguard Worker         {
2163*f6dc9357SAndroid Build Coastguard Worker           thereAreUnknownFolders_Deleted = true;
2164*f6dc9357SAndroid Build Coastguard Worker           index = k_ParentFolderIndex_Deleted;
2165*f6dc9357SAndroid Build Coastguard Worker         }
2166*f6dc9357SAndroid Build Coastguard Worker       }
2167*f6dc9357SAndroid Build Coastguard Worker       item.ParentFolder = index;
2168*f6dc9357SAndroid Build Coastguard Worker     }
2169*f6dc9357SAndroid Build Coastguard Worker   }
2170*f6dc9357SAndroid Build Coastguard Worker 
2171*f6dc9357SAndroid Build Coastguard Worker   unsigned virtIndex = Items.Size();
2172*f6dc9357SAndroid Build Coastguard Worker   if (_showSystemFiles)
2173*f6dc9357SAndroid Build Coastguard Worker   {
2174*f6dc9357SAndroid Build Coastguard Worker     _systemFolderIndex = (int)(virtIndex++);
2175*f6dc9357SAndroid Build Coastguard Worker     VirtFolderNames.Add(kVirtualFolder_System);
2176*f6dc9357SAndroid Build Coastguard Worker   }
2177*f6dc9357SAndroid Build Coastguard Worker   if (thereAreUnknownFolders_Normal)
2178*f6dc9357SAndroid Build Coastguard Worker   {
2179*f6dc9357SAndroid Build Coastguard Worker     _lostFolderIndex_Normal = (int)(virtIndex++);
2180*f6dc9357SAndroid Build Coastguard Worker     VirtFolderNames.Add(kVirtualFolder_Lost_Normal);
2181*f6dc9357SAndroid Build Coastguard Worker   }
2182*f6dc9357SAndroid Build Coastguard Worker   if (thereAreUnknownFolders_Deleted)
2183*f6dc9357SAndroid Build Coastguard Worker   {
2184*f6dc9357SAndroid Build Coastguard Worker     _lostFolderIndex_Deleted = (int)(virtIndex++);
2185*f6dc9357SAndroid Build Coastguard Worker     VirtFolderNames.Add(kVirtualFolder_Lost_Deleted);
2186*f6dc9357SAndroid Build Coastguard Worker   }
2187*f6dc9357SAndroid Build Coastguard Worker 
2188*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2189*f6dc9357SAndroid Build Coastguard Worker }
2190*f6dc9357SAndroid Build Coastguard Worker 
2191*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final:
2192*f6dc9357SAndroid Build Coastguard Worker   public IInArchive,
2193*f6dc9357SAndroid Build Coastguard Worker   public IArchiveGetRawProps,
2194*f6dc9357SAndroid Build Coastguard Worker   public IInArchiveGetStream,
2195*f6dc9357SAndroid Build Coastguard Worker   public ISetProperties,
2196*f6dc9357SAndroid Build Coastguard Worker   public CMyUnknownImp,
2197*f6dc9357SAndroid Build Coastguard Worker   public CDatabase
2198*f6dc9357SAndroid Build Coastguard Worker {
2199*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACES_IMP_UNK_4(
2200*f6dc9357SAndroid Build Coastguard Worker       IInArchive,
2201*f6dc9357SAndroid Build Coastguard Worker       IArchiveGetRawProps,
2202*f6dc9357SAndroid Build Coastguard Worker       IInArchiveGetStream,
2203*f6dc9357SAndroid Build Coastguard Worker       ISetProperties)
2204*f6dc9357SAndroid Build Coastguard Worker };
2205*f6dc9357SAndroid Build Coastguard Worker 
2206*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
2207*f6dc9357SAndroid Build Coastguard Worker {
2208*f6dc9357SAndroid Build Coastguard Worker   *numProps = 2;
2209*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2210*f6dc9357SAndroid Build Coastguard Worker }
2211*f6dc9357SAndroid Build Coastguard Worker 
2212*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
2213*f6dc9357SAndroid Build Coastguard Worker {
2214*f6dc9357SAndroid Build Coastguard Worker   *name = NULL;
2215*f6dc9357SAndroid Build Coastguard Worker   *propID = index == 0 ? kpidNtReparse : kpidNtSecure;
2216*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2217*f6dc9357SAndroid Build Coastguard Worker }
2218*f6dc9357SAndroid Build Coastguard Worker 
2219*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
2220*f6dc9357SAndroid Build Coastguard Worker {
2221*f6dc9357SAndroid Build Coastguard Worker   *parentType = NParentType::kDir;
2222*f6dc9357SAndroid Build Coastguard Worker   int par = -1;
2223*f6dc9357SAndroid Build Coastguard Worker 
2224*f6dc9357SAndroid Build Coastguard Worker   if (index < Items.Size())
2225*f6dc9357SAndroid Build Coastguard Worker   {
2226*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[index];
2227*f6dc9357SAndroid Build Coastguard Worker 
2228*f6dc9357SAndroid Build Coastguard Worker     if (item.ParentHost >= 0)
2229*f6dc9357SAndroid Build Coastguard Worker     {
2230*f6dc9357SAndroid Build Coastguard Worker       *parentType = NParentType::kAltStream;
2231*f6dc9357SAndroid Build Coastguard Worker       par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost);
2232*f6dc9357SAndroid Build Coastguard Worker     }
2233*f6dc9357SAndroid Build Coastguard Worker     else if (item.RecIndex < kNumSysRecs)
2234*f6dc9357SAndroid Build Coastguard Worker     {
2235*f6dc9357SAndroid Build Coastguard Worker       if (_showSystemFiles)
2236*f6dc9357SAndroid Build Coastguard Worker         par = _systemFolderIndex;
2237*f6dc9357SAndroid Build Coastguard Worker     }
2238*f6dc9357SAndroid Build Coastguard Worker     else if (item.ParentFolder >= 0)
2239*f6dc9357SAndroid Build Coastguard Worker       par = item.ParentFolder;
2240*f6dc9357SAndroid Build Coastguard Worker     else if (item.ParentFolder == k_ParentFolderIndex_Lost)
2241*f6dc9357SAndroid Build Coastguard Worker       par = _lostFolderIndex_Normal;
2242*f6dc9357SAndroid Build Coastguard Worker     else if (item.ParentFolder == k_ParentFolderIndex_Deleted)
2243*f6dc9357SAndroid Build Coastguard Worker       par = _lostFolderIndex_Deleted;
2244*f6dc9357SAndroid Build Coastguard Worker   }
2245*f6dc9357SAndroid Build Coastguard Worker   *parent = (UInt32)(Int32)par;
2246*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2247*f6dc9357SAndroid Build Coastguard Worker }
2248*f6dc9357SAndroid Build Coastguard Worker 
2249*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
2250*f6dc9357SAndroid Build Coastguard Worker {
2251*f6dc9357SAndroid Build Coastguard Worker   *data = NULL;
2252*f6dc9357SAndroid Build Coastguard Worker   *dataSize = 0;
2253*f6dc9357SAndroid Build Coastguard Worker   *propType = 0;
2254*f6dc9357SAndroid Build Coastguard Worker 
2255*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidName)
2256*f6dc9357SAndroid Build Coastguard Worker   {
2257*f6dc9357SAndroid Build Coastguard Worker     #ifdef MY_CPU_LE
2258*f6dc9357SAndroid Build Coastguard Worker     const UString2 *s;
2259*f6dc9357SAndroid Build Coastguard Worker     if (index >= Items.Size())
2260*f6dc9357SAndroid Build Coastguard Worker       s = &VirtFolderNames[index - Items.Size()];
2261*f6dc9357SAndroid Build Coastguard Worker     else
2262*f6dc9357SAndroid Build Coastguard Worker     {
2263*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = Items[index];
2264*f6dc9357SAndroid Build Coastguard Worker       const CMftRec &rec = Recs[item.RecIndex];
2265*f6dc9357SAndroid Build Coastguard Worker       if (item.IsAltStream())
2266*f6dc9357SAndroid Build Coastguard Worker         s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
2267*f6dc9357SAndroid Build Coastguard Worker       else
2268*f6dc9357SAndroid Build Coastguard Worker         s = &rec.FileNames[item.NameIndex].Name;
2269*f6dc9357SAndroid Build Coastguard Worker     }
2270*f6dc9357SAndroid Build Coastguard Worker     if (s->IsEmpty())
2271*f6dc9357SAndroid Build Coastguard Worker       *data = (const wchar_t *)EmptyString;
2272*f6dc9357SAndroid Build Coastguard Worker     else
2273*f6dc9357SAndroid Build Coastguard Worker       *data = s->GetRawPtr();
2274*f6dc9357SAndroid Build Coastguard Worker     *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t);
2275*f6dc9357SAndroid Build Coastguard Worker     *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE;
2276*f6dc9357SAndroid Build Coastguard Worker     #endif
2277*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2278*f6dc9357SAndroid Build Coastguard Worker   }
2279*f6dc9357SAndroid Build Coastguard Worker 
2280*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidNtReparse)
2281*f6dc9357SAndroid Build Coastguard Worker   {
2282*f6dc9357SAndroid Build Coastguard Worker     if (index >= Items.Size())
2283*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2284*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[index];
2285*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[item.RecIndex];
2286*f6dc9357SAndroid Build Coastguard Worker     const CByteBuffer &reparse = rec.ReparseData;
2287*f6dc9357SAndroid Build Coastguard Worker 
2288*f6dc9357SAndroid Build Coastguard Worker     if (reparse.Size() != 0)
2289*f6dc9357SAndroid Build Coastguard Worker     {
2290*f6dc9357SAndroid Build Coastguard Worker       *dataSize = (UInt32)reparse.Size();
2291*f6dc9357SAndroid Build Coastguard Worker       *propType = NPropDataType::kRaw;
2292*f6dc9357SAndroid Build Coastguard Worker       *data = (const Byte *)reparse;
2293*f6dc9357SAndroid Build Coastguard Worker     }
2294*f6dc9357SAndroid Build Coastguard Worker   }
2295*f6dc9357SAndroid Build Coastguard Worker 
2296*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidNtSecure)
2297*f6dc9357SAndroid Build Coastguard Worker   {
2298*f6dc9357SAndroid Build Coastguard Worker     if (index >= Items.Size())
2299*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2300*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[index];
2301*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[item.RecIndex];
2302*f6dc9357SAndroid Build Coastguard Worker     if (rec.SiAttr.SecurityId > 0)
2303*f6dc9357SAndroid Build Coastguard Worker     {
2304*f6dc9357SAndroid Build Coastguard Worker       UInt64 offset;
2305*f6dc9357SAndroid Build Coastguard Worker       UInt32 size;
2306*f6dc9357SAndroid Build Coastguard Worker       if (FindSecurityDescritor(rec.SiAttr.SecurityId, offset, size))
2307*f6dc9357SAndroid Build Coastguard Worker       {
2308*f6dc9357SAndroid Build Coastguard Worker         *dataSize = size;
2309*f6dc9357SAndroid Build Coastguard Worker         *propType = NPropDataType::kRaw;
2310*f6dc9357SAndroid Build Coastguard Worker         *data = (const Byte *)SecurData + offset;
2311*f6dc9357SAndroid Build Coastguard Worker       }
2312*f6dc9357SAndroid Build Coastguard Worker     }
2313*f6dc9357SAndroid Build Coastguard Worker   }
2314*f6dc9357SAndroid Build Coastguard Worker 
2315*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2316*f6dc9357SAndroid Build Coastguard Worker }
2317*f6dc9357SAndroid Build Coastguard Worker 
2318*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
2319*f6dc9357SAndroid Build Coastguard Worker {
2320*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2321*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
2322*f6dc9357SAndroid Build Coastguard Worker   if (index >= Items.Size())
2323*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2324*f6dc9357SAndroid Build Coastguard Worker   IInStream *stream2;
2325*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = Items[index];
2326*f6dc9357SAndroid Build Coastguard Worker   const CMftRec &rec = Recs[item.RecIndex];
2327*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2);
2328*f6dc9357SAndroid Build Coastguard Worker   *stream = (ISequentialInStream *)stream2;
2329*f6dc9357SAndroid Build Coastguard Worker   return res;
2330*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2331*f6dc9357SAndroid Build Coastguard Worker }
2332*f6dc9357SAndroid Build Coastguard Worker 
2333*f6dc9357SAndroid Build Coastguard Worker /*
2334*f6dc9357SAndroid Build Coastguard Worker enum
2335*f6dc9357SAndroid Build Coastguard Worker {
2336*f6dc9357SAndroid Build Coastguard Worker   kpidLink2 = kpidUserDefined,
2337*f6dc9357SAndroid Build Coastguard Worker   kpidLinkType,
2338*f6dc9357SAndroid Build Coastguard Worker   kpidRecMTime,
2339*f6dc9357SAndroid Build Coastguard Worker   kpidRecMTime2,
2340*f6dc9357SAndroid Build Coastguard Worker   kpidMTime2,
2341*f6dc9357SAndroid Build Coastguard Worker   kpidCTime2,
2342*f6dc9357SAndroid Build Coastguard Worker   kpidATime2
2343*f6dc9357SAndroid Build Coastguard Worker };
2344*f6dc9357SAndroid Build Coastguard Worker 
2345*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kProps[] =
2346*f6dc9357SAndroid Build Coastguard Worker {
2347*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidPath, VT_BSTR},
2348*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidSize, VT_UI8},
2349*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidPackSize, VT_UI8},
2350*f6dc9357SAndroid Build Coastguard Worker 
2351*f6dc9357SAndroid Build Coastguard Worker   // { NULL, kpidLink, VT_BSTR},
2352*f6dc9357SAndroid Build Coastguard Worker 
2353*f6dc9357SAndroid Build Coastguard Worker   // { "Link 2", kpidLink2, VT_BSTR},
2354*f6dc9357SAndroid Build Coastguard Worker   // { "Link Type", kpidLinkType, VT_UI2},
2355*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidINode, VT_UI8},
2356*f6dc9357SAndroid Build Coastguard Worker 
2357*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidMTime, VT_FILETIME},
2358*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCTime, VT_FILETIME},
2359*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidATime, VT_FILETIME},
2360*f6dc9357SAndroid Build Coastguard Worker 
2361*f6dc9357SAndroid Build Coastguard Worker   // { "Record Modified", kpidRecMTime, VT_FILETIME},
2362*f6dc9357SAndroid Build Coastguard Worker 
2363*f6dc9357SAndroid Build Coastguard Worker   // { "Modified 2", kpidMTime2, VT_FILETIME},
2364*f6dc9357SAndroid Build Coastguard Worker   // { "Created 2", kpidCTime2, VT_FILETIME},
2365*f6dc9357SAndroid Build Coastguard Worker   // { "Accessed 2", kpidATime2, VT_FILETIME},
2366*f6dc9357SAndroid Build Coastguard Worker   // { "Record Modified 2", kpidRecMTime2, VT_FILETIME},
2367*f6dc9357SAndroid Build Coastguard Worker 
2368*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidAttrib, VT_UI4},
2369*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidNumBlocks, VT_UI4},
2370*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidIsDeleted, VT_BOOL},
2371*f6dc9357SAndroid Build Coastguard Worker };
2372*f6dc9357SAndroid Build Coastguard Worker */
2373*f6dc9357SAndroid Build Coastguard Worker 
2374*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
2375*f6dc9357SAndroid Build Coastguard Worker {
2376*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
2377*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
2378*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
2379*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
2380*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
2381*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
2382*f6dc9357SAndroid Build Coastguard Worker   kpidATime,
2383*f6dc9357SAndroid Build Coastguard Worker   kpidChangeTime,
2384*f6dc9357SAndroid Build Coastguard Worker   kpidAttrib,
2385*f6dc9357SAndroid Build Coastguard Worker   kpidLinks,
2386*f6dc9357SAndroid Build Coastguard Worker   kpidINode,
2387*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks,
2388*f6dc9357SAndroid Build Coastguard Worker   kpidNumAltStreams,
2389*f6dc9357SAndroid Build Coastguard Worker   kpidIsAltStream,
2390*f6dc9357SAndroid Build Coastguard Worker   kpidShortName,
2391*f6dc9357SAndroid Build Coastguard Worker   kpidIsDeleted
2392*f6dc9357SAndroid Build Coastguard Worker };
2393*f6dc9357SAndroid Build Coastguard Worker 
2394*f6dc9357SAndroid Build Coastguard Worker enum
2395*f6dc9357SAndroid Build Coastguard Worker {
2396*f6dc9357SAndroid Build Coastguard Worker   kpidRecordSize = kpidUserDefined
2397*f6dc9357SAndroid Build Coastguard Worker };
2398*f6dc9357SAndroid Build Coastguard Worker 
2399*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kArcProps[] =
2400*f6dc9357SAndroid Build Coastguard Worker {
2401*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidVolumeName, VT_BSTR},
2402*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidFileSystem, VT_BSTR},
2403*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidClusterSize, VT_UI4},
2404*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidSectorSize, VT_UI4},
2405*f6dc9357SAndroid Build Coastguard Worker   { "MFT Record Size", kpidRecordSize, VT_UI4},
2406*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidHeadersSize, VT_UI8},
2407*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCTime, VT_FILETIME},
2408*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidId, VT_UI8},
2409*f6dc9357SAndroid Build Coastguard Worker };
2410*f6dc9357SAndroid Build Coastguard Worker 
2411*f6dc9357SAndroid Build Coastguard Worker /*
2412*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
2413*f6dc9357SAndroid Build Coastguard Worker {
2414*f6dc9357SAndroid Build Coastguard Worker   kpidVolumeName,
2415*f6dc9357SAndroid Build Coastguard Worker   kpidFileSystem,
2416*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
2417*f6dc9357SAndroid Build Coastguard Worker   kpidHeadersSize,
2418*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
2419*f6dc9357SAndroid Build Coastguard Worker 
2420*f6dc9357SAndroid Build Coastguard Worker   kpidSectorSize,
2421*f6dc9357SAndroid Build Coastguard Worker   kpidId
2422*f6dc9357SAndroid Build Coastguard Worker   // kpidSectorsPerTrack,
2423*f6dc9357SAndroid Build Coastguard Worker   // kpidNumHeads,
2424*f6dc9357SAndroid Build Coastguard Worker   // kpidHiddenSectors
2425*f6dc9357SAndroid Build Coastguard Worker };
2426*f6dc9357SAndroid Build Coastguard Worker */
2427*f6dc9357SAndroid Build Coastguard Worker 
2428*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
2429*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_WITH_NAME
2430*f6dc9357SAndroid Build Coastguard Worker 
2431*f6dc9357SAndroid Build Coastguard Worker static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop)
2432*f6dc9357SAndroid Build Coastguard Worker {
2433*f6dc9357SAndroid Build Coastguard Worker   FILETIME ft;
2434*f6dc9357SAndroid Build Coastguard Worker   ft.dwLowDateTime = (DWORD)t;
2435*f6dc9357SAndroid Build Coastguard Worker   ft.dwHighDateTime = (DWORD)(t >> 32);
2436*f6dc9357SAndroid Build Coastguard Worker   prop = ft;
2437*f6dc9357SAndroid Build Coastguard Worker }
2438*f6dc9357SAndroid Build Coastguard Worker 
2439*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
2440*f6dc9357SAndroid Build Coastguard Worker {
2441*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2442*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
2443*f6dc9357SAndroid Build Coastguard Worker 
2444*f6dc9357SAndroid Build Coastguard Worker   const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL);
2445*f6dc9357SAndroid Build Coastguard Worker 
2446*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
2447*f6dc9357SAndroid Build Coastguard Worker   {
2448*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize: prop = Header.ClusterSize(); break;
2449*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = PhySize; break;
2450*f6dc9357SAndroid Build Coastguard Worker     /*
2451*f6dc9357SAndroid Build Coastguard Worker     case kpidHeadersSize:
2452*f6dc9357SAndroid Build Coastguard Worker     {
2453*f6dc9357SAndroid Build Coastguard Worker       UInt64 val = 0;
2454*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < kNumSysRecs; i++)
2455*f6dc9357SAndroid Build Coastguard Worker       {
2456*f6dc9357SAndroid Build Coastguard Worker         printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize());
2457*f6dc9357SAndroid Build Coastguard Worker         if (i == 8)
2458*f6dc9357SAndroid Build Coastguard Worker           i = i
2459*f6dc9357SAndroid Build Coastguard Worker         val += Recs[i].GetPackSize();
2460*f6dc9357SAndroid Build Coastguard Worker       }
2461*f6dc9357SAndroid Build Coastguard Worker       prop = val;
2462*f6dc9357SAndroid Build Coastguard Worker       break;
2463*f6dc9357SAndroid Build Coastguard Worker     }
2464*f6dc9357SAndroid Build Coastguard Worker     */
2465*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;
2466*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.MTime, prop); break;
2467*f6dc9357SAndroid Build Coastguard Worker     case kpidShortComment:
2468*f6dc9357SAndroid Build Coastguard Worker     case kpidVolumeName:
2469*f6dc9357SAndroid Build Coastguard Worker     {
2470*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, VolAttrs)
2471*f6dc9357SAndroid Build Coastguard Worker       {
2472*f6dc9357SAndroid Build Coastguard Worker         const CAttr &attr = VolAttrs[i];
2473*f6dc9357SAndroid Build Coastguard Worker         if (attr.Type == ATTR_TYPE_VOLUME_NAME)
2474*f6dc9357SAndroid Build Coastguard Worker         {
2475*f6dc9357SAndroid Build Coastguard Worker           UString2 name;
2476*f6dc9357SAndroid Build Coastguard Worker           GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name);
2477*f6dc9357SAndroid Build Coastguard Worker           if (!name.IsEmpty())
2478*f6dc9357SAndroid Build Coastguard Worker             prop = name.GetRawPtr();
2479*f6dc9357SAndroid Build Coastguard Worker           break;
2480*f6dc9357SAndroid Build Coastguard Worker         }
2481*f6dc9357SAndroid Build Coastguard Worker       }
2482*f6dc9357SAndroid Build Coastguard Worker       break;
2483*f6dc9357SAndroid Build Coastguard Worker     }
2484*f6dc9357SAndroid Build Coastguard Worker     case kpidFileSystem:
2485*f6dc9357SAndroid Build Coastguard Worker     {
2486*f6dc9357SAndroid Build Coastguard Worker       AString s ("NTFS");
2487*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, VolAttrs)
2488*f6dc9357SAndroid Build Coastguard Worker       {
2489*f6dc9357SAndroid Build Coastguard Worker         const CAttr &attr = VolAttrs[i];
2490*f6dc9357SAndroid Build Coastguard Worker         if (attr.Type == ATTR_TYPE_VOLUME_INFO)
2491*f6dc9357SAndroid Build Coastguard Worker         {
2492*f6dc9357SAndroid Build Coastguard Worker           CVolInfo vi;
2493*f6dc9357SAndroid Build Coastguard Worker           if (attr.ParseVolInfo(vi))
2494*f6dc9357SAndroid Build Coastguard Worker           {
2495*f6dc9357SAndroid Build Coastguard Worker             s.Add_Space();
2496*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(vi.MajorVer);
2497*f6dc9357SAndroid Build Coastguard Worker             s.Add_Dot();
2498*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(vi.MinorVer);
2499*f6dc9357SAndroid Build Coastguard Worker           }
2500*f6dc9357SAndroid Build Coastguard Worker           break;
2501*f6dc9357SAndroid Build Coastguard Worker         }
2502*f6dc9357SAndroid Build Coastguard Worker       }
2503*f6dc9357SAndroid Build Coastguard Worker       prop = s;
2504*f6dc9357SAndroid Build Coastguard Worker       break;
2505*f6dc9357SAndroid Build Coastguard Worker     }
2506*f6dc9357SAndroid Build Coastguard Worker     case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
2507*f6dc9357SAndroid Build Coastguard Worker     case kpidRecordSize: prop = (UInt32)1 << Header.MftRecordSizeLog; break;
2508*f6dc9357SAndroid Build Coastguard Worker     case kpidId: prop = Header.SerialNumber; break;
2509*f6dc9357SAndroid Build Coastguard Worker 
2510*f6dc9357SAndroid Build Coastguard Worker     case kpidIsTree: prop = true; break;
2511*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDeleted: prop = _showDeletedFiles; break;
2512*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAltStream: prop = ThereAreAltStreams; break;
2513*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAux: prop = true; break;
2514*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = true; break;
2515*f6dc9357SAndroid Build Coastguard Worker 
2516*f6dc9357SAndroid Build Coastguard Worker     case kpidWarning:
2517*f6dc9357SAndroid Build Coastguard Worker       if (_lostFolderIndex_Normal >= 0)
2518*f6dc9357SAndroid Build Coastguard Worker         prop = "There are lost files";
2519*f6dc9357SAndroid Build Coastguard Worker       break;
2520*f6dc9357SAndroid Build Coastguard Worker 
2521*f6dc9357SAndroid Build Coastguard Worker     /*
2522*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
2523*f6dc9357SAndroid Build Coastguard Worker     {
2524*f6dc9357SAndroid Build Coastguard Worker       UInt32 flags = 0;
2525*f6dc9357SAndroid Build Coastguard Worker       if (_headerWarning)
2526*f6dc9357SAndroid Build Coastguard Worker         flags |= k_ErrorFlags_HeadersError;
2527*f6dc9357SAndroid Build Coastguard Worker       if (flags != 0)
2528*f6dc9357SAndroid Build Coastguard Worker         prop = flags;
2529*f6dc9357SAndroid Build Coastguard Worker       break;
2530*f6dc9357SAndroid Build Coastguard Worker     }
2531*f6dc9357SAndroid Build Coastguard Worker     */
2532*f6dc9357SAndroid Build Coastguard Worker 
2533*f6dc9357SAndroid Build Coastguard Worker     // case kpidMediaType: prop = Header.MediaType; break;
2534*f6dc9357SAndroid Build Coastguard Worker     // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
2535*f6dc9357SAndroid Build Coastguard Worker     // case kpidNumHeads: prop = Header.NumHeads; break;
2536*f6dc9357SAndroid Build Coastguard Worker     // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
2537*f6dc9357SAndroid Build Coastguard Worker   }
2538*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
2539*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2540*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2541*f6dc9357SAndroid Build Coastguard Worker }
2542*f6dc9357SAndroid Build Coastguard Worker 
2543*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
2544*f6dc9357SAndroid Build Coastguard Worker {
2545*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2546*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
2547*f6dc9357SAndroid Build Coastguard Worker   if (index >= Items.Size())
2548*f6dc9357SAndroid Build Coastguard Worker   {
2549*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
2550*f6dc9357SAndroid Build Coastguard Worker     {
2551*f6dc9357SAndroid Build Coastguard Worker       case kpidName:
2552*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
2553*f6dc9357SAndroid Build Coastguard Worker         prop = VirtFolderNames[index - Items.Size()].GetRawPtr();
2554*f6dc9357SAndroid Build Coastguard Worker         break;
2555*f6dc9357SAndroid Build Coastguard Worker       case kpidIsDir: prop = true; break;
2556*f6dc9357SAndroid Build Coastguard Worker       case kpidIsAux: prop = true; break;
2557*f6dc9357SAndroid Build Coastguard Worker       case kpidIsDeleted:
2558*f6dc9357SAndroid Build Coastguard Worker         if ((int)index == _lostFolderIndex_Deleted)
2559*f6dc9357SAndroid Build Coastguard Worker           prop = true;
2560*f6dc9357SAndroid Build Coastguard Worker         break;
2561*f6dc9357SAndroid Build Coastguard Worker     }
2562*f6dc9357SAndroid Build Coastguard Worker     prop.Detach(value);
2563*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2564*f6dc9357SAndroid Build Coastguard Worker   }
2565*f6dc9357SAndroid Build Coastguard Worker 
2566*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = Items[index];
2567*f6dc9357SAndroid Build Coastguard Worker   const CMftRec &rec = Recs[item.RecIndex];
2568*f6dc9357SAndroid Build Coastguard Worker 
2569*f6dc9357SAndroid Build Coastguard Worker   const CAttr *data= NULL;
2570*f6dc9357SAndroid Build Coastguard Worker   if (item.DataIndex >= 0)
2571*f6dc9357SAndroid Build Coastguard Worker     data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
2572*f6dc9357SAndroid Build Coastguard Worker 
2573*f6dc9357SAndroid Build Coastguard Worker   // const CFileNameAttr *fn = &rec.FileNames[item.NameIndex];
2574*f6dc9357SAndroid Build Coastguard Worker   /*
2575*f6dc9357SAndroid Build Coastguard Worker   if (rec.FileNames.Size() > 0)
2576*f6dc9357SAndroid Build Coastguard Worker     fn = &rec.FileNames[0];
2577*f6dc9357SAndroid Build Coastguard Worker   */
2578*f6dc9357SAndroid Build Coastguard Worker 
2579*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
2580*f6dc9357SAndroid Build Coastguard Worker   {
2581*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
2582*f6dc9357SAndroid Build Coastguard Worker       GetItemPath(index, prop);
2583*f6dc9357SAndroid Build Coastguard Worker       break;
2584*f6dc9357SAndroid Build Coastguard Worker 
2585*f6dc9357SAndroid Build Coastguard Worker     /*
2586*f6dc9357SAndroid Build Coastguard Worker     case kpidLink:
2587*f6dc9357SAndroid Build Coastguard Worker       if (!rec.ReparseAttr.SubsName.IsEmpty())
2588*f6dc9357SAndroid Build Coastguard Worker       {
2589*f6dc9357SAndroid Build Coastguard Worker         prop = rec.ReparseAttr.SubsName;
2590*f6dc9357SAndroid Build Coastguard Worker       }
2591*f6dc9357SAndroid Build Coastguard Worker       break;
2592*f6dc9357SAndroid Build Coastguard Worker     case kpidLink2:
2593*f6dc9357SAndroid Build Coastguard Worker       if (!rec.ReparseAttr.PrintName.IsEmpty())
2594*f6dc9357SAndroid Build Coastguard Worker       {
2595*f6dc9357SAndroid Build Coastguard Worker         prop = rec.ReparseAttr.PrintName;
2596*f6dc9357SAndroid Build Coastguard Worker       }
2597*f6dc9357SAndroid Build Coastguard Worker       break;
2598*f6dc9357SAndroid Build Coastguard Worker 
2599*f6dc9357SAndroid Build Coastguard Worker     case kpidLinkType:
2600*f6dc9357SAndroid Build Coastguard Worker       if (rec.ReparseAttr.Tag != 0)
2601*f6dc9357SAndroid Build Coastguard Worker       {
2602*f6dc9357SAndroid Build Coastguard Worker         prop = (rec.ReparseAttr.Tag & 0xFFFF);
2603*f6dc9357SAndroid Build Coastguard Worker       }
2604*f6dc9357SAndroid Build Coastguard Worker       break;
2605*f6dc9357SAndroid Build Coastguard Worker     */
2606*f6dc9357SAndroid Build Coastguard Worker 
2607*f6dc9357SAndroid Build Coastguard Worker     case kpidINode:
2608*f6dc9357SAndroid Build Coastguard Worker     {
2609*f6dc9357SAndroid Build Coastguard Worker       // const CMftRec &rec = Recs[item.RecIndex];
2610*f6dc9357SAndroid Build Coastguard Worker       // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex;
2611*f6dc9357SAndroid Build Coastguard Worker       prop = (UInt32)item.RecIndex;
2612*f6dc9357SAndroid Build Coastguard Worker       break;
2613*f6dc9357SAndroid Build Coastguard Worker     }
2614*f6dc9357SAndroid Build Coastguard Worker     case kpidStreamId:
2615*f6dc9357SAndroid Build Coastguard Worker     {
2616*f6dc9357SAndroid Build Coastguard Worker       if (item.DataIndex >= 0)
2617*f6dc9357SAndroid Build Coastguard Worker         prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex;
2618*f6dc9357SAndroid Build Coastguard Worker       break;
2619*f6dc9357SAndroid Build Coastguard Worker     }
2620*f6dc9357SAndroid Build Coastguard Worker 
2621*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
2622*f6dc9357SAndroid Build Coastguard Worker     {
2623*f6dc9357SAndroid Build Coastguard Worker       const UString2 *s;
2624*f6dc9357SAndroid Build Coastguard Worker       if (item.IsAltStream())
2625*f6dc9357SAndroid Build Coastguard Worker         s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
2626*f6dc9357SAndroid Build Coastguard Worker       else
2627*f6dc9357SAndroid Build Coastguard Worker         s = &rec.FileNames[item.NameIndex].Name;
2628*f6dc9357SAndroid Build Coastguard Worker       if (s->IsEmpty())
2629*f6dc9357SAndroid Build Coastguard Worker         prop = (const wchar_t *)EmptyString;
2630*f6dc9357SAndroid Build Coastguard Worker       else
2631*f6dc9357SAndroid Build Coastguard Worker         prop = s->GetRawPtr();
2632*f6dc9357SAndroid Build Coastguard Worker       break;
2633*f6dc9357SAndroid Build Coastguard Worker     }
2634*f6dc9357SAndroid Build Coastguard Worker 
2635*f6dc9357SAndroid Build Coastguard Worker     case kpidShortName:
2636*f6dc9357SAndroid Build Coastguard Worker     {
2637*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsAltStream())
2638*f6dc9357SAndroid Build Coastguard Worker       {
2639*f6dc9357SAndroid Build Coastguard Worker         int dosNameIndex = rec.FindDosName(item.NameIndex);
2640*f6dc9357SAndroid Build Coastguard Worker         if (dosNameIndex >= 0)
2641*f6dc9357SAndroid Build Coastguard Worker         {
2642*f6dc9357SAndroid Build Coastguard Worker           const UString2 &s = rec.FileNames[dosNameIndex].Name;
2643*f6dc9357SAndroid Build Coastguard Worker           if (s.IsEmpty())
2644*f6dc9357SAndroid Build Coastguard Worker             prop = (const wchar_t *)EmptyString;
2645*f6dc9357SAndroid Build Coastguard Worker           else
2646*f6dc9357SAndroid Build Coastguard Worker             prop = s.GetRawPtr();
2647*f6dc9357SAndroid Build Coastguard Worker         }
2648*f6dc9357SAndroid Build Coastguard Worker       }
2649*f6dc9357SAndroid Build Coastguard Worker       break;
2650*f6dc9357SAndroid Build Coastguard Worker     }
2651*f6dc9357SAndroid Build Coastguard Worker 
2652*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = item.IsDir(); break;
2653*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAltStream: prop = item.IsAltStream(); break;
2654*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDeleted: prop = !rec.InUse(); break;
2655*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAux: prop = false; break;
2656*f6dc9357SAndroid Build Coastguard Worker 
2657*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
2658*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
2659*f6dc9357SAndroid Build Coastguard Worker     case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
2660*f6dc9357SAndroid Build Coastguard Worker     case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break;
2661*f6dc9357SAndroid Build Coastguard Worker 
2662*f6dc9357SAndroid Build Coastguard Worker     /*
2663*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break;
2664*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime2: if (fn) NtfsTimeToProp(fn->CTime, prop); break;
2665*f6dc9357SAndroid Build Coastguard Worker     case kpidATime2: if (fn) NtfsTimeToProp(fn->ATime, prop); break;
2666*f6dc9357SAndroid Build Coastguard Worker     case kpidRecMTime2: if (fn) NtfsTimeToProp(fn->ThisRecMTime, prop); break;
2667*f6dc9357SAndroid Build Coastguard Worker     */
2668*f6dc9357SAndroid Build Coastguard Worker 
2669*f6dc9357SAndroid Build Coastguard Worker     case kpidAttrib:
2670*f6dc9357SAndroid Build Coastguard Worker     {
2671*f6dc9357SAndroid Build Coastguard Worker       UInt32 attrib;
2672*f6dc9357SAndroid Build Coastguard Worker       /* WinXP-64: The CFileNameAttr::Attrib is not updated  after some changes. Why?
2673*f6dc9357SAndroid Build Coastguard Worker          CSiAttr:attrib is updated better. So we use CSiAttr:Sttrib */
2674*f6dc9357SAndroid Build Coastguard Worker       /*
2675*f6dc9357SAndroid Build Coastguard Worker       if (fn)
2676*f6dc9357SAndroid Build Coastguard Worker         attrib = fn->Attrib;
2677*f6dc9357SAndroid Build Coastguard Worker       else
2678*f6dc9357SAndroid Build Coastguard Worker       */
2679*f6dc9357SAndroid Build Coastguard Worker         attrib = rec.SiAttr.Attrib;
2680*f6dc9357SAndroid Build Coastguard Worker       if (item.IsDir())
2681*f6dc9357SAndroid Build Coastguard Worker         attrib |= FILE_ATTRIBUTE_DIRECTORY;
2682*f6dc9357SAndroid Build Coastguard Worker 
2683*f6dc9357SAndroid Build Coastguard Worker       /* some system entries can contain extra flags (Index View).
2684*f6dc9357SAndroid Build Coastguard Worker       // 0x10000000   (Directory)
2685*f6dc9357SAndroid Build Coastguard Worker       // 0x20000000   FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View)
2686*f6dc9357SAndroid Build Coastguard Worker       But we don't need them */
2687*f6dc9357SAndroid Build Coastguard Worker       attrib &= 0xFFFF;
2688*f6dc9357SAndroid Build Coastguard Worker 
2689*f6dc9357SAndroid Build Coastguard Worker       prop = attrib;
2690*f6dc9357SAndroid Build Coastguard Worker       break;
2691*f6dc9357SAndroid Build Coastguard Worker     }
2692*f6dc9357SAndroid Build Coastguard Worker     case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break;
2693*f6dc9357SAndroid Build Coastguard Worker 
2694*f6dc9357SAndroid Build Coastguard Worker     case kpidNumAltStreams:
2695*f6dc9357SAndroid Build Coastguard Worker     {
2696*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsAltStream())
2697*f6dc9357SAndroid Build Coastguard Worker       {
2698*f6dc9357SAndroid Build Coastguard Worker         unsigned num = rec.DataRefs.Size();
2699*f6dc9357SAndroid Build Coastguard Worker         if (num > 0)
2700*f6dc9357SAndroid Build Coastguard Worker         {
2701*f6dc9357SAndroid Build Coastguard Worker           if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty())
2702*f6dc9357SAndroid Build Coastguard Worker             num--;
2703*f6dc9357SAndroid Build Coastguard Worker           if (num > 0)
2704*f6dc9357SAndroid Build Coastguard Worker             prop = (UInt32)num;
2705*f6dc9357SAndroid Build Coastguard Worker         }
2706*f6dc9357SAndroid Build Coastguard Worker       }
2707*f6dc9357SAndroid Build Coastguard Worker       break;
2708*f6dc9357SAndroid Build Coastguard Worker     }
2709*f6dc9357SAndroid Build Coastguard Worker 
2710*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
2711*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
2712*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
2713*f6dc9357SAndroid Build Coastguard Worker   }
2714*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
2715*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2716*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2717*f6dc9357SAndroid Build Coastguard Worker }
2718*f6dc9357SAndroid Build Coastguard Worker 
2719*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
2720*f6dc9357SAndroid Build Coastguard Worker {
2721*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2722*f6dc9357SAndroid Build Coastguard Worker   {
2723*f6dc9357SAndroid Build Coastguard Worker     OpenCallback = callback;
2724*f6dc9357SAndroid Build Coastguard Worker     InStream = stream;
2725*f6dc9357SAndroid Build Coastguard Worker     HRESULT res;
2726*f6dc9357SAndroid Build Coastguard Worker     try
2727*f6dc9357SAndroid Build Coastguard Worker     {
2728*f6dc9357SAndroid Build Coastguard Worker       res = CDatabase::Open();
2729*f6dc9357SAndroid Build Coastguard Worker       if (res == S_OK)
2730*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2731*f6dc9357SAndroid Build Coastguard Worker     }
2732*f6dc9357SAndroid Build Coastguard Worker     catch(...)
2733*f6dc9357SAndroid Build Coastguard Worker     {
2734*f6dc9357SAndroid Build Coastguard Worker       Close();
2735*f6dc9357SAndroid Build Coastguard Worker       throw;
2736*f6dc9357SAndroid Build Coastguard Worker     }
2737*f6dc9357SAndroid Build Coastguard Worker     Close();
2738*f6dc9357SAndroid Build Coastguard Worker     return res;
2739*f6dc9357SAndroid Build Coastguard Worker   }
2740*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2741*f6dc9357SAndroid Build Coastguard Worker }
2742*f6dc9357SAndroid Build Coastguard Worker 
2743*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
2744*f6dc9357SAndroid Build Coastguard Worker {
2745*f6dc9357SAndroid Build Coastguard Worker   ClearAndClose();
2746*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2747*f6dc9357SAndroid Build Coastguard Worker }
2748*f6dc9357SAndroid Build Coastguard Worker 
2749*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
2750*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
2751*f6dc9357SAndroid Build Coastguard Worker {
2752*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2753*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
2754*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
2755*f6dc9357SAndroid Build Coastguard Worker     numItems = Items.Size();
2756*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
2757*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2758*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
2759*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
2760*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
2761*f6dc9357SAndroid Build Coastguard Worker   {
2762*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
2763*f6dc9357SAndroid Build Coastguard Worker     if (index >= (UInt32)Items.Size())
2764*f6dc9357SAndroid Build Coastguard Worker       continue;
2765*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[allFilesMode ? i : indices[i]];
2766*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[item.RecIndex];
2767*f6dc9357SAndroid Build Coastguard Worker     if (item.DataIndex >= 0)
2768*f6dc9357SAndroid Build Coastguard Worker       totalSize += rec.GetSize((unsigned)item.DataIndex);
2769*f6dc9357SAndroid Build Coastguard Worker   }
2770*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
2771*f6dc9357SAndroid Build Coastguard Worker 
2772*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPackSize;
2773*f6dc9357SAndroid Build Coastguard Worker   totalSize = totalPackSize = 0;
2774*f6dc9357SAndroid Build Coastguard Worker 
2775*f6dc9357SAndroid Build Coastguard Worker   UInt32 clusterSize = Header.ClusterSize();
2776*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer buf(clusterSize);
2777*f6dc9357SAndroid Build Coastguard Worker 
2778*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
2779*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
2780*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
2781*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, CDummyOutStream> outStream;
2782*f6dc9357SAndroid Build Coastguard Worker 
2783*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
2784*f6dc9357SAndroid Build Coastguard Worker   {
2785*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPackSize;
2786*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalSize;
2787*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
2788*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
2789*f6dc9357SAndroid Build Coastguard Worker       break;
2790*f6dc9357SAndroid Build Coastguard Worker 
2791*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
2792*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
2793*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
2794*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
2795*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
2796*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
2797*f6dc9357SAndroid Build Coastguard Worker 
2798*f6dc9357SAndroid Build Coastguard Worker     if (index >= (UInt32)Items.Size() || Items[index].IsDir())
2799*f6dc9357SAndroid Build Coastguard Worker     {
2800*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
2801*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
2802*f6dc9357SAndroid Build Coastguard Worker       continue;
2803*f6dc9357SAndroid Build Coastguard Worker     }
2804*f6dc9357SAndroid Build Coastguard Worker 
2805*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[index];
2806*f6dc9357SAndroid Build Coastguard Worker 
2807*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !realOutStream)
2808*f6dc9357SAndroid Build Coastguard Worker       continue;
2809*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
2810*f6dc9357SAndroid Build Coastguard Worker 
2811*f6dc9357SAndroid Build Coastguard Worker     outStream->SetStream(realOutStream);
2812*f6dc9357SAndroid Build Coastguard Worker     realOutStream.Release();
2813*f6dc9357SAndroid Build Coastguard Worker     outStream->Init();
2814*f6dc9357SAndroid Build Coastguard Worker 
2815*f6dc9357SAndroid Build Coastguard Worker     const CMftRec &rec = Recs[item.RecIndex];
2816*f6dc9357SAndroid Build Coastguard Worker 
2817*f6dc9357SAndroid Build Coastguard Worker     int res = NExtract::NOperationResult::kDataError;
2818*f6dc9357SAndroid Build Coastguard Worker     {
2819*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<IInStream> inStream;
2820*f6dc9357SAndroid Build Coastguard Worker       HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream);
2821*f6dc9357SAndroid Build Coastguard Worker       if (hres == S_FALSE)
2822*f6dc9357SAndroid Build Coastguard Worker         res = NExtract::NOperationResult::kUnsupportedMethod;
2823*f6dc9357SAndroid Build Coastguard Worker       else
2824*f6dc9357SAndroid Build Coastguard Worker       {
2825*f6dc9357SAndroid Build Coastguard Worker         RINOK(hres)
2826*f6dc9357SAndroid Build Coastguard Worker         if (inStream)
2827*f6dc9357SAndroid Build Coastguard Worker         {
2828*f6dc9357SAndroid Build Coastguard Worker           hres = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps);
2829*f6dc9357SAndroid Build Coastguard Worker           if (hres != S_OK &&  hres != S_FALSE)
2830*f6dc9357SAndroid Build Coastguard Worker           {
2831*f6dc9357SAndroid Build Coastguard Worker             RINOK(hres)
2832*f6dc9357SAndroid Build Coastguard Worker           }
2833*f6dc9357SAndroid Build Coastguard Worker           if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK)
2834*f6dc9357SAndroid Build Coastguard Worker             res = NExtract::NOperationResult::kOK;
2835*f6dc9357SAndroid Build Coastguard Worker         }
2836*f6dc9357SAndroid Build Coastguard Worker       }
2837*f6dc9357SAndroid Build Coastguard Worker     }
2838*f6dc9357SAndroid Build Coastguard Worker     if (item.DataIndex >= 0)
2839*f6dc9357SAndroid Build Coastguard Worker     {
2840*f6dc9357SAndroid Build Coastguard Worker       const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
2841*f6dc9357SAndroid Build Coastguard Worker       totalPackSize += data.GetPackSize();
2842*f6dc9357SAndroid Build Coastguard Worker       totalSize += data.GetSize();
2843*f6dc9357SAndroid Build Coastguard Worker     }
2844*f6dc9357SAndroid Build Coastguard Worker     outStream->ReleaseStream();
2845*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(res))
2846*f6dc9357SAndroid Build Coastguard Worker   }
2847*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2848*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2849*f6dc9357SAndroid Build Coastguard Worker }
2850*f6dc9357SAndroid Build Coastguard Worker 
2851*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
2852*f6dc9357SAndroid Build Coastguard Worker {
2853*f6dc9357SAndroid Build Coastguard Worker   *numItems = Items.Size() + VirtFolderNames.Size();
2854*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2855*f6dc9357SAndroid Build Coastguard Worker }
2856*f6dc9357SAndroid Build Coastguard Worker 
2857*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
2858*f6dc9357SAndroid Build Coastguard Worker {
2859*f6dc9357SAndroid Build Coastguard Worker   InitProps();
2860*f6dc9357SAndroid Build Coastguard Worker 
2861*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numProps; i++)
2862*f6dc9357SAndroid Build Coastguard Worker   {
2863*f6dc9357SAndroid Build Coastguard Worker     const wchar_t *name = names[i];
2864*f6dc9357SAndroid Build Coastguard Worker     const PROPVARIANT &prop = values[i];
2865*f6dc9357SAndroid Build Coastguard Worker 
2866*f6dc9357SAndroid Build Coastguard Worker     if (StringsAreEqualNoCase_Ascii(name, "ld"))
2867*f6dc9357SAndroid Build Coastguard Worker     {
2868*f6dc9357SAndroid Build Coastguard Worker       RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles))
2869*f6dc9357SAndroid Build Coastguard Worker     }
2870*f6dc9357SAndroid Build Coastguard Worker     else if (StringsAreEqualNoCase_Ascii(name, "ls"))
2871*f6dc9357SAndroid Build Coastguard Worker     {
2872*f6dc9357SAndroid Build Coastguard Worker       RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles))
2873*f6dc9357SAndroid Build Coastguard Worker     }
2874*f6dc9357SAndroid Build Coastguard Worker     else if (IsString1PrefixedByString2_NoCase_Ascii(name, "mt"))
2875*f6dc9357SAndroid Build Coastguard Worker     {
2876*f6dc9357SAndroid Build Coastguard Worker     }
2877*f6dc9357SAndroid Build Coastguard Worker     else if (IsString1PrefixedByString2_NoCase_Ascii(name, "memuse"))
2878*f6dc9357SAndroid Build Coastguard Worker     {
2879*f6dc9357SAndroid Build Coastguard Worker     }
2880*f6dc9357SAndroid Build Coastguard Worker     else
2881*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
2882*f6dc9357SAndroid Build Coastguard Worker   }
2883*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2884*f6dc9357SAndroid Build Coastguard Worker }
2885*f6dc9357SAndroid Build Coastguard Worker 
2886*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
2887*f6dc9357SAndroid Build Coastguard Worker 
2888*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2889*f6dc9357SAndroid Build Coastguard Worker   "NTFS", "ntfs img", NULL, 0xD9,
2890*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
2891*f6dc9357SAndroid Build Coastguard Worker   3,
2892*f6dc9357SAndroid Build Coastguard Worker   0,
2893*f6dc9357SAndroid Build Coastguard Worker   NULL)
2894*f6dc9357SAndroid Build Coastguard Worker 
2895*f6dc9357SAndroid Build Coastguard Worker }}
2896