xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/LvmHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // LvmHandler.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/7zCrc.h"
6 #include "../../../C/CpuArch.h"
7 
8 #include "../../Common/ComTry.h"
9 #include "../../Common/MyBuffer.h"
10 #include "../../Common/StringToInt.h"
11 
12 #include "../../Windows/PropVariantUtils.h"
13 #include "../../Windows/TimeUtils.h"
14 
15 #include "../Common/RegisterArc.h"
16 #include "../Common/StreamUtils.h"
17 
18 #include "HandlerCont.h"
19 
20 #define Get32(p) GetUi32(p)
21 #define Get64(p) GetUi64(p)
22 
23 #define LE_32(offs, dest) dest = Get32(p + (offs))
24 #define LE_64(offs, dest) dest = Get64(p + (offs))
25 
26 using namespace NWindows;
27 
28 namespace NArchive {
29 namespace NLvm {
30 
31 #define SIGNATURE { 'L', 'A', 'B', 'E', 'L', 'O', 'N', 'E'  }
32 
33 static const unsigned k_SignatureSize = 8;
34 static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
35 
36 static const unsigned k_Signature2Size = 8;
37 static const Byte k_Signature2[k_Signature2Size] =
38     { 'L', 'V', 'M', '2', ' ', '0', '0', '1'  };
39 
40 static const Byte FMTT_MAGIC[16] =
41     { ' ', 'L', 'V', 'M', '2', ' ', 'x', '[', '5', 'A', '%', 'r', '0', 'N', '*', '>'  };
42 
43 static const UInt32 kSectorSize = 512;
44 
45 
46 struct CPropVal
47 {
48   bool IsNumber;
49   AString String;
50   UInt64 Number;
51 
CPropValNArchive::NLvm::CPropVal52   CPropVal(): IsNumber(false), Number(0) {}
53 };
54 
55 
56 struct CConfigProp
57 {
58   AString Name;
59 
60   bool IsVector;
61   CPropVal Val;
62   CObjectVector<CPropVal> Vector;
63 
CConfigPropNArchive::NLvm::CConfigProp64   CConfigProp(): IsVector(false) {}
65 };
66 
67 
68 class CConfigItem
69 {
70 public:
71   AString Name;
72   CObjectVector<CConfigProp> Props;
73   CObjectVector<CConfigItem> Items;
74 
75   const char *ParseItem(const char *s, int numAllowedLevels);
76 
77   int FindProp(const char *name) const throw();
78   bool GetPropVal_Number(const char *name, UInt64 &val) const throw();
79   bool GetPropVal_String(const char *name, AString &val) const;
80 
81   int FindSubItem(const char *tag) const throw();
82 };
83 
84 struct CConfig
85 {
86   CConfigItem Root;
87 
88   bool Parse(const char *s);
89 };
90 
91 
IsSpaceChar(char c)92 static bool IsSpaceChar(char c)
93 {
94   return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
95 }
96 
SkipSpaces(const char * s)97 static const char *SkipSpaces(const char * s)
98 {
99   for (;; s++)
100   {
101     const char c = *s;
102     if (c == 0)
103       return s;
104     if (!IsSpaceChar(c))
105     {
106       if (c != '#')
107         return s;
108       s++;
109       for (;;)
110       {
111         const char c2 = *s;
112         if (c2 == 0)
113           return s;
114         if (c2 == '\n')
115           break;
116         s++;
117       }
118     }
119   }
120 }
121 
122 #define SKIP_SPACES(s) s = SkipSpaces(s);
123 
FindProp(const char * name) const124 int CConfigItem::FindProp(const char *name) const throw()
125 {
126   FOR_VECTOR (i, Props)
127     if (Props[i].Name == name)
128       return (int)i;
129   return -1;
130 }
131 
GetPropVal_Number(const char * name,UInt64 & val) const132 bool CConfigItem::GetPropVal_Number(const char *name, UInt64 &val) const throw()
133 {
134   val = 0;
135   int index = FindProp(name);
136   if (index < 0)
137     return false;
138   const CConfigProp &prop = Props[index];
139   if (prop.IsVector)
140     return false;
141   if (!prop.Val.IsNumber)
142     return false;
143   val = prop.Val.Number;
144   return true;
145 }
146 
GetPropVal_String(const char * name,AString & val) const147 bool CConfigItem::GetPropVal_String(const char *name, AString &val) const
148 {
149   val.Empty();
150   int index = FindProp(name);
151   if (index < 0)
152     return false;
153   const CConfigProp &prop = Props[index];
154   if (prop.IsVector)
155     return false;
156   if (prop.Val.IsNumber)
157     return false;
158   val = prop.Val.String;
159   return true;
160 }
161 
FindSubItem(const char * tag) const162 int CConfigItem::FindSubItem(const char *tag) const throw()
163 {
164   FOR_VECTOR (i, Items)
165     if (Items[i].Name == tag)
166       return (int)i;
167   return -1;
168 }
169 
FillProp(const char * s,CPropVal & val)170 static const char *FillProp(const char *s, CPropVal &val)
171 {
172   SKIP_SPACES(s)
173   const char c = *s;
174   if (c == 0)
175     return NULL;
176 
177   if (c == '\"')
178   {
179     s++;
180     val.IsNumber = false;
181     val.String.Empty();
182 
183     for (;;)
184     {
185       const char c2 = *s;
186       if (c2 == 0)
187         return NULL;
188       s++;
189       if (c2 == '\"')
190         break;
191       val.String += c2;
192     }
193   }
194   else
195   {
196     const char *end;
197     val.IsNumber = true;
198     val.Number = ConvertStringToUInt64(s, &end);
199     if (s == end)
200       return NULL;
201     s = end;
202   }
203 
204   SKIP_SPACES(s)
205   return s;
206 }
207 
208 
ParseItem(const char * s,int numAllowedLevels)209 const char *CConfigItem::ParseItem(const char *s, int numAllowedLevels)
210 {
211   if (numAllowedLevels < 0)
212     return NULL;
213 
214   for (;;)
215   {
216     SKIP_SPACES(s)
217     const char *beg = s;
218 
219     for (;; s++)
220     {
221       char c = *s;
222       if (c == 0 || c == '}')
223       {
224         if (s != beg)
225           return NULL;
226         return s;
227       }
228       if (IsSpaceChar(c) || c == '=' || c == '{')
229         break;
230     }
231 
232     if (s == beg)
233       return NULL;
234 
235     AString name;
236     name.SetFrom(beg, (unsigned)(s - beg));
237 
238     SKIP_SPACES(s)
239 
240     if (*s == 0 || *s == '}')
241       return NULL;
242 
243     if (*s == '{')
244     {
245       s++;
246       CConfigItem &item = Items.AddNew();
247       item.Name = name;
248       s = item.ParseItem(s, numAllowedLevels - 1);
249       if (!s)
250         return NULL;
251       if (*s != '}')
252         return NULL;
253       s++;
254       continue;
255     }
256 
257     if (*s != '=')
258       continue;
259 
260     s++;
261     SKIP_SPACES(s)
262     if (*s == 0)
263       return NULL;
264     CConfigProp &prop = Props.AddNew();
265 
266     prop.Name = name;
267 
268     if (*s == '[')
269     {
270       s++;
271       prop.IsVector = true;
272 
273       for (;;)
274       {
275         SKIP_SPACES(s)
276         char c = *s;
277         if (c == 0)
278           return NULL;
279         if (c == ']')
280         {
281           s++;
282           break;
283         }
284 
285         CPropVal val;
286 
287         s = FillProp(s, val);
288         if (!s)
289           return NULL;
290         prop.Vector.Add(val);
291         SKIP_SPACES(s)
292 
293         if (*s == ',')
294         {
295           s++;
296           continue;
297         }
298         if (*s != ']')
299           return NULL;
300         s++;
301         break;
302       }
303     }
304     else
305     {
306       prop.IsVector = false;
307       s = FillProp(s, prop.Val);
308       if (!s)
309         return NULL;
310     }
311   }
312 }
313 
314 
Parse(const char * s)315 bool CConfig::Parse(const char *s)
316 {
317   s = Root.ParseItem(s, 10);
318   if (!s)
319     return false;
320   SKIP_SPACES(s)
321   return *s == 0;
322 }
323 
324 
325 /*
326 static const CUInt32PCharPair g_PartitionFlags[] =
327 {
328   { 0, "Sys" },
329   { 1, "Ignore" },
330   { 2, "Legacy" },
331   { 60, "Win-Read-only" },
332   { 62, "Win-Hidden" },
333   { 63, "Win-Not-Automount" }
334 };
335 */
336 
337 /*
338 static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
339 
340 static void PrintHex(unsigned v, char *s)
341 {
342   s[0] = GetHex((v >> 4) & 0xF);
343   s[1] = GetHex(v & 0xF);
344 }
345 
346 static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
347 {
348   PrintHex(val >> 8, s);
349   PrintHex(val & 0xFF, s + 2);
350 }
351 
352 static void GuidToString(const Byte *g, char *s)
353 {
354   ConvertUInt32ToHex8Digits(Get32(g   ),  s);  s += 8;  *s++ = '-';
355   ConvertUInt16ToHex4Digits(Get16(g + 4), s);  s += 4;  *s++ = '-';
356   ConvertUInt16ToHex4Digits(Get16(g + 6), s);  s += 4;  *s++ = '-';
357   for (unsigned i = 0; i < 8; i++)
358   {
359     if (i == 2)
360       *s++ = '-';
361     PrintHex(g[8 + i], s);
362     s += 2;
363   }
364   *s = 0;
365 }
366 
367 */
368 
369 struct CPhyVol
370 {
371   AString Name;
372 
373   // AString id;
374   // AString device; // "/dev/sda2"
375   // AString status; // ["ALLOCATABLE"]
376   // AString flags; // []
377   // UInt64 dev_size; // in sectors
378   UInt64 pe_start; // in sectors
379   UInt64 pe_count; // in extents
380 
ParseNArchive::NLvm::CPhyVol381   bool Parse(const CConfigItem &ci)
382   {
383     Name = ci.Name;
384     // ci.GetPropVal_String("id", id);
385     // ci.GetPropVal_String("device", device);
386     bool res = true;
387     // if (!ci.GetPropVal_Number("dev_size", dev_size)) res = false;
388     if (!ci.GetPropVal_Number("pe_start", pe_start)) res = false;
389     if (!ci.GetPropVal_Number("pe_count", pe_count)) res = false;
390     return res;
391   }
392 };
393 
394 struct CStripe
395 {
396   AString Name; // "pv0";
397   UInt64 ExtentOffset; // ????
398 };
399 
400 struct CSegment
401 {
402   UInt64 start_extent;
403   UInt64 extent_count;
404   AString type;
405   CObjectVector<CStripe> stripes;
406 
IsPosSizeOkNArchive::NLvm::CSegment407   bool IsPosSizeOk() const
408   {
409     return
410         (start_extent < ((UInt64)1 << 63)) &&
411         (extent_count < ((UInt64)1 << 63));
412   }
413 
GetEndExtentNArchive::NLvm::CSegment414   UInt64 GetEndExtent() const { return start_extent + extent_count; }
415 
ParseNArchive::NLvm::CSegment416   bool Parse(const CConfigItem &si)
417   {
418     UInt64 stripe_count;
419 
420     if (!si.GetPropVal_Number("start_extent", start_extent)) return false;
421     if (!si.GetPropVal_Number("extent_count", extent_count)) return false;
422     if (!si.GetPropVal_Number("stripe_count", stripe_count)) return false;
423     if (!si.GetPropVal_String("type", type)) return false;
424 
425     //if (stripe_count != 1) return false;
426 
427     const int spi = si.FindProp("stripes");
428     if (spi < 0)
429       return false;
430 
431     const CConfigProp &prop = si.Props[spi];
432     if (!prop.IsVector)
433       return false;
434 
435     if (stripe_count > (1 << 20))
436       return false;
437 
438     const unsigned numStripes = (unsigned)stripe_count;
439     if (prop.Vector.Size() != numStripes * 2)
440       return false;
441 
442     for (unsigned i = 0; i < numStripes; i++)
443     {
444       const CPropVal &v0 = prop.Vector[i * 2];
445       const CPropVal &v1 = prop.Vector[i * 2 + 1];
446       if (v0.IsNumber || !v1.IsNumber)
447         return false;
448       CStripe stripe;
449       stripe.Name = v0.String;
450       stripe.ExtentOffset = v1.Number;
451       stripes.Add(stripe);
452     }
453 
454     return true;
455   }
456 };
457 
458 
459 struct CLogVol
460 {
461   bool IsSupported;
462 
463   AString Name;
464 
465   AString id;
466   AString status; // ["READ", "WRITE", "VISIBLE"]
467   AString flags; // []
468 
469   // UInt64 Pos;
470   // UInt64 Size;
471 
472   // UInt64 GetSize() const { return Size; }
473   // UInt64 GetPos() const { return Pos; }
474 
475   CObjectVector<CSegment> Segments;
476 
CLogVolNArchive::NLvm::CLogVol477   CLogVol(): /* Pos(0), Size(0), */ IsSupported(false) {}
478 
ParseNArchive::NLvm::CLogVol479   bool Parse(const CConfigItem &ci)
480   {
481     Name = ci.Name;
482 
483     UInt64 segment_count;
484     if (!ci.GetPropVal_Number("segment_count", segment_count))
485       return false;
486 
487     if (ci.Items.Size() != segment_count)
488       return false;
489 
490     FOR_VECTOR (segIndex, ci.Items)
491     {
492       const CConfigItem &si = ci.Items[segIndex];
493       {
494         AString t ("segment");
495         t.Add_UInt32(segIndex + 1);
496         if (si.Name != t)
497           return false;
498       }
499 
500       CSegment segment;
501 
502       if (!segment.Parse(si))
503         return false;
504 
505       // item.Size += (segment.extent_count * _extentSize) << 9;
506 
507       Segments.Add(segment);
508     }
509 
510     IsSupported = true;
511     return true;
512   }
513 
GetNumExtentsNArchive::NLvm::CLogVol514   bool GetNumExtents(UInt64 &numExtents) const
515   {
516     numExtents = 0;
517     if (Segments.IsEmpty())
518       return true;
519     unsigned i;
520     for (i = 1; i < Segments.Size(); i++)
521       if (!Segments[i].IsPosSizeOk())
522         return false;
523     for (i = 1; i < Segments.Size(); i++)
524       if (Segments[i - 1].GetEndExtent() != Segments[i].start_extent)
525         return false;
526     numExtents = Segments.Back().GetEndExtent();
527     return true;
528   }
529 };
530 
531 
532 struct CItem
533 {
534   int LogVol;
535   int PhyVol;
536   UInt64 Pos;
537   UInt64 Size;
538   AString Name;
539   bool IsSupported;
540 
CItemNArchive::NLvm::CItem541   CItem(): LogVol(-1), PhyVol(-1), Pos(0), Size(0), IsSupported(false) {}
542 };
543 
544 
545 struct CVolGroup
546 {
547   CObjectVector<CLogVol> _logVols;
548   CObjectVector<CPhyVol> _phyVols;
549   AString _id;
550   int _extentSizeBits;
551 
552   /*
553   UInt64 secno; // 3
554   AString status; // ["RESIZEABLE", "READ", "WRITE"]
555   AString flags; // []
556   UInt64 max_lv; // 0
557   UInt64 max_pv; // 0
558   UInt64 metadata_copies; // 0
559   */
560 
ClearNArchive::NLvm::CVolGroup561   void Clear()
562   {
563     _logVols.Clear();
564     _phyVols.Clear();
565     _id.Empty();
566     _extentSizeBits = -1;
567   }
568 };
569 
570 
571 Z7_class_CHandler_final: public CHandlerCont, public CVolGroup
572 {
573   Z7_IFACE_COM7_IMP(IInArchive_Cont)
574 
575   CObjectVector<CItem> _items;
576 
577   UInt64 _cTime;
578 
579   bool _isArc;
580 
581   UInt64 _phySize;
582   CByteBuffer _buffer;
583 
584   UInt64 _cfgPos;
585   UInt64 _cfgSize;
586 
587   HRESULT Open2(IInStream *stream);
588 
589   virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override
590   {
591     if (index >= _items.Size())
592     {
593       pos = _cfgPos;
594       size = _cfgSize;
595       return NExtract::NOperationResult::kOK;
596     }
597     const CItem &item = _items[index];
598     if (!item.IsSupported)
599       return NExtract::NOperationResult::kUnsupportedMethod;
600     pos = item.Pos;
601     size = item.Size;
602     return NExtract::NOperationResult::kOK;
603   }
604 };
605 
606 static const UInt32 LVM_CRC_INIT_VAL = 0xf597a6cf;
607 
608 static UInt32 Z7_FASTCALL LvmCrcCalc(const void *data, size_t size)
609 {
610   return CrcUpdate(LVM_CRC_INIT_VAL, data, size);
611 }
612 
613 struct CRawLocn
614 {
615   UInt64 Offset;  /* Offset in bytes to start sector */
616   UInt64 Size;    /* Bytes */
617   UInt32 Checksum;
618   UInt32 Flags;
619 
620   bool IsEmpty() const { return Offset == 0 && Size == 0; }
621 
622   void Parse(const Byte *p)
623   {
624     LE_64(0x00, Offset);
625     LE_64(0x08, Size);
626     LE_32(0x10, Checksum);
627     LE_32(0x14, Flags);
628   }
629 };
630 
631 // #define MDA_HEADER_SIZE 512
632 
633 struct mda_header
634 {
635   UInt64 Start;   /* Absolute start byte of mda_header */
636   UInt64 Size;    /* Size of metadata area */
637 
638   CRecordVector<CRawLocn> raw_locns;
639 
640   bool Parse(const Byte *p, size_t size)
641   {
642     if (memcmp(p + 4, FMTT_MAGIC, 16) != 0)
643       return false;
644     UInt32 version;
645     LE_32(0x14, version);
646     if (version != 1)
647       return false;
648     LE_64(0x18, Start);
649     LE_64(0x20, Size);
650 
651     unsigned pos = 0x28;
652 
653     for (;;)
654     {
655       if (pos + 0x18 > size)
656         return false;
657       CRawLocn locn;
658       locn.Parse(p + pos);
659       if (locn.IsEmpty())
660         break;
661       pos += 0x18;
662       raw_locns.Add(locn);
663     }
664 
665     return true;
666   }
667 };
668 
669 
670 static int inline GetLog(UInt64 num)
671 {
672   for (unsigned i = 0; i < 64; i++)
673     if (((UInt64)1 << i) == num)
674       return (int)i;
675   return -1;
676 }
677 
678 #define ID_LEN 32
679 
680 HRESULT CHandler::Open2(IInStream *stream)
681 {
682   _buffer.Alloc(kSectorSize * 2);
683   RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2))
684 
685   const Byte *buf = _buffer;
686 
687   buf += kSectorSize;
688 
689   // label_header
690 
691   if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
692     return S_FALSE;
693   const UInt64 sectorNumber = Get64(buf + 8);
694   if (sectorNumber != 1)
695     return S_FALSE;
696   if (Get32(buf + 16) != LvmCrcCalc(buf + 20, kSectorSize - 20))
697     return S_FALSE;
698 
699   const UInt32 offsetToCont = Get32(buf + 20);
700   if (memcmp(buf + 24, k_Signature2, k_Signature2Size) != 0)
701     return S_FALSE;
702 
703   if (offsetToCont != 32)
704     return S_FALSE;
705 
706   // pv_header
707 
708   size_t pos = offsetToCont;
709   const Byte *p = buf;
710 
711   /*
712   {
713     Byte id[ID_LEN];
714     memcpy(id, p + pos, ID_LEN);
715   }
716   */
717 
718   pos += ID_LEN;
719   const UInt64 device_size_xl = Get64(p + pos);
720   pos += 8;
721 
722   _phySize = device_size_xl;
723   _isArc = true;
724 
725   for (;;)
726   {
727     if (pos > kSectorSize - 16)
728       return S_FALSE;
729     // disk_locn (data areas)
730     UInt64 offset = Get64(p + pos);
731     UInt64 size = Get64(p + pos + 8);
732     pos += 16;
733     if (offset == 0 && size == 0)
734       break;
735   }
736 
737   CConfig cfg;
738   // bool isFinded = false;
739 
740   // for (;;)
741   {
742     if (pos > kSectorSize - 16)
743       return S_FALSE;
744     // disk_locn (metadata area headers)
745     UInt64 offset = Get64(p + pos);
746     UInt64 size = Get64(p + pos + 8);
747     pos += 16;
748     if (offset == 0 && size == 0)
749     {
750       // break;
751       return S_FALSE;
752     }
753 
754     CByteBuffer meta;
755     const size_t sizeT = (size_t)size;
756     if (sizeT != size)
757       return S_FALSE;
758     meta.Alloc(sizeT);
759     RINOK(InStream_SeekSet(stream, offset))
760     RINOK(ReadStream_FALSE(stream, meta, sizeT))
761     if (Get32(meta) != LvmCrcCalc(meta + 4, kSectorSize - 4))
762       return S_FALSE;
763     mda_header mh;
764     if (!mh.Parse(meta, kSectorSize))
765       return S_FALSE;
766 
767     if (mh.raw_locns.Size() != 1)
768       return S_FALSE;
769     unsigned g = 0;
770     // for (unsigned g = 0; g < mh.raw_locns.Size(); g++)
771     {
772       const CRawLocn &locn = mh.raw_locns[g];
773 
774       CByteBuffer vgBuf;
775       if (locn.Size > ((UInt32)1 << 24))
776         return S_FALSE;
777 
778       const size_t vgSize = (size_t)locn.Size;
779       if (vgSize == 0)
780         return S_FALSE;
781 
782       vgBuf.Alloc(vgSize);
783 
784       _cfgPos = offset + locn.Offset;
785       _cfgSize = vgSize;
786       RINOK(InStream_SeekSet(stream, _cfgPos))
787       RINOK(ReadStream_FALSE(stream, vgBuf, vgSize))
788       if (locn.Checksum != LvmCrcCalc(vgBuf, vgSize))
789         return S_FALSE;
790 
791       {
792         AString s;
793         s.SetFrom_CalcLen((const char *)(const Byte *)vgBuf, (unsigned)vgSize);
794         _cfgSize = s.Len();
795         if (!cfg.Parse(s))
796           return S_FALSE;
797         // isFinded = true;
798         // break;
799       }
800     }
801 
802     // if (isFinded) break;
803   }
804 
805   // if (!isFinded) return S_FALSE;
806 
807   if (cfg.Root.Items.Size() != 1)
808     return S_FALSE;
809   const CConfigItem &volGroup = cfg.Root.Items[0];
810   if (volGroup.Name != "VolGroup00")
811     return S_FALSE;
812 
813   volGroup.GetPropVal_String("id", _id);
814 
815   if (!cfg.Root.GetPropVal_Number("creation_time", _cTime))
816     _cTime = 0;
817 
818   UInt64 extentSize;
819   if (!volGroup.GetPropVal_Number("extent_size", extentSize))
820     return S_FALSE;
821 
822   _extentSizeBits = GetLog(extentSize);
823   if (_extentSizeBits < 0 || _extentSizeBits > (62 - 9))
824     return S_FALSE;
825 
826 
827   {
828     int pvsIndex = volGroup.FindSubItem("physical_volumes");
829     if (pvsIndex < 0)
830       return S_FALSE;
831 
832     const CConfigItem &phyVols = volGroup.Items[pvsIndex];
833 
834     FOR_VECTOR (i, phyVols.Items)
835     {
836       const CConfigItem &ci = phyVols.Items[i];
837       CPhyVol pv;
838       if (!pv.Parse(ci))
839         return S_FALSE;
840       _phyVols.Add(pv);
841     }
842   }
843 
844   {
845     int lvIndex = volGroup.FindSubItem("logical_volumes");
846     if (lvIndex < 0)
847       return S_FALSE;
848 
849     const CConfigItem &logVolumes = volGroup.Items[lvIndex];
850 
851     FOR_VECTOR (i, logVolumes.Items)
852     {
853       const CConfigItem &ci = logVolumes.Items[i];
854       CLogVol &lv = _logVols.AddNew();
855       lv.Parse(ci) ; // check error
856     }
857   }
858 
859   {
860     FOR_VECTOR (i, _logVols)
861     {
862       CLogVol &lv = _logVols[i];
863 
864       CItem item;
865 
866       item.LogVol = (int)i;
867       item.Pos = 0;
868       item.Size = 0;
869       item.Name = lv.Name;
870 
871       if (lv.IsSupported)
872       {
873         UInt64 numExtents;
874         lv.IsSupported = lv.GetNumExtents(numExtents);
875 
876         if (lv.IsSupported)
877         {
878           lv.IsSupported = false;
879           item.Size = numExtents << (_extentSizeBits + 9);
880 
881           if (lv.Segments.Size() == 1)
882           {
883             const CSegment &segment = lv.Segments[0];
884             if (segment.stripes.Size() == 1)
885             {
886               const CStripe &stripe = segment.stripes[0];
887               FOR_VECTOR (pvIndex, _phyVols)
888               {
889                 const CPhyVol &pv = _phyVols[pvIndex];
890                 if (pv.Name == stripe.Name)
891                 {
892                   item.Pos = (pv.pe_start + (stripe.ExtentOffset << _extentSizeBits)) << 9;
893                   lv.IsSupported = true;
894                   item.IsSupported = true;
895                   break;
896                 }
897               }
898             }
899           }
900         }
901       }
902 
903       _items.Add(item);
904     }
905   }
906 
907   {
908     FOR_VECTOR (i, _phyVols)
909     {
910       const CPhyVol &pv = _phyVols[i];
911 
912       if (pv.pe_start > (UInt64)1 << (62 - 9))
913         return S_FALSE;
914       if (pv.pe_count > (UInt64)1 << (62 - 9 - _extentSizeBits))
915         return S_FALSE;
916 
917       CItem item;
918 
919       item.PhyVol = (int)i;
920       item.Pos = pv.pe_start << 9;
921       item.Size = pv.pe_count << (_extentSizeBits + 9);
922       item.Name = pv.Name;
923       item.IsSupported = true;
924 
925       _items.Add(item);
926     }
927   }
928 
929   return S_OK;
930 }
931 
932 
933 Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
934     const UInt64 * /* maxCheckStartPosition */,
935     IArchiveOpenCallback * /* openArchiveCallback */))
936 {
937   COM_TRY_BEGIN
938   Close();
939   RINOK(Open2(stream))
940   _stream = stream;
941   return S_OK;
942   COM_TRY_END
943 }
944 
945 
946 Z7_COM7F_IMF(CHandler::Close())
947 {
948   CVolGroup::Clear();
949 
950   _cfgPos = 0;
951   _cfgSize = 0;
952   _cTime = 0;
953   _phySize = 0;
954   _isArc = false;
955   _items.Clear();
956 
957   _stream.Release();
958   return S_OK;
959 }
960 
961 
962 static const Byte kProps[] =
963 {
964   kpidPath,
965   kpidSize,
966   kpidFileSystem,
967   kpidCharacts,
968   kpidOffset,
969   kpidId
970 };
971 
972 static const Byte kArcProps[] =
973 {
974   kpidId,
975   kpidCTime,
976   kpidClusterSize
977 };
978 
979 IMP_IInArchive_Props
980 IMP_IInArchive_ArcProps
981 
982 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
983 {
984   COM_TRY_BEGIN
985   NCOM::CPropVariant prop;
986 
987   switch (propID)
988   {
989     case kpidMainSubfile:
990     {
991       /*
992       if (_items.Size() == 1)
993         prop = (UInt32)0;
994       */
995       break;
996     }
997     case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
998     case kpidId:
999     {
1000       prop = _id;
1001       break;
1002     }
1003     case kpidClusterSize:
1004     {
1005       if (_extentSizeBits >= 0)
1006         prop = ((UInt64)1 << (_extentSizeBits + 9));
1007       break;
1008     }
1009     case kpidCTime:
1010     {
1011       if (_cTime != 0)
1012       {
1013         FILETIME ft;
1014         NTime::UnixTime64_To_FileTime((Int64)_cTime, ft);
1015         prop = ft;
1016       }
1017       break;
1018     }
1019     case kpidErrorFlags:
1020     {
1021       UInt32 v = 0;
1022       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
1023       // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
1024       // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
1025       if (v == 0 && !_stream)
1026         v |= kpv_ErrorFlags_UnsupportedMethod;
1027       if (v != 0)
1028         prop = v;
1029       break;
1030     }
1031   }
1032 
1033   prop.Detach(value);
1034   return S_OK;
1035   COM_TRY_END
1036 }
1037 
1038 
1039 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1040 {
1041   *numItems = _items.Size() + (_cfgSize == 0 ? 0 : 1);
1042   return S_OK;
1043 }
1044 
1045 
1046 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
1047 {
1048   COM_TRY_BEGIN
1049   NCOM::CPropVariant prop;
1050 
1051   const CItem &item = _items[index];
1052 
1053   // const CLogVol &item = _items[index];
1054 
1055   if (index >= _items.Size())
1056   {
1057     switch (propID)
1058     {
1059       case kpidPath:
1060       {
1061         prop = "meta.txt";
1062         break;
1063       }
1064 
1065       case kpidSize:
1066       case kpidPackSize: prop = _cfgSize; break;
1067     }
1068   }
1069   else
1070   {
1071     switch (propID)
1072     {
1073     case kpidPath:
1074       {
1075         AString s = item.Name;
1076         s += ".img";
1077         prop = s;
1078         break;
1079       }
1080 
1081     case kpidSize:
1082     case kpidPackSize: prop = item.Size; break;
1083     case kpidOffset: prop = item.Pos; break;
1084 
1085     case kpidId:
1086       {
1087         // prop = item.id;
1088         break;
1089       }
1090 
1091       // case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break;
1092     }
1093   }
1094 
1095   prop.Detach(value);
1096   return S_OK;
1097   COM_TRY_END
1098 }
1099 
1100 REGISTER_ARC_I(
1101   "LVM", "lvm", NULL, 0xBF,
1102   k_Signature,
1103   kSectorSize,
1104   0,
1105   NULL)
1106 
1107 }}
1108