kpartx: fix dos partition rollover error
[multipath-tools/.git] / kpartx / dos.c
1 /*
2  * Source: copy of util-linux' partx dos.c
3  *
4  * Copyrights of the original file apply 
5  * Copyright (c) 2005 Bastian Blank
6  */
7 #include "kpartx.h"
8 #include "byteorder.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include "dos.h"
12
13 static int
14 is_extended(int type) {
15         return (type == 5 || type == 0xf || type == 0x85);
16 }
17
18 static int
19 read_extended_partition(int fd, struct partition *ep, int en,
20                         struct slice *sp, int ns)
21 {
22         struct partition p;
23         unsigned long start, here, next;
24         unsigned char *bp;
25         int loopct = 0;
26         int moretodo = 1;
27         int i, n=0;
28
29         int sector_size_mul = get_sector_size(fd)/512;
30
31         next = start = sector_size_mul * le32_to_cpu(ep->start_sect);
32
33         while (moretodo) {
34                 here = next;
35                 moretodo = 0;
36                 if (++loopct > 100)
37                         return n;
38
39                 bp = (unsigned char *)getblock(fd, here);
40                 if (bp == NULL)
41                         return n;
42
43                 if (bp[510] != 0x55 || bp[511] != 0xaa)
44                         return n;
45
46                 for (i=0; i<2; i++) {
47                         memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
48                         if (is_extended(p.sys_type)) {
49                                 if (p.nr_sects && !moretodo) {
50                                         next = start + sector_size_mul * le32_to_cpu(p.start_sect);
51                                         moretodo = 1;
52                                 }
53                                 continue;
54                         }
55                         if (n < ns) {
56                                 sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect);
57                                 sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects);
58                                 sp[n].container = en + 1;
59                                 n++;
60                         } else {
61                                 fprintf(stderr,
62                                     "dos_extd_partition: too many slices\n");
63                                 return n;
64                         }
65                         loopct = 0;
66                 }
67         }
68         return n;
69 }
70
71 static int
72 is_gpt(int type) {
73         return (type == 0xEE);
74 }
75
76 int
77 read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
78         struct partition p;
79         unsigned long offset = all.start;
80         int i, n=4;
81         unsigned char *bp;
82         uint64_t  sector_size_mul = get_sector_size(fd)/512;
83
84         bp = (unsigned char *)getblock(fd, offset);
85         if (bp == NULL)
86                 return -1;
87
88         if (bp[510] != 0x55 || bp[511] != 0xaa)
89                 return -1;
90
91         for (i=0; i<4; i++) {
92                 memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
93                 if (is_gpt(p.sys_type))
94                         return 0;
95                 if (i < ns) {
96                         sp[i].start =  sector_size_mul * le32_to_cpu(p.start_sect);
97                         sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects);
98                 } else {
99                         fprintf(stderr,
100                                 "dos_partition: too many slices\n");
101                         break;
102                 }
103                 if (is_extended(p.sys_type)) {
104                         /* extended partitions only get one or
105                            two sectors mapped for LILO to install,
106                            whichever is needed to have 1kb of space */
107                         if (sector_size_mul == 1)
108                                 sp[i].size = 2;
109                         else sp[i].size = sector_size_mul;
110                         n += read_extended_partition(fd, &p, i, sp+n, ns-n);
111                 }
112         }
113         return n;
114 }