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