1/* 2 * volume_id - reads filesystem label and uuid 3 * 4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21#include "volume_id_internal.h" 22 23struct msdos_partition_entry { 24 uint8_t boot_ind; 25 uint8_t head; 26 uint8_t sector; 27 uint8_t cyl; 28 uint8_t sys_ind; 29 uint8_t end_head; 30 uint8_t end_sector; 31 uint8_t end_cyl; 32 uint32_t start_sect; 33 uint32_t nr_sects; 34} PACKED; 35 36#define MSDOS_PARTTABLE_OFFSET 0x1be 37#define MSDOS_SIG_OFF 0x1fe 38#define BSIZE 0x200 39#define DOS_EXTENDED_PARTITION 0x05 40#define LINUX_EXTENDED_PARTITION 0x85 41#define WIN98_EXTENDED_PARTITION 0x0f 42#define LINUX_RAID_PARTITION 0xfd 43#define is_extended(type) \ 44 (type == DOS_EXTENDED_PARTITION || \ 45 type == WIN98_EXTENDED_PARTITION || \ 46 type == LINUX_EXTENDED_PARTITION) 47#define is_raid(type) \ 48 (type == LINUX_RAID_PARTITION) 49 50int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off) 51{ 52 const uint8_t *buf; 53 int i; 54 uint64_t poff; 55 uint64_t plen; 56 uint64_t extended = 0; 57 uint64_t current; 58 uint64_t next; 59 int limit; 60 int empty = 1; 61 struct msdos_partition_entry *part; 62 struct volume_id_partition *p; 63 64 dbg("probing at offset 0x%llx", (unsigned long long) off); 65 66 buf = volume_id_get_buffer(id, off, 0x200); 67 if (buf == NULL) 68 return -1; 69 70 if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa) 71 return -1; 72 73 /* check flags on all entries for a valid partition table */ 74 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; 75 for (i = 0; i < 4; i++) { 76 if (part[i].boot_ind != 0 77 && part[i].boot_ind != 0x80 78 ) { 79 return -1; 80 } 81 82 if (part[i].nr_sects != 0) 83 empty = 0; 84 } 85 if (empty == 1) 86 return -1; 87 88 if (id->partitions != NULL) 89 free(id->partitions); 90 id->partitions = xzalloc(VOLUME_ID_PARTITIONS_MAX * 91 sizeof(struct volume_id_partition)); 92 93 for (i = 0; i < 4; i++) { 94 poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; 95 plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; 96 97 if (plen == 0) 98 continue; 99 100 p = &id->partitions[i]; 101 102// p->pt_type_raw = part[i].sys_ind; 103 104 if (is_extended(part[i].sys_ind)) { 105 dbg("found extended partition at 0x%llx", (unsigned long long) poff); 106// volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE); 107// p->type = "msdos_extended_partition"; 108 if (extended == 0) 109 extended = off + poff; 110 } else { 111 dbg("found 0x%x data partition at 0x%llx, len 0x%llx", 112 part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); 113 114// if (is_raid(part[i].sys_ind)) 115// volume_id_set_usage_part(p, VOLUME_ID_RAID); 116// else 117// volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); 118 } 119 120// p->pt_off = off + poff; 121// p->pt_len = plen; 122 id->partition_count = i+1; 123 } 124 125 next = extended; 126 current = extended; 127 limit = 50; 128 129 /* follow extended partition chain and add data partitions */ 130 while (next != 0) { 131 if (limit-- == 0) { 132 dbg("extended chain limit reached"); 133 break; 134 } 135 136 buf = volume_id_get_buffer(id, current, 0x200); 137 if (buf == NULL) 138 break; 139 140 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; 141 142 if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa) 143 break; 144 145 next = 0; 146 147 for (i = 0; i < 4; i++) { 148 poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; 149 plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; 150 151 if (plen == 0) 152 continue; 153 154 if (is_extended(part[i].sys_ind)) { 155 dbg("found extended partition at 0x%llx", (unsigned long long) poff); 156 if (next == 0) 157 next = extended + poff; 158 } else { 159 dbg("found 0x%x data partition at 0x%llx, len 0x%llx", 160 part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); 161 162 /* we always start at the 5th entry */ 163// while (id->partition_count < 4) 164// volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED); 165 if (id->partition_count < 4) 166 id->partition_count = 4; 167 168 p = &id->partitions[id->partition_count]; 169 170// if (is_raid(part[i].sys_ind)) 171// volume_id_set_usage_part(p, VOLUME_ID_RAID); 172// else 173// volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); 174 175// p->pt_off = current + poff; 176// p->pt_len = plen; 177 id->partition_count++; 178 179// p->pt_type_raw = part[i].sys_ind; 180 181 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) { 182 dbg("too many partitions"); 183 next = 0; 184 } 185 } 186 } 187 188 current = next; 189 } 190 191// volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); 192// id->type = "msdos_partition_table"; 193 194 return 0; 195} 196