Changeset 6453e306 in mainline for uspace/lib/gpt/libgpt.c
- Timestamp:
- 2013-12-25T16:09:43Z (11 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ac36aed
- Parents:
- d51beba3
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/gpt/libgpt.c
rd51beba3 r6453e306 1 1 /* 2 * Copyright (c) 2011 , 2012,2013 Dominik Taborsky2 * Copyright (c) 2011-2013 Dominik Taborsky 3 3 * All rights reserved. 4 4 * … … 34 34 35 35 /* TODO: 36 * Th is implementation only supports fixed size partition entries. Specification37 * requires otherwise, though. Use void * array and casting to achieve that.36 * The implementation currently supports fixed size partition entries only. 37 * The specification requires otherwise, though. 38 38 */ 39 39 … … 46 46 #include <assert.h> 47 47 #include <byteorder.h> 48 #include < checksum.h>48 #include <adt/checksum.h> 49 49 #include <mem.h> 50 50 #include <sys/typefmt.h> 51 51 #include <mbr.h> 52 53 52 #include <align.h> 54 53 #include "libgpt.h" 55 54 56 55 static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *); 57 static gpt_partitions_t * 56 static gpt_partitions_t *alloc_part_array(uint32_t); 58 57 static int extend_part_array(gpt_partitions_t *); 59 58 static int reduce_part_array(gpt_partitions_t *); … … 62 61 static bool check_encaps(gpt_part_t *, uint64_t, uint64_t); 63 62 64 /** Allocate memory for gptlabel */65 gpt_label_t * 63 /** Allocate a GPT label */ 64 gpt_label_t *gpt_alloc_label(void) 66 65 { 67 66 gpt_label_t *label = malloc(sizeof(gpt_label_t)); … … 69 68 return NULL; 70 69 71 /* This is necessary so that gpt_part_foreach does not segfault */72 70 label->parts = gpt_alloc_partitions(); 73 if (label == NULL) {71 if (label->parts == NULL) { 74 72 free(label); 75 73 return NULL; … … 77 75 78 76 label->gpt = NULL; 79 80 77 label->device = 0; 81 78 … … 83 80 } 84 81 85 /** Free gpt_label_t structure*/82 /** Free a GPT label */ 86 83 void gpt_free_label(gpt_label_t *label) 87 84 { … … 95 92 } 96 93 97 /** Allocate memory for gptheader */98 gpt_t * 94 /** Allocate a GPT header */ 95 gpt_t *gpt_alloc_header(size_t size) 99 96 { 100 97 gpt_t *gpt = malloc(sizeof(gpt_t)); … … 102 99 return NULL; 103 100 104 /* 105 * We might need only sizeof(gpt_header_t), but we should follow 101 /* 102 * We might need only sizeof(gpt_header_t), but we should follow 106 103 * specs and have zeroes through all the rest of the block 107 104 */ 108 size_t final_size = size > sizeof(gpt_header_t) ? size : sizeof(gpt_header_t);105 size_t final_size = max(size, sizeof(gpt_header_t)); 109 106 gpt->header = malloc(final_size); 110 107 if (gpt->header == NULL) { … … 113 110 } 114 111 115 /* Enter some sane defaults. */116 112 memset(gpt->header, 0, final_size); 117 113 memcpy(gpt->header->efi_signature, efi_signature, 8); … … 121 117 gpt->header->entry_size = host2uint32_t_le(sizeof(gpt_entry_t)); 122 118 123 124 119 return gpt; 125 120 } 126 121 127 /** free() GPT header including gpt->header_lba*/122 /** Free a GPT header */ 128 123 void gpt_free_gpt(gpt_t *gpt) 129 124 { … … 132 127 } 133 128 134 /** Read GPT from specific device 135 * @param label label structure to fill 136 * @param dev_handle device to read GPT from 137 * 138 * @return EOK on success, errorcode on error 129 /** Read GPT from a device 130 * 131 * @param label Label to read. 132 * @param dev_handle Device to read GPT from. 133 * 134 * @return EOK on success, error code on error. 135 * 139 136 */ 140 137 int gpt_read_header(gpt_label_t *label, service_id_t dev_handle) 141 138 { 142 int rc; 143 size_t b_size; 144 145 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512); 146 if (rc != EOK) 147 goto fail; 148 149 rc = block_get_bsize(dev_handle, &b_size); 150 if (rc != EOK) 151 goto fini_fail; 139 int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512); 140 if (rc != EOK) 141 return rc; 142 143 size_t block_size; 144 rc = block_get_bsize(dev_handle, &block_size); 145 if (rc != EOK) 146 goto end; 152 147 153 148 if (label->gpt == NULL) { 154 label->gpt = gpt_alloc_header(b _size);149 label->gpt = gpt_alloc_header(block_size); 155 150 if (label->gpt == NULL) { 156 151 rc = ENOMEM; 157 goto fini_fail;152 goto end; 158 153 } 159 154 } 160 155 161 rc = load_and_check_header(dev_handle, GPT_HDR_BA, b_size, label->gpt->header); 162 if (rc == EBADCHECKSUM || rc == EINVAL) { 163 aoff64_t n_blocks; 164 rc = block_get_nblocks(dev_handle, &n_blocks); 165 if (rc != EOK) 166 goto free_fail; 167 168 rc = load_and_check_header(dev_handle, n_blocks - 1, b_size, label->gpt->header); 169 if (rc == EBADCHECKSUM || rc == EINVAL) 170 goto free_fail; 156 rc = load_and_check_header(dev_handle, GPT_HDR_BA, block_size, 157 label->gpt->header); 158 if ((rc == EBADCHECKSUM) || (rc == EINVAL)) { 159 aoff64_t blocks; 160 rc = block_get_nblocks(dev_handle, &blocks); 161 if (rc != EOK) { 162 gpt_free_gpt(label->gpt); 163 goto end; 164 } 165 166 rc = load_and_check_header(dev_handle, blocks - 1, block_size, 167 label->gpt->header); 168 if ((rc == EBADCHECKSUM) || (rc == EINVAL)) { 169 gpt_free_gpt(label->gpt); 170 goto end; 171 } 171 172 } 172 173 173 174 label->device = dev_handle; 175 rc = EOK; 176 177 end: 174 178 block_fini(dev_handle); 175 return EOK;176 177 free_fail:178 gpt_free_gpt(label->gpt);179 label->gpt = NULL;180 fini_fail:181 block_fini(dev_handle);182 fail:183 179 return rc; 184 180 } 185 181 186 182 /** Write GPT header to device 187 * @param label GPT label header to be written188 * @param dev_handle device handle to write the data to189 * 190 * @return EOK on success, libblock error code otherwise191 * 192 * Note: Firstly write partitions (if modified), then gpt header.183 * 184 * @param label Label to be written. 185 * @param dev_handle Device to write the GPT to. 186 * 187 * @return EOK on success, libblock error code otherwise. 188 * 193 189 */ 194 190 int gpt_write_header(gpt_label_t *label, service_id_t dev_handle) 195 191 { 196 int rc;197 size_t b_size;198 199 192 /* The comm_size argument (the last one) is ignored */ 200 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);201 if ( rc != EOK && rc != EEXIST)193 int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096); 194 if ((rc != EOK) && (rc != EEXIST)) 202 195 return rc; 203 196 204 rc = block_get_bsize(dev_handle, &b_size); 205 if (rc != EOK) 206 return rc; 207 208 aoff64_t n_blocks; 209 rc = block_get_nblocks(dev_handle, &n_blocks); 210 if (rc != EOK) { 211 block_fini(dev_handle); 212 return rc; 213 } 214 215 uint64_t tmp; 197 size_t block_size; 198 rc = block_get_bsize(dev_handle, &block_size); 199 if (rc != EOK) 200 goto end; 201 202 aoff64_t blocks; 203 rc = block_get_nblocks(dev_handle, &blocks); 204 if (rc != EOK) 205 goto end; 216 206 217 207 gpt_set_random_uuid(label->gpt->header->disk_guid); 218 208 219 209 /* Prepare the backup header */ 220 label->gpt->header->alternate_lba = label->gpt->header-> my_lba;221 label->gpt->header-> my_lba = host2uint64_t_le(n_blocks - 1);222 223 tmp= label->gpt->header->entry_lba;224 label->gpt->header->entry_lba = host2uint64_t_le( n_blocks -225 (uint32_t_le2host(label->gpt->header->fillries) * sizeof(gpt_entry_t))226 / b_size - 1);210 label->gpt->header->alternate_lba = label->gpt->header->current_lba; 211 label->gpt->header->current_lba = host2uint64_t_le(blocks - 1); 212 213 uint64_t lba = label->gpt->header->entry_lba; 214 label->gpt->header->entry_lba = host2uint64_t_le(blocks - 215 (uint32_t_le2host(label->gpt->header->fillries) * 216 sizeof(gpt_entry_t)) / block_size - 1); 227 217 228 218 label->gpt->header->header_crc32 = 0; 229 label->gpt->header->header_crc32 = host2uint32_t_le(230 compute_crc32((uint8_t *) label->gpt->header,231 219 label->gpt->header->header_crc32 = 220 host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header, 221 uint32_t_le2host(label->gpt->header->header_size))); 232 222 233 223 /* Write to backup GPT header location */ 234 rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, label->gpt->header); 235 if (rc != EOK) { 236 block_fini(dev_handle); 237 return rc; 238 } 239 224 rc = block_write_direct(dev_handle, blocks - 1, GPT_HDR_BS, 225 label->gpt->header); 226 if (rc != EOK) 227 goto end; 240 228 241 229 /* Prepare the main header */ 242 label->gpt->header->entry_lba = tmp;243 244 tmp= label->gpt->header->alternate_lba;245 label->gpt->header->alternate_lba = label->gpt->header-> my_lba;246 label->gpt->header-> my_lba = tmp;230 label->gpt->header->entry_lba = lba; 231 232 lba = label->gpt->header->alternate_lba; 233 label->gpt->header->alternate_lba = label->gpt->header->current_lba; 234 label->gpt->header->current_lba = lba; 247 235 248 236 label->gpt->header->header_crc32 = 0; 249 label->gpt->header->header_crc32 = host2uint32_t_le(250 compute_crc32((uint8_t *) label->gpt->header,251 237 label->gpt->header->header_crc32 = 238 host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header, 239 uint32_t_le2host(label->gpt->header->header_size))); 252 240 253 241 /* Write to main GPT header location */ 254 rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header); 255 if (rc != EOK) 256 return rc; 242 rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, 243 label->gpt->header); 244 if (rc != EOK) 245 goto end; 257 246 258 247 /* Write Protective MBR */ 259 248 br_block_t mbr; 260 249 memset(&mbr, 0, 512); 250 261 251 memset(mbr.pte[0].first_chs, 1, 3); 262 252 mbr.pte[0].ptype = 0xEE; 263 memset(mbr.pte[0].last_chs, 0x FF, 3);253 memset(mbr.pte[0].last_chs, 0xff, 3); 264 254 mbr.pte[0].first_lba = host2uint32_t_le(1); 265 mbr.pte[0].length = 0x FFFFFFFF;255 mbr.pte[0].length = 0xffffffff; 266 256 mbr.signature = host2uint16_t_le(BR_SIGNATURE); 267 257 268 258 rc = block_write_direct(dev_handle, 0, 1, &mbr); 259 260 end: 269 261 block_fini(dev_handle); 270 if (rc != EOK) 271 return rc; 272 273 return 0; 262 return rc; 274 263 } 275 264 276 265 /** Alloc partition array */ 277 gpt_partitions_t * gpt_alloc_partitions()266 gpt_partitions_t *gpt_alloc_partitions(void) 278 267 { 279 268 return alloc_part_array(GPT_MIN_PART_NUM); … … 281 270 282 271 /** Parse partitions from GPT 283 * @param label GPT label to be parsed 284 * 285 * @return EOK on success, errorcode otherwise 272 * 273 * @param label GPT label to be parsed. 274 * 275 * @return EOK on success, error code otherwise. 276 * 286 277 */ 287 278 int gpt_read_partitions(gpt_label_t *label) 288 279 { 289 int rc;290 unsigned int i;291 280 uint32_t fillries = uint32_t_le2host(label->gpt->header->fillries); 292 281 uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size); … … 295 284 if (label->parts == NULL) { 296 285 label->parts = alloc_part_array(fillries); 297 if (label->parts == NULL) {286 if (label->parts == NULL) 298 287 return ENOMEM; 299 } 300 } 301 302 /* comm_size is ignored */ 303 rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t)); 304 if (rc != EOK) 305 goto fail; 306 288 } 289 290 int rc = block_init(EXCHANGE_SERIALIZE, label->device, 291 sizeof(gpt_entry_t)); 292 if (rc != EOK) { 293 gpt_free_partitions(label->parts); 294 label->parts = NULL; 295 goto end; 296 } 297 307 298 size_t block_size; 308 299 rc = block_get_bsize(label->device, &block_size); 309 if (rc != EOK) 310 goto fini_fail; 311 300 if (rc != EOK) { 301 gpt_free_partitions(label->parts); 302 label->parts = NULL; 303 goto end; 304 } 305 312 306 aoff64_t pos = ent_lba * block_size; 313 314 /* 315 * Now we read just sizeof(gpt_entry_t) bytes for each entry from the device. 316 * Hopefully, this does not bypass cache (no mention in libblock.c), 317 * and also allows us to have variable partition entry size (but we 318 * will always read just sizeof(gpt_entry_t) bytes - hopefully they 319 * don't break backward compatibility) 320 */ 321 for (i = 0; i < fillries; ++i) { 322 /*FIXME: this does bypass cache... */ 323 rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), label->parts->part_array + i); 324 /* 325 * FIXME: but seqread() is just too complex... 326 * rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t)); 327 */ 307 308 for (uint32_t i = 0; i < fillries; i++) { 309 rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), 310 label->parts->part_array + i); 328 311 pos += ent_size; 329 330 if (rc != EOK) 331 goto fini_fail; 332 } 333 334 uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array, 335 fillries * ent_size); 336 337 if (uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc) 338 { 312 313 if (rc != EOK) { 314 gpt_free_partitions(label->parts); 315 label->parts = NULL; 316 goto end; 317 } 318 } 319 320 uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array, 321 fillries * ent_size); 322 323 if (uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc) { 339 324 rc = EBADCHECKSUM; 340 goto fini_fail; 341 } 342 325 gpt_free_partitions(label->parts); 326 label->parts = NULL; 327 goto end; 328 } 329 330 rc = EOK; 331 332 end: 343 333 block_fini(label->device); 344 return EOK;345 346 fini_fail:347 block_fini(label->device);348 349 fail:350 gpt_free_partitions(label->parts);351 label->parts = NULL;352 334 return rc; 353 335 } 354 336 355 337 /** Write GPT and partitions to device 356 * Note: also writes the header. 357 * @param label label to write 358 * @param dev_handle device to write the data to 359 * 360 * @return returns EOK on succes, errorcode otherwise 338 * 339 * Note: Also writes the header. 340 * 341 * @param label Label to write. 342 * @param dev_handle Device to write the data to. 343 * 344 * @return EOK on succes, error code otherwise 345 * 361 346 */ 362 347 int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle) 363 348 { 364 int rc;365 size_t b_size;366 367 349 /* comm_size of 4096 is ignored */ 368 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);369 if ( rc != EOK && rc != EEXIST)350 int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096); 351 if ((rc != EOK) && (rc != EEXIST)) 370 352 return rc; 371 353 372 rc = block_get_bsize(dev_handle, &b_size); 354 size_t block_size; 355 rc = block_get_bsize(dev_handle, &block_size); 373 356 if (rc != EOK) 374 357 goto fail; 375 358 376 aoff64_t n_blocks;377 rc = block_get_nblocks(dev_handle, & n_blocks);359 aoff64_t blocks; 360 rc = block_get_nblocks(dev_handle, &blocks); 378 361 if (rc != EOK) 379 362 goto fail; 380 363 381 /* When we're creating a new label from scratch, we need to fill 382 * the header with sensible defaults. */ 383 if (label->gpt == NULL) { 384 label->gpt = gpt_alloc_header(b_size); 385 } 386 387 uint32_t e_size = uint32_t_le2host(label->gpt->header->entry_size); 388 size_t fillries = label->parts->fill > GPT_MIN_PART_NUM ? label->parts->fill : GPT_MIN_PART_NUM; 389 390 if (e_size != sizeof(gpt_entry_t)) 364 if (label->gpt == NULL) 365 label->gpt = gpt_alloc_header(block_size); 366 367 uint32_t entry_size = 368 uint32_t_le2host(label->gpt->header->entry_size); 369 size_t fillries = (label->parts->fill > GPT_MIN_PART_NUM) ? 370 label->parts->fill : GPT_MIN_PART_NUM; 371 372 if (entry_size != sizeof(gpt_entry_t)) 391 373 return ENOTSUP; 392 374 393 375 label->gpt->header->fillries = host2uint32_t_le(fillries); 394 uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / b_size; 395 uint64_t gpt_space = arr_blocks + GPT_HDR_BS + 1; /* +1 for Protective MBR */ 376 377 uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / block_size; 378 379 /* Include Protective MBR */ 380 uint64_t gpt_space = arr_blocks + GPT_HDR_BS + 1; 381 396 382 label->gpt->header->first_usable_lba = host2uint64_t_le(gpt_space); 397 label->gpt->header->last_usable_lba = host2uint64_t_le(n_blocks - gpt_space - 1); 383 label->gpt->header->last_usable_lba = 384 host2uint64_t_le(blocks - gpt_space - 1); 398 385 399 386 /* Perform checks */ … … 402 389 continue; 403 390 404 if (!check_encaps(p, n_blocks, gpt_space)) {391 if (!check_encaps(p, blocks, gpt_space)) { 405 392 rc = ERANGE; 406 393 goto fail; … … 420 407 } 421 408 422 label->gpt->header->pe_array_crc32 = host2uint32_t_le(compute_crc32( 423 (uint8_t *) label->parts->part_array, 424 fillries * e_size)); 425 409 label->gpt->header->pe_array_crc32 = 410 host2uint32_t_le(compute_crc32((uint8_t *) label->parts->part_array, 411 fillries * entry_size)); 426 412 427 413 /* Write to backup GPT partition array location */ 428 rc = block_write_direct(dev_handle, n_blocks - arr_blocks - 1,429 414 rc = block_write_direct(dev_handle, blocks - arr_blocks - 1, 415 arr_blocks, label->parts->part_array); 430 416 if (rc != EOK) 431 417 goto fail; 432 418 433 419 /* Write to main GPT partition array location */ 434 rc = block_write_direct(dev_handle, uint64_t_le2host(label->gpt->header->entry_lba), 435 arr_blocks, label->parts->part_array); 420 rc = block_write_direct(dev_handle, 421 uint64_t_le2host(label->gpt->header->entry_lba), 422 arr_blocks, label->parts->part_array); 436 423 if (rc != EOK) 437 424 goto fail; … … 444 431 } 445 432 446 /** Alloc new partition 447 * 448 * @return returns pointer to the new partition or NULL 449 * 450 * Note: use either gpt_alloc_partition or gpt_get_partition. 433 /** Allocate a new partition 434 * 435 * Note: Use either gpt_alloc_partition() or gpt_get_partition(). 451 436 * This returns a memory block (zero-filled) and needs gpt_add_partition() 452 437 * to be called to insert it into a partition array. 453 438 * Requires you to call gpt_free_partition afterwards. 454 */ 455 gpt_part_t * gpt_alloc_partition(void) 456 { 457 gpt_part_t *p = malloc(sizeof(gpt_part_t)); 458 if (p == NULL) 439 * 440 * @return Pointer to the new partition or NULL. 441 * 442 */ 443 gpt_part_t *gpt_alloc_partition(void) 444 { 445 gpt_part_t *partition = malloc(sizeof(gpt_part_t)); 446 if (partition == NULL) 459 447 return NULL; 460 448 461 memset(p, 0, sizeof(gpt_part_t)); 462 463 return p; 464 } 465 466 /** Alloc new partition already inside the label 467 * 468 * @param label label to carry new partition 469 * 470 * @return returns pointer to the new partition or NULL on ENOMEM 471 * 472 * Note: use either gpt_alloc_partition or gpt_get_partition. 449 memset(partition, 0, sizeof(gpt_part_t)); 450 451 return partition; 452 } 453 454 /** Allocate a new partition already inside the label 455 * 456 * Note: Use either gpt_alloc_partition() or gpt_get_partition(). 473 457 * This one returns a pointer to the first empty structure already 474 458 * inside the array, so don't call gpt_add_partition() afterwards. 475 459 * This is the one you will usually want. 476 */ 477 gpt_part_t * gpt_get_partition(gpt_label_t *label) 478 { 479 gpt_part_t *p; 480 460 * 461 * @param label Label to carry new partition. 462 * 463 * @return Pointer to the new partition or NULL. 464 * 465 */ 466 gpt_part_t *gpt_get_partition(gpt_label_t *label) 467 { 468 gpt_part_t *partition; 481 469 482 470 /* Find the first empty entry */ … … 487 475 } 488 476 489 p = label->parts->part_array + label->parts->fill++; 490 491 } while (gpt_get_part_type(p) != GPT_PTE_UNUSED); 492 493 return p; 477 partition = label->parts->part_array + label->parts->fill++; 478 } while (gpt_get_part_type(partition) != GPT_PTE_UNUSED); 479 480 return partition; 494 481 } 495 482 496 483 /** Get partition already inside the label 497 484 * 498 * @param label label to carrying the partition 499 * @param idx index of the partition 500 * 501 * @return returns pointer to the partition 502 * or NULL when out of range 503 * 504 * Note: For new partitions use either gpt_alloc_partition or 505 * gpt_get_partition unless you want a partition at a specific place. 485 * Note: For new partitions use either gpt_alloc_partition() or 486 * gpt_get_partition() unless you want a partition at a specific place. 506 487 * This returns a pointer to a structure already inside the array, 507 488 * so don't call gpt_add_partition() afterwards. … … 510 491 * for indexes smaller than either 128 or the actual number of filled 511 492 * entries. 512 */ 513 gpt_part_t * gpt_get_partition_at(gpt_label_t *label, size_t idx) 514 { 515 return NULL; 516 517 if (idx >= GPT_MIN_PART_NUM && idx >= label->parts->fill) 493 * 494 * @param label Label to carrying the partition. 495 * @param idx Index of the partition. 496 * 497 * @return Pointer to the partition or NULL when out of range. 498 * 499 */ 500 gpt_part_t *gpt_get_partition_at(gpt_label_t *label, size_t idx) 501 { 502 if ((idx >= GPT_MIN_PART_NUM) && (idx >= label->parts->fill)) 518 503 return NULL; 519 504 … … 523 508 /** Copy partition into partition array 524 509 * 525 * @param parts target label 526 * @param partition source partition to copy 527 * 528 * @return -1 on error, 0 otherwise 529 * 530 * Note: for use with gpt_alloc_partition() only. You will get 510 * Note: For use with gpt_alloc_partition() only. You will get 531 511 * duplicates with gpt_get_partition(). 532 * Note: does not call gpt_free_partition()! 512 * Note: Does not call gpt_free_partition()! 513 * 514 * @param parts Target label 515 * @param partition Source partition to copy 516 * 517 * @return EOK on succes, error code otherwise 518 * 533 519 */ 534 520 int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition) 535 521 { 536 gpt_part_t *p;537 522 /* Find the first empty entry */ 523 524 gpt_part_t *part; 525 538 526 do { 539 527 if (label->parts->fill == label->parts->arr_size) { … … 542 530 } 543 531 544 p = label->parts->part_array + label->parts->fill++; 545 546 } while (gpt_get_part_type(p) != GPT_PTE_UNUSED); 547 548 549 memcpy(p, partition, sizeof(gpt_entry_t)); 550 551 532 part = label->parts->part_array + label->parts->fill++; 533 } while (gpt_get_part_type(part) != GPT_PTE_UNUSED); 534 535 memcpy(part, partition, sizeof(gpt_entry_t)); 552 536 return EOK; 553 537 } 554 538 555 539 /** Remove partition from array 556 * @param label label to remove from 557 * @param idx index of the partition to remove 558 * 559 * @return EOK on success, ENOMEM on array reduction failure 560 * 561 * Note: even if it fails, the partition still gets removed. Only 540 * 541 * Note: Even if it fails, the partition still gets removed. Only 562 542 * reducing the array failed. 543 * 544 * @param label Label to remove from 545 * @param idx Index of the partition to remove 546 * 547 * @return EOK on success, ENOMEM on array reduction failure 548 * 563 549 */ 564 550 int gpt_remove_partition(gpt_label_t *label, size_t idx) … … 567 553 return EINVAL; 568 554 569 /* 570 * FIXME !555 /* 556 * FIXME: 571 557 * If we allow blank spots, we break the array. If we have more than 572 558 * 128 partitions in the array and then remove something from 573 559 * the first 128 partitions, we would forget to write the last one. 574 560 */ 561 575 562 memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t)); 576 563 … … 578 565 label->parts->fill = idx; 579 566 580 /* 581 * FIXME! HOPEFULLY FIXED. 582 * We cannot reduce the array so simply. We may have some partitions 583 * there since we allow blank spots. 584 */ 585 gpt_part_t * p; 586 587 if (label->parts->fill > GPT_MIN_PART_NUM && 588 label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) { 589 for (p = gpt_get_partition_at(label, label->parts->arr_size / 2); 590 p < label->parts->part_array + label->parts->arr_size; ++p) { 591 if (gpt_get_part_type(p) != GPT_PTE_UNUSED) 592 return EOK; 567 gpt_part_t *partition; 568 569 if ((label->parts->fill > GPT_MIN_PART_NUM) && 570 (label->parts->fill < (label->parts->arr_size / 2) - 571 GPT_IGNORE_FILL_NUM)) { 572 for (partition = gpt_get_partition_at(label, label->parts->arr_size / 2); 573 partition < label->parts->part_array + label->parts->arr_size; 574 partition++) { 575 if (gpt_get_part_type(partition) != GPT_PTE_UNUSED) 576 return EOK; 593 577 } 594 578 … … 596 580 return ENOMEM; 597 581 } 598 582 599 583 return EOK; 600 584 } … … 602 586 /** Free partition list 603 587 * 604 * @param parts partition list to be freed 605 */ 606 void gpt_free_partitions(gpt_partitions_t * parts) 588 * @param parts Partition list to be freed 589 * 590 */ 591 void gpt_free_partitions(gpt_partitions_t *parts) 607 592 { 608 593 free(parts->part_array); … … 610 595 } 611 596 612 /** Get partition type by linear search 613 * (hopefully this doesn't get slow) 614 */ 615 size_t gpt_get_part_type(gpt_part_t * p) 597 /** Get partition type */ 598 size_t gpt_get_part_type(gpt_part_t *partition) 616 599 { 617 600 size_t i; 618 601 619 602 for (i = 0; gpt_ptypes[i].guid != NULL; i++) { 620 if (p->part_type[3] == get_byte(gpt_ptypes[i].guid +0) && 621 p->part_type[2] == get_byte(gpt_ptypes[i].guid +2) && 622 p->part_type[1] == get_byte(gpt_ptypes[i].guid +4) && 623 p->part_type[0] == get_byte(gpt_ptypes[i].guid +6) && 624 625 p->part_type[5] == get_byte(gpt_ptypes[i].guid +8) && 626 p->part_type[4] == get_byte(gpt_ptypes[i].guid +10) && 627 628 p->part_type[7] == get_byte(gpt_ptypes[i].guid +12) && 629 p->part_type[6] == get_byte(gpt_ptypes[i].guid +14) && 630 631 p->part_type[8] == get_byte(gpt_ptypes[i].guid +16) && 632 p->part_type[9] == get_byte(gpt_ptypes[i].guid +18) && 633 p->part_type[10] == get_byte(gpt_ptypes[i].guid +20) && 634 p->part_type[11] == get_byte(gpt_ptypes[i].guid +22) && 635 p->part_type[12] == get_byte(gpt_ptypes[i].guid +24) && 636 p->part_type[13] == get_byte(gpt_ptypes[i].guid +26) && 637 p->part_type[14] == get_byte(gpt_ptypes[i].guid +28) && 638 p->part_type[15] == get_byte(gpt_ptypes[i].guid +30)) 639 break; 603 if ((partition->part_type[3] == get_byte(gpt_ptypes[i].guid + 0)) && 604 (partition->part_type[2] == get_byte(gpt_ptypes[i].guid + 2)) && 605 (partition->part_type[1] == get_byte(gpt_ptypes[i].guid + 4)) && 606 (partition->part_type[0] == get_byte(gpt_ptypes[i].guid + 6)) && 607 (partition->part_type[5] == get_byte(gpt_ptypes[i].guid + 8)) && 608 (partition->part_type[4] == get_byte(gpt_ptypes[i].guid + 10)) && 609 (partition->part_type[7] == get_byte(gpt_ptypes[i].guid + 12)) && 610 (partition->part_type[6] == get_byte(gpt_ptypes[i].guid + 14)) && 611 (partition->part_type[8] == get_byte(gpt_ptypes[i].guid + 16)) && 612 (partition->part_type[9] == get_byte(gpt_ptypes[i].guid + 18)) && 613 (partition->part_type[10] == get_byte(gpt_ptypes[i].guid + 20)) && 614 (partition->part_type[11] == get_byte(gpt_ptypes[i].guid + 22)) && 615 (partition->part_type[12] == get_byte(gpt_ptypes[i].guid + 24)) && 616 (partition->part_type[13] == get_byte(gpt_ptypes[i].guid + 26)) && 617 (partition->part_type[14] == get_byte(gpt_ptypes[i].guid + 28)) && 618 (partition->part_type[15] == get_byte(gpt_ptypes[i].guid + 30))) 619 return i; 640 620 } 641 621 … … 643 623 } 644 624 645 /** Set partition type 646 * @param p partition to be set 647 * @param type partition type to set 648 * - see our fine selection at gpt_ptypes to choose from 649 */ 650 void gpt_set_part_type(gpt_part_t * p, size_t type) 625 /** Set partition type */ 626 void gpt_set_part_type(gpt_part_t *partition, size_t type) 651 627 { 652 628 /* Beware: first 3 blocks are byteswapped! */ 653 p ->part_type[3] = get_byte(gpt_ptypes[type].guid +0);654 p ->part_type[2] = get_byte(gpt_ptypes[type].guid +2);655 p ->part_type[1] = get_byte(gpt_ptypes[type].guid +4);656 p ->part_type[0] = get_byte(gpt_ptypes[type].guid +6);657 658 p ->part_type[5] = get_byte(gpt_ptypes[type].guid +8);659 p ->part_type[4] = get_byte(gpt_ptypes[type].guid +10);660 661 p ->part_type[7] = get_byte(gpt_ptypes[type].guid +12);662 p ->part_type[6] = get_byte(gpt_ptypes[type].guid +14);663 664 p ->part_type[8] = get_byte(gpt_ptypes[type].guid +16);665 p ->part_type[9] = get_byte(gpt_ptypes[type].guid +18);666 p ->part_type[10] = get_byte(gpt_ptypes[type].guid +20);667 p ->part_type[11] = get_byte(gpt_ptypes[type].guid +22);668 p ->part_type[12] = get_byte(gpt_ptypes[type].guid +24);669 p ->part_type[13] = get_byte(gpt_ptypes[type].guid +26);670 p ->part_type[14] = get_byte(gpt_ptypes[type].guid +28);671 p ->part_type[15] = get_byte(gpt_ptypes[type].guid +30);629 partition->part_type[3] = get_byte(gpt_ptypes[type].guid + 0); 630 partition->part_type[2] = get_byte(gpt_ptypes[type].guid + 2); 631 partition->part_type[1] = get_byte(gpt_ptypes[type].guid + 4); 632 partition->part_type[0] = get_byte(gpt_ptypes[type].guid + 6); 633 634 partition->part_type[5] = get_byte(gpt_ptypes[type].guid + 8); 635 partition->part_type[4] = get_byte(gpt_ptypes[type].guid + 10); 636 637 partition->part_type[7] = get_byte(gpt_ptypes[type].guid + 12); 638 partition->part_type[6] = get_byte(gpt_ptypes[type].guid + 14); 639 640 partition->part_type[8] = get_byte(gpt_ptypes[type].guid + 16); 641 partition->part_type[9] = get_byte(gpt_ptypes[type].guid + 18); 642 partition->part_type[10] = get_byte(gpt_ptypes[type].guid + 20); 643 partition->part_type[11] = get_byte(gpt_ptypes[type].guid + 22); 644 partition->part_type[12] = get_byte(gpt_ptypes[type].guid + 24); 645 partition->part_type[13] = get_byte(gpt_ptypes[type].guid + 26); 646 partition->part_type[14] = get_byte(gpt_ptypes[type].guid + 28); 647 partition->part_type[15] = get_byte(gpt_ptypes[type].guid + 30); 672 648 } 673 649 674 650 /** Get partition starting LBA */ 675 uint64_t gpt_get_start_lba(gpt_part_t * p)676 { 677 return uint64_t_le2host(p ->start_lba);651 uint64_t gpt_get_start_lba(gpt_part_t *partition) 652 { 653 return uint64_t_le2host(partition->start_lba); 678 654 } 679 655 680 656 /** Set partition starting LBA */ 681 void gpt_set_start_lba(gpt_part_t * p, uint64_t start)682 { 683 p ->start_lba = host2uint64_t_le(start);657 void gpt_set_start_lba(gpt_part_t *partition, uint64_t start) 658 { 659 partition->start_lba = host2uint64_t_le(start); 684 660 } 685 661 686 662 /** Get partition ending LBA */ 687 uint64_t gpt_get_end_lba(gpt_part_t * p)688 { 689 return uint64_t_le2host(p ->end_lba);663 uint64_t gpt_get_end_lba(gpt_part_t *partition) 664 { 665 return uint64_t_le2host(partition->end_lba); 690 666 } 691 667 692 668 /** Set partition ending LBA */ 693 void gpt_set_end_lba(gpt_part_t * p, uint64_t end)694 { 695 p ->end_lba = host2uint64_t_le(end);669 void gpt_set_end_lba(gpt_part_t *partition, uint64_t end) 670 { 671 partition->end_lba = host2uint64_t_le(end); 696 672 } 697 673 698 674 /** Get partition name */ 699 unsigned char * gpt_get_part_name(gpt_part_t * p)700 { 701 return p ->part_name;675 unsigned char * gpt_get_part_name(gpt_part_t *partition) 676 { 677 return partition->part_name; 702 678 } 703 679 704 680 /** Copy partition name */ 705 void gpt_set_part_name(gpt_part_t *p , char *name, size_t length)681 void gpt_set_part_name(gpt_part_t *partition, char *name, size_t length) 706 682 { 707 683 if (length >= 72) 708 684 length = 71; 709 710 memcpy(p ->part_name, name, length);711 p ->part_name[length] = '\0';685 686 memcpy(partition->part_name, name, length); 687 partition->part_name[length] = '\0'; 712 688 } 713 689 714 690 /** Get partition attribute */ 715 bool gpt_get_flag(gpt_part_t * p, GPT_ATTRflag)716 { 717 return (p ->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;691 bool gpt_get_flag(gpt_part_t *partition, gpt_attr_t flag) 692 { 693 return (partition->attributes & (((uint64_t) 1) << flag)) ? 1 : 0; 718 694 } 719 695 720 696 /** Set partition attribute */ 721 void gpt_set_flag(gpt_part_t * p, GPT_ATTRflag, bool value)722 { 723 uint64_t attr = p ->attributes;724 697 void gpt_set_flag(gpt_part_t *partition, gpt_attr_t flag, bool value) 698 { 699 uint64_t attr = partition->attributes; 700 725 701 if (value) 726 702 attr = attr | (((uint64_t) 1) << flag); 727 703 else 728 704 attr = attr ^ (attr & (((uint64_t) 1) << flag)); 729 730 p ->attributes = attr;705 706 partition->attributes = attr; 731 707 } 732 708 733 709 /** Generate a new pseudo-random UUID 734 * @param uuid Pointer to the UUID to overwrite. 735 */ 736 void gpt_set_random_uuid(uint8_t * uuid) 710 * 711 * FIXME: This UUID generator is not compliant with RFC 4122. 712 * 713 */ 714 void gpt_set_random_uuid(uint8_t *uuid) 737 715 { 738 716 srandom((unsigned int) (size_t) uuid); 739 717 740 unsigned int i; 741 for (i = 0; i < 16/sizeof(long int); ++i) 742 ((long int *)uuid)[i] = random(); 743 718 for (size_t i = 0; i < 16; i++) 719 uuid[i] = random(); 744 720 } 745 721 … … 747 723 uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment) 748 724 { 749 uint64_t div = addr / alignment; 750 return (div + 1) * alignment; 751 } 752 753 /* Internal functions follow */ 754 755 static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, size_t b_size, gpt_header_t * header) 756 { 757 int rc; 758 759 rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header); 725 return ALIGN_UP(addr + 1, alignment); 726 } 727 728 static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, 729 size_t block_size, gpt_header_t *header) 730 { 731 int rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header); 760 732 if (rc != EOK) 761 733 return rc; 762 763 unsigned int i; 734 764 735 /* Check the EFI signature */ 765 for ( i = 0; i < 8; ++i) {736 for (unsigned int i = 0; i < 8; i++) { 766 737 if (header->efi_signature[i] != efi_signature[i]) 767 738 return EINVAL; 768 739 } 769 740 770 741 /* Check the CRC32 of the header */ 771 742 uint32_t crc = header->header_crc32; 772 743 header->header_crc32 = 0; 744 773 745 if (crc != compute_crc32((uint8_t *) header, header->header_size)) 774 746 return EBADCHECKSUM; 775 747 else 776 748 header->header_crc32 = crc; 777 749 778 750 /* Check for zeroes in the rest of the block */ 779 for ( i = sizeof(gpt_header_t); i < b_size; ++i) {751 for (size_t i = sizeof(gpt_header_t); i < block_size; i++) { 780 752 if (((uint8_t *) header)[i] != 0) 781 753 return EINVAL; 782 754 } 783 755 784 756 return EOK; 785 757 } 786 758 787 static gpt_partitions_t * alloc_part_array(uint32_t num) 788 { 789 gpt_partitions_t * res = malloc(sizeof(gpt_partitions_t)); 790 if (res == NULL) { 791 errno = ENOMEM; 759 static gpt_partitions_t *alloc_part_array(uint32_t num) 760 { 761 gpt_partitions_t *res = malloc(sizeof(gpt_partitions_t)); 762 if (res == NULL) 792 763 return NULL; 793 }794 764 795 765 uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM; … … 797 767 if (res->part_array == NULL) { 798 768 free(res); 799 errno = ENOMEM;800 769 return NULL; 801 770 } … … 805 774 res->fill = 0; 806 775 res->arr_size = num; 807 776 808 777 return res; 809 778 } 810 779 811 static int extend_part_array(gpt_partitions_t * p)812 { 813 size_t nsize = p ->arr_size * 2;814 gpt_entry_t * tmp= malloc(nsize * sizeof(gpt_entry_t));815 if ( tmp == NULL) {816 errno =ENOMEM;817 return -1;818 }819 820 memcpy(tmp, p->part_array, p->fill * sizeof(gpt_entry_t));821 free(p->part_array);822 p ->part_array = tmp;823 p ->arr_size = nsize;824 825 return 0;826 } 827 828 static int reduce_part_array(gpt_partitions_t * p)829 { 830 if (p ->arr_size > GPT_MIN_PART_NUM) {831 unsigned int nsize = p ->arr_size / 2;780 static int extend_part_array(gpt_partitions_t *partition) 781 { 782 size_t nsize = partition->arr_size * 2; 783 gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t)); 784 if (entry == NULL) 785 return ENOMEM; 786 787 memcpy(entry, partition->part_array, partition->fill * 788 sizeof(gpt_entry_t)); 789 free(partition->part_array); 790 791 partition->part_array = entry; 792 partition->arr_size = nsize; 793 794 return EOK; 795 } 796 797 static int reduce_part_array(gpt_partitions_t *partition) 798 { 799 if (partition->arr_size > GPT_MIN_PART_NUM) { 800 unsigned int nsize = partition->arr_size / 2; 832 801 nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM; 833 gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t)); 834 if (tmp == NULL) 802 803 gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t)); 804 if (entry == NULL) 835 805 return ENOMEM; 836 837 memcpy( tmp, p->part_array, p->fill < nsize ? p->fill : nsize);838 free(p->part_array);839 p->part_array = tmp;840 p->arr_size = nsize;841 }842 843 return 0;844 } 845 846 /* Parse a byte from a string in hexadecimal 847 * i.e., "FF" => 255 848 */849 static uint8_t get_byte(const char * 806 807 memcpy(entry, partition->part_array, 808 partition->fill < nsize ? partition->fill : nsize); 809 free(partition->part_array); 810 811 partition->part_array = entry; 812 partition->arr_size = nsize; 813 } 814 815 return EOK; 816 } 817 818 /* Parse a byte from a string in hexadecimal */ 819 static uint8_t get_byte(const char *c) 850 820 { 851 821 uint8_t val = 0; 852 char hex[3] = {*c, *(c +1), 0};853 854 errno =str_uint8_t(hex, NULL, 16, false, &val);822 char hex[3] = {*c, *(c + 1), 0}; 823 824 str_uint8_t(hex, NULL, 16, false, &val); 855 825 return val; 856 826 } 857 827 858 static bool check_overlap(gpt_part_t * p1, gpt_part_t * p2) 859 { 860 if (gpt_get_start_lba(p1) < gpt_get_start_lba(p2) && gpt_get_end_lba(p1) < gpt_get_start_lba(p2)) { 828 static bool check_overlap(gpt_part_t *part1, gpt_part_t *part2) 829 { 830 if ((gpt_get_start_lba(part1) < gpt_get_start_lba(part2)) && 831 (gpt_get_end_lba(part1) < gpt_get_start_lba(part2))) 861 832 return false; 862 } else if (gpt_get_start_lba(p1) > gpt_get_start_lba(p2) && gpt_get_end_lba(p2) < gpt_get_start_lba(p1)) { 833 834 if ((gpt_get_start_lba(part1) > gpt_get_start_lba(part2)) && 835 (gpt_get_end_lba(part2) < gpt_get_start_lba(part1))) 863 836 return false; 864 } 865 837 866 838 return true; 867 839 } 868 840 869 static bool check_encaps(gpt_part_t *p, uint64_t n_blocks, uint64_t first_lba) 870 { 871 /* 872 * We allow "<=" in the second expression because it lacks MBR so 873 * it's by 1 block smaller. 841 static bool check_encaps(gpt_part_t *part, uint64_t blocks, 842 uint64_t first_lba) 843 { 844 /* 845 * We allow "<=" in the second expression because it lacks 846 * MBR so it is smaller by 1 block. 874 847 */ 875 if (gpt_get_start_lba(p) >= first_lba && gpt_get_end_lba(p) <= n_blocks - first_lba) 848 if ((gpt_get_start_lba(part) >= first_lba) && 849 (gpt_get_end_lba(part) <= blocks - first_lba)) 876 850 return true; 877 851
Note:
See TracChangeset
for help on using the changeset viewer.