Changeset 6453e306 in mainline for uspace/lib/gpt/libgpt.c


Ignore:
Timestamp:
2013-12-25T16:09:43Z (11 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ac36aed
Parents:
d51beba3
Message:

basic code review and coding style cleanup

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/gpt/libgpt.c

    rd51beba3 r6453e306  
    11/*
    2  * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
     2 * Copyright (c) 2011-2013 Dominik Taborsky
    33 * All rights reserved.
    44 *
     
    3434
    3535/* TODO:
    36  * This implementation only supports fixed size partition entries. Specification
    37  * 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.
    3838 */
    3939
     
    4646#include <assert.h>
    4747#include <byteorder.h>
    48 #include <checksum.h>
     48#include <adt/checksum.h>
    4949#include <mem.h>
    5050#include <sys/typefmt.h>
    5151#include <mbr.h>
    52 
    53 
     52#include <align.h>
    5453#include "libgpt.h"
    5554
    5655static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *);
    57 static gpt_partitions_t * alloc_part_array(uint32_t);
     56static gpt_partitions_t *alloc_part_array(uint32_t);
    5857static int extend_part_array(gpt_partitions_t *);
    5958static int reduce_part_array(gpt_partitions_t *);
     
    6261static bool check_encaps(gpt_part_t *, uint64_t, uint64_t);
    6362
    64 /** Allocate memory for gpt label */
    65 gpt_label_t * gpt_alloc_label(void)
     63/** Allocate a GPT label */
     64gpt_label_t *gpt_alloc_label(void)
    6665{
    6766        gpt_label_t *label = malloc(sizeof(gpt_label_t));
     
    6968                return NULL;
    7069       
    71         /* This is necessary so that gpt_part_foreach does not segfault */
    7270        label->parts = gpt_alloc_partitions();
    73         if (label == NULL) {
     71        if (label->parts == NULL) {
    7472                free(label);
    7573                return NULL;
     
    7775       
    7876        label->gpt = NULL;
    79        
    8077        label->device = 0;
    8178       
     
    8380}
    8481
    85 /** Free gpt_label_t structure */
     82/** Free a GPT label */
    8683void gpt_free_label(gpt_label_t *label)
    8784{
     
    9592}
    9693
    97 /** Allocate memory for gpt header */
    98 gpt_t * gpt_alloc_header(size_t size)
     94/** Allocate a GPT header */
     95gpt_t *gpt_alloc_header(size_t size)
    9996{
    10097        gpt_t *gpt = malloc(sizeof(gpt_t));
     
    10299                return NULL;
    103100       
    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
    106103         * specs and have zeroes through all the rest of the block
    107104         */
    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));
    109106        gpt->header = malloc(final_size);
    110107        if (gpt->header == NULL) {
     
    113110        }
    114111       
    115         /* Enter some sane defaults. */
    116112        memset(gpt->header, 0, final_size);
    117113        memcpy(gpt->header->efi_signature, efi_signature, 8);
     
    121117        gpt->header->entry_size = host2uint32_t_le(sizeof(gpt_entry_t));
    122118       
    123        
    124119        return gpt;
    125120}
    126121
    127 /** free() GPT header including gpt->header_lba */
     122/** Free a GPT header */
    128123void gpt_free_gpt(gpt_t *gpt)
    129124{
     
    132127}
    133128
    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 *
    139136 */
    140137int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
    141138{
    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;
    152147       
    153148        if (label->gpt == NULL) {
    154                 label->gpt = gpt_alloc_header(b_size);
     149                label->gpt = gpt_alloc_header(block_size);
    155150                if (label->gpt == NULL) {
    156151                        rc = ENOMEM;
    157                         goto fini_fail;
     152                        goto end;
    158153                }
    159154        }
    160155       
    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                }
    171172        }
    172173       
    173174        label->device = dev_handle;
     175        rc = EOK;
     176       
     177end:
    174178        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:
    183179        return rc;
    184180}
    185181
    186182/** Write GPT header to device
    187  * @param label        GPT label header to be written
    188  * @param dev_handle   device handle to write the data to
    189  *
    190  * @return             EOK on success, libblock error code otherwise
    191  *
    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 *
    193189 */
    194190int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
    195191{
    196         int rc;
    197         size_t b_size;
    198        
    199192        /* 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))
    202195                return rc;
    203196       
    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;
    216206       
    217207        gpt_set_random_uuid(label->gpt->header->disk_guid);
    218208       
    219209        /* 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);
    227217       
    228218        label->gpt->header->header_crc32 = 0;
    229         label->gpt->header->header_crc32 = host2uint32_t_le(
    230             compute_crc32((uint8_t *) label->gpt->header,
    231                 uint32_t_le2host(label->gpt->header->header_size)));
     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)));
    232222       
    233223        /* 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;
    240228       
    241229        /* 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;
    247235       
    248236        label->gpt->header->header_crc32 = 0;
    249         label->gpt->header->header_crc32 = host2uint32_t_le(
    250             compute_crc32((uint8_t *) label->gpt->header,
    251                 uint32_t_le2host(label->gpt->header->header_size)));
     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)));
    252240       
    253241        /* 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;
    257246       
    258247        /* Write Protective MBR */
    259248        br_block_t mbr;
    260249        memset(&mbr, 0, 512);
     250       
    261251        memset(mbr.pte[0].first_chs, 1, 3);
    262252        mbr.pte[0].ptype = 0xEE;
    263         memset(mbr.pte[0].last_chs, 0xFF, 3);
     253        memset(mbr.pte[0].last_chs, 0xff, 3);
    264254        mbr.pte[0].first_lba = host2uint32_t_le(1);
    265         mbr.pte[0].length = 0xFFFFFFFF;
     255        mbr.pte[0].length = 0xffffffff;
    266256        mbr.signature = host2uint16_t_le(BR_SIGNATURE);
    267257       
    268258        rc = block_write_direct(dev_handle, 0, 1, &mbr);
     259       
     260end:
    269261        block_fini(dev_handle);
    270         if (rc != EOK)
    271                 return rc;
    272        
    273         return 0;
     262        return rc;
    274263}
    275264
    276265/** Alloc partition array */
    277 gpt_partitions_t * gpt_alloc_partitions()
     266gpt_partitions_t *gpt_alloc_partitions(void)
    278267{
    279268        return alloc_part_array(GPT_MIN_PART_NUM);
     
    281270
    282271/** 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 *
    286277 */
    287278int gpt_read_partitions(gpt_label_t *label)
    288279{
    289         int rc;
    290         unsigned int i;
    291280        uint32_t fillries = uint32_t_le2host(label->gpt->header->fillries);
    292281        uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size);
     
    295284        if (label->parts == NULL) {
    296285                label->parts = alloc_part_array(fillries);
    297                 if (label->parts == NULL) {
     286                if (label->parts == NULL)
    298287                        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       
    307298        size_t block_size;
    308299        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       
    312306        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);
    328311                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) {
    339324                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       
     332end:
    343333        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;
    352334        return rc;
    353335}
    354336
    355337/** 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 *
    361346 */
    362347int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
    363348{
    364         int rc;
    365         size_t b_size;
    366        
    367349        /* 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))
    370352                return rc;
    371353       
    372         rc = block_get_bsize(dev_handle, &b_size);
     354        size_t block_size;
     355        rc = block_get_bsize(dev_handle, &block_size);
    373356        if (rc != EOK)
    374357                goto fail;
    375358       
    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);
    378361        if (rc != EOK)
    379362                goto fail;
    380363       
    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))
    391373                return ENOTSUP;
    392 
     374       
    393375        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       
    396382        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);
    398385       
    399386        /* Perform checks */
     
    402389                        continue;
    403390               
    404                 if (!check_encaps(p, n_blocks, gpt_space)) {
     391                if (!check_encaps(p, blocks, gpt_space)) {
    405392                        rc = ERANGE;
    406393                        goto fail;
     
    420407        }
    421408       
    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));
    426412       
    427413        /* Write to backup GPT partition array location */
    428         rc = block_write_direct(dev_handle, n_blocks - arr_blocks - 1,
    429                  arr_blocks, label->parts->part_array);
     414        rc = block_write_direct(dev_handle, blocks - arr_blocks - 1,
     415            arr_blocks, label->parts->part_array);
    430416        if (rc != EOK)
    431417                goto fail;
    432418       
    433419        /* 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);
    436423        if (rc != EOK)
    437424                goto fail;
     
    444431}
    445432
    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().
    451436 * This returns a memory block (zero-filled) and needs gpt_add_partition()
    452437 * to be called to insert it into a partition array.
    453438 * 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 */
     443gpt_part_t *gpt_alloc_partition(void)
     444{
     445        gpt_part_t *partition = malloc(sizeof(gpt_part_t));
     446        if (partition == NULL)
    459447                return NULL;
    460448       
    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().
    473457 * This one returns a pointer to the first empty structure already
    474458 * inside the array, so don't call gpt_add_partition() afterwards.
    475459 * 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 */
     466gpt_part_t *gpt_get_partition(gpt_label_t *label)
     467{
     468        gpt_part_t *partition;
    481469       
    482470        /* Find the first empty entry */
     
    487475                }
    488476               
    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;
    494481}
    495482
    496483/** Get partition already inside the label
    497484 *
    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.
    506487 * This returns a pointer to a structure already inside the array,
    507488 * so don't call gpt_add_partition() afterwards.
     
    510491 * for indexes smaller than either 128 or the actual number of filled
    511492 * 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 */
     500gpt_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))
    518503                return NULL;
    519504       
     
    523508/** Copy partition into partition array
    524509 *
    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
    531511 * 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 *
    533519 */
    534520int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
    535521{
    536         gpt_part_t *p;
    537522        /* Find the first empty entry */
     523       
     524        gpt_part_t *part;
     525       
    538526        do {
    539527                if (label->parts->fill == label->parts->arr_size) {
     
    542530                }
    543531               
    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));
    552536        return EOK;
    553537}
    554538
    555539/** 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
    562542 * 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 *
    563549 */
    564550int gpt_remove_partition(gpt_label_t *label, size_t idx)
     
    567553                return EINVAL;
    568554       
    569         /* 
    570          * FIXME!
     555        /*
     556         * FIXME:
    571557         * If we allow blank spots, we break the array. If we have more than
    572558         * 128 partitions in the array and then remove something from
    573559         * the first 128 partitions, we would forget to write the last one.
    574560         */
     561       
    575562        memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
    576563       
     
    578565                label->parts->fill = idx;
    579566       
    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;
    593577                }
    594578               
     
    596580                        return ENOMEM;
    597581        }
    598 
     582       
    599583        return EOK;
    600584}
     
    602586/** Free partition list
    603587 *
    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 */
     591void gpt_free_partitions(gpt_partitions_t *parts)
    607592{
    608593        free(parts->part_array);
     
    610595}
    611596
    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 */
     598size_t gpt_get_part_type(gpt_part_t *partition)
    616599{
    617600        size_t i;
    618601       
    619602        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;
    640620        }
    641621       
     
    643623}
    644624
    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 */
     626void gpt_set_part_type(gpt_part_t *partition, size_t type)
    651627{
    652628        /* 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);
    672648}
    673649
    674650/** Get partition starting LBA */
    675 uint64_t gpt_get_start_lba(gpt_part_t * p)
    676 {
    677         return uint64_t_le2host(p->start_lba);
     651uint64_t gpt_get_start_lba(gpt_part_t *partition)
     652{
     653        return uint64_t_le2host(partition->start_lba);
    678654}
    679655
    680656/** 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);
     657void gpt_set_start_lba(gpt_part_t *partition, uint64_t start)
     658{
     659        partition->start_lba = host2uint64_t_le(start);
    684660}
    685661
    686662/** Get partition ending LBA */
    687 uint64_t gpt_get_end_lba(gpt_part_t * p)
    688 {
    689         return uint64_t_le2host(p->end_lba);
     663uint64_t gpt_get_end_lba(gpt_part_t *partition)
     664{
     665        return uint64_t_le2host(partition->end_lba);
    690666}
    691667
    692668/** 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);
     669void gpt_set_end_lba(gpt_part_t *partition, uint64_t end)
     670{
     671        partition->end_lba = host2uint64_t_le(end);
    696672}
    697673
    698674/** Get partition name */
    699 unsigned char * gpt_get_part_name(gpt_part_t * p)
    700 {
    701         return p->part_name;
     675unsigned char * gpt_get_part_name(gpt_part_t *partition)
     676{
     677        return partition->part_name;
    702678}
    703679
    704680/** Copy partition name */
    705 void gpt_set_part_name(gpt_part_t *p, char *name, size_t length)
     681void gpt_set_part_name(gpt_part_t *partition, char *name, size_t length)
    706682{
    707683        if (length >= 72)
    708684                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';
    712688}
    713689
    714690/** Get partition attribute */
    715 bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
    716 {
    717         return (p->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
     691bool gpt_get_flag(gpt_part_t *partition, gpt_attr_t flag)
     692{
     693        return (partition->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
    718694}
    719695
    720696/** Set partition attribute */
    721 void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
    722 {
    723         uint64_t attr = p->attributes;
    724 
     697void gpt_set_flag(gpt_part_t *partition, gpt_attr_t flag, bool value)
     698{
     699        uint64_t attr = partition->attributes;
     700       
    725701        if (value)
    726702                attr = attr | (((uint64_t) 1) << flag);
    727703        else
    728704                attr = attr ^ (attr & (((uint64_t) 1) << flag));
    729 
    730         p->attributes = attr;
     705       
     706        partition->attributes = attr;
    731707}
    732708
    733709/** 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 */
     714void gpt_set_random_uuid(uint8_t *uuid)
    737715{
    738716        srandom((unsigned int) (size_t) uuid);
    739717       
    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();
    744720}
    745721
     
    747723uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment)
    748724{
    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
     728static 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);
    760732        if (rc != EOK)
    761733                return rc;
    762 
    763         unsigned int i;
     734       
    764735        /* Check the EFI signature */
    765         for (i = 0; i < 8; ++i) {
     736        for (unsigned int i = 0; i < 8; i++) {
    766737                if (header->efi_signature[i] != efi_signature[i])
    767738                        return EINVAL;
    768739        }
    769 
     740       
    770741        /* Check the CRC32 of the header */
    771742        uint32_t crc = header->header_crc32;
    772743        header->header_crc32 = 0;
     744       
    773745        if (crc != compute_crc32((uint8_t *) header, header->header_size))
    774746                return EBADCHECKSUM;
    775747        else
    776748                header->header_crc32 = crc;
    777 
     749       
    778750        /* 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++) {
    780752                if (((uint8_t *) header)[i] != 0)
    781753                        return EINVAL;
    782754        }
    783 
     755       
    784756        return EOK;
    785757}
    786758
    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;
     759static gpt_partitions_t *alloc_part_array(uint32_t num)
     760{
     761        gpt_partitions_t *res = malloc(sizeof(gpt_partitions_t));
     762        if (res == NULL)
    792763                return NULL;
    793         }
    794764       
    795765        uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
     
    797767        if (res->part_array == NULL) {
    798768                free(res);
    799                 errno = ENOMEM;
    800769                return NULL;
    801770        }
     
    805774        res->fill = 0;
    806775        res->arr_size = num;
    807 
     776       
    808777        return res;
    809778}
    810779
    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;
     780static 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
     797static 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;
    832801                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)
    835805                        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 * c)
     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 */
     819static uint8_t get_byte(const char *c)
    850820{
    851821        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);
    855825        return val;
    856826}
    857827
    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)) {
     828static 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)))
    861832                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)))
    863836                return false;
    864         }
    865 
     837       
    866838        return true;
    867839}
    868840
    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.
     841static 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.
    874847         */
    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))
    876850                return true;
    877851       
Note: See TracChangeset for help on using the changeset viewer.