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


Ignore:
Timestamp:
2013-04-20T01:13:44Z (12 years ago)
Author:
Dominik Taborsky (AT DOT) <brembyseznamcz>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8f6c7785
Parents:
e91d17a
Message:

mbr && gpt fix

File:
1 edited

Legend:

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

    re91d17a rd617050  
    5656static int reduce_part_array(gpt_partitions_t * p);
    5757static long long nearest_larger_int(double a);
     58static int gpt_memcmp(const void * a, const void * b, size_t len);
    5859
    5960/** Read GPT from specific device
    6061 * @param       dev_handle      device to read GPT from
    61  * 
     62 *
    6263 * @return                              GPT record on success, NULL on error
    6364 */
     
    6667        int rc;
    6768        size_t b_size;
    68        
     69
    6970        rc = block_get_bsize(dev_handle, &b_size);
    7071        if (rc != EOK) {
     
    7273                return NULL;
    7374        }
    74        
     75
    7576        gpt_t * gpt = malloc(sizeof(gpt_t));
    7677        if (gpt == NULL) {
     
    7879                return NULL;
    7980        }
    80        
     81
    8182        gpt->raw_data = malloc(b_size);// We might need only sizeof(gpt_header_t),
    82         if (gpt == NULL) {                              // but we should follow specs and have 
     83        if (gpt == NULL) {                              // but we should follow specs and have
    8384                free(gpt);                                      // zeroes through all the rest of the block
    8485                errno = ENOMEM;
    8586                return NULL;
    8687        }
    87        
    88        
     88
     89
    8990        rc = load_and_check_header(dev_handle, GPT_HDR_BA, b_size, gpt->raw_data);
    9091        if (rc == EBADCHECKSUM || rc == EINVAL) {
     
    9596                        goto fail;
    9697                }
    97                
     98
    9899                rc = load_and_check_header(dev_handle, n_blocks - 1, b_size, gpt->raw_data);
    99100                if (rc == EBADCHECKSUM || rc == EINVAL) {
     
    102103                }
    103104        }
    104        
     105
    105106        gpt->device = dev_handle;
    106        
     107
    107108        return gpt;
    108109
     
    115116 * @param header                GPT header to be written
    116117 * @param dev_handle    device handle to write the data to
    117  * 
     118 *
    118119 * @return                              0 on success, libblock error code otherwise
    119  * 
     120 *
    120121 * Note: Firstly write partitions (if changed), then gpt header.
    121122 */
     
    124125        int rc;
    125126        size_t b_size;
    126        
     127
    127128        gpt->raw_data->header_crc32 = 0;
    128129        gpt->raw_data->header_crc32 = compute_crc32((uint8_t *) gpt->raw_data,
    129130                                        uint32_t_le2host(gpt->raw_data->header_size));
    130        
     131
    131132        rc = block_get_bsize(dev_handle, &b_size);
    132133        if (rc != EOK)
    133134                return rc;
    134        
     135
    135136        rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
    136137        if (rc != EOK)
    137138                return rc;
    138        
     139
    139140        /* Write to main GPT header location */
    140141        rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, gpt->raw_data);
     
    142143                block_fini(dev_handle);
    143144                return rc;
    144        
     145
    145146        aoff64_t n_blocks;
    146147        rc = block_get_nblocks(dev_handle, &n_blocks);
    147148        if (rc != EOK)
    148149                return rc;
    149        
     150
    150151        /* Write to backup GPT header location */
    151152        //FIXME: those idiots thought it would be cool to have these fields in reverse order...
     
    154155        if (rc != EOK)
    155156                return rc;
    156                
     157
    157158        return 0;
    158159}
     
    160161/** Parse partitions from GPT
    161162 * @param gpt   GPT to be parsed
    162  * 
     163 *
    163164 * @return              partition linked list pointer or NULL on error
    164165 *                              error code is stored in errno
     
    172173        uint32_t ent_size = uint32_t_le2host(gpt->raw_data->entry_size);
    173174        uint64_t ent_lba = uint64_t_le2host(gpt->raw_data->entry_lba);
    174        
     175
    175176        res = alloc_part_array(fill);
    176177        if (res == NULL) {
     
    178179                return NULL;
    179180        }
    180        
     181
    181182        /* We can limit comm_size like this:
    182183         *  - we don't need more bytes
     
    188189                return NULL;
    189190        }
    190        
     191
    191192        size_t block_size;
    192193        rc = block_get_bsize(gpt->device, &block_size);
     
    196197                return NULL;
    197198        }
    198        
     199
    199200        //size_t bufpos = 0;
    200201        //size_t buflen = 0;
    201202        aoff64_t pos = ent_lba * block_size;
    202        
     203
    203204        /* Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
    204205         * Hopefully, this does not bypass cache (no mention in libblock.c),
     
    212213                //rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
    213214                pos += ent_size;
    214                
     215
    215216                if (rc != EOK) {
    216217                        gpt_free_partitions(res);
     
    219220                }
    220221        }
    221        
     222
    222223        /* FIXME: so far my boasting about variable partition entry size
    223224         * will not work. The CRC32 checksums will be different.
     
    226227         */
    227228        uint32_t crc = compute_crc32((uint8_t *) res->part_array, res->fill * sizeof(gpt_entry_t));
    228        
     229
    229230        if(uint32_t_le2host(gpt->raw_data->pe_array_crc32) != crc)
    230231        {
     
    233234                return NULL;
    234235        }
    235        
     236
    236237        return res;
    237238}
     
    241242 * @param header                GPT header belonging to the 'parts' partitions
    242243 * @param dev_handle    device to write the data to
    243  * 
     244 *
    244245 * @return                              returns EOK on succes, specific error code otherwise
    245246 */
     
    248249        int rc;
    249250        size_t b_size;
    250        
     251
    251252        gpt->raw_data->pe_array_crc32 = compute_crc32((uint8_t *) parts->part_array, parts->fill * gpt->raw_data->entry_size);
    252        
     253
    253254        rc = block_get_bsize(dev_handle, &b_size);
    254255        if (rc != EOK)
    255256                return rc;
    256        
     257
    257258        rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
    258259        if (rc != EOK)
    259260                return rc;
    260        
     261
    261262        /* Write to main GPT partition array location */
    262         rc = block_write_direct(dev_handle, uint64_t_le2host(gpt->raw_data->entry_lba), 
    263                         nearest_larger_int((uint64_t_le2host(gpt->raw_data->entry_size) * parts->fill) / b_size), 
     263        rc = block_write_direct(dev_handle, uint64_t_le2host(gpt->raw_data->entry_lba),
     264                        nearest_larger_int((uint64_t_le2host(gpt->raw_data->entry_size) * parts->fill) / b_size),
    264265                        parts->part_array);
    265266        if (rc != EOK)
    266267                block_fini(dev_handle);
    267268                return rc;
    268        
     269
    269270        aoff64_t n_blocks;
    270271        rc = block_get_nblocks(dev_handle, &n_blocks);
    271272        if (rc != EOK)
    272273                return rc;
    273        
     274
    274275        /* Write to backup GPT partition array location */
    275276        //rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, header->raw_data);
     
    277278        if (rc != EOK)
    278279                return rc;
    279        
    280        
     280
     281
    281282        return gpt_write_gpt_header(gpt, dev_handle);
    282283}
    283284
    284285/** Alloc new partition
    285  * 
     286 *
    286287 * @param parts         partition table to carry new partition
    287  * 
     288 *
    288289 * @return                      returns pointer to the new partition or NULL on ENOMEM
    289  * 
     290 *
    290291 * Note: use either gpt_alloc_partition or gpt_add_partition. The first
    291  * returns a pointer to write your data to, the second copies the data 
     292 * returns a pointer to write your data to, the second copies the data
    292293 * (and does not free the memory).
    293294 */
     
    298299                        return NULL;
    299300        }
    300        
     301
    301302        return parts->part_array + parts->fill++;
    302303}
    303304
    304305/** Copy partition into partition array
    305  * 
     306 *
    306307 * @param parts                 target partition array
    307308 * @param partition             source partition to copy
    308  * 
     309 *
    309310 * @return                              -1 on error, 0 otherwise
    310  * 
     311 *
    311312 * Note: use either gpt_alloc_partition or gpt_add_partition. The first
    312  * returns a pointer to write your data to, the second copies the data 
     313 * returns a pointer to write your data to, the second copies the data
    313314 * (and does not free the memory).
    314315 */
     
    317318        if (parts->fill == parts->arr_size) {
    318319                if (extend_part_array(parts) == -1)
    319                         return -1;
     320                        return ENOMEM;
    320321        }
    321322        extend_part_array(parts);
    322         return parts;
     323        return EOK;;
    323324}
    324325
    325326/** Remove partition from array
    326  * 
     327 *
    327328 * @param idx           index of the partition to remove
    328  * 
     329 *
    329330 * @return                      -1 on error, 0 otherwise
    330  * 
     331 *
    331332 * Note: even if it fails, the partition still gets removed. Only
    332333 * reducing the array failed.
     
    335336{
    336337        if (idx != parts->fill - 1) {
    337                 memcpy(parts->part_array + idx, parts->part_array + fill - 1, sizeof(gpt_entry_t));
     338                memcpy(parts->part_array + idx, parts->part_array + parts->fill - 1, sizeof(gpt_entry_t));
    338339                parts->fill -= 1;
    339340        }
    340        
     341
    341342        if (parts->fill < (parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
    342343                if (reduce_part_array(parts) == -1)
    343344                        return -1;
    344345        }
    345        
     346
    346347        return 0;
    347348}
     
    355356
    356357/** Free partition list
    357  * 
     358 *
    358359 * @param parts         partition list to be freed
    359360 */
     
    371372        size_t i;
    372373        for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
    373                 if (memcmp(p->raw_data.part_type, gpt_ptypes[i].guid, 16) == 0) {
     374                if (gpt_memcmp(p->part_type, gpt_ptypes[i].guid, 16) == 0) {
    374375                        break;
    375376                }
     
    381382 * @param p                     partition to be set
    382383 * @param type          partition type to set
    383  *                                      - see gpt_ptypes to choose from
    384  *
    385  */
    386 void gpt_set_part_type(gpt_part_t * p, int type)
     384 *                                      - see our fine selection at gpt_ptypes to choose from
     385 */
     386void gpt_set_part_type(gpt_part_t * p, size_t type)
    387387{
    388388        /* Beware: first 3 blocks are byteswapped! */
    389         p->raw_data.part_type[3] = gpt_ptypes[type].guid[0];
    390         p->raw_data.part_type[2] = gpt_ptypes[type].guid[1];
    391         p->raw_data.part_type[1] = gpt_ptypes[type].guid[2];
    392         p->raw_data.part_type[0] = gpt_ptypes[type].guid[3];
    393        
    394         p->raw_data.part_type[5] = gpt_ptypes[type].guid[4];
    395         p->raw_data.part_type[4] = gpt_ptypes[type].guid[5];
    396        
    397         p->raw_data.part_type[7] = gpt_ptypes[type].guid[6];
    398         p->raw_data.part_type[6] = gpt_ptypes[type].guid[7];
    399        
    400         p->raw_data.part_type[8] = gpt_ptypes[type].guid[8];
    401         p->raw_data.part_type[9] = gpt_ptypes[type].guid[9];
    402         p->raw_data.part_type[10] = gpt_ptypes[type].guid[10];
    403         p->raw_data.part_type[11] = gpt_ptypes[type].guid[11];
    404         p->raw_data.part_type[12] = gpt_ptypes[type].guid[12];
    405         p->raw_data.part_type[13] = gpt_ptypes[type].guid[13];
    406         p->raw_data.part_type[14] = gpt_ptypes[type].guid[14];
    407         p->raw_data.part_type[15] = gpt_ptypes[type].guid[15];
    408 }
    409 
    410 char * gpt_get_part_name(gpt_entry_t * p)
    411 {
    412         return p->raw_data.part_name;
     389        p->part_type[3] = gpt_ptypes[type].guid[0];
     390        p->part_type[2] = gpt_ptypes[type].guid[1];
     391        p->part_type[1] = gpt_ptypes[type].guid[2];
     392        p->part_type[0] = gpt_ptypes[type].guid[3];
     393
     394        p->part_type[5] = gpt_ptypes[type].guid[4];
     395        p->part_type[4] = gpt_ptypes[type].guid[5];
     396
     397        p->part_type[7] = gpt_ptypes[type].guid[6];
     398        p->part_type[6] = gpt_ptypes[type].guid[7];
     399
     400        p->part_type[8] = gpt_ptypes[type].guid[8];
     401        p->part_type[9] = gpt_ptypes[type].guid[9];
     402        p->part_type[10] = gpt_ptypes[type].guid[10];
     403        p->part_type[11] = gpt_ptypes[type].guid[11];
     404        p->part_type[12] = gpt_ptypes[type].guid[12];
     405        p->part_type[13] = gpt_ptypes[type].guid[13];
     406        p->part_type[14] = gpt_ptypes[type].guid[14];
     407        p->part_type[15] = gpt_ptypes[type].guid[15];
     408}
     409
     410/** Get partition starting LBA */
     411uint64_t gpt_get_start_lba(gpt_part_t * p)
     412{
     413        return uint64_t_le2host(p->start_lba);
     414}
     415
     416/** Set partition starting LBA */
     417void gpt_set_start_lba(gpt_part_t * p, uint64_t start)
     418{
     419        p->start_lba = host2uint64_t_le(start);
     420}
     421
     422/** Get partition ending LBA */
     423uint64_t gpt_get_end_lba(gpt_part_t * p)
     424{
     425        return uint64_t_le2host(p->end_lba);
     426}
     427
     428/** Set partition ending LBA */
     429void gpt_set_end_lba(gpt_part_t * p, uint64_t end)
     430{
     431        p->end_lba = host2uint64_t_le(end);
     432}
     433
     434
     435unsigned char * gpt_get_part_name(gpt_part_t * p)
     436{
     437        return p->part_name;
    413438}
    414439
    415440/** Copy partition name */
    416 void gpt_set_part_name(gpt_entry_t * p, char * name[], size_t length)
     441void gpt_set_part_name(gpt_part_t * p, char * name[], size_t length)
    417442{
    418443        if (length >= 72)
    419444                length = 71;
    420        
     445
    421446        memcpy(p->part_name, name, length);
    422447        p->part_name[length] = '\0';
     
    424449
    425450/** Get partition attribute */
    426 extern bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
    427 {
    428         return (p->raw_data.attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
     451bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
     452{
     453        return (p->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
    429454}
    430455
    431456/** Set partition attribute */
    432 extern void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
    433 {
    434         uint64_t attr = p->raw_data.attributes;
     457void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
     458{
     459        uint64_t attr = p->attributes;
    435460
    436461        if (value)
     
    439464                attr = attr ^ (attr & (((uint64_t) 1) << flag));
    440465
    441         p->raw_data.attributes = attr;
     466        p->attributes = attr;
    442467}
    443468
     
    447472{
    448473        int rc;
    449        
     474
    450475        rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
    451476        if (rc != EOK)
    452477                return rc;
    453        
     478
    454479        rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
    455480        block_fini(dev_handle);
    456481        if (rc != EOK)
    457482                return rc;
    458        
    459        
     483
     484
    460485        unsigned int i;
    461486        /* Check the EFI signature */
     
    464489                        return EINVAL;
    465490        }
    466        
     491
    467492        /* Check the CRC32 of the header */
    468493        uint32_t crc = header->header_crc32;
     
    472497        else
    473498                header->header_crc32 = crc;
    474        
     499
    475500        /* Check for zeroes in the rest of the block */
    476501        for (i = sizeof(gpt_header_t); i < b_size; ++i) {
     
    478503                        return EINVAL;
    479504        }
    480                
     505
    481506        return EOK;
    482507}
     
    489514                return NULL;
    490515        }
    491        
     516
    492517        uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
    493518        res->part_array = malloc(size * sizeof(gpt_entry_t));
     
    497522                return NULL;
    498523        }
    499        
     524
    500525        res->fill = num;
    501526        res->arr_size = size;
    502        
     527
    503528        return res;
    504529}
     
    512537                return -1;
    513538        }
    514        
     539
    515540        memcpy(tmp, p->part_array, p->fill);
    516541        free(p->part_array);
    517542        p->part_array = tmp;
    518543        p->arr_size = nsize;
    519        
     544
    520545        return 0;
    521546}
     
    530555                        return -1;
    531556                }
    532                
     557
    533558                memcpy(tmp, p->part_array, p->fill < nsize ? p->fill  : nsize);
    534559                free(p->part_array);
     
    536561                p->arr_size = nsize;
    537562        }
    538        
     563
    539564        return 0;
    540565}
     
    546571                return (long long) a;
    547572        }
    548        
     573
    549574        return ((long long) a) + 1;
    550575}
    551576
    552 
    553 
    554 
     577static int gpt_memcmp(const void * a, const void * b, size_t len)
     578{
     579        size_t i;
     580        int diff;
     581        const unsigned char * x = a;
     582        const unsigned char * y = b;
     583
     584        for (i = 0; i < len; i++) {
     585                diff = (int)*(x++) - (int)*(y++);
     586                if (diff != 0) {
     587                        return diff;
     588                }
     589        }
     590        return 0;
     591}
     592
     593
     594
     595
Note: See TracChangeset for help on using the changeset viewer.