Changeset dc76f4a in mainline for uspace/lib/gpt/libgpt.c


Ignore:
Timestamp:
2013-07-29T00:48:51Z (11 years ago)
Author:
Dominik Taborsky (AT DOT) <brembyseznamcz>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
675de6d
Parents:
c3cbbb2
Message:

libmbr, libgpt polishing

File:
1 edited

Legend:

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

    rc3cbbb2 rdc76f4a  
    5151#include "libgpt.h"
    5252
    53 static int load_and_check_header(service_id_t handle, aoff64_t addr, size_t b_size, gpt_header_t *header);
    54 static gpt_partitions_t * alloc_part_array(uint32_t num);
     53static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *);
     54static gpt_partitions_t * alloc_part_array(uint32_t);
    5555static int extend_part_array(gpt_partitions_t *);
    5656static int reduce_part_array(gpt_partitions_t *);
    57 static long long nearest_larger_int(double a);
     57//static long long nearest_larger_int(double);
    5858static uint8_t get_byte(const char *);
    59 static int check_overlap(gpt_part_t * p1, gpt_part_t * p2);
     59static bool check_overlap(gpt_part_t *, gpt_part_t *);
    6060
    6161/** Allocate memory for gpt label */
     
    6666                return NULL;
    6767       
     68        /* This is necessary so that gpt_part_foreach does not segfault */
     69        label->parts = gpt_alloc_partitions();
     70        if (label == NULL) {
     71                free(label);
     72                return NULL;
     73        }
     74       
    6875        label->gpt = NULL;
    69         label->parts = NULL;
     76       
    7077        label->device = 0;
    7178       
     
    9299                return NULL;
    93100       
    94         // We might need only sizeof(gpt_header_t),
    95         // but we should follow specs and have
    96         // zeroes through all the rest of the block
     101        /*
     102         * We might need only sizeof(gpt_header_t), but we should follow
     103         * specs and have zeroes through all the rest of the block
     104         */
    97105        size_t final_size = size > sizeof(gpt_header_t) ? size : sizeof(gpt_header_t);
    98106        gpt->header = malloc(final_size);
     
    178186        int rc;
    179187        size_t b_size;
    180 
    181         label->gpt->header->header_crc32 = 0;
    182         label->gpt->header->header_crc32 = compute_crc32((uint8_t *) label->gpt->header,
    183                                         uint32_t_le2host(label->gpt->header->header_size));
    184 
    185         rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
     188       
     189        /* The comm_size argument (the last one) is ignored */
     190        rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
    186191        if (rc != EOK && rc != EEXIST)
    187192                return rc;
    188 
     193       
    189194        rc = block_get_bsize(dev_handle, &b_size);
    190195        if (rc != EOK)
    191196                return rc;
    192 
    193         /* Write to main GPT header location */
    194         rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
    195         if (rc != EOK) {
    196                 block_fini(dev_handle);
    197                 return rc;
    198         }
    199 
     197       
    200198        aoff64_t n_blocks;
    201199        rc = block_get_nblocks(dev_handle, &n_blocks);
     
    204202                return rc;
    205203        }
    206 
     204       
     205        uint64_t tmp;
     206       
     207        /* Prepare the backup header */
     208        label->gpt->header->alternate_lba = label->gpt->header->my_lba;
     209        label->gpt->header->my_lba = host2uint64_t_le(n_blocks - 1);
     210       
     211        tmp = label->gpt->header->entry_lba;
     212        label->gpt->header->entry_lba = host2uint64_t_le(n_blocks -
     213            (uint32_t_le2host(label->gpt->header->fillries) * sizeof(gpt_entry_t))
     214            / b_size - 1);
     215       
     216        label->gpt->header->header_crc32 = 0;
     217        label->gpt->header->header_crc32 = host2uint32_t_le(
     218            compute_crc32((uint8_t *) label->gpt->header,
     219                uint32_t_le2host(label->gpt->header->header_size)));
     220       
    207221        /* Write to backup GPT header location */
    208         //FIXME: those idiots thought it would be cool to have these fields in reverse order...
    209222        rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, label->gpt->header);
     223        if (rc != EOK) {
     224                block_fini(dev_handle);
     225                return rc;
     226        }
     227       
     228       
     229        /* Prepare the main header */
     230        label->gpt->header->entry_lba = tmp;
     231       
     232        tmp = label->gpt->header->alternate_lba;
     233        label->gpt->header->alternate_lba = label->gpt->header->my_lba;
     234        label->gpt->header->my_lba = tmp;
     235       
     236        label->gpt->header->header_crc32 = 0;
     237        label->gpt->header->header_crc32 = host2uint32_t_le(
     238            compute_crc32((uint8_t *) label->gpt->header,
     239                uint32_t_le2host(label->gpt->header->header_size)));
     240       
     241        /* Write to main GPT header location */
     242        rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
    210243        block_fini(dev_handle);
    211244        if (rc != EOK)
    212245                return rc;
    213 
     246       
     247       
    214248        return 0;
    215249}
     
    218252gpt_partitions_t * gpt_alloc_partitions()
    219253{
    220         return alloc_part_array(128);
     254        return alloc_part_array(GPT_MIN_PART_NUM);
    221255}
    222256
     
    241275        }
    242276
    243         /* We can limit comm_size like this:
    244          *  - we don't need more bytes
    245          *  - the size of GPT partition entry can be different to 128 bytes */
    246277        /* comm_size is ignored */
    247278        rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t));
     
    258289        aoff64_t pos = ent_lba * block_size;
    259290
    260         /* Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
     291        /*
     292         * Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
    261293         * Hopefully, this does not bypass cache (no mention in libblock.c),
    262294         * and also allows us to have variable partition entry size (but we
    263295         * will always read just sizeof(gpt_entry_t) bytes - hopefully they
    264          * don't break backward compatibility) */
     296         * don't break backward compatibility)
     297         */
    265298        for (i = 0; i < fillries; ++i) {
    266                 //FIXME: this does bypass cache...
     299                /*FIXME: this does bypass cache... */
    267300                rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), label->parts->part_array + i);
    268                 //FIXME: but seqread() is just too complex...
    269                 //rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
     301                /*
     302                 * FIXME: but seqread() is just too complex...
     303                 * rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
     304                 */
    270305                pos += ent_size;
    271306
     
    274309        }
    275310
    276         /* FIXME: so far my boasting about variable partition entry size
     311        /*
     312         * FIXME: so far my boasting about variable partition entry size
    277313         * will not work. The CRC32 checksums will be different.
    278314         * This can't be fixed easily - we'd have to run the checksum
     
    333369                goto fail;
    334370       
     371        uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / b_size;
     372        label->gpt->header->first_usable_lba = host2uint64_t_le(arr_blocks + 1);
     373        label->gpt->header->last_usable_lba = host2uint64_t_le(n_blocks - arr_blocks - 2);
     374       
     375       
    335376        /* Write to backup GPT partition array location */
    336         //rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, header->raw_data);
     377        rc = block_write_direct(dev_handle, n_blocks - arr_blocks - 1,
     378                 arr_blocks, label->parts->part_array);
    337379        if (rc != EOK)
    338380                goto fail;
     
    340382        /* Write to main GPT partition array location */
    341383        rc = block_write_direct(dev_handle, uint64_t_le2host(label->gpt->header->entry_lba),
    342                  nearest_larger_int((uint64_t_le2host(label->gpt->header->entry_size) * fillries) / b_size),
    343                  label->parts->part_array);
     384                 arr_blocks, label->parts->part_array);
    344385        if (rc != EOK)
    345386                goto fail;
     
    442483int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
    443484{
    444         if (label->parts->fill == label->parts->arr_size) {
    445                 if (extend_part_array(label->parts) == -1)
    446                         return ENOMEM;
    447         }
    448        
    449         /*FIXME:
    450          * Check dimensions and stuff! */
     485        /* FIXME: Check dimensions! */
    451486        gpt_part_foreach(label, p) {
    452487                if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
     
    456491        }
    457492       
    458         memcpy(label->parts->part_array + label->parts->fill++,
    459                partition, sizeof(gpt_part_t));
    460        
     493        gpt_part_t *p;
     494        /* Find the first empty entry */
     495        do {
     496                if (label->parts->fill == label->parts->arr_size) {
     497                        if (extend_part_array(label->parts) == -1)
     498                                return ENOMEM;
     499                }
     500               
     501                p = label->parts->part_array + label->parts->fill++;
     502               
     503        } while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
     504       
     505       
     506        memcpy(p, partition, sizeof(gpt_entry_t));
    461507       
    462508       
     
    475521int gpt_remove_partition(gpt_label_t *label, size_t idx)
    476522{
    477         if (idx >= label->parts->fill)
     523        if (idx >= label->parts->arr_size)
    478524                return EINVAL;
    479525       
    480         /* FIXME!
     526        /*
     527         * FIXME!
    481528         * If we allow blank spots, we break the array. If we have more than
    482529         * 128 partitions in the array and then remove something from
    483          * the first 128 partitions, we would forget to write the last one.*/
     530         * the first 128 partitions, we would forget to write the last one.
     531         */
    484532        memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
    485533       
    486         label->parts->fill = idx;
    487        
    488         /* FIXME! HOPEFULLY FIXED.
     534        if (label->parts->fill > idx)
     535                label->parts->fill = idx;
     536       
     537        /*
     538         * FIXME! HOPEFULLY FIXED.
    489539         * We cannot reduce the array so simply. We may have some partitions
    490          * there since we allow blank spots. */
     540         * there since we allow blank spots.
     541         */
    491542        gpt_part_t * p;
    492         if (label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
     543       
     544        if (label->parts->fill > GPT_MIN_PART_NUM &&
     545            label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
    493546                for (p = gpt_get_partition_at(label, label->parts->arr_size / 2);
    494547                     p < label->parts->part_array + label->parts->arr_size; ++p) {
     
    635688}
    636689
     690/** Generate a new pseudo-random UUID
     691 * @param uuid Pointer to the UUID to overwrite.
     692 */
    637693void gpt_set_random_uuid(uint8_t * uuid)
    638694{
     
    645701}
    646702
    647 // Internal functions follow //
     703/** Get next aligned address */
     704uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment)
     705{
     706        uint64_t div = addr / alignment;
     707        return (div + 1) * alignment;
     708}
     709
     710/* Internal functions follow */
    648711
    649712static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, size_t b_size, gpt_header_t * header)
     
    686749                return NULL;
    687750        }
    688 
     751       
    689752        uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
    690753        res->part_array = malloc(size * sizeof(gpt_entry_t));
     
    694757                return NULL;
    695758        }
    696 
     759       
     760        memset(res->part_array, 0, size * sizeof(gpt_entry_t));
     761       
    697762        res->fill = 0;
    698763        res->arr_size = num;
     
    727792                        return ENOMEM;
    728793
    729                 memcpy(tmp, p->part_array, p->fill < nsize ? p->fill  : nsize);
     794                memcpy(tmp, p->part_array, p->fill < nsize ? p->fill : nsize);
    730795                free(p->part_array);
    731796                p->part_array = tmp;
     
    736801}
    737802
    738 //FIXME: replace this with a library call, if it exists
    739 static long long nearest_larger_int(double a)
     803/*static long long nearest_larger_int(double a)
    740804{
    741805        if ((long long) a == a) {
     
    744808
    745809        return ((long long) a) + 1;
    746 }
    747 
     810}*/
     811
     812/* Parse a byte from a string in hexadecimal
     813 * i.e., "FF" => 255
     814 */
    748815static uint8_t get_byte(const char * c)
    749816{
     
    755822}
    756823
    757 static int check_overlap(gpt_part_t * p1, gpt_part_t * p2)
     824static bool check_overlap(gpt_part_t * p1, gpt_part_t * p2)
    758825{
    759826        if (gpt_get_start_lba(p1) < gpt_get_start_lba(p2) && gpt_get_end_lba(p1) <= gpt_get_start_lba(p2)) {
    760                 return 0;
     827                return false;
    761828        } else if (gpt_get_start_lba(p1) > gpt_get_start_lba(p2) && gpt_get_end_lba(p2) <= gpt_get_start_lba(p1)) {
    762                 return 0;
    763         }
    764 
    765         return 1;
    766 }
    767 
    768 
     829                return false;
     830        }
     831
     832        return true;
     833}
     834
     835
Note: See TracChangeset for help on using the changeset viewer.