xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Iso/IsoHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // IsoHandler.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/ComTry.h"
6 #include "../../../Common/MyLinux.h"
7 #include "../../../Common/StringConvert.h"
8 
9 #include "../../Common/LimitedStreams.h"
10 #include "../../Common/ProgressUtils.h"
11 #include "../../Common/StreamUtils.h"
12 
13 #include "../../Compress/CopyCoder.h"
14 
15 #include "../Common/ItemNameUtils.h"
16 
17 #include "IsoHandler.h"
18 
19 using namespace NWindows;
20 using namespace NTime;
21 
22 namespace NArchive {
23 namespace NIso {
24 
25 static const Byte kProps[] =
26 {
27   kpidPath,
28   kpidIsDir,
29   kpidSize,
30   kpidPackSize,
31   kpidMTime,
32   // kpidCTime,
33   // kpidATime,
34   kpidPosixAttrib,
35   // kpidUserId,
36   // kpidGroupId,
37   // kpidLinks,
38   kpidSymLink
39 };
40 
41 static const Byte kArcProps[] =
42 {
43   kpidComment,
44   kpidCTime,
45   kpidMTime,
46   // kpidHeadersSize
47 };
48 
49 IMP_IInArchive_Props
50 IMP_IInArchive_ArcProps
51 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback *))52 Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
53     const UInt64 * /* maxCheckStartPosition */,
54     IArchiveOpenCallback * /* openArchiveCallback */))
55 {
56   COM_TRY_BEGIN
57   Close();
58   {
59     RINOK(_archive.Open(stream))
60     _stream = stream;
61   }
62   return S_OK;
63   COM_TRY_END
64 }
65 
Z7_COM7F_IMF(CHandler::Close ())66 Z7_COM7F_IMF(CHandler::Close())
67 {
68   _archive.Clear();
69   _stream.Release();
70   return S_OK;
71 }
72 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))73 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
74 {
75   *numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
76   return S_OK;
77 }
78 
AddString(AString & s,const char * name,const Byte * p,unsigned size)79 static void AddString(AString &s, const char *name, const Byte *p, unsigned size)
80 {
81   unsigned i;
82   for (i = 0; i < size && p[i]; i++);
83   for (; i > 0 && p[i - 1] == ' '; i--);
84   if (i != 0)
85   {
86     AString d;
87     d.SetFrom((const char *)p, i);
88     s += name;
89     s += ": ";
90     s += d;
91     s.Add_LF();
92   }
93 }
94 
AddProp_Size64(AString & s,const char * name,UInt64 size)95 static void AddProp_Size64(AString &s, const char *name, UInt64 size)
96 {
97   s += name;
98   s += ": ";
99   s.Add_UInt64(size);
100   s.Add_LF();
101 }
102 
103 #define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v))
104 
AddErrorMessage(AString & s,const char * message)105 static void AddErrorMessage(AString &s, const char *message)
106 {
107   if (!s.IsEmpty())
108     s += ". ";
109   s += message;
110 }
111 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))112 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
113 {
114   COM_TRY_BEGIN
115   NCOM::CPropVariant prop;
116   if (_stream)
117   {
118   const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
119   switch (propID)
120   {
121     case kpidComment:
122     {
123       AString s;
124       ADD_STRING("System", SystemId);
125       ADD_STRING("Volume", VolumeId);
126       ADD_STRING("VolumeSet", VolumeSetId);
127       ADD_STRING("Publisher", PublisherId);
128       ADD_STRING("Preparer", DataPreparerId);
129       ADD_STRING("Application", ApplicationId);
130       ADD_STRING("Copyright", CopyrightFileId);
131       ADD_STRING("Abstract", AbstractFileId);
132       ADD_STRING("Bib", BibFileId);
133       // ADD_STRING("EscapeSequence", EscapeSequence);
134       AddProp_Size64(s, "VolumeSpaceSize", vol.Get_VolumeSpaceSize_inBytes());
135       AddProp_Size64(s, "VolumeSetSize", vol.VolumeSetSize);
136       AddProp_Size64(s, "VolumeSequenceNumber", vol.VolumeSequenceNumber);
137 
138       prop = s;
139       break;
140     }
141     case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
142     case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
143   }
144   }
145 
146   switch (propID)
147   {
148     case kpidPhySize: prop = _archive.PhySize; break;
149     case kpidErrorFlags:
150     {
151       UInt32 v = 0;
152       if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
153       if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
154       if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError;
155       prop = v;
156       break;
157     }
158 
159     case kpidError:
160     {
161       AString s;
162       if (_archive.IncorrectBigEndian)
163         AddErrorMessage(s, "Incorrect big-endian headers");
164       if (_archive.SelfLinkedDirs)
165         AddErrorMessage(s, "Self-linked directory");
166       if (_archive.TooDeepDirs)
167         AddErrorMessage(s, "Too deep directory levels");
168       if (!s.IsEmpty())
169         prop = s;
170       break;
171     }
172   }
173   prop.Detach(value);
174   return S_OK;
175   COM_TRY_END
176 }
177 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))178 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
179 {
180   COM_TRY_BEGIN
181   NCOM::CPropVariant prop;
182   if (index >= (UInt32)_archive.Refs.Size())
183   {
184     index -= _archive.Refs.Size();
185     const CBootInitialEntry &be = _archive.BootEntries[index];
186     switch (propID)
187     {
188       case kpidPath:
189       {
190         AString s ("[BOOT]" STRING_PATH_SEPARATOR);
191         if (_archive.BootEntries.Size() != 1)
192         {
193           s.Add_UInt32(index + 1);
194           s.Add_Minus();
195         }
196         s += be.GetName();
197         prop = s;
198         break;
199       }
200       case kpidIsDir: prop = false; break;
201       case kpidSize:
202       case kpidPackSize:
203         prop = (UInt64)_archive.GetBootItemSize(index);
204         break;
205     }
206   }
207   else
208   {
209     const CRef &ref = _archive.Refs[index];
210     const CDir &item = ref.Dir->_subItems[ref.Index];
211     switch (propID)
212     {
213       case kpidPath:
214         // if (item.FileId.GetCapacity() >= 0)
215         {
216           UString s;
217           if (_archive.IsJoliet())
218             item.GetPathU(s);
219           else
220             s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
221 
222           if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1')
223             s.DeleteFrom(s.Len() - 2);
224 
225           if (!s.IsEmpty() && s.Back() == L'.')
226             s.DeleteBack();
227 
228           NItemName::ReplaceToOsSlashes_Remove_TailSlash(s);
229           prop = s;
230         }
231         break;
232 
233       case kpidSymLink:
234         if (_archive.IsSusp)
235         {
236           UInt32 mode;
237           if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode))
238           {
239             if (MY_LIN_S_ISLNK(mode))
240             {
241               AString s8;
242               if (item.GetSymLink(_archive.SuspSkipSize, s8))
243               {
244                 UString s = MultiByteToUnicodeString(s8, CP_OEMCP);
245                 prop = s;
246               }
247             }
248           }
249         }
250         break;
251 
252 
253       case kpidPosixAttrib:
254       /*
255       case kpidLinks:
256       case kpidUserId:
257       case kpidGroupId:
258       */
259       {
260         if (_archive.IsSusp)
261         {
262           UInt32 t = 0;
263           switch (propID)
264           {
265             case kpidPosixAttrib: t = k_Px_Mode; break;
266             /*
267             case kpidLinks: t = k_Px_Links; break;
268             case kpidUserId: t = k_Px_User; break;
269             case kpidGroupId: t = k_Px_Group; break;
270             */
271           }
272           UInt32 v;
273           if (item.GetPx(_archive.SuspSkipSize, t, v))
274             prop = v;
275         }
276         break;
277       }
278 
279       case kpidIsDir: prop = item.IsDir(); break;
280       case kpidSize:
281       case kpidPackSize:
282         if (!item.IsDir())
283           prop = (UInt64)ref.TotalSize;
284         break;
285 
286       case kpidMTime:
287       // case kpidCTime:
288       // case kpidATime:
289       {
290         // if
291         item.DateTime.GetFileTime(prop);
292         /*
293         else
294         {
295           UInt32 t = 0;
296           switch (propID)
297           {
298             case kpidMTime: t = k_Tf_MTime; break;
299             case kpidCTime: t = k_Tf_CTime; break;
300             case kpidATime: t = k_Tf_ATime; break;
301           }
302           CRecordingDateTime dt;
303           if (item.GetTf(_archive.SuspSkipSize, t, dt))
304           {
305             FILETIME utc;
306             if (dt.GetFileTime(utc))
307               prop = utc;
308           }
309         }
310         */
311         break;
312       }
313     }
314   }
315   prop.Detach(value);
316   return S_OK;
317   COM_TRY_END
318 }
319 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))320 Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
321     Int32 testMode, IArchiveExtractCallback *extractCallback))
322 {
323   COM_TRY_BEGIN
324   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
325   if (allFilesMode)
326     numItems = _archive.Refs.Size();
327   if (numItems == 0)
328     return S_OK;
329   UInt64 totalSize = 0;
330   UInt32 i;
331   for (i = 0; i < numItems; i++)
332   {
333     UInt32 index = (allFilesMode ? i : indices[i]);
334     if (index < (UInt32)_archive.Refs.Size())
335     {
336       const CRef &ref = _archive.Refs[index];
337       const CDir &item = ref.Dir->_subItems[ref.Index];
338       if (!item.IsDir())
339         totalSize += ref.TotalSize;
340     }
341     else
342       totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
343   }
344   RINOK(extractCallback->SetTotal(totalSize))
345 
346   UInt64 currentTotalSize = 0;
347   UInt64 currentItemSize;
348 
349   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
350   lps->Init(extractCallback, false);
351   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
352   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
353   inStream->SetStream(_stream);
354 
355   for (i = 0;; i++, currentTotalSize += currentItemSize)
356   {
357     lps->InSize = lps->OutSize = currentTotalSize;
358     RINOK(lps->SetCur())
359     if (i >= numItems)
360       break;
361     currentItemSize = 0;
362     Int32 opRes = NExtract::NOperationResult::kOK;
363   {
364     CMyComPtr<ISequentialOutStream> realOutStream;
365     const Int32 askMode = testMode ?
366         NExtract::NAskMode::kTest :
367         NExtract::NAskMode::kExtract;
368     const UInt32 index = allFilesMode ? i : indices[i];
369 
370     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
371 
372     UInt64 blockIndex;
373     if (index < (UInt32)_archive.Refs.Size())
374     {
375       const CRef &ref = _archive.Refs[index];
376       const CDir &item = ref.Dir->_subItems[ref.Index];
377       if (item.IsDir())
378       {
379         RINOK(extractCallback->PrepareOperation(askMode))
380         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
381         continue;
382       }
383       currentItemSize = ref.TotalSize;
384       blockIndex = item.ExtentLocation;
385     }
386     else
387     {
388       unsigned bootIndex = index - _archive.Refs.Size();
389       const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
390       currentItemSize = _archive.GetBootItemSize(bootIndex);
391       blockIndex = be.LoadRBA;
392     }
393 
394 
395     if (!testMode && !realOutStream)
396       continue;
397 
398     RINOK(extractCallback->PrepareOperation(askMode))
399 
400     if (index < (UInt32)_archive.Refs.Size())
401     {
402       const CRef &ref = _archive.Refs[index];
403       UInt64 offset = 0;
404       for (UInt32 e = 0; e < ref.NumExtents; e++)
405       {
406         const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
407         if (item2.Size == 0)
408           continue;
409         lps->InSize = lps->OutSize = currentTotalSize + offset;
410         RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize))
411         inStream->Init(item2.Size);
412         RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
413         if (copyCoder->TotalSize != item2.Size)
414         {
415           opRes = NExtract::NOperationResult::kDataError;
416           break;
417         }
418         offset += item2.Size;
419       }
420     }
421     else
422     {
423       RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize))
424       inStream->Init(currentItemSize);
425       RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
426       if (copyCoder->TotalSize != currentItemSize)
427         opRes = NExtract::NOperationResult::kDataError;
428     }
429     // realOutStream.Release();
430   }
431     RINOK(extractCallback->SetOperationResult(opRes))
432   }
433   return S_OK;
434   COM_TRY_END
435 }
436 
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))437 Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
438 {
439   COM_TRY_BEGIN
440   *stream = NULL;
441   UInt64 blockIndex;
442   UInt64 currentItemSize;
443 
444   if (index < _archive.Refs.Size())
445   {
446     const CRef &ref = _archive.Refs[index];
447     const CDir &item = ref.Dir->_subItems[ref.Index];
448     if (item.IsDir())
449       return S_FALSE;
450 
451     if (ref.NumExtents > 1)
452     {
453       CExtentsStream *extentStreamSpec = new CExtentsStream();
454       CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
455 
456       extentStreamSpec->Stream = _stream;
457 
458       UInt64 virtOffset = 0;
459       for (UInt32 i = 0; i < ref.NumExtents; i++)
460       {
461         const CDir &item2 = ref.Dir->_subItems[ref.Index + i];
462         if (item2.Size == 0)
463           continue;
464         CSeekExtent se;
465         se.Phy = (UInt64)item2.ExtentLocation * kBlockSize;
466         se.Virt = virtOffset;
467         extentStreamSpec->Extents.Add(se);
468         virtOffset += item2.Size;
469       }
470       if (virtOffset != ref.TotalSize)
471         return S_FALSE;
472       CSeekExtent se;
473       se.Phy = 0;
474       se.Virt = virtOffset;
475       extentStreamSpec->Extents.Add(se);
476       extentStreamSpec->Init();
477       *stream = extentStream.Detach();
478       return S_OK;
479     }
480 
481     currentItemSize = item.Size;
482     blockIndex = item.ExtentLocation;
483   }
484   else
485   {
486     unsigned bootIndex = index - _archive.Refs.Size();
487     const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
488     currentItemSize = _archive.GetBootItemSize(bootIndex);
489     blockIndex = be.LoadRBA;
490   }
491 
492   return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream);
493   COM_TRY_END
494 }
495 
496 }}
497