xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/CpioHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // CpioHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyLinux.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/UTFConvert.h"
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "Common/ItemNameUtils.h"
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
28*f6dc9357SAndroid Build Coastguard Worker namespace NCpio {
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker static const Byte kMagicBin0 = 0xC7;
31*f6dc9357SAndroid Build Coastguard Worker static const Byte kMagicBin1 = 0x71;
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker static const Byte kMagicHex    = '1'; // New ASCII Format
34*f6dc9357SAndroid Build Coastguard Worker static const Byte kMagicHexCrc = '2'; // New CRC Format
35*f6dc9357SAndroid Build Coastguard Worker static const Byte kMagicOct    = '7'; // Portable ASCII Format
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker static const char * const kName_TRAILER = "TRAILER!!!";
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4;
40*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11;
41*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_HexRecord_Size = 6 + 13 * 8;
42*f6dc9357SAndroid Build Coastguard Worker 
43*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_RecordSize_Max = k_HexRecord_Size;
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker enum EType
46*f6dc9357SAndroid Build Coastguard Worker {
47*f6dc9357SAndroid Build Coastguard Worker   k_Type_BinLe,
48*f6dc9357SAndroid Build Coastguard Worker   k_Type_BinBe,
49*f6dc9357SAndroid Build Coastguard Worker   k_Type_Oct,
50*f6dc9357SAndroid Build Coastguard Worker   k_Type_Hex,
51*f6dc9357SAndroid Build Coastguard Worker   k_Type_HexCrc
52*f6dc9357SAndroid Build Coastguard Worker };
53*f6dc9357SAndroid Build Coastguard Worker 
54*f6dc9357SAndroid Build Coastguard Worker static const char * const k_Types[] =
55*f6dc9357SAndroid Build Coastguard Worker {
56*f6dc9357SAndroid Build Coastguard Worker     "Binary LE"
57*f6dc9357SAndroid Build Coastguard Worker   , "Binary BE"
58*f6dc9357SAndroid Build Coastguard Worker   , "Portable ASCII"
59*f6dc9357SAndroid Build Coastguard Worker   , "New ASCII"
60*f6dc9357SAndroid Build Coastguard Worker   , "New CRC"
61*f6dc9357SAndroid Build Coastguard Worker };
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker struct CItem
64*f6dc9357SAndroid Build Coastguard Worker {
65*f6dc9357SAndroid Build Coastguard Worker   UInt32 inode;
66*f6dc9357SAndroid Build Coastguard Worker   unsigned MainIndex_ForInode;
67*f6dc9357SAndroid Build Coastguard Worker   UInt32 Mode;
68*f6dc9357SAndroid Build Coastguard Worker   UInt32 MTime;
69*f6dc9357SAndroid Build Coastguard Worker   UInt32 DevMajor;
70*f6dc9357SAndroid Build Coastguard Worker   UInt32 DevMinor;
71*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
72*f6dc9357SAndroid Build Coastguard Worker   AString Name;
73*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumLinks;
74*f6dc9357SAndroid Build Coastguard Worker   UInt32 UID;
75*f6dc9357SAndroid Build Coastguard Worker   UInt32 GID;
76*f6dc9357SAndroid Build Coastguard Worker   UInt32 RDevMajor;
77*f6dc9357SAndroid Build Coastguard Worker   UInt32 RDevMinor;
78*f6dc9357SAndroid Build Coastguard Worker   UInt32 ChkSum;
79*f6dc9357SAndroid Build Coastguard Worker 
80*f6dc9357SAndroid Build Coastguard Worker   UInt32 AlignMask;
81*f6dc9357SAndroid Build Coastguard Worker   EType Type;
82*f6dc9357SAndroid Build Coastguard Worker 
83*f6dc9357SAndroid Build Coastguard Worker   UInt32 HeaderSize;
84*f6dc9357SAndroid Build Coastguard Worker   UInt64 HeaderPos;
85*f6dc9357SAndroid Build Coastguard Worker 
86*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data; // for symlink
87*f6dc9357SAndroid Build Coastguard Worker 
88*f6dc9357SAndroid Build Coastguard Worker 
GetAlignedSizeNArchive::NCpio::CItem89*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetAlignedSize(UInt32 size) const
90*f6dc9357SAndroid Build Coastguard Worker   {
91*f6dc9357SAndroid Build Coastguard Worker     return (size + AlignMask) & ~(UInt32)AlignMask;
92*f6dc9357SAndroid Build Coastguard Worker   }
93*f6dc9357SAndroid Build Coastguard Worker 
GetPackSizeNArchive::NCpio::CItem94*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPackSize() const
95*f6dc9357SAndroid Build Coastguard Worker   {
96*f6dc9357SAndroid Build Coastguard Worker     const UInt64 alignMask64 = AlignMask;
97*f6dc9357SAndroid Build Coastguard Worker     return (Size + alignMask64) & ~(UInt64)alignMask64;
98*f6dc9357SAndroid Build Coastguard Worker   }
99*f6dc9357SAndroid Build Coastguard Worker 
IsSame_inode_DevNArchive::NCpio::CItem100*f6dc9357SAndroid Build Coastguard Worker   bool IsSame_inode_Dev(const CItem &item) const
101*f6dc9357SAndroid Build Coastguard Worker   {
102*f6dc9357SAndroid Build Coastguard Worker     return inode == item.inode
103*f6dc9357SAndroid Build Coastguard Worker         && DevMajor == item.DevMajor
104*f6dc9357SAndroid Build Coastguard Worker         && DevMinor == item.DevMinor;
105*f6dc9357SAndroid Build Coastguard Worker   }
106*f6dc9357SAndroid Build Coastguard Worker 
IsBinNArchive::NCpio::CItem107*f6dc9357SAndroid Build Coastguard Worker   bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; }
IsCrcFormatNArchive::NCpio::CItem108*f6dc9357SAndroid Build Coastguard Worker   bool IsCrcFormat() const { return Type == k_Type_HexCrc; }
IsDirNArchive::NCpio::CItem109*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
Is_SymLinkNArchive::NCpio::CItem110*f6dc9357SAndroid Build Coastguard Worker   bool Is_SymLink() const { return MY_LIN_S_ISLNK(Mode); }
IsTrailerNArchive::NCpio::CItem111*f6dc9357SAndroid Build Coastguard Worker   bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
GetDataPositionNArchive::NCpio::CItem112*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
113*f6dc9357SAndroid Build Coastguard Worker };
114*f6dc9357SAndroid Build Coastguard Worker 
115*f6dc9357SAndroid Build Coastguard Worker 
116*f6dc9357SAndroid Build Coastguard Worker enum EErrorType
117*f6dc9357SAndroid Build Coastguard Worker {
118*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_OK,
119*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_BadSignature,
120*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_Corrupted,
121*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_UnexpectedEnd
122*f6dc9357SAndroid Build Coastguard Worker };
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker 
125*f6dc9357SAndroid Build Coastguard Worker struct CInArchive
126*f6dc9357SAndroid Build Coastguard Worker {
127*f6dc9357SAndroid Build Coastguard Worker   EErrorType errorType;
128*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *Stream;
129*f6dc9357SAndroid Build Coastguard Worker   UInt64 Processed;
130*f6dc9357SAndroid Build Coastguard Worker   CItem item;
131*f6dc9357SAndroid Build Coastguard Worker 
132*f6dc9357SAndroid Build Coastguard Worker   HRESULT Read(void *data, size_t *size);
133*f6dc9357SAndroid Build Coastguard Worker   HRESULT GetNextItem();
134*f6dc9357SAndroid Build Coastguard Worker };
135*f6dc9357SAndroid Build Coastguard Worker 
Read(void * data,size_t * size)136*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Read(void *data, size_t *size)
137*f6dc9357SAndroid Build Coastguard Worker {
138*f6dc9357SAndroid Build Coastguard Worker   const HRESULT res = ReadStream(Stream, data, size);
139*f6dc9357SAndroid Build Coastguard Worker   Processed += *size;
140*f6dc9357SAndroid Build Coastguard Worker   return res;
141*f6dc9357SAndroid Build Coastguard Worker }
142*f6dc9357SAndroid Build Coastguard Worker 
143*f6dc9357SAndroid Build Coastguard Worker 
CheckOctRecord(const Byte * p)144*f6dc9357SAndroid Build Coastguard Worker static bool CheckOctRecord(const Byte *p)
145*f6dc9357SAndroid Build Coastguard Worker {
146*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 6; i < k_OctRecord_Size; i++)
147*f6dc9357SAndroid Build Coastguard Worker   {
148*f6dc9357SAndroid Build Coastguard Worker     const unsigned c = (unsigned)p[i] - '0';
149*f6dc9357SAndroid Build Coastguard Worker     if (c > 7)
150*f6dc9357SAndroid Build Coastguard Worker       return false;
151*f6dc9357SAndroid Build Coastguard Worker   }
152*f6dc9357SAndroid Build Coastguard Worker   return true;
153*f6dc9357SAndroid Build Coastguard Worker }
154*f6dc9357SAndroid Build Coastguard Worker 
CheckHexRecord(const Byte * p)155*f6dc9357SAndroid Build Coastguard Worker static bool CheckHexRecord(const Byte *p)
156*f6dc9357SAndroid Build Coastguard Worker {
157*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 6; i < k_HexRecord_Size; i++)
158*f6dc9357SAndroid Build Coastguard Worker   {
159*f6dc9357SAndroid Build Coastguard Worker     unsigned c = p[i];
160*f6dc9357SAndroid Build Coastguard Worker     c -= '0';
161*f6dc9357SAndroid Build Coastguard Worker     if (c > 9)
162*f6dc9357SAndroid Build Coastguard Worker     {
163*f6dc9357SAndroid Build Coastguard Worker       c -= 'A' - '0';
164*f6dc9357SAndroid Build Coastguard Worker       c &= ~0x20u;
165*f6dc9357SAndroid Build Coastguard Worker       if (c > 5)
166*f6dc9357SAndroid Build Coastguard Worker         return false;
167*f6dc9357SAndroid Build Coastguard Worker     }
168*f6dc9357SAndroid Build Coastguard Worker   }
169*f6dc9357SAndroid Build Coastguard Worker   return true;
170*f6dc9357SAndroid Build Coastguard Worker }
171*f6dc9357SAndroid Build Coastguard Worker 
ReadHex(const Byte * p)172*f6dc9357SAndroid Build Coastguard Worker static UInt32 ReadHex(const Byte *p)
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker   char sz[16];
175*f6dc9357SAndroid Build Coastguard Worker   memcpy(sz, p, 8);
176*f6dc9357SAndroid Build Coastguard Worker   sz[8] = 0;
177*f6dc9357SAndroid Build Coastguard Worker   const char *end;
178*f6dc9357SAndroid Build Coastguard Worker   return ConvertHexStringToUInt32(sz, &end);
179*f6dc9357SAndroid Build Coastguard Worker }
180*f6dc9357SAndroid Build Coastguard Worker 
ReadOct6(const Byte * p)181*f6dc9357SAndroid Build Coastguard Worker static UInt32 ReadOct6(const Byte *p)
182*f6dc9357SAndroid Build Coastguard Worker {
183*f6dc9357SAndroid Build Coastguard Worker   char sz[16];
184*f6dc9357SAndroid Build Coastguard Worker   memcpy(sz, p, 6);
185*f6dc9357SAndroid Build Coastguard Worker   sz[6] = 0;
186*f6dc9357SAndroid Build Coastguard Worker   const char *end;
187*f6dc9357SAndroid Build Coastguard Worker   return ConvertOctStringToUInt32(sz, &end);
188*f6dc9357SAndroid Build Coastguard Worker }
189*f6dc9357SAndroid Build Coastguard Worker 
ReadOct11(const Byte * p)190*f6dc9357SAndroid Build Coastguard Worker static UInt64 ReadOct11(const Byte *p)
191*f6dc9357SAndroid Build Coastguard Worker {
192*f6dc9357SAndroid Build Coastguard Worker   char sz[16];
193*f6dc9357SAndroid Build Coastguard Worker   memcpy(sz, p, 11);
194*f6dc9357SAndroid Build Coastguard Worker   sz[11] = 0;
195*f6dc9357SAndroid Build Coastguard Worker   const char *end;
196*f6dc9357SAndroid Build Coastguard Worker   return ConvertOctStringToUInt64(sz, &end);
197*f6dc9357SAndroid Build Coastguard Worker }
198*f6dc9357SAndroid Build Coastguard Worker 
199*f6dc9357SAndroid Build Coastguard Worker 
200*f6dc9357SAndroid Build Coastguard Worker #define READ_HEX(    y, dest)  dest = ReadHex  (p + 6 + (y) * 8);
201*f6dc9357SAndroid Build Coastguard Worker #define READ_OCT_6(  y, dest)  dest = ReadOct6 (p + 6 + (y));
202*f6dc9357SAndroid Build Coastguard Worker #define READ_OCT_11( y, dest)  dest = ReadOct11(p + 6 + (y));
203*f6dc9357SAndroid Build Coastguard Worker 
204*f6dc9357SAndroid Build Coastguard Worker #define Get32spec(p) (((UInt32)GetUi16(p) << 16) + GetUi16(p + 2))
205*f6dc9357SAndroid Build Coastguard Worker #define G16(offs, v) v = GetUi16(p + (offs))
206*f6dc9357SAndroid Build Coastguard Worker #define G32(offs, v) v = Get32spec(p + (offs))
207*f6dc9357SAndroid Build Coastguard Worker 
208*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNameSizeMax = 1 << 12;
209*f6dc9357SAndroid Build Coastguard Worker 
210*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Cpio(const Byte * p,size_t size)211*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size)
212*f6dc9357SAndroid Build Coastguard Worker {
213*f6dc9357SAndroid Build Coastguard Worker   if (size < k_BinRecord_Size)
214*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
215*f6dc9357SAndroid Build Coastguard Worker 
216*f6dc9357SAndroid Build Coastguard Worker   UInt32 namePos;
217*f6dc9357SAndroid Build Coastguard Worker   UInt32 nameSize;
218*f6dc9357SAndroid Build Coastguard Worker   UInt32 mode;
219*f6dc9357SAndroid Build Coastguard Worker   // UInt32 rDevMinor;
220*f6dc9357SAndroid Build Coastguard Worker   UInt32 rDevMajor = 0;
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker   if (p[0] == '0')
223*f6dc9357SAndroid Build Coastguard Worker   {
224*f6dc9357SAndroid Build Coastguard Worker     if (p[1] != '7' ||
225*f6dc9357SAndroid Build Coastguard Worker         p[2] != '0' ||
226*f6dc9357SAndroid Build Coastguard Worker         p[3] != '7' ||
227*f6dc9357SAndroid Build Coastguard Worker         p[4] != '0')
228*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
229*f6dc9357SAndroid Build Coastguard Worker     if (p[5] == kMagicOct)
230*f6dc9357SAndroid Build Coastguard Worker     {
231*f6dc9357SAndroid Build Coastguard Worker       if (size < k_OctRecord_Size)
232*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
233*f6dc9357SAndroid Build Coastguard Worker       if (!CheckOctRecord(p))
234*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
235*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (2 * 6, mode)
236*f6dc9357SAndroid Build Coastguard Worker       // READ_OCT_6 (6 * 6, rDevMinor)
237*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (7 * 6 + 11, nameSize)
238*f6dc9357SAndroid Build Coastguard Worker       namePos = k_OctRecord_Size;
239*f6dc9357SAndroid Build Coastguard Worker     }
240*f6dc9357SAndroid Build Coastguard Worker     else if (p[5] == kMagicHex || p[5] == kMagicHexCrc)
241*f6dc9357SAndroid Build Coastguard Worker     {
242*f6dc9357SAndroid Build Coastguard Worker       if (size < k_HexRecord_Size)
243*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
244*f6dc9357SAndroid Build Coastguard Worker       if (!CheckHexRecord(p))
245*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
246*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (1, mode)
247*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (9, rDevMajor)
248*f6dc9357SAndroid Build Coastguard Worker       // READ_HEX (10, rDevMinor)
249*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (11, nameSize)
250*f6dc9357SAndroid Build Coastguard Worker       namePos = k_HexRecord_Size;
251*f6dc9357SAndroid Build Coastguard Worker     }
252*f6dc9357SAndroid Build Coastguard Worker     else
253*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
254*f6dc9357SAndroid Build Coastguard Worker   }
255*f6dc9357SAndroid Build Coastguard Worker   else
256*f6dc9357SAndroid Build Coastguard Worker   {
257*f6dc9357SAndroid Build Coastguard Worker     if (p[0] == kMagicBin0 && p[1] == kMagicBin1)
258*f6dc9357SAndroid Build Coastguard Worker     {
259*f6dc9357SAndroid Build Coastguard Worker       mode = GetUi16(p + 6);
260*f6dc9357SAndroid Build Coastguard Worker       // rDevMinor = GetUi16(p + 14);
261*f6dc9357SAndroid Build Coastguard Worker       nameSize = GetUi16(p + 20);
262*f6dc9357SAndroid Build Coastguard Worker     }
263*f6dc9357SAndroid Build Coastguard Worker     else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
264*f6dc9357SAndroid Build Coastguard Worker     {
265*f6dc9357SAndroid Build Coastguard Worker       mode = GetBe16(p + 6);
266*f6dc9357SAndroid Build Coastguard Worker       // rDevMinor = GetBe16(p + 14);
267*f6dc9357SAndroid Build Coastguard Worker       nameSize = GetBe16(p + 20);
268*f6dc9357SAndroid Build Coastguard Worker     }
269*f6dc9357SAndroid Build Coastguard Worker     else
270*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
271*f6dc9357SAndroid Build Coastguard Worker     namePos = k_BinRecord_Size;
272*f6dc9357SAndroid Build Coastguard Worker   }
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker   if (mode >= (1 << 16))
275*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
276*f6dc9357SAndroid Build Coastguard Worker 
277*f6dc9357SAndroid Build Coastguard Worker   /* v23.02: we have disabled rDevMinor check because real file
278*f6dc9357SAndroid Build Coastguard Worker      from Apple contains rDevMinor==255 by some unknown reason */
279*f6dc9357SAndroid Build Coastguard Worker   if (rDevMajor != 0
280*f6dc9357SAndroid Build Coastguard Worker       // || rDevMinor != 0
281*f6dc9357SAndroid Build Coastguard Worker       )
282*f6dc9357SAndroid Build Coastguard Worker   {
283*f6dc9357SAndroid Build Coastguard Worker     if (!MY_LIN_S_ISCHR(mode) &&
284*f6dc9357SAndroid Build Coastguard Worker         !MY_LIN_S_ISBLK(mode))
285*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
286*f6dc9357SAndroid Build Coastguard Worker   }
287*f6dc9357SAndroid Build Coastguard Worker 
288*f6dc9357SAndroid Build Coastguard Worker   // nameSize must include the null byte
289*f6dc9357SAndroid Build Coastguard Worker   if (nameSize == 0 || nameSize > kNameSizeMax)
290*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
291*f6dc9357SAndroid Build Coastguard Worker   {
292*f6dc9357SAndroid Build Coastguard Worker     unsigned lim = namePos + nameSize - 1;
293*f6dc9357SAndroid Build Coastguard Worker     if (lim >= size)
294*f6dc9357SAndroid Build Coastguard Worker       lim = (unsigned)size;
295*f6dc9357SAndroid Build Coastguard Worker     else if (p[lim] != 0)
296*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
297*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = namePos; i < lim; i++)
298*f6dc9357SAndroid Build Coastguard Worker       if (p[i] == 0)
299*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
300*f6dc9357SAndroid Build Coastguard Worker   }
301*f6dc9357SAndroid Build Coastguard Worker 
302*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
303*f6dc9357SAndroid Build Coastguard Worker }
304*f6dc9357SAndroid Build Coastguard Worker }
305*f6dc9357SAndroid Build Coastguard Worker 
306*f6dc9357SAndroid Build Coastguard Worker 
307*f6dc9357SAndroid Build Coastguard Worker #define READ_STREAM(_dest_, _size_) \
308*f6dc9357SAndroid Build Coastguard Worker   { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \
309*f6dc9357SAndroid Build Coastguard Worker if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } }
310*f6dc9357SAndroid Build Coastguard Worker 
GetNextItem()311*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::GetNextItem()
312*f6dc9357SAndroid Build Coastguard Worker {
313*f6dc9357SAndroid Build Coastguard Worker   errorType = k_ErrorType_BadSignature;
314*f6dc9357SAndroid Build Coastguard Worker 
315*f6dc9357SAndroid Build Coastguard Worker   Byte p[k_RecordSize_Max];
316*f6dc9357SAndroid Build Coastguard Worker 
317*f6dc9357SAndroid Build Coastguard Worker   READ_STREAM(p, k_BinRecord_Size)
318*f6dc9357SAndroid Build Coastguard Worker 
319*f6dc9357SAndroid Build Coastguard Worker   UInt32 nameSize;
320*f6dc9357SAndroid Build Coastguard Worker   UInt32 namePos;
321*f6dc9357SAndroid Build Coastguard Worker 
322*f6dc9357SAndroid Build Coastguard Worker   /* we try to reduce probability of false detection,
323*f6dc9357SAndroid Build Coastguard Worker      so we check some fields for unuxpected values */
324*f6dc9357SAndroid Build Coastguard Worker 
325*f6dc9357SAndroid Build Coastguard Worker   if (p[0] != '0')
326*f6dc9357SAndroid Build Coastguard Worker   {
327*f6dc9357SAndroid Build Coastguard Worker          if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { item.Type = k_Type_BinLe; }
328*f6dc9357SAndroid Build Coastguard Worker     else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
329*f6dc9357SAndroid Build Coastguard Worker     {
330*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 2; i < k_BinRecord_Size; i += 2)
331*f6dc9357SAndroid Build Coastguard Worker       {
332*f6dc9357SAndroid Build Coastguard Worker         const Byte b = p[i];
333*f6dc9357SAndroid Build Coastguard Worker         p[i] = p[i + 1];
334*f6dc9357SAndroid Build Coastguard Worker         p[i + 1] = b;
335*f6dc9357SAndroid Build Coastguard Worker       }
336*f6dc9357SAndroid Build Coastguard Worker       item.Type = k_Type_BinBe;
337*f6dc9357SAndroid Build Coastguard Worker     }
338*f6dc9357SAndroid Build Coastguard Worker     else
339*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker     errorType = k_ErrorType_Corrupted;
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker     item.AlignMask = 2 - 1;
344*f6dc9357SAndroid Build Coastguard Worker     item.DevMajor = 0;
345*f6dc9357SAndroid Build Coastguard Worker     item.RDevMajor = 0;
346*f6dc9357SAndroid Build Coastguard Worker     item.ChkSum = 0;
347*f6dc9357SAndroid Build Coastguard Worker 
348*f6dc9357SAndroid Build Coastguard Worker     G16(2, item.DevMinor);
349*f6dc9357SAndroid Build Coastguard Worker     G16(4, item.inode);
350*f6dc9357SAndroid Build Coastguard Worker     G16(6, item.Mode);
351*f6dc9357SAndroid Build Coastguard Worker     G16(8, item.UID);
352*f6dc9357SAndroid Build Coastguard Worker     G16(10, item.GID);
353*f6dc9357SAndroid Build Coastguard Worker     G16(12, item.NumLinks);
354*f6dc9357SAndroid Build Coastguard Worker     G16(14, item.RDevMinor);
355*f6dc9357SAndroid Build Coastguard Worker     G32(16, item.MTime);
356*f6dc9357SAndroid Build Coastguard Worker     G16(20, nameSize);
357*f6dc9357SAndroid Build Coastguard Worker     G32(22, item.Size);
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker     namePos = k_BinRecord_Size;
360*f6dc9357SAndroid Build Coastguard Worker   }
361*f6dc9357SAndroid Build Coastguard Worker   else
362*f6dc9357SAndroid Build Coastguard Worker   {
363*f6dc9357SAndroid Build Coastguard Worker     if (p[1] != '7' ||
364*f6dc9357SAndroid Build Coastguard Worker         p[2] != '0' ||
365*f6dc9357SAndroid Build Coastguard Worker         p[3] != '7' ||
366*f6dc9357SAndroid Build Coastguard Worker         p[4] != '0')
367*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
368*f6dc9357SAndroid Build Coastguard Worker     if (p[5] == kMagicOct)
369*f6dc9357SAndroid Build Coastguard Worker     {
370*f6dc9357SAndroid Build Coastguard Worker       errorType = k_ErrorType_Corrupted;
371*f6dc9357SAndroid Build Coastguard Worker 
372*f6dc9357SAndroid Build Coastguard Worker       item.Type = k_Type_Oct;
373*f6dc9357SAndroid Build Coastguard Worker       READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size)
374*f6dc9357SAndroid Build Coastguard Worker       item.AlignMask = 1 - 1;
375*f6dc9357SAndroid Build Coastguard Worker       item.DevMajor = 0;
376*f6dc9357SAndroid Build Coastguard Worker       item.RDevMajor = 0;
377*f6dc9357SAndroid Build Coastguard Worker       item.ChkSum = 0;
378*f6dc9357SAndroid Build Coastguard Worker 
379*f6dc9357SAndroid Build Coastguard Worker       if (!CheckOctRecord(p))
380*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
381*f6dc9357SAndroid Build Coastguard Worker 
382*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (0, item.DevMinor)
383*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (1 * 6, item.inode)
384*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (2 * 6, item.Mode)
385*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (3 * 6, item.UID)
386*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (4 * 6, item.GID)
387*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (5 * 6, item.NumLinks)
388*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (6 * 6, item.RDevMinor)
389*f6dc9357SAndroid Build Coastguard Worker       {
390*f6dc9357SAndroid Build Coastguard Worker         UInt64 mTime64;
391*f6dc9357SAndroid Build Coastguard Worker         READ_OCT_11 (7 * 6, mTime64)
392*f6dc9357SAndroid Build Coastguard Worker         item.MTime = 0;
393*f6dc9357SAndroid Build Coastguard Worker         if (mTime64 <= (UInt32)(Int32)-1)
394*f6dc9357SAndroid Build Coastguard Worker           item.MTime = (UInt32)mTime64;
395*f6dc9357SAndroid Build Coastguard Worker       }
396*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_6 (7 * 6 + 11, nameSize)
397*f6dc9357SAndroid Build Coastguard Worker       READ_OCT_11 (8 * 6 + 11, item.Size)  // ?????
398*f6dc9357SAndroid Build Coastguard Worker 
399*f6dc9357SAndroid Build Coastguard Worker       namePos = k_OctRecord_Size;
400*f6dc9357SAndroid Build Coastguard Worker     }
401*f6dc9357SAndroid Build Coastguard Worker     else
402*f6dc9357SAndroid Build Coastguard Worker     {
403*f6dc9357SAndroid Build Coastguard Worker            if (p[5] == kMagicHex)    item.Type = k_Type_Hex;
404*f6dc9357SAndroid Build Coastguard Worker       else if (p[5] == kMagicHexCrc) item.Type = k_Type_HexCrc;
405*f6dc9357SAndroid Build Coastguard Worker       else return S_OK;
406*f6dc9357SAndroid Build Coastguard Worker 
407*f6dc9357SAndroid Build Coastguard Worker       errorType = k_ErrorType_Corrupted;
408*f6dc9357SAndroid Build Coastguard Worker 
409*f6dc9357SAndroid Build Coastguard Worker       READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size)
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker       if (!CheckHexRecord(p))
412*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
413*f6dc9357SAndroid Build Coastguard Worker 
414*f6dc9357SAndroid Build Coastguard Worker       item.AlignMask = 4 - 1;
415*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (0, item.inode)
416*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (1, item.Mode)
417*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (2, item.UID)
418*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (3, item.GID)
419*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (4, item.NumLinks)
420*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (5, item.MTime)
421*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (6, item.Size)
422*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (7, item.DevMajor)
423*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (8, item.DevMinor)
424*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (9, item.RDevMajor)
425*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (10, item.RDevMinor)
426*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (11, nameSize)
427*f6dc9357SAndroid Build Coastguard Worker       READ_HEX (12, item.ChkSum)
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker       if (item.Type == k_Type_Hex && item.ChkSum != 0)
430*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker       namePos = k_HexRecord_Size;
433*f6dc9357SAndroid Build Coastguard Worker     }
434*f6dc9357SAndroid Build Coastguard Worker   }
435*f6dc9357SAndroid Build Coastguard Worker 
436*f6dc9357SAndroid Build Coastguard Worker   if (item.Mode >= (1 << 16))
437*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
438*f6dc9357SAndroid Build Coastguard Worker 
439*f6dc9357SAndroid Build Coastguard Worker   /* v23.02: we have disabled rDevMinor check because real file
440*f6dc9357SAndroid Build Coastguard Worker      from Apple contains rDevMinor==255 by some unknown reason */
441*f6dc9357SAndroid Build Coastguard Worker   if (item.RDevMajor != 0
442*f6dc9357SAndroid Build Coastguard Worker       // || item.RDevMinor != 0
443*f6dc9357SAndroid Build Coastguard Worker       )
444*f6dc9357SAndroid Build Coastguard Worker   {
445*f6dc9357SAndroid Build Coastguard Worker     if (!MY_LIN_S_ISCHR(item.Mode) &&
446*f6dc9357SAndroid Build Coastguard Worker         !MY_LIN_S_ISBLK(item.Mode))
447*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
448*f6dc9357SAndroid Build Coastguard Worker   }
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker   // Size must be 0 for FIFOs and directories
451*f6dc9357SAndroid Build Coastguard Worker   if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode))
452*f6dc9357SAndroid Build Coastguard Worker     if (item.Size != 0)
453*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
454*f6dc9357SAndroid Build Coastguard Worker 
455*f6dc9357SAndroid Build Coastguard Worker   // nameSize must include the null byte
456*f6dc9357SAndroid Build Coastguard Worker   if (nameSize == 0 || nameSize > kNameSizeMax)
457*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
458*f6dc9357SAndroid Build Coastguard Worker   item.HeaderSize = item.GetAlignedSize(namePos + nameSize);
459*f6dc9357SAndroid Build Coastguard Worker   const UInt32 rem = item.HeaderSize - namePos;
460*f6dc9357SAndroid Build Coastguard Worker   char *s = item.Name.GetBuf(rem);
461*f6dc9357SAndroid Build Coastguard Worker   size_t processedSize = rem;
462*f6dc9357SAndroid Build Coastguard Worker   RINOK(Read(s, &processedSize))
463*f6dc9357SAndroid Build Coastguard Worker   if (processedSize != rem)
464*f6dc9357SAndroid Build Coastguard Worker   {
465*f6dc9357SAndroid Build Coastguard Worker     item.Name.ReleaseBuf_SetEnd(0);
466*f6dc9357SAndroid Build Coastguard Worker     errorType = k_ErrorType_UnexpectedEnd;
467*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
468*f6dc9357SAndroid Build Coastguard Worker   }
469*f6dc9357SAndroid Build Coastguard Worker   bool pad_error = false;
470*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = nameSize; i < processedSize; i++)
471*f6dc9357SAndroid Build Coastguard Worker     if (s[i] != 0)
472*f6dc9357SAndroid Build Coastguard Worker       pad_error = true;
473*f6dc9357SAndroid Build Coastguard Worker   item.Name.ReleaseBuf_CalcLen(nameSize);
474*f6dc9357SAndroid Build Coastguard Worker   if (item.Name.Len() + 1 != nameSize || pad_error)
475*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
476*f6dc9357SAndroid Build Coastguard Worker   errorType = k_ErrorType_OK;
477*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
478*f6dc9357SAndroid Build Coastguard Worker }
479*f6dc9357SAndroid Build Coastguard Worker 
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker 
482*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
483*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
484*f6dc9357SAndroid Build Coastguard Worker )
485*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem> _items;
486*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
487*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
488*f6dc9357SAndroid Build Coastguard Worker   EType _type;
489*f6dc9357SAndroid Build Coastguard Worker   EErrorType _error;
490*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
491*f6dc9357SAndroid Build Coastguard Worker   bool _moreThanOneHardLinks_Error;
492*f6dc9357SAndroid Build Coastguard Worker   bool _numLinks_Error;
493*f6dc9357SAndroid Build Coastguard Worker   bool _pad_Error;
494*f6dc9357SAndroid Build Coastguard Worker   bool _symLink_Error;
495*f6dc9357SAndroid Build Coastguard Worker };
496*f6dc9357SAndroid Build Coastguard Worker 
497*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
498*f6dc9357SAndroid Build Coastguard Worker {
499*f6dc9357SAndroid Build Coastguard Worker   kpidSubType
500*f6dc9357SAndroid Build Coastguard Worker };
501*f6dc9357SAndroid Build Coastguard Worker 
502*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
503*f6dc9357SAndroid Build Coastguard Worker {
504*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
505*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
506*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
507*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
508*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
509*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib,
510*f6dc9357SAndroid Build Coastguard Worker   kpidLinks,
511*f6dc9357SAndroid Build Coastguard Worker   kpidINode,
512*f6dc9357SAndroid Build Coastguard Worker   kpidUserId,
513*f6dc9357SAndroid Build Coastguard Worker   kpidGroupId,
514*f6dc9357SAndroid Build Coastguard Worker   kpidDevMajor,
515*f6dc9357SAndroid Build Coastguard Worker   kpidDevMinor,
516*f6dc9357SAndroid Build Coastguard Worker   kpidDeviceMajor,
517*f6dc9357SAndroid Build Coastguard Worker   kpidDeviceMinor,
518*f6dc9357SAndroid Build Coastguard Worker   kpidChecksum,
519*f6dc9357SAndroid Build Coastguard Worker   kpidSymLink,
520*f6dc9357SAndroid Build Coastguard Worker   kpidStreamId, // for debug
521*f6dc9357SAndroid Build Coastguard Worker   kpidOffset
522*f6dc9357SAndroid Build Coastguard Worker };
523*f6dc9357SAndroid Build Coastguard Worker 
524*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
525*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
526*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))527*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
528*f6dc9357SAndroid Build Coastguard Worker {
529*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
530*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
531*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
532*f6dc9357SAndroid Build Coastguard Worker   {
533*f6dc9357SAndroid Build Coastguard Worker     case kpidSubType: prop = k_Types[(unsigned)_type]; break;
534*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
535*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = true; break;
536*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
537*f6dc9357SAndroid Build Coastguard Worker     {
538*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
539*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc)
540*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_IsNotArc;
541*f6dc9357SAndroid Build Coastguard Worker       switch (_error)
542*f6dc9357SAndroid Build Coastguard Worker       {
543*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
544*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_Corrupted:     v |= kpv_ErrorFlags_HeadersError; break;
545*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_OK:
546*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_BadSignature:
547*f6dc9357SAndroid Build Coastguard Worker         // default:
548*f6dc9357SAndroid Build Coastguard Worker           break;
549*f6dc9357SAndroid Build Coastguard Worker       }
550*f6dc9357SAndroid Build Coastguard Worker       prop = v;
551*f6dc9357SAndroid Build Coastguard Worker       break;
552*f6dc9357SAndroid Build Coastguard Worker     }
553*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
554*f6dc9357SAndroid Build Coastguard Worker     {
555*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
556*f6dc9357SAndroid Build Coastguard Worker       if (_moreThanOneHardLinks_Error)
557*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_UnsupportedFeature; // kpv_ErrorFlags_HeadersError
558*f6dc9357SAndroid Build Coastguard Worker       if (_numLinks_Error
559*f6dc9357SAndroid Build Coastguard Worker           || _pad_Error
560*f6dc9357SAndroid Build Coastguard Worker           || _symLink_Error)
561*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_HeadersError;
562*f6dc9357SAndroid Build Coastguard Worker       if (v != 0)
563*f6dc9357SAndroid Build Coastguard Worker         prop = v;
564*f6dc9357SAndroid Build Coastguard Worker       break;
565*f6dc9357SAndroid Build Coastguard Worker     }
566*f6dc9357SAndroid Build Coastguard Worker   }
567*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
568*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
569*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
570*f6dc9357SAndroid Build Coastguard Worker }
571*f6dc9357SAndroid Build Coastguard Worker 
572*f6dc9357SAndroid Build Coastguard Worker 
CompareItems(const unsigned * p1,const unsigned * p2,void * param)573*f6dc9357SAndroid Build Coastguard Worker static int CompareItems(const unsigned *p1, const unsigned *p2, void *param)
574*f6dc9357SAndroid Build Coastguard Worker {
575*f6dc9357SAndroid Build Coastguard Worker   const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
576*f6dc9357SAndroid Build Coastguard Worker   const unsigned index1 = *p1;
577*f6dc9357SAndroid Build Coastguard Worker   const unsigned index2 = *p2;
578*f6dc9357SAndroid Build Coastguard Worker   const CItem &i1 = items[index1];
579*f6dc9357SAndroid Build Coastguard Worker   const CItem &i2 = items[index2];
580*f6dc9357SAndroid Build Coastguard Worker   if (i1.DevMajor < i2.DevMajor) return -1;
581*f6dc9357SAndroid Build Coastguard Worker   if (i1.DevMajor > i2.DevMajor) return 1;
582*f6dc9357SAndroid Build Coastguard Worker   if (i1.DevMinor < i2.DevMinor) return -1;
583*f6dc9357SAndroid Build Coastguard Worker   if (i1.DevMinor > i2.DevMinor) return 1;
584*f6dc9357SAndroid Build Coastguard Worker   if (i1.inode < i2.inode) return -1;
585*f6dc9357SAndroid Build Coastguard Worker   if (i1.inode > i2.inode) return 1;
586*f6dc9357SAndroid Build Coastguard Worker   if (i1.IsDir())
587*f6dc9357SAndroid Build Coastguard Worker   {
588*f6dc9357SAndroid Build Coastguard Worker     if (!i2.IsDir())
589*f6dc9357SAndroid Build Coastguard Worker       return -1;
590*f6dc9357SAndroid Build Coastguard Worker   }
591*f6dc9357SAndroid Build Coastguard Worker   else if (i2.IsDir())
592*f6dc9357SAndroid Build Coastguard Worker     return 1;
593*f6dc9357SAndroid Build Coastguard Worker   return MyCompare(index1, index2);
594*f6dc9357SAndroid Build Coastguard Worker }
595*f6dc9357SAndroid Build Coastguard Worker 
596*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * callback))597*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
598*f6dc9357SAndroid Build Coastguard Worker {
599*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
600*f6dc9357SAndroid Build Coastguard Worker   {
601*f6dc9357SAndroid Build Coastguard Worker     Close();
602*f6dc9357SAndroid Build Coastguard Worker 
603*f6dc9357SAndroid Build Coastguard Worker     UInt64 endPos;
604*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_AtBegin_GetSize(stream, endPos))
605*f6dc9357SAndroid Build Coastguard Worker     if (callback)
606*f6dc9357SAndroid Build Coastguard Worker     {
607*f6dc9357SAndroid Build Coastguard Worker       RINOK(callback->SetTotal(NULL, &endPos))
608*f6dc9357SAndroid Build Coastguard Worker     }
609*f6dc9357SAndroid Build Coastguard Worker 
610*f6dc9357SAndroid Build Coastguard Worker     CInArchive arc;
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker     arc.Stream = stream;
613*f6dc9357SAndroid Build Coastguard Worker     arc.Processed = 0;
614*f6dc9357SAndroid Build Coastguard Worker 
615*f6dc9357SAndroid Build Coastguard Worker     for (;;)
616*f6dc9357SAndroid Build Coastguard Worker     {
617*f6dc9357SAndroid Build Coastguard Worker       CItem &item = arc.item;
618*f6dc9357SAndroid Build Coastguard Worker       item.HeaderPos = arc.Processed;
619*f6dc9357SAndroid Build Coastguard Worker 
620*f6dc9357SAndroid Build Coastguard Worker       RINOK(arc.GetNextItem())
621*f6dc9357SAndroid Build Coastguard Worker 
622*f6dc9357SAndroid Build Coastguard Worker       _error = arc.errorType;
623*f6dc9357SAndroid Build Coastguard Worker 
624*f6dc9357SAndroid Build Coastguard Worker       if (_error != k_ErrorType_OK)
625*f6dc9357SAndroid Build Coastguard Worker       {
626*f6dc9357SAndroid Build Coastguard Worker         if (_error == k_ErrorType_BadSignature ||
627*f6dc9357SAndroid Build Coastguard Worker             _error == k_ErrorType_Corrupted)
628*f6dc9357SAndroid Build Coastguard Worker           arc.Processed = item.HeaderPos;
629*f6dc9357SAndroid Build Coastguard Worker         break;
630*f6dc9357SAndroid Build Coastguard Worker       }
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker       if (_items.IsEmpty())
633*f6dc9357SAndroid Build Coastguard Worker         _type = item.Type;
634*f6dc9357SAndroid Build Coastguard Worker       else if (_items.Back().Type != item.Type)
635*f6dc9357SAndroid Build Coastguard Worker       {
636*f6dc9357SAndroid Build Coastguard Worker         _error = k_ErrorType_Corrupted;
637*f6dc9357SAndroid Build Coastguard Worker         arc.Processed = item.HeaderPos;
638*f6dc9357SAndroid Build Coastguard Worker         break;
639*f6dc9357SAndroid Build Coastguard Worker       }
640*f6dc9357SAndroid Build Coastguard Worker 
641*f6dc9357SAndroid Build Coastguard Worker       if (item.IsTrailer())
642*f6dc9357SAndroid Build Coastguard Worker         break;
643*f6dc9357SAndroid Build Coastguard Worker 
644*f6dc9357SAndroid Build Coastguard Worker       item.MainIndex_ForInode = _items.Size();
645*f6dc9357SAndroid Build Coastguard Worker       _items.Add(item);
646*f6dc9357SAndroid Build Coastguard Worker 
647*f6dc9357SAndroid Build Coastguard Worker       const UInt64 dataSize = item.GetPackSize();
648*f6dc9357SAndroid Build Coastguard Worker       arc.Processed += dataSize;
649*f6dc9357SAndroid Build Coastguard Worker       if (arc.Processed > endPos)
650*f6dc9357SAndroid Build Coastguard Worker       {
651*f6dc9357SAndroid Build Coastguard Worker         _error = k_ErrorType_UnexpectedEnd;
652*f6dc9357SAndroid Build Coastguard Worker         break;
653*f6dc9357SAndroid Build Coastguard Worker       }
654*f6dc9357SAndroid Build Coastguard Worker 
655*f6dc9357SAndroid Build Coastguard Worker       if (item.Is_SymLink() && dataSize <= (1 << 12) && item.Size != 0)
656*f6dc9357SAndroid Build Coastguard Worker       {
657*f6dc9357SAndroid Build Coastguard Worker         size_t cur = (size_t)dataSize;
658*f6dc9357SAndroid Build Coastguard Worker         CByteBuffer buf;
659*f6dc9357SAndroid Build Coastguard Worker         buf.Alloc(cur);
660*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadStream(stream, buf, &cur))
661*f6dc9357SAndroid Build Coastguard Worker         if (cur != dataSize)
662*f6dc9357SAndroid Build Coastguard Worker         {
663*f6dc9357SAndroid Build Coastguard Worker           _error = k_ErrorType_UnexpectedEnd;
664*f6dc9357SAndroid Build Coastguard Worker           break;
665*f6dc9357SAndroid Build Coastguard Worker         }
666*f6dc9357SAndroid Build Coastguard Worker         size_t i;
667*f6dc9357SAndroid Build Coastguard Worker 
668*f6dc9357SAndroid Build Coastguard Worker         for (i = (size_t)item.Size; i < dataSize; i++)
669*f6dc9357SAndroid Build Coastguard Worker           if (buf[i] != 0)
670*f6dc9357SAndroid Build Coastguard Worker             break;
671*f6dc9357SAndroid Build Coastguard Worker         if (i != dataSize)
672*f6dc9357SAndroid Build Coastguard Worker           _pad_Error = true;
673*f6dc9357SAndroid Build Coastguard Worker 
674*f6dc9357SAndroid Build Coastguard Worker         for (i = 0; i < (size_t)item.Size; i++)
675*f6dc9357SAndroid Build Coastguard Worker           if (buf[i] == 0)
676*f6dc9357SAndroid Build Coastguard Worker             break;
677*f6dc9357SAndroid Build Coastguard Worker         if (i != (size_t)item.Size)
678*f6dc9357SAndroid Build Coastguard Worker           _symLink_Error = true;
679*f6dc9357SAndroid Build Coastguard Worker         else
680*f6dc9357SAndroid Build Coastguard Worker           _items.Back().Data.CopyFrom(buf, (size_t)item.Size);
681*f6dc9357SAndroid Build Coastguard Worker       }
682*f6dc9357SAndroid Build Coastguard Worker       else if (dataSize != 0)
683*f6dc9357SAndroid Build Coastguard Worker       {
684*f6dc9357SAndroid Build Coastguard Worker         UInt64 newPos;
685*f6dc9357SAndroid Build Coastguard Worker         RINOK(stream->Seek((Int64)dataSize, STREAM_SEEK_CUR, &newPos))
686*f6dc9357SAndroid Build Coastguard Worker         if (arc.Processed != newPos)
687*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
688*f6dc9357SAndroid Build Coastguard Worker       }
689*f6dc9357SAndroid Build Coastguard Worker 
690*f6dc9357SAndroid Build Coastguard Worker       if (callback && (_items.Size() & 0xFFF) == 0)
691*f6dc9357SAndroid Build Coastguard Worker       {
692*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles = _items.Size();
693*f6dc9357SAndroid Build Coastguard Worker         RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos))
694*f6dc9357SAndroid Build Coastguard Worker       }
695*f6dc9357SAndroid Build Coastguard Worker     }
696*f6dc9357SAndroid Build Coastguard Worker 
697*f6dc9357SAndroid Build Coastguard Worker     _phySize = arc.Processed;
698*f6dc9357SAndroid Build Coastguard Worker   }
699*f6dc9357SAndroid Build Coastguard Worker 
700*f6dc9357SAndroid Build Coastguard Worker   {
701*f6dc9357SAndroid Build Coastguard Worker     if (_error != k_ErrorType_OK)
702*f6dc9357SAndroid Build Coastguard Worker     {
703*f6dc9357SAndroid Build Coastguard Worker       // we try to reduce probability of false detection
704*f6dc9357SAndroid Build Coastguard Worker       if (_items.Size() == 0)
705*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
706*f6dc9357SAndroid Build Coastguard Worker       // bin file uses small signature. So we do additional check for single item case.
707*f6dc9357SAndroid Build Coastguard Worker       if (_items.Size() == 1 && _items[0].IsBin())
708*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
709*f6dc9357SAndroid Build Coastguard Worker     }
710*f6dc9357SAndroid Build Coastguard Worker     else
711*f6dc9357SAndroid Build Coastguard Worker     {
712*f6dc9357SAndroid Build Coastguard Worker       // Read tailing zeros.
713*f6dc9357SAndroid Build Coastguard Worker       // Most of cpio files use 512-bytes aligned zeros
714*f6dc9357SAndroid Build Coastguard Worker       // rare case: 4K/8K aligment is possible also
715*f6dc9357SAndroid Build Coastguard Worker       const unsigned kTailSize_MAX = 1 << 9;
716*f6dc9357SAndroid Build Coastguard Worker       Byte buf[kTailSize_MAX];
717*f6dc9357SAndroid Build Coastguard Worker 
718*f6dc9357SAndroid Build Coastguard Worker       unsigned pos = (unsigned)_phySize & (kTailSize_MAX - 1);
719*f6dc9357SAndroid Build Coastguard Worker       if (pos != 0) // use this check to support 512 bytes alignment only
720*f6dc9357SAndroid Build Coastguard Worker       for (;;)
721*f6dc9357SAndroid Build Coastguard Worker       {
722*f6dc9357SAndroid Build Coastguard Worker         const unsigned rem = kTailSize_MAX - pos;
723*f6dc9357SAndroid Build Coastguard Worker         size_t processed = rem;
724*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadStream(stream, buf + pos, &processed))
725*f6dc9357SAndroid Build Coastguard Worker         if (processed != rem)
726*f6dc9357SAndroid Build Coastguard Worker           break;
727*f6dc9357SAndroid Build Coastguard Worker         for (; pos < kTailSize_MAX && buf[pos] == 0; pos++)
728*f6dc9357SAndroid Build Coastguard Worker         {}
729*f6dc9357SAndroid Build Coastguard Worker         if (pos != kTailSize_MAX)
730*f6dc9357SAndroid Build Coastguard Worker           break;
731*f6dc9357SAndroid Build Coastguard Worker         _phySize += processed;
732*f6dc9357SAndroid Build Coastguard Worker         pos = 0;
733*f6dc9357SAndroid Build Coastguard Worker 
734*f6dc9357SAndroid Build Coastguard Worker         //       use break to support 512   bytes alignment zero tail
735*f6dc9357SAndroid Build Coastguard Worker         // don't use break to support 512*n bytes alignment zero tail
736*f6dc9357SAndroid Build Coastguard Worker         break;
737*f6dc9357SAndroid Build Coastguard Worker       }
738*f6dc9357SAndroid Build Coastguard Worker     }
739*f6dc9357SAndroid Build Coastguard Worker   }
740*f6dc9357SAndroid Build Coastguard Worker 
741*f6dc9357SAndroid Build Coastguard Worker   {
742*f6dc9357SAndroid Build Coastguard Worker     /* there was such cpio archive example with hard links:
743*f6dc9357SAndroid Build Coastguard Worker        {
744*f6dc9357SAndroid Build Coastguard Worker          all hard links (same dev/inode) are stored in neighboring items, and
745*f6dc9357SAndroid Build Coastguard Worker            (item.Size == 0)  for non last hard link items
746*f6dc9357SAndroid Build Coastguard Worker            (item.Size != 0)  for     last hard link item
747*f6dc9357SAndroid Build Coastguard Worker        }
748*f6dc9357SAndroid Build Coastguard Worker        but here we sort items by (dev/inode) to support cases
749*f6dc9357SAndroid Build Coastguard Worker        where hard links (same dev/inode) are not stored in neighboring items.
750*f6dc9357SAndroid Build Coastguard Worker 
751*f6dc9357SAndroid Build Coastguard Worker        // note: some cpio files have (numLinks == 0) ??
752*f6dc9357SAndroid Build Coastguard Worker     */
753*f6dc9357SAndroid Build Coastguard Worker 
754*f6dc9357SAndroid Build Coastguard Worker     CUIntVector indices;
755*f6dc9357SAndroid Build Coastguard Worker     {
756*f6dc9357SAndroid Build Coastguard Worker       const unsigned numItems = _items.Size();
757*f6dc9357SAndroid Build Coastguard Worker       indices.ClearAndSetSize(numItems);
758*f6dc9357SAndroid Build Coastguard Worker       if (numItems != 0)
759*f6dc9357SAndroid Build Coastguard Worker       {
760*f6dc9357SAndroid Build Coastguard Worker         unsigned *vals = &indices[0];
761*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = 0; i < numItems; i++)
762*f6dc9357SAndroid Build Coastguard Worker           vals[i] = i;
763*f6dc9357SAndroid Build Coastguard Worker         indices.Sort(CompareItems, (void *)&_items);
764*f6dc9357SAndroid Build Coastguard Worker       }
765*f6dc9357SAndroid Build Coastguard Worker     }
766*f6dc9357SAndroid Build Coastguard Worker 
767*f6dc9357SAndroid Build Coastguard Worker     /* Note: if cpio archive (maybe incorrect) contains
768*f6dc9357SAndroid Build Coastguard Worker        more then one non empty streams with identical inode number,
769*f6dc9357SAndroid Build Coastguard Worker        we want to extract all such data streams too.
770*f6dc9357SAndroid Build Coastguard Worker 
771*f6dc9357SAndroid Build Coastguard Worker        So we place items with identical inode to groups:
772*f6dc9357SAndroid Build Coastguard Worker        all items in group will have same MainIndex_ForInode,
773*f6dc9357SAndroid Build Coastguard Worker        that is index of last item in group with (Size != 0).
774*f6dc9357SAndroid Build Coastguard Worker        Another (non last) items in group have (Size == 0).
775*f6dc9357SAndroid Build Coastguard Worker        If there are another hard links with same inode number
776*f6dc9357SAndroid Build Coastguard Worker        after (Size != 0) item, we place them to another next group(s).
777*f6dc9357SAndroid Build Coastguard Worker 
778*f6dc9357SAndroid Build Coastguard Worker        Check it: maybe we should use single group for items
779*f6dc9357SAndroid Build Coastguard Worker        with identical inode instead, and ignore some extra data streams ?
780*f6dc9357SAndroid Build Coastguard Worker     */
781*f6dc9357SAndroid Build Coastguard Worker 
782*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < indices.Size();)
783*f6dc9357SAndroid Build Coastguard Worker     {
784*f6dc9357SAndroid Build Coastguard Worker       unsigned k;
785*f6dc9357SAndroid Build Coastguard Worker       {
786*f6dc9357SAndroid Build Coastguard Worker         const CItem &item_Base = _items[indices[i]];
787*f6dc9357SAndroid Build Coastguard Worker 
788*f6dc9357SAndroid Build Coastguard Worker         if (item_Base.IsDir())
789*f6dc9357SAndroid Build Coastguard Worker         {
790*f6dc9357SAndroid Build Coastguard Worker           i++;
791*f6dc9357SAndroid Build Coastguard Worker           continue;
792*f6dc9357SAndroid Build Coastguard Worker         }
793*f6dc9357SAndroid Build Coastguard Worker 
794*f6dc9357SAndroid Build Coastguard Worker         if (i != 0)
795*f6dc9357SAndroid Build Coastguard Worker         {
796*f6dc9357SAndroid Build Coastguard Worker           const CItem &item_Prev = _items[indices[i - 1]];
797*f6dc9357SAndroid Build Coastguard Worker           if (!item_Prev.IsDir())
798*f6dc9357SAndroid Build Coastguard Worker             if (item_Base.IsSame_inode_Dev(item_Prev))
799*f6dc9357SAndroid Build Coastguard Worker               _moreThanOneHardLinks_Error = true;
800*f6dc9357SAndroid Build Coastguard Worker         }
801*f6dc9357SAndroid Build Coastguard Worker 
802*f6dc9357SAndroid Build Coastguard Worker         if (item_Base.Size != 0)
803*f6dc9357SAndroid Build Coastguard Worker         {
804*f6dc9357SAndroid Build Coastguard Worker           if (item_Base.NumLinks != 1)
805*f6dc9357SAndroid Build Coastguard Worker             _numLinks_Error = true;
806*f6dc9357SAndroid Build Coastguard Worker           i++;
807*f6dc9357SAndroid Build Coastguard Worker           continue;
808*f6dc9357SAndroid Build Coastguard Worker         }
809*f6dc9357SAndroid Build Coastguard Worker 
810*f6dc9357SAndroid Build Coastguard Worker         for (k = i + 1; k < indices.Size();)
811*f6dc9357SAndroid Build Coastguard Worker         {
812*f6dc9357SAndroid Build Coastguard Worker           const CItem &item = _items[indices[k]];
813*f6dc9357SAndroid Build Coastguard Worker           if (item.IsDir())
814*f6dc9357SAndroid Build Coastguard Worker             break;
815*f6dc9357SAndroid Build Coastguard Worker           if (!item.IsSame_inode_Dev(item_Base))
816*f6dc9357SAndroid Build Coastguard Worker             break;
817*f6dc9357SAndroid Build Coastguard Worker           k++;
818*f6dc9357SAndroid Build Coastguard Worker           if (item.Size != 0)
819*f6dc9357SAndroid Build Coastguard Worker             break;
820*f6dc9357SAndroid Build Coastguard Worker         }
821*f6dc9357SAndroid Build Coastguard Worker       }
822*f6dc9357SAndroid Build Coastguard Worker 
823*f6dc9357SAndroid Build Coastguard Worker       const unsigned numLinks = k - i;
824*f6dc9357SAndroid Build Coastguard Worker       for (;;)
825*f6dc9357SAndroid Build Coastguard Worker       {
826*f6dc9357SAndroid Build Coastguard Worker         CItem &item = _items[indices[i]];
827*f6dc9357SAndroid Build Coastguard Worker         if (item.NumLinks != numLinks)
828*f6dc9357SAndroid Build Coastguard Worker           _numLinks_Error = true;
829*f6dc9357SAndroid Build Coastguard Worker         if (++i == k)
830*f6dc9357SAndroid Build Coastguard Worker           break;
831*f6dc9357SAndroid Build Coastguard Worker         // if (item.Size == 0)
832*f6dc9357SAndroid Build Coastguard Worker         item.MainIndex_ForInode = indices[k - 1];
833*f6dc9357SAndroid Build Coastguard Worker       }
834*f6dc9357SAndroid Build Coastguard Worker     }
835*f6dc9357SAndroid Build Coastguard Worker   }
836*f6dc9357SAndroid Build Coastguard Worker 
837*f6dc9357SAndroid Build Coastguard Worker   _isArc = true;
838*f6dc9357SAndroid Build Coastguard Worker   _stream = stream;
839*f6dc9357SAndroid Build Coastguard Worker 
840*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
841*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
842*f6dc9357SAndroid Build Coastguard Worker }
843*f6dc9357SAndroid Build Coastguard Worker 
844*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())845*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
846*f6dc9357SAndroid Build Coastguard Worker {
847*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
848*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
849*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
850*f6dc9357SAndroid Build Coastguard Worker   _type = k_Type_BinLe;
851*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
852*f6dc9357SAndroid Build Coastguard Worker   _moreThanOneHardLinks_Error = false;
853*f6dc9357SAndroid Build Coastguard Worker   _numLinks_Error = false;
854*f6dc9357SAndroid Build Coastguard Worker   _pad_Error = false;
855*f6dc9357SAndroid Build Coastguard Worker   _symLink_Error = false;
856*f6dc9357SAndroid Build Coastguard Worker   _error = k_ErrorType_OK;
857*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
858*f6dc9357SAndroid Build Coastguard Worker }
859*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))860*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
861*f6dc9357SAndroid Build Coastguard Worker {
862*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
863*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
864*f6dc9357SAndroid Build Coastguard Worker }
865*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))866*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
867*f6dc9357SAndroid Build Coastguard Worker {
868*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
869*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
870*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
871*f6dc9357SAndroid Build Coastguard Worker 
872*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
873*f6dc9357SAndroid Build Coastguard Worker   {
874*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
875*f6dc9357SAndroid Build Coastguard Worker     {
876*f6dc9357SAndroid Build Coastguard Worker       UString res;
877*f6dc9357SAndroid Build Coastguard Worker       bool needConvert = true;
878*f6dc9357SAndroid Build Coastguard Worker       #ifdef _WIN32
879*f6dc9357SAndroid Build Coastguard Worker       // if (
880*f6dc9357SAndroid Build Coastguard Worker       ConvertUTF8ToUnicode(item.Name, res);
881*f6dc9357SAndroid Build Coastguard Worker       // )
882*f6dc9357SAndroid Build Coastguard Worker         needConvert = false;
883*f6dc9357SAndroid Build Coastguard Worker       #endif
884*f6dc9357SAndroid Build Coastguard Worker       if (needConvert)
885*f6dc9357SAndroid Build Coastguard Worker         res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
886*f6dc9357SAndroid Build Coastguard Worker       prop = NItemName::GetOsPath(res);
887*f6dc9357SAndroid Build Coastguard Worker       break;
888*f6dc9357SAndroid Build Coastguard Worker     }
889*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = item.IsDir(); break;
890*f6dc9357SAndroid Build Coastguard Worker 
891*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:
892*f6dc9357SAndroid Build Coastguard Worker       prop = (UInt64)_items[item.MainIndex_ForInode].Size;
893*f6dc9357SAndroid Build Coastguard Worker       break;
894*f6dc9357SAndroid Build Coastguard Worker 
895*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:
896*f6dc9357SAndroid Build Coastguard Worker       prop = (UInt64)item.GetPackSize();
897*f6dc9357SAndroid Build Coastguard Worker       break;
898*f6dc9357SAndroid Build Coastguard Worker 
899*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
900*f6dc9357SAndroid Build Coastguard Worker     {
901*f6dc9357SAndroid Build Coastguard Worker       if (item.MTime != 0)
902*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_UnixTime(prop, item.MTime);
903*f6dc9357SAndroid Build Coastguard Worker       break;
904*f6dc9357SAndroid Build Coastguard Worker     }
905*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib: prop = item.Mode; break;
906*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = item.inode; break;
907*f6dc9357SAndroid Build Coastguard Worker     case kpidStreamId:
908*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsDir())
909*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item.MainIndex_ForInode;
910*f6dc9357SAndroid Build Coastguard Worker       break;
911*f6dc9357SAndroid Build Coastguard Worker     case kpidDevMajor: prop = (UInt32)item.DevMajor; break;
912*f6dc9357SAndroid Build Coastguard Worker     case kpidDevMinor: prop = (UInt32)item.DevMinor; break;
913*f6dc9357SAndroid Build Coastguard Worker 
914*f6dc9357SAndroid Build Coastguard Worker     case kpidUserId: prop = item.UID; break;
915*f6dc9357SAndroid Build Coastguard Worker     case kpidGroupId: prop = item.GID; break;
916*f6dc9357SAndroid Build Coastguard Worker 
917*f6dc9357SAndroid Build Coastguard Worker     case kpidSymLink:
918*f6dc9357SAndroid Build Coastguard Worker       if (item.Is_SymLink() && item.Data.Size() != 0)
919*f6dc9357SAndroid Build Coastguard Worker       {
920*f6dc9357SAndroid Build Coastguard Worker         AString s;
921*f6dc9357SAndroid Build Coastguard Worker         s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size());
922*f6dc9357SAndroid Build Coastguard Worker         if (s.Len() == item.Data.Size())
923*f6dc9357SAndroid Build Coastguard Worker         {
924*f6dc9357SAndroid Build Coastguard Worker           UString u;
925*f6dc9357SAndroid Build Coastguard Worker           bool needConvert = true;
926*f6dc9357SAndroid Build Coastguard Worker           #ifdef _WIN32
927*f6dc9357SAndroid Build Coastguard Worker             // if (
928*f6dc9357SAndroid Build Coastguard Worker             ConvertUTF8ToUnicode(item.Name, u);
929*f6dc9357SAndroid Build Coastguard Worker             // )
930*f6dc9357SAndroid Build Coastguard Worker             needConvert = false;
931*f6dc9357SAndroid Build Coastguard Worker           #endif
932*f6dc9357SAndroid Build Coastguard Worker           if (needConvert)
933*f6dc9357SAndroid Build Coastguard Worker             u = MultiByteToUnicodeString(s, CP_OEMCP);
934*f6dc9357SAndroid Build Coastguard Worker           prop = u;
935*f6dc9357SAndroid Build Coastguard Worker         }
936*f6dc9357SAndroid Build Coastguard Worker       }
937*f6dc9357SAndroid Build Coastguard Worker       break;
938*f6dc9357SAndroid Build Coastguard Worker 
939*f6dc9357SAndroid Build Coastguard Worker     case kpidLinks: prop = item.NumLinks; break;
940*f6dc9357SAndroid Build Coastguard Worker     case kpidDeviceMajor:
941*f6dc9357SAndroid Build Coastguard Worker       // if (item.RDevMajor != 0)
942*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item.RDevMajor;
943*f6dc9357SAndroid Build Coastguard Worker       break;
944*f6dc9357SAndroid Build Coastguard Worker     case kpidDeviceMinor:
945*f6dc9357SAndroid Build Coastguard Worker       // if (item.RDevMinor != 0)
946*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item.RDevMinor;
947*f6dc9357SAndroid Build Coastguard Worker       break;
948*f6dc9357SAndroid Build Coastguard Worker     case kpidChecksum:
949*f6dc9357SAndroid Build Coastguard Worker       if (item.IsCrcFormat())
950*f6dc9357SAndroid Build Coastguard Worker         prop = item.ChkSum;
951*f6dc9357SAndroid Build Coastguard Worker       break;
952*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset: prop = item.GetDataPosition(); break;
953*f6dc9357SAndroid Build Coastguard Worker   }
954*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
955*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
956*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
957*f6dc9357SAndroid Build Coastguard Worker }
958*f6dc9357SAndroid Build Coastguard Worker 
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
961*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithSum
962*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
963*f6dc9357SAndroid Build Coastguard Worker )
964*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _stream;
965*f6dc9357SAndroid Build Coastguard Worker   UInt32 _checksum;
966*f6dc9357SAndroid Build Coastguard Worker   bool _calculate;
967*f6dc9357SAndroid Build Coastguard Worker public:
968*f6dc9357SAndroid Build Coastguard Worker   void SetStream(ISequentialOutStream *stream) { _stream = stream; }
969*f6dc9357SAndroid Build Coastguard Worker   void ReleaseStream() { _stream.Release(); }
970*f6dc9357SAndroid Build Coastguard Worker   void Init(bool calculate)
971*f6dc9357SAndroid Build Coastguard Worker   {
972*f6dc9357SAndroid Build Coastguard Worker     _calculate = calculate;
973*f6dc9357SAndroid Build Coastguard Worker     _checksum = 0;
974*f6dc9357SAndroid Build Coastguard Worker   }
975*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetChecksum() const { return _checksum; }
976*f6dc9357SAndroid Build Coastguard Worker };
977*f6dc9357SAndroid Build Coastguard Worker 
978*f6dc9357SAndroid Build Coastguard Worker 
979*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize))
980*f6dc9357SAndroid Build Coastguard Worker {
981*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = S_OK;
982*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
983*f6dc9357SAndroid Build Coastguard Worker     result = _stream->Write(data, size, &size);
984*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
985*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
986*f6dc9357SAndroid Build Coastguard Worker   if (_calculate)
987*f6dc9357SAndroid Build Coastguard Worker   {
988*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = (const Byte *)data;
989*f6dc9357SAndroid Build Coastguard Worker     const Byte *lim = p + size;
990*f6dc9357SAndroid Build Coastguard Worker     UInt32 sum = _checksum;
991*f6dc9357SAndroid Build Coastguard Worker     if (size >= 4)
992*f6dc9357SAndroid Build Coastguard Worker     {
993*f6dc9357SAndroid Build Coastguard Worker       lim -= 4 - 1;
994*f6dc9357SAndroid Build Coastguard Worker       do
995*f6dc9357SAndroid Build Coastguard Worker       {
996*f6dc9357SAndroid Build Coastguard Worker         sum += p[0] + p[1] + p[2] + p[3];
997*f6dc9357SAndroid Build Coastguard Worker         p += 4;
998*f6dc9357SAndroid Build Coastguard Worker       }
999*f6dc9357SAndroid Build Coastguard Worker       while (p < lim);
1000*f6dc9357SAndroid Build Coastguard Worker       lim += 4 - 1;
1001*f6dc9357SAndroid Build Coastguard Worker     }
1002*f6dc9357SAndroid Build Coastguard Worker     if (p != lim) { sum += *p++;
1003*f6dc9357SAndroid Build Coastguard Worker     if (p != lim) { sum += *p++;
1004*f6dc9357SAndroid Build Coastguard Worker     if (p != lim) { sum += *p++; }}}
1005*f6dc9357SAndroid Build Coastguard Worker     _checksum = sum;
1006*f6dc9357SAndroid Build Coastguard Worker   }
1007*f6dc9357SAndroid Build Coastguard Worker   return result;
1008*f6dc9357SAndroid Build Coastguard Worker }
1009*f6dc9357SAndroid Build Coastguard Worker 
1010*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1011*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
1012*f6dc9357SAndroid Build Coastguard Worker {
1013*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1014*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1015*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
1016*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
1017*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
1018*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1019*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
1020*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1021*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1022*f6dc9357SAndroid Build Coastguard Worker   {
1023*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1024*f6dc9357SAndroid Build Coastguard Worker     const CItem &item2 = _items[index];
1025*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[item2.MainIndex_ForInode];
1026*f6dc9357SAndroid Build Coastguard Worker     totalSize += item.Size;
1027*f6dc9357SAndroid Build Coastguard Worker   }
1028*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
1029*f6dc9357SAndroid Build Coastguard Worker 
1030*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1031*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1032*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
1033*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
1034*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(_stream);
1035*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, COutStreamWithSum> outStreamSum;
1036*f6dc9357SAndroid Build Coastguard Worker 
1037*f6dc9357SAndroid Build Coastguard Worker   UInt64 total_PackSize = 0;
1038*f6dc9357SAndroid Build Coastguard Worker   UInt64 total_UnpackSize = 0;
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
1041*f6dc9357SAndroid Build Coastguard Worker   {
1042*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = total_PackSize;
1043*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = total_UnpackSize;
1044*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1045*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
1046*f6dc9357SAndroid Build Coastguard Worker       break;
1047*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
1048*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
1049*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
1050*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1051*f6dc9357SAndroid Build Coastguard Worker     const CItem &item2 = _items[index];
1052*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[item2.MainIndex_ForInode];
1053*f6dc9357SAndroid Build Coastguard Worker     {
1054*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> outStream;
1055*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &outStream, askMode))
1056*f6dc9357SAndroid Build Coastguard Worker 
1057*f6dc9357SAndroid Build Coastguard Worker       total_PackSize += item2.GetPackSize();
1058*f6dc9357SAndroid Build Coastguard Worker       total_UnpackSize += item.Size;
1059*f6dc9357SAndroid Build Coastguard Worker 
1060*f6dc9357SAndroid Build Coastguard Worker       if (item2.IsDir())
1061*f6dc9357SAndroid Build Coastguard Worker       {
1062*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->PrepareOperation(askMode))
1063*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
1064*f6dc9357SAndroid Build Coastguard Worker         continue;
1065*f6dc9357SAndroid Build Coastguard Worker       }
1066*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !outStream)
1067*f6dc9357SAndroid Build Coastguard Worker         continue;
1068*f6dc9357SAndroid Build Coastguard Worker       outStreamSum->Init(item.IsCrcFormat());
1069*f6dc9357SAndroid Build Coastguard Worker       outStreamSum->SetStream(outStream);
1070*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
1071*f6dc9357SAndroid Build Coastguard Worker     }
1072*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(_stream, item.GetDataPosition()))
1073*f6dc9357SAndroid Build Coastguard Worker     inStream->Init(item.Size);
1074*f6dc9357SAndroid Build Coastguard Worker     RINOK(copyCoder.Interface()->Code(inStream, outStreamSum, NULL, NULL, lps))
1075*f6dc9357SAndroid Build Coastguard Worker     outStreamSum->ReleaseStream();
1076*f6dc9357SAndroid Build Coastguard Worker     Int32 res = NExtract::NOperationResult::kDataError;
1077*f6dc9357SAndroid Build Coastguard Worker     if (copyCoder->TotalSize == item.Size)
1078*f6dc9357SAndroid Build Coastguard Worker     {
1079*f6dc9357SAndroid Build Coastguard Worker       res = NExtract::NOperationResult::kOK;
1080*f6dc9357SAndroid Build Coastguard Worker       if (item.IsCrcFormat() && item.ChkSum != outStreamSum->GetChecksum())
1081*f6dc9357SAndroid Build Coastguard Worker         res = NExtract::NOperationResult::kCRCError;
1082*f6dc9357SAndroid Build Coastguard Worker     }
1083*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(res))
1084*f6dc9357SAndroid Build Coastguard Worker   }
1085*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1086*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1087*f6dc9357SAndroid Build Coastguard Worker }
1088*f6dc9357SAndroid Build Coastguard Worker 
1089*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
1090*f6dc9357SAndroid Build Coastguard Worker {
1091*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1092*f6dc9357SAndroid Build Coastguard Worker   const CItem &item2 = _items[index];
1093*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[item2.MainIndex_ForInode];
1094*f6dc9357SAndroid Build Coastguard Worker   return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
1095*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1096*f6dc9357SAndroid Build Coastguard Worker }
1097*f6dc9357SAndroid Build Coastguard Worker 
1098*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = {
1099*f6dc9357SAndroid Build Coastguard Worker     5, '0', '7', '0', '7', '0',
1100*f6dc9357SAndroid Build Coastguard Worker     2, kMagicBin0, kMagicBin1,
1101*f6dc9357SAndroid Build Coastguard Worker     2, kMagicBin1, kMagicBin0 };
1102*f6dc9357SAndroid Build Coastguard Worker 
1103*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
1104*f6dc9357SAndroid Build Coastguard Worker   "Cpio", "cpio", NULL, 0xED,
1105*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
1106*f6dc9357SAndroid Build Coastguard Worker   0,
1107*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kMultiSignature,
1108*f6dc9357SAndroid Build Coastguard Worker   IsArc_Cpio)
1109*f6dc9357SAndroid Build Coastguard Worker 
1110*f6dc9357SAndroid Build Coastguard Worker }}
1111