Kernel - VFS API Update - ReadDir caller provided buffer
[tpg/acess2.git] / KernelLand / Modules / Storage / LVM / mbr.c
1 /*
2  * Acess2 Logical Volume Manager
3  * - By John Hodge (thePowersGang)
4  * 
5  * mbr.c
6  * - MBR Parsing Code
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include "lvm.h"
11 #include "mbr.h"
12
13 // === PROTOTYPES ===
14  int    LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector);
15 void    LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector);
16 Uint64  LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length);
17
18 // === GLOBALS ===
19 tLVM_Format     gLVM_MBRType = {
20         .Name = "MBR",
21         .CountSubvolumes = LVM_MBR_CountSubvolumes,
22         .PopulateSubvolumes = LVM_MBR_PopulateSubvolumes
23 };
24
25 // === CODE ===
26 /**
27  * \brief Initialise a volume as 
28  */
29 int LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector)
30 {
31         tMBR    *MBR = FirstSector;
32          int    i;
33         Uint64  extendedLBA;
34         Uint64  base, len;
35          int    numPartitions = 0;
36         
37         ENTER("pVolume pFirstSector", Volume, FirstSector);
38         
39         // Count Partitions
40         numPartitions = 0;
41         extendedLBA = 0;
42         for( i = 0; i < 4; i ++ )
43         {
44                 if( MBR->Parts[i].SystemID == 0 )       continue;
45         
46                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
47                 {
48                         base = MBR->Parts[i].LBAStart;
49                 }
50                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
51                 {
52                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
53                 }
54                 else
55                         continue ;      // Invalid, so don't count
56                 
57                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 )
58                 {
59                         LOG("Extended Partition at 0x%llx", base);
60                         if(extendedLBA != 0) {
61                                 Log_Warning(
62                                         "LBA MBR",
63                                         "Volume %p has multiple extended partitions, ignoring all but first",
64                                         Volume
65                                         );
66                                 continue;
67                         }
68                         extendedLBA = base;
69                 }
70                 else
71                 {
72                         LOG("Primary Partition at 0x%llx", base);
73                         numPartitions ++;
74                 }
75         }
76         while(extendedLBA != 0)
77         {
78                 extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
79                 if( extendedLBA == (Uint64)-1 )
80                         break;
81                 numPartitions ++;
82         }
83         LOG("numPartitions = %i", numPartitions);
84
85         LEAVE('i', numPartitions);
86         return numPartitions;   
87 }
88
89 void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector)
90 {
91         Uint64  extendedLBA;
92         Uint64  base, len;
93          int    i, j;
94         tMBR    *MBR = FirstSector;
95
96         ENTER("pVolume pFirstSector", Volume, FirstSector);
97         
98         // --- Fill Partition Info ---
99         extendedLBA = 0;
100         for( j = 0, i = 0; i < 4; i ++ )
101         {
102                 LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
103                 if( MBR->Parts[i].SystemID == 0 )       continue;
104                 if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
105                 {
106                         base = MBR->Parts[i].LBAStart;
107                         len = MBR->Parts[i].LBALength;
108                 }
109                 else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
110                 {
111                         base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
112                         len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
113                 }
114                 else
115                         continue;
116                 
117                 if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
118                         if(extendedLBA == 0)
119                                 extendedLBA = base;
120                         continue;
121                 }
122                 // Create Partition
123                 LVM_int_SetSubvolume_Anon( Volume, j, base, len );
124                 j ++;
125                 
126         }
127         // Scan extended partitions
128         while(extendedLBA != 0)
129         {
130                 extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
131                 if(extendedLBA == (Uint64)-1)
132                         break;
133                 LVM_int_SetSubvolume_Anon( Volume, j, base, len );
134                 j ++ ;
135         }
136         
137         LEAVE('-');
138 }
139
140 /**
141  * \brief Reads an extended partition
142  * \return LBA of next Extended, -1 on error, 0 for last
143  */
144 Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length)
145 {
146         Uint64  link = 0;
147          int    bFoundPart = 0;;
148          int    i;
149         tMBR    mbr;
150         Uint64  base, len;
151         
152         // TODO: Handle non-512 byte sectors
153         if( LVM_int_ReadVolume( Volume, Addr, 1, &mbr ) != 0 )
154                 return -1;      // Stop on Errors
155         
156         for( i = 0; i < 4; i ++ )
157         {
158                 if( mbr.Parts[i].SystemID == 0 )        continue;
159                 
160                 // LBA 24
161                 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
162                         base = mbr.Parts[i].LBAStart;
163                         len = mbr.Parts[i].LBALength;
164                 }
165                 // LBA 48
166                 else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
167                         base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
168                         len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
169                 }
170                 else {
171                         Log_Warning("LVM MBR",
172                                 "Unknown partition type 0x%x, Volume %p Ext 0x%llx Part %i",
173                                 mbr.Parts[i].Boot, Volume, Addr, i
174                                 );
175                         return -1;
176                 }
177                 
178                 switch(mbr.Parts[i].SystemID)
179                 {
180                 case 0xF:
181                 case 0x5:
182                         if(link != 0) {
183                                 Log_Warning("LVM MBR",
184                                         "Volume %p has two forward links in the extended partition",
185                                         Volume
186                                         );
187                                 return -1;
188                         }
189                         link = base;
190                         break;
191                 default:
192                         if(bFoundPart) {
193                                 Warning("LVM MBR",
194                                         "Volume %p has more than one partition in the extended partition at 0x%llx",
195                                         Volume, Addr
196                                         );
197                                 return -1;
198                         }
199                         bFoundPart = 1;
200                         *Base = Addr + base;    // Extended partitions are based off the sub-mbr
201                         *Length = len;
202                         break;
203                 }
204         }
205         
206         if(!bFoundPart) {
207                 Log_Warning("LVM MBR",
208                         "No partition in extended partiton, Volume %p 0x%llx",
209                         Volume, Addr
210                         );
211                 return -1;
212         }
213         
214         return link;
215 }

UCC git Repository :: git.ucc.asn.au