xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/RpmHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // RpmHandler.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/CpuArch.h"
6 
7 #include "../../Common/MyBuffer.h"
8 #include "../../Common/ComTry.h"
9 #include "../../Common/IntToString.h"
10 #include "../../Common/StringConvert.h"
11 #include "../../Common/UTFConvert.h"
12 
13 #include "../../Windows/PropVariant.h"
14 #include "../../Windows/PropVariantUtils.h"
15 #include "../../Windows/TimeUtils.h"
16 
17 #include "../Common/RegisterArc.h"
18 #include "../Common/StreamUtils.h"
19 
20 #include "HandlerCont.h"
21 
22 // #define Z7_RPM_SHOW_METADATA
23 
24 using namespace NWindows;
25 
26 #define Get16(p) GetBe16(p)
27 #define Get32(p) GetBe32(p)
28 
29 namespace NArchive {
30 namespace NRpm {
31 
32 static const unsigned kNameSize = 66;
33 static const unsigned kLeadSize = kNameSize + 30;
34 static const unsigned k_HeaderSig_Size = 16;
35 static const unsigned k_Entry_Size = 16;
36 
37 #define RPMSIG_NONE         0  // Old signature
38 #define RPMSIG_PGP262_1024  1  // Old signature
39 #define RPMSIG_HEADERSIG    5  // New signature
40 
41 enum
42 {
43   kRpmType_Bin = 0,
44   kRpmType_Src = 1
45 };
46 
47 // There are two sets of TAGs: signature tags and header tags
48 
49 // ----- Signature TAGs -----
50 
51 #define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit)
52 
53 // ----- Header TAGs -----
54 
55 #define RPMTAG_NAME       1000
56 #define RPMTAG_VERSION    1001
57 #define RPMTAG_RELEASE    1002
58 #define RPMTAG_BUILDTIME  1006
59 #define RPMTAG_OS         1021  // string (old version used int?)
60 #define RPMTAG_ARCH       1022  // string (old version used int?)
61 #define RPMTAG_PAYLOADFORMAT      1124
62 #define RPMTAG_PAYLOADCOMPRESSOR  1125
63 // #define RPMTAG_PAYLOADFLAGS       1126
64 
65 enum
66 {
67   k_EntryType_NULL,
68   k_EntryType_CHAR,
69   k_EntryType_INT8,
70   k_EntryType_INT16,
71   k_EntryType_INT32,
72   k_EntryType_INT64,
73   k_EntryType_STRING,
74   k_EntryType_BIN,
75   k_EntryType_STRING_ARRAY,
76   k_EntryType_I18NSTRING
77 };
78 
79 static const char * const k_CPUs[] =
80 {
81     "noarch"
82   , "i386"
83   , "alpha"
84   , "sparc"
85   , "mips"
86   , "ppc"
87   , "m68k"
88   , "sgi"
89   , "rs6000"
90   , "ia64"
91   , "sparc64"  // 10 ???
92   , "mipsel"
93   , "arm"
94   , "m68kmint"
95   , "s390"
96   , "s390x"
97   , "ppc64"
98   , "sh"
99   , "xtensa"
100   , "aarch64"       // 19
101   , "mipsr6"        // 20
102   , "mips64r6"      // 21
103   , "riscv64"       // 22
104   , "loongarch64"   // 23
105   // , "24"
106   // , "25"
107   // , "loongarch64"   // 26  : why 23 and 26 for loongarch64?
108   // 255 for some non specified arch
109 };
110 
111 static const char * const k_OS[] =
112 {
113     "0"
114   , "Linux"
115   , "Irix"
116   , "solaris"
117   , "SunOS"
118   , "AmigaOS" // AIX
119   , "HP-UX"
120   , "osf"
121   , "FreeBSD"
122   , "SCO_SV"
123   , "Irix64"
124   , "NextStep"
125   , "bsdi"
126   , "machten"
127   , "cygwin32-NT"
128   , "cygwin32-95"
129   , "MP_RAS"
130   , "MiNT"
131   , "OS/390"
132   , "VM/ESA"
133   , "Linux/390"  // "Linux/ESA"
134   , "Darwin" // "MacOSX" 21
135 };
136 
137 struct CLead
138 {
139   Byte Major;
140   // Byte Minor;
141   UInt16 Type;
142   UInt16 Cpu;
143   UInt16 Os;
144   UInt16 SignatureType;
145   char Name[kNameSize];
146   // char Reserved[16];
147 
ParseNArchive::NRpm::CLead148   void Parse(const Byte *p)
149   {
150     Major = p[4];
151     // Minor = p[5];
152     Type = Get16(p + 6);
153     Cpu= Get16(p + 8);
154     memcpy(Name, p + 10, kNameSize);
155     p += 10 + kNameSize;
156     Os = Get16(p);
157     SignatureType = Get16(p + 2);
158   }
159 
IsSupportedNArchive::NRpm::CLead160   bool IsSupported() const { return Major >= 3 && Type <= 1; }
161 };
162 
163 struct CEntry
164 {
165   UInt32 Tag;
166   UInt32 Type;
167   UInt32 Offset;
168   UInt32 Count;
169 
ParseNArchive::NRpm::CEntry170   void Parse(const Byte *p)
171   {
172     Tag = Get32(p + 0);
173     Type = Get32(p + 4);
174     Offset = Get32(p + 8);
175     Count = Get32(p + 12);
176   }
177 };
178 
179 
180 #ifdef Z7_RPM_SHOW_METADATA
181 struct CMetaFile
182 {
183   UInt32 Tag;
184   UInt32 Offset;
185   UInt32 Size;
186 };
187 #endif
188 
189 Z7_class_CHandler_final: public CHandlerCont
190 {
191   Z7_IFACE_COM7_IMP(IInArchive_Cont)
192 
193   UInt64 _headersSize; // is equal to start offset of payload data
194   UInt64 _payloadSize;
195   UInt64 _size;
196     // _size = _payloadSize, if (_payloadSize_Defined)
197     // _size = (fileSize - _headersSize), if (!_payloadSize_Defined)
198   UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined)
199   UInt32 _headerPlusPayload_Size;
200   UInt32 _buildTime;
201 
202   bool _payloadSize_Defined;
203   bool _phySize_Defined;
204   bool _headerPlusPayload_Size_Defined;
205   bool _time_Defined;
206 
207   Byte _payloadSig[6]; // start data of payload
208 
209   AString _name;    // p7zip
210   AString _version; // 9.20.1
211   AString _release; // 8.1.1
212   AString _arch;    // x86_64
213   AString _os;      // linux
214 
215   AString _format;      // cpio
216   AString _compressor;  // xz, gzip, bzip2, lzma, zstd
217 
218   CLead _lead;
219 
220   #ifdef Z7_RPM_SHOW_METADATA
221   AString _metadata;
222   CRecordVector<CMetaFile> _metaFiles;
223   #endif
224 
225   void SetTime(NCOM::CPropVariant &prop) const
226   {
227     if (_time_Defined && _buildTime != 0)
228       PropVariant_SetFrom_UnixTime(prop, _buildTime);
229   }
230 
231   void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const
232   {
233     UString us;
234     if (!ConvertUTF8ToUnicode(s, us))
235       us = GetUnicodeString(s);
236     if (!us.IsEmpty())
237       prop = us;
238   }
239 
240   void AddCPU(AString &s) const;
241   AString GetBaseName() const;
242   void AddSubFileExtension(AString &res) const;
243 
244   HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader);
245   HRESULT Open2(ISequentialInStream *stream);
246 
247   virtual int GetItem_ExtractInfo(UInt32 /* index */, UInt64 &pos, UInt64 &size) const Z7_override
248   {
249     pos = _headersSize;
250     size = _size;
251     return NExtract::NOperationResult::kOK;
252   }
253 };
254 
255 static const Byte kArcProps[] =
256 {
257   kpidHeadersSize,
258   kpidCpu,
259   kpidHostOS,
260   kpidCTime
261   #ifdef Z7_RPM_SHOW_METADATA
262   , kpidComment
263   #endif
264 };
265 
266 static const Byte kProps[] =
267 {
268   kpidPath,
269   kpidSize,
270   kpidCTime
271 };
272 
273 IMP_IInArchive_Props
274 IMP_IInArchive_ArcProps
275 
276 void CHandler::AddCPU(AString &s) const
277 {
278   if (!_arch.IsEmpty())
279     s += _arch;
280   else
281   {
282     if (_lead.Type == kRpmType_Bin)
283     {
284       if (_lead.Cpu < Z7_ARRAY_SIZE(k_CPUs))
285         s += k_CPUs[_lead.Cpu];
286       else
287         s.Add_UInt32(_lead.Cpu);
288     }
289   }
290 }
291 
292 AString CHandler::GetBaseName() const
293 {
294   AString s;
295   if (!_name.IsEmpty())
296   {
297     s = _name;
298     if (!_version.IsEmpty())
299     {
300       s.Add_Minus();
301       s += _version;
302     }
303     if (!_release.IsEmpty())
304     {
305       s.Add_Minus();
306       s += _release;
307     }
308   }
309   else
310     s.SetFrom_CalcLen(_lead.Name, kNameSize);
311 
312   s.Add_Dot();
313   if (_lead.Type == kRpmType_Src)
314     s += "src";
315   else
316     AddCPU(s);
317   return s;
318 }
319 
320 void CHandler::AddSubFileExtension(AString &res) const
321 {
322   if (!_format.IsEmpty())
323     res += _format;
324   else
325     res += "cpio";
326   res.Add_Dot();
327 
328   const char *s;
329 
330   if (!_compressor.IsEmpty())
331   {
332     s = _compressor;
333     if (_compressor == "bzip2")
334       s = "bz2";
335     else if (_compressor == "gzip")
336       s = "gz";
337     else if (_compressor == "zstd")
338       s = "zst";
339   }
340   else
341   {
342     const Byte *p = _payloadSig;
343     if (p[0] == 0x1F && p[1] == 0x8B && p[2] == 8)
344       s = "gz";
345     else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0)
346       s = "xz";
347     else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9')
348       s = "bz2";
349     else if (p[0] == 0x28 && p[1] == 0xb5 && p[2] == 0x2f && p[3] == 0xfd)
350       s = "zst";
351     else
352       s = "lzma";
353   }
354 
355   res += s;
356 }
357 
358 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
359 {
360   COM_TRY_BEGIN
361   NCOM::CPropVariant prop;
362   switch (propID)
363   {
364     case kpidMainSubfile: prop = (UInt32)0; break;
365 
366     case kpidHeadersSize: prop = _headersSize; break;
367     case kpidPhySize: if (_phySize_Defined) prop = _phySize; break;
368 
369     case kpidMTime:
370     case kpidCTime:
371       SetTime(prop);
372       break;
373 
374     case kpidCpu:
375       {
376         AString s;
377         AddCPU(s);
378         /*
379         if (_lead.Type == kRpmType_Src)
380           s = "src";
381         */
382         SetStringProp(s, prop);
383         break;
384       }
385 
386     case kpidHostOS:
387       {
388         if (!_os.IsEmpty())
389           SetStringProp(_os, prop);
390         else
391         {
392           TYPE_TO_PROP(k_OS, _lead.Os, prop);
393         }
394         break;
395       }
396 
397     #ifdef Z7_RPM_SHOW_METADATA
398     // case kpidComment: SetStringProp(_metadata, prop); break;
399     #endif
400 
401     case kpidName:
402     {
403       SetStringProp(GetBaseName() + ".rpm", prop);
404       break;
405     }
406   }
407   prop.Detach(value);
408   return S_OK;
409   COM_TRY_END
410 }
411 
412 
413 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
414 {
415   NWindows::NCOM::CPropVariant prop;
416   if (index == 0)
417   switch (propID)
418   {
419     case kpidSize:
420     case kpidPackSize:
421       prop = _size;
422       break;
423 
424     case kpidMTime:
425     case kpidCTime:
426       SetTime(prop);
427       break;
428 
429     case kpidPath:
430     {
431       AString s (GetBaseName());
432       s.Add_Dot();
433       AddSubFileExtension(s);
434       SetStringProp(s, prop);
435       break;
436     }
437 
438     /*
439     case kpidExtension:
440     {
441       prop = GetSubFileExtension();
442       break;
443     }
444     */
445   }
446   #ifdef Z7_RPM_SHOW_METADATA
447   else
448   {
449     index--;
450     if (index > _metaFiles.Size())
451       return E_INVALIDARG;
452     const CMetaFile &meta = _metaFiles[index];
453     switch (propID)
454     {
455       case kpidSize:
456       case kpidPackSize:
457         prop = meta.Size;
458         break;
459 
460       case kpidMTime:
461       case kpidCTime:
462         SetTime(prop);
463         break;
464 
465       case kpidPath:
466       {
467         AString s ("[META]");
468         s.Add_PathSepar();
469         s.Add_UInt32(meta.Tag);
470         prop = s;
471         break;
472       }
473     }
474   }
475   #endif
476 
477   prop.Detach(value);
478   return S_OK;
479 }
480 
481 
482 HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader)
483 {
484   UInt32 numEntries;
485   UInt32 dataLen;
486   {
487     char buf[k_HeaderSig_Size];
488     RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size))
489     if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version
490       return S_FALSE;
491     // reserved = Get32(buf + 4);
492     numEntries = Get32(buf + 8);
493     dataLen = Get32(buf + 12);
494     if (numEntries >= 1 << 24)
495       return S_FALSE;
496   }
497   size_t indexSize = (size_t)numEntries * k_Entry_Size;
498   size_t headerSize = indexSize + dataLen;
499   if (headerSize < dataLen)
500     return S_FALSE;
501   CByteBuffer buffer(headerSize);
502   RINOK(ReadStream_FALSE(stream, buffer, headerSize))
503 
504   for (UInt32 i = 0; i < numEntries; i++)
505   {
506     CEntry entry;
507 
508     entry.Parse(buffer + (size_t)i * k_Entry_Size);
509     if (entry.Offset > dataLen)
510       return S_FALSE;
511 
512     const Byte *p = buffer + indexSize + entry.Offset;
513     size_t rem = dataLen - entry.Offset;
514 
515     if (!isMainHeader)
516     {
517       if (entry.Tag == RPMSIGTAG_SIZE &&
518           entry.Type == k_EntryType_INT32)
519       {
520         if (rem < 4 || entry.Count != 1)
521           return S_FALSE;
522         _headerPlusPayload_Size = Get32(p);
523         _headerPlusPayload_Size_Defined = true;
524       }
525     }
526     else
527     {
528       #ifdef Z7_RPM_SHOW_METADATA
529       {
530         _metadata.Add_UInt32(entry.Tag);
531         _metadata += ": ";
532       }
533       #endif
534 
535       if (entry.Type == k_EntryType_STRING)
536       {
537         if (entry.Count != 1)
538           return S_FALSE;
539         size_t j;
540         for (j = 0; j < rem && p[j] != 0; j++);
541         if (j == rem)
542           return S_FALSE;
543         AString s((const char *)p);
544         switch (entry.Tag)
545         {
546           case RPMTAG_NAME: _name = s; break;
547           case RPMTAG_VERSION: _version = s; break;
548           case RPMTAG_RELEASE: _release = s; break;
549           case RPMTAG_ARCH: _arch = s; break;
550           case RPMTAG_OS: _os = s; break;
551           case RPMTAG_PAYLOADFORMAT: _format = s; break;
552           case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break;
553         }
554 
555         #ifdef Z7_RPM_SHOW_METADATA
556         _metadata += s;
557         #endif
558       }
559       else if (entry.Type == k_EntryType_INT32)
560       {
561         if (rem / 4 < entry.Count)
562           return S_FALSE;
563         if (entry.Tag == RPMTAG_BUILDTIME)
564         {
565           if (entry.Count != 1)
566             return S_FALSE;
567           _buildTime = Get32(p);
568           _time_Defined = true;
569         }
570 
571         #ifdef Z7_RPM_SHOW_METADATA
572         for (UInt32 t = 0; t < entry.Count; t++)
573         {
574           if (t != 0)
575             _metadata.Add_Space();
576           _metadata.Add_UInt32(Get32(p + t * 4));
577         }
578         #endif
579       }
580 
581       #ifdef Z7_RPM_SHOW_METADATA
582 
583       else if (
584           entry.Type == k_EntryType_STRING_ARRAY ||
585           entry.Type == k_EntryType_I18NSTRING)
586       {
587         const Byte *p2 = p;
588         size_t rem2 = rem;
589         for (UInt32 t = 0; t < entry.Count; t++)
590         {
591           if (rem2 == 0)
592             return S_FALSE;
593           if (t != 0)
594             _metadata.Add_LF();
595           size_t j;
596           for (j = 0; j < rem2 && p2[j] != 0; j++);
597           if (j == rem2)
598             return S_FALSE;
599           _metadata += (const char *)p2;
600           j++;
601           p2 += j;
602           rem2 -= j;
603         }
604       }
605       else if (entry.Type == k_EntryType_INT16)
606       {
607         if (rem / 2 < entry.Count)
608           return S_FALSE;
609         for (UInt32 t = 0; t < entry.Count; t++)
610         {
611           if (t != 0)
612             _metadata.Add_Space();
613           _metadata.Add_UInt32(Get16(p + t * 2));
614         }
615       }
616       else if (entry.Type == k_EntryType_BIN)
617       {
618         if (rem < entry.Count)
619           return S_FALSE;
620         for (UInt32 t = 0; t < entry.Count; t++)
621         {
622           const unsigned b = p[t];
623           _metadata += GET_HEX_CHAR_UPPER(b >> 4);
624           _metadata += GET_HEX_CHAR_UPPER(b & 0xF);
625         }
626       }
627       else
628       {
629         // p = p;
630       }
631 
632       _metadata.Add_LF();
633       #endif
634     }
635 
636     #ifdef Z7_RPM_SHOW_METADATA
637     CMetaFile meta;
638     meta.Offset = entry.Offset;
639     meta.Tag = entry.Tag;
640     meta.Size = entry.Count;
641     _metaFiles.Add(meta);
642     #endif
643   }
644 
645   headerSize += k_HeaderSig_Size;
646   _headersSize += headerSize;
647   if (isMainHeader && _headerPlusPayload_Size_Defined)
648   {
649     if (_headerPlusPayload_Size < headerSize)
650       return S_FALSE;
651     _payloadSize = _headerPlusPayload_Size - headerSize;
652     _size = _payloadSize;
653     _phySize = _headersSize + _payloadSize;
654     _payloadSize_Defined = true;
655     _phySize_Defined = true;
656   }
657   return S_OK;
658 }
659 
660 HRESULT CHandler::Open2(ISequentialInStream *stream)
661 {
662   {
663     Byte buf[kLeadSize];
664     RINOK(ReadStream_FALSE(stream, buf, kLeadSize))
665     if (Get32(buf) != 0xEDABEEDB)
666       return S_FALSE;
667     _lead.Parse(buf);
668     if (!_lead.IsSupported())
669       return S_FALSE;
670   }
671 
672   _headersSize = kLeadSize;
673 
674   if (_lead.SignatureType == RPMSIG_NONE)
675   {
676 
677   }
678   else if (_lead.SignatureType == RPMSIG_PGP262_1024)
679   {
680     Byte temp[256];
681     RINOK(ReadStream_FALSE(stream, temp, sizeof(temp)))
682   }
683   else if (_lead.SignatureType == RPMSIG_HEADERSIG)
684   {
685     RINOK(ReadHeader(stream, false))
686     unsigned pos = (unsigned)_headersSize & 7;
687     if (pos != 0)
688     {
689       Byte temp[8];
690       unsigned num = 8 - pos;
691       RINOK(ReadStream_FALSE(stream, temp, num))
692       _headersSize += num;
693     }
694   }
695   else
696     return S_FALSE;
697 
698   return ReadHeader(stream, true);
699 }
700 
701 
702 Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *))
703 {
704   COM_TRY_BEGIN
705   {
706     Close();
707     RINOK(Open2(inStream))
708 
709     // start of payload is allowed to be unaligned
710     RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig)))
711 
712     if (!_payloadSize_Defined)
713     {
714       UInt64 endPos;
715       RINOK(InStream_GetSize_SeekToEnd(inStream, endPos))
716       _size = endPos - _headersSize;
717     }
718     _stream = inStream;
719     return S_OK;
720   }
721   COM_TRY_END
722 }
723 
724 Z7_COM7F_IMF(CHandler::Close())
725 {
726   _headersSize = 0;
727   _payloadSize = 0;
728   _size = 0;
729   _phySize = 0;
730   _headerPlusPayload_Size = 0;
731 
732   _payloadSize_Defined = false;
733   _phySize_Defined = false;
734   _headerPlusPayload_Size_Defined = false;
735   _time_Defined = false;
736 
737   _name.Empty();
738   _version.Empty();
739   _release.Empty();
740   _arch.Empty();
741   _os.Empty();
742 
743   _format.Empty();
744   _compressor.Empty();
745 
746   #ifdef Z7_RPM_SHOW_METADATA
747   _metadata.Empty();
748   _metaFiles.Size();
749   #endif
750 
751   _stream.Release();
752   return S_OK;
753 }
754 
755 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
756 {
757   *numItems = 1
758   #ifdef Z7_RPM_SHOW_METADATA
759     + _metaFiles.Size()
760   #endif
761   ;
762 
763   return S_OK;
764 }
765 
766 static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB};
767 
768 REGISTER_ARC_I(
769   "Rpm", "rpm", NULL, 0xEB,
770   k_Signature,
771   0,
772   0,
773   NULL)
774 
775 }}
776