/* in this function */ static int hfs_extent_key_cmp(HfsPrivateGenericKey* a, HfsPrivateGenericKey* b) { HfsExtentKey* key1 = (HfsExtentKey*) a; HfsExtentKey* key2 = (HfsExtentKey*) b; /* do NOT use a substraction, because */ /* 0xFFFFFFFF - 1 = 0xFFFFFFFE so this */ /* would return -2, despite the fact */ /* 0xFFFFFFFF > 1 !!! (this is the 2.4 bug) */ if (key1->file_ID != key2->file_ID) return PED_BE32_TO_CPU(key1->file_ID) < PED_BE32_TO_CPU(key2->file_ID) ? -1 : +1; if (key1->type != key2->type) return (int)(key1->type - key2->type); if (key1->start == key2->start) return 0; /* the whole thing wont work with 16 bits ints */ /* anyway */ return (int)( PED_BE16_TO_CPU(key1->start) - PED_BE16_TO_CPU(key2->start) ); }
static int hfs_extract_bitmap(const char* filename, PedFileSystem* fs) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; HfsMasterDirectoryBlock* mdb = priv_data->mdb; unsigned int count; FILE* fout; PedSector sect; fout = fopen(filename, "w"); if (!fout) return 0; for (sect = PED_BE16_TO_CPU(mdb->volume_bitmap_block); sect < PED_BE16_TO_CPU(mdb->start_block); sect += count) { uint16_t st_block = PED_BE16_TO_CPU(mdb->start_block); count = (st_block-sect) < BLOCK_MAX_BUFF ? (st_block-sect) : BLOCK_MAX_BUFF; if (!ped_geometry_read(fs->geom, extract_buffer, sect, count)) goto err_close; if (!fwrite (extract_buffer, count * PED_SECTOR_SIZE_DEFAULT, 1, fout)) goto err_close; } return (fclose(fout) == 0 ? 1 : 0); err_close: fclose(fout); return 0; }
static int hfsplus_clobber (PedGeometry* geom) { unsigned int i = 1; uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; HfsMasterDirectoryBlock *mdb; mdb = (HfsMasterDirectoryBlock *) buf; if (!ped_geometry_read (geom, buf, 2, 1)) return 0; if (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE) { /* embedded hfs+ */ PedGeometry *embedded; i = PED_BE32_TO_CPU(mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; embedded = ped_geometry_new ( geom->dev, (PedSector) geom->start + PED_BE16_TO_CPU (mdb->start_block) + (PedSector) PED_BE16_TO_CPU ( mdb->old_new.embedded.location.start_block ) * i, (PedSector) PED_BE16_TO_CPU ( mdb->old_new.embedded.location.block_count ) * i ); if (!embedded) i = 0; else { i = hfs_clobber (embedded); ped_geometry_destroy (embedded); } } /* non-embedded or envelop destroy as hfs */ return ( hfs_clobber (geom) && i ); }
/* warning : only works on data forks */ static int hfs_get_extent_containing (HfsPrivateFile* file, unsigned int block, HfsExtDataRec cache, uint16_t* ptr_start_cache) { uint8_t record[sizeof (HfsExtentKey) + sizeof (HfsExtDataRec)]; HfsExtentKey search; HfsExtentKey* ret_key = (HfsExtentKey*) record; HfsExtDescriptor* ret_cache = (HfsExtDescriptor*) (record + sizeof (HfsExtentKey)); HfsPrivateFSData* priv_data = (HfsPrivateFSData*) file->fs->type_specific; search.key_length = sizeof (HfsExtentKey) - 1; search.type = HFS_DATA_FORK; search.file_ID = file->CNID; search.start = PED_CPU_TO_BE16 (block); if (!hfs_btree_search (priv_data->extent_file, (HfsPrivateGenericKey*) &search, record, sizeof (record), NULL)) return 0; if (ret_key->file_ID != search.file_ID || ret_key->type != search.type) return 0; memcpy (cache, ret_cache, sizeof(HfsExtDataRec)); *ptr_start_cache = PED_BE16_TO_CPU (ret_key->start); return 1; }
/* This function check if fblock is a bad block */ int hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; HfsPrivateLinkExtent* walk; for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) { /* Won't compile without the strange cast ! gcc bug ? */ /* or maybe C subtilties... */ if ((fblock >= PED_BE16_TO_CPU (walk->extent.start_block)) && (fblock < (unsigned int) (PED_BE16_TO_CPU ( walk->extent.start_block) + PED_BE16_TO_CPU ( walk->extent.block_count)))) return 1; } return 0; }
/* Used by hfsplus_probe and hfs_probe */ PedGeometry* hfs_and_wrapper_probe (PedGeometry* geom) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; HfsMasterDirectoryBlock *mdb; PedGeometry* geom_ret; PedSector search, max; PED_ASSERT (geom != NULL); PED_ASSERT (hfsc_can_use_geom (geom)); mdb = (HfsMasterDirectoryBlock *) buf; /* is 5 an intelligent value ? */ if ((geom->length < 5) || (!ped_geometry_read (geom, buf, 2, 1)) || (mdb->signature != PED_CPU_TO_BE16 (HFS_SIGNATURE)) ) return NULL; search = ((PedSector) PED_BE16_TO_CPU (mdb->start_block) + ((PedSector) PED_BE16_TO_CPU (mdb->total_blocks) * (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT ))); max = search + (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT); if (!(geom_ret = ped_geometry_new (geom->dev, geom->start, search + 2))) return NULL; for (; search < max; search++) { if (!ped_geometry_set (geom_ret, geom_ret->start, search + 2) || !ped_geometry_read (geom_ret, buf, search, 1)) break; if (mdb->signature == PED_CPU_TO_BE16 (HFS_SIGNATURE)) return geom_ret; } ped_geometry_destroy (geom_ret); return NULL; }
/* return the block which should be used to pack data to have at least free fblock blocks at the end of the volume */ unsigned int hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; unsigned int block; for (block = PED_BE16_TO_CPU (priv_data->mdb->total_blocks) - 1; block && fblock; block--) { if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) fblock--; } while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) block--; if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) block++; return block; }
/* On error this function returns 0 */ PedSector hfs_get_empty_end (const PedFileSystem *fs) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; HfsMasterDirectoryBlock* mdb = priv_data->mdb; unsigned int block, last_bad, end_free_blocks; /* find the next block to the last bad block of the volume */ if (!hfs_read_bad_blocks (fs)) return 0; HfsPrivateLinkExtent* l; last_bad = 0; for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) { if ((unsigned int) PED_BE16_TO_CPU (l->extent.start_block) + PED_BE16_TO_CPU (l->extent.block_count) > last_bad) last_bad = PED_BE16_TO_CPU (l->extent.start_block) + PED_BE16_TO_CPU (l->extent.block_count); } /* Count the free blocks from last_bad to the end of the volume */ end_free_blocks = 0; for (block = last_bad; block < PED_BE16_TO_CPU (mdb->total_blocks); block++) { if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) end_free_blocks++; } /* Calculate the block that will by the first free at the end of the volume */ block = PED_BE16_TO_CPU (mdb->total_blocks) - end_free_blocks; return (PedSector) PED_BE16_TO_CPU (mdb->start_block) + (PedSector) block * (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT); }
/* This function reads bad blocks extents in the extents file and store it in f.s. specific data of fs */ int hfs_read_bad_blocks (const PedFileSystem *fs) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific; if (priv_data->bad_blocks_loaded) return 1; { uint8_t record[sizeof (HfsExtentKey) + sizeof (HfsExtDataRec)]; HfsExtentKey search; HfsExtentKey* ret_key = (HfsExtentKey*) record; HfsExtDescriptor* ret_cache = (HfsExtDescriptor*) (record + sizeof (HfsExtentKey)); unsigned int block, last_start, first_pass = 1; search.key_length = sizeof (HfsExtentKey) - 1; search.type = HFS_DATA_FORK; search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID); last_start = -1; block = 0; while (1) { int i; search.start = PED_CPU_TO_BE16 (block); if (!hfs_btree_search (priv_data->extent_file, (HfsPrivateGenericKey*) &search, record, sizeof (record), NULL) || ret_key->file_ID != search.file_ID || ret_key->type != search.type) { if (first_pass) break; else goto errbb; } if (PED_BE16_TO_CPU (ret_key->start) == last_start) break; last_start = PED_BE16_TO_CPU (ret_key->start); for (i = 0; i < HFS_EXT_NB; i++) { if (ret_cache[i].block_count) { HfsPrivateLinkExtent* new_xt = (HfsPrivateLinkExtent*) ped_malloc ( sizeof (HfsPrivateLinkExtent)); if (!new_xt) goto errbb; new_xt->next = priv_data->bad_blocks_xtent_list; memcpy(&(new_xt->extent), ret_cache+i, sizeof (HfsExtDescriptor)); priv_data->bad_blocks_xtent_list = new_xt; priv_data->bad_blocks_xtent_nb++; block += PED_BE16_TO_CPU ( ret_cache[i].block_count); } } first_pass = 0; } priv_data->bad_blocks_loaded = 1; return 1;} errbb: hfs_free_bad_blocks_list(priv_data->bad_blocks_xtent_list); priv_data->bad_blocks_xtent_list=NULL; priv_data->bad_blocks_xtent_nb=0; return 0; }
/* return 0 on error */ static PedSector hfs_file_find_sector (HfsPrivateFile* file, PedSector sector) { HfsPrivateFSData* priv_data = (HfsPrivateFSData*) file->fs->type_specific; unsigned int sect_by_block = PED_BE32_TO_CPU ( priv_data->mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; unsigned int i, s, vol_block; unsigned int block = sector / sect_by_block; unsigned int offset = sector % sect_by_block; /* in the three first extent */ for (s = 0, i = 0; i < HFS_EXT_NB; i++) { if ((block >= s) && ( block < s + PED_BE16_TO_CPU ( file->first[i].block_count))) { vol_block = (block - s) + PED_BE16_TO_CPU ( file->first[i].start_block); goto sector_found; } s += PED_BE16_TO_CPU (file->first[i].block_count); } /* in the three cached extent */ if (file->start_cache && block >= file->start_cache) for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) { if ((block >= s) && (block < s + PED_BE16_TO_CPU ( file->cache[i].block_count))) { vol_block = (block - s) + PED_BE16_TO_CPU ( file->cache[i].start_block); goto sector_found; } s += PED_BE16_TO_CPU (file->cache[i].block_count); } /* update cache */ if (!hfs_get_extent_containing (file, block, file->cache, &(file->start_cache))) { ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL, _("Could not update the extent cache for HFS file with " "CNID %X."), PED_BE32_TO_CPU(file->CNID)); return 0; } /* in the three cached extent */ PED_ASSERT(file->start_cache && block >= file->start_cache, return 0); for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) { if ((block >= s) && (block < s + PED_BE16_TO_CPU ( file->cache[i].block_count))) { vol_block = (block - s) + PED_BE16_TO_CPU ( file->cache[i].start_block); goto sector_found; } s += PED_BE16_TO_CPU (file->cache[i].block_count); } return 0; sector_found: return (PedSector) PED_BE16_TO_CPU (priv_data->mdb->start_block) + (PedSector) vol_block * sect_by_block + offset; }
static int hfsplus_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPExtentKey* extent_key; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; if (!priv_data->extents_file->sect_nb) { ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, _("This HFS+ volume has no extents overflow " "file. This is quite unusual!")); return 1; } if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0)) return 0; header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc (bsize); if (!node) return -1; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->extents_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { uint8_t where; extent_key = (HfsPExtentKey*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(bsize - 2*i))))); extent = (HfsPExtDescriptor*) (((uint8_t*)extent_key) + sizeof (HfsPExtentKey)); /* check for obvious error in FS */ if (((uint8_t*)extent_key - node < HFS_FIRST_REC) || ((uint8_t*)extent - node >= (signed)bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return -1; } switch (extent_key->file_ID) { case PED_CPU_TO_BE32 (HFS_XTENT_ID) : if (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL, _("The extents overflow file should not" " contain its own extents! You should " "check the file system.")) != PED_EXCEPTION_IGNORE) return 0; where = CR_BTREE_EXT_EXT; break; case PED_CPU_TO_BE32 (HFS_CATALOG_ID) : where = CR_BTREE_EXT_CAT; break; case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) : where = CR_BTREE_EXT_ALLOC; break; case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) : where = CR_BTREE_EXT_START; break; case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) : where = CR_BTREE_EXT_ATTR; break; default : where = CR_BTREE_EXT_0; break; } for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, where, j ) ) { free (node); return 0; } } } } free (node); return 1; }
/* Update the HFS wrapper mdb and bad blocks file to reflect the new geometry of the embedded HFS+ volume */ static int hfsplus_wrapper_update (PedFileSystem* fs) { uint8_t node[PED_SECTOR_SIZE_DEFAULT]; HfsCPrivateLeafRec ref; HfsExtentKey key; HfsNodeDescriptor* node_desc = (HfsNodeDescriptor*) node; HfsExtentKey* ret_key; HfsExtDescriptor* ret_data; unsigned int i; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*) priv_data->wrapper->type_specific; unsigned int hfs_sect_block = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) / PED_SECTOR_SIZE_DEFAULT ; PedSector hfsplus_sect = (PedSector) PED_BE32_TO_CPU (priv_data->vh->total_blocks) * ( PED_BE32_TO_CPU (priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT ); unsigned int hfs_blocks_embedded = (hfsplus_sect + hfs_sect_block - 1) / hfs_sect_block; unsigned int hfs_blocks_embedded_old; /* update HFS wrapper MDB */ hfs_blocks_embedded_old = PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new .embedded.location.block_count ); hfs_priv_data->mdb->old_new.embedded.location.block_count = PED_CPU_TO_BE16 (hfs_blocks_embedded); /* maybe macOS will boot with this */ /* update : yes it does \o/ :) */ hfs_priv_data->mdb->free_blocks = PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks) + hfs_blocks_embedded_old - hfs_blocks_embedded ); if (!hfs_update_mdb(priv_data->wrapper)) return 0; /* force reload bad block list */ if (hfs_priv_data->bad_blocks_loaded) { hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list); hfs_priv_data->bad_blocks_xtent_list = NULL; hfs_priv_data->bad_blocks_xtent_nb = 0; hfs_priv_data->bad_blocks_loaded = 0; } /* clean HFS wrapper allocation map */ for (i = PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new.embedded .location.start_block ) + hfs_blocks_embedded; i < PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new.embedded .location.start_block ) + hfs_blocks_embedded_old; i++ ) { CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i); } /* and save it */ if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map, PED_BE16_TO_CPU ( hfs_priv_data->mdb->volume_bitmap_block ), ( PED_BE16_TO_CPU ( hfs_priv_data->mdb->total_blocks ) + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8))) return 0; if (!ped_geometry_sync (fs->geom)) return 0; /* search and update the bad blocks file */ key.key_length = sizeof(key) - 1; key.type = HFS_DATA_FORK; key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID); key.start = 0; if (!hfs_btree_search (hfs_priv_data->extent_file, (HfsPrivateGenericKey*) &key, NULL, 0, &ref)) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("An error occurred while looking for the mandatory " "bad blocks file.")); return 0; } if (!hfs_file_read_sector (hfs_priv_data->extent_file, node, ref.node_number)) return 0; ret_key = (HfsExtentKey*) (node + ref.record_pos); ret_data = (HfsExtDescriptor*) ( node + ref.record_pos + sizeof (HfsExtentKey) ); while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) { for (i = 0; i < HFS_EXT_NB; i++) { if ( ret_data[i].start_block == hfs_priv_data->mdb->old_new .embedded.location.start_block) { ret_data[i].block_count = hfs_priv_data->mdb->old_new .embedded.location.block_count; /* found ! : update */ if (!hfs_file_write_sector ( hfs_priv_data->extent_file, node, ref.node_number) || !ped_geometry_sync(fs->geom)) return 0; return 1; } } if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) { ref.record_number++; } else { ref.node_number = PED_BE32_TO_CPU (node_desc->next); if (!ref.node_number || !hfs_file_read_sector(hfs_priv_data->extent_file, node, ref.node_number)) goto bb_not_found; ref.record_number = 1; } ref.record_pos = PED_BE16_TO_CPU (*((uint16_t *) (node + (PED_SECTOR_SIZE_DEFAULT - 2*ref.record_number)))); ret_key = (HfsExtentKey*) (node + ref.record_pos); ret_data = (HfsExtDescriptor*) ( node + ref.record_pos + sizeof (HfsExtentKey) ); } bb_not_found: /* not found : not a valid hfs+ wrapper : failure */ ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("It seems there is an error in the HFS wrapper: the bad " "blocks file doesn't contain the embedded HFS+ volume.")); return 0; }
PedFileSystem* hfsplus_open (PedGeometry* geom) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; PedFileSystem* fs; HfsPVolumeHeader* vh; HfsPPrivateFSData* priv_data; PedGeometry* wrapper_geom; unsigned int map_sectors; if (!hfsc_can_use_geom (geom)) return NULL; fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); if (!fs) goto hpo; vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader)); if (!vh) goto hpo_fs; priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData)); if (!priv_data) goto hpo_vh; fs->geom = ped_geometry_duplicate (geom); if (!fs->geom) goto hpo_pd; fs->type_specific = (void*) priv_data; if ((wrapper_geom = hfs_and_wrapper_probe (geom))) { HfsPrivateFSData* hfs_priv_data; PedSector abs_sect, length; unsigned int bs; ped_geometry_destroy (wrapper_geom); priv_data->wrapper = hfs_open(geom); if (!priv_data->wrapper) goto hpo_gm; hfs_priv_data = (HfsPrivateFSData*) priv_data->wrapper->type_specific; bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; abs_sect = (PedSector) geom->start + (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->start_block) + (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new .embedded.location.start_block ) * bs; length = (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new .embedded.location.block_count) * bs; priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect, length); if (!priv_data->plus_geom) goto hpo_wr; priv_data->free_geom = 1; } else { priv_data->wrapper = NULL; priv_data->plus_geom = fs->geom; priv_data->free_geom = 0; } if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg; memcpy (vh, buf, sizeof (HfsPVolumeHeader)); priv_data->vh = vh; if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE) && vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) { ped_exception_throw ( PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, _("No valid HFS[+X] signature has been found while " "opening.")); goto hpo_pg; } if (vh->signature == PED_CPU_TO_BE16(HFSP_SIGNATURE) && vh->version != PED_CPU_TO_BE16(HFSP_VERSION)) { if (ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_IGNORE_CANCEL, _("Version %d of HFS+ isn't supported."), PED_BE16_TO_CPU(vh->version)) != PED_EXCEPTION_IGNORE) goto hpo_pg; } if (vh->signature == PED_CPU_TO_BE16(HFSX_SIGNATURE) && vh->version != PED_CPU_TO_BE16(HFSX_VERSION)) { if (ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_IGNORE_CANCEL, _("Version %d of HFSX isn't supported."), PED_BE16_TO_CPU(vh->version)) != PED_EXCEPTION_IGNORE) goto hpo_pg; } priv_data->jib_start_block = 0; priv_data->jl_start_block = 0; if (vh->attributes & PED_CPU_TO_BE32(1<<HFSP_JOURNALED)) { if (!hfsj_replay_journal(fs)) goto hpo_pg; } priv_data->bad_blocks_loaded = 0; priv_data->bad_blocks_xtent_nb = 0; priv_data->bad_blocks_xtent_list = NULL; priv_data->extents_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID), vh->extents_file.extents, PED_BE64_TO_CPU ( vh->extents_file.logical_size ) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->extents_file) goto hpo_pg; priv_data->catalog_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID), vh->catalog_file.extents, PED_BE64_TO_CPU ( vh->catalog_file.logical_size ) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->catalog_file) goto hpo_ce; priv_data->attributes_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID), vh->attributes_file.extents, PED_BE64_TO_CPU ( vh->attributes_file.logical_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->attributes_file) goto hpo_cc; map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks) + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); priv_data->dirty_alloc_map = (uint8_t*) ped_malloc ((map_sectors + 7) / 8); if (!priv_data->dirty_alloc_map) goto hpo_cl; memset(priv_data->dirty_alloc_map, 0, (map_sectors + 7) / 8); priv_data->alloc_map = (uint8_t*) ped_malloc (map_sectors * PED_SECTOR_SIZE_DEFAULT); if (!priv_data->alloc_map) goto hpo_dm; priv_data->allocation_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID), vh->allocation_file.extents, PED_BE64_TO_CPU ( vh->allocation_file.logical_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->allocation_file) goto hpo_am; if (!hfsplus_file_read (priv_data->allocation_file, priv_data->alloc_map, 0, map_sectors)) { hfsplus_close(fs); return NULL; } fs->type = &hfsplus_type; fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1) && !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1); return fs; /*--- clean error handling ---*/ hpo_am: free(priv_data->alloc_map); hpo_dm: free(priv_data->dirty_alloc_map); hpo_cl: hfsplus_file_close (priv_data->attributes_file); hpo_cc: hfsplus_file_close (priv_data->catalog_file); hpo_ce: hfsplus_file_close (priv_data->extents_file); hpo_pg: if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom); hpo_wr: if (priv_data->wrapper) hfs_close(priv_data->wrapper); hpo_gm: ped_geometry_destroy (fs->geom); hpo_pd: free(priv_data); hpo_vh: free(vh); hpo_fs: free(fs); hpo: return NULL; }
int hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; unsigned int nblock, nfree; unsigned int block, to_free; HfsPrivateFSData* priv_data; HfsMasterDirectoryBlock* mdb; int resize = 1; unsigned int hfs_sect_block; PedSector hgee; /* check preconditions */ PED_ASSERT (fs != NULL); PED_ASSERT (fs->geom != NULL); PED_ASSERT (geom != NULL); #ifdef DEBUG PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0); #else if ((hgee = hfs_get_empty_end(fs)) == 0) return 0; #endif PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0); if (ped_geometry_test_equal(fs->geom, geom)) return 1; priv_data = (HfsPrivateFSData*) fs->type_specific; mdb = priv_data->mdb; hfs_sect_block = PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; if (fs->geom->start != geom->start || geom->length > fs->geom->length || geom->length < hgee + 2) { ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_CANCEL, _("Sorry, HFS cannot be resized that way yet.")); return 0; } /* Flush caches */ if (!ped_geometry_sync(fs->geom)) return 0; /* Clear the unmounted bit */ mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED )); if (!ped_geometry_read (fs->geom, buf, 2, 1)) return 0; memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock)); if ( !ped_geometry_write (fs->geom, buf, 2, 1) || !ped_geometry_sync (fs->geom)) return 0; ped_timer_reset (timer); ped_timer_set_state_name(timer, _("shrinking")); ped_timer_update(timer, 0.0); /* relocate data */ to_free = ( fs->geom->length - geom->length + hfs_sect_block - 1 ) / hfs_sect_block ; block = hfs_find_start_pack (fs, to_free); if (!hfs_pack_free_space_from_block (fs, block, timer, to_free)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Data relocation has failed.")); goto write_MDB; } /* Calculate new block number and other MDB field */ nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) ) / hfs_sect_block; nfree = PED_BE16_TO_CPU (mdb->free_blocks) - ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock ); /* Check that all block after future end are really free */ for (block = nblock; block < PED_BE16_TO_CPU (mdb->total_blocks); block++) { if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Data relocation left some data in the end " "of the volume.")); goto write_MDB; } } /* Mark out of volume blocks as used (broken implementations compatibility) */ for ( block = nblock; block < (1 << 16); ++block) SET_BLOC_OCCUPATION(priv_data->alloc_map,block); /* save the allocation map I do not write until start of allocation blocks but only until pre-resize end of bitmap blocks because the specifications do _not_ assert that everything until allocation blocks is boot, mdb and alloc */ ped_geometry_write(fs->geom, priv_data->alloc_map, PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block), ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks) + PED_SECTOR_SIZE_DEFAULT * 8 - 1) / (PED_SECTOR_SIZE_DEFAULT * 8)); /* Update geometry */ if (resize) { /* update in fs structure */ if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock) mdb->next_allocation = PED_CPU_TO_BE16 (0); mdb->total_blocks = PED_CPU_TO_BE16 (nblock); mdb->free_blocks = PED_CPU_TO_BE16 (nfree); /* update parted structure */ fs->geom->length = geom->length; fs->geom->end = fs->geom->start + geom->length - 1; } /* Set the unmounted bit */ mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED ); /* Effective write */ write_MDB: ped_timer_set_state_name(timer,_("writing HFS Master Directory Block")); if (!hfs_update_mdb(fs)) { ped_geometry_sync(geom); return 0; } if (!ped_geometry_sync(geom)) return 0; ped_timer_update(timer, 1.0); return (resize); }
static int hfsj_replay_transaction(PedFileSystem* fs, HfsJJournalHeader* jh, PedSector jsector, PedSector jlength) { PedSector start, sector; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsJBlockListHeader* blhdr; uint8_t* block; unsigned int blhdr_nbsect; int i, r; uint32_t cksum, size; blhdr_nbsect = PED_BE32_TO_CPU(jh->blhdr_size) / PED_SECTOR_SIZE_DEFAULT; blhdr = (HfsJBlockListHeader*) ped_malloc (blhdr_nbsect * PED_SECTOR_SIZE_DEFAULT); if (!blhdr) return 0; start = PED_BE64_TO_CPU(jh->start) / PED_SECTOR_SIZE_DEFAULT; do { start = hfsj_journal_read(priv_data->plus_geom, jh, jsector, jlength, start, blhdr_nbsect, blhdr); if (!start) goto err_replay; cksum = PED_BE32_TO_CPU(blhdr->checksum); blhdr->checksum = 0; if (cksum!=hfsj_calc_checksum((uint8_t*)blhdr, sizeof(*blhdr))){ ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Bad block list header checksum.")); goto err_replay; } blhdr->checksum = PED_CPU_TO_BE32(cksum); for (i=1; i < PED_BE16_TO_CPU(blhdr->num_blocks); ++i) { size = PED_BE32_TO_CPU(blhdr->binfo[i].bsize); sector = PED_BE64_TO_CPU(blhdr->binfo[i].bnum); if (!size) continue; if (size % PED_SECTOR_SIZE_DEFAULT) { ped_exception_throw( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Invalid size of a transaction " "block while replaying the journal " "(%i bytes)."), size); goto err_replay; } block = (uint8_t*) ped_malloc(size); if (!block) goto err_replay; start = hfsj_journal_read(priv_data->plus_geom, jh, jsector, jlength, start, size / PED_SECTOR_SIZE_DEFAULT, block); if (!start) { ped_free (block); goto err_replay; } /* the sector stored in the journal seems to be relative to the begin of the block device which contains the hfs+ journaled volume */ if (sector != ~0LL) r = ped_geometry_write (fs->geom, block, sector, size / PED_SECTOR_SIZE_DEFAULT); else r = 1; ped_free (block); /* check if wrapper mdb or vh with no wrapper has changed */ if ( (sector != ~0LL) && (2 >= sector) && (2 < sector + size / PED_SECTOR_SIZE_DEFAULT) ) hfsj_vh_replayed = 1; /* check if vh of embedded hfs+ has changed */ if ( (sector != ~0LL) && (priv_data->plus_geom != fs->geom) && (sector + fs->geom->start - priv_data->plus_geom->start <= 2) && (sector + size / PED_SECTOR_SIZE_DEFAULT + fs->geom->start - priv_data->plus_geom->start > 2) ) hfsj_vh_replayed = 1; if (!r) goto err_replay; } } while (blhdr->binfo[0].next); jh->start = PED_CPU_TO_BE64(start * PED_SECTOR_SIZE_DEFAULT); ped_free (blhdr); return (ped_geometry_sync (fs->geom)); err_replay: ped_free (blhdr); return 0; }
/* other BTrees has well */ int hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key, void *record_out, unsigned int record_size, HfsCPrivateLeafRec* record_ref) { uint8_t node[PED_SECTOR_SIZE_DEFAULT]; HfsHeaderRecord* header; HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node; HfsPrivateGenericKey* record_key = NULL; unsigned int node_number, record_number; int i; /* Read the header node */ if (!hfs_file_read_sector(b_tree_file, node, 0)) return 0; header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(PED_SECTOR_SIZE_DEFAULT-2)))))); /* Get the node number of the root */ node_number = PED_BE32_TO_CPU(header->root_node); if (!node_number) return 0; /* Read the root node */ if (!hfs_file_read_sector(b_tree_file, node, node_number)) return 0; /* Follow the white rabbit */ while (1) { record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = record_number; i; i--) { record_key = (HfsPrivateGenericKey*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(PED_SECTOR_SIZE_DEFAULT - 2*i))))); /* check for obvious error in FS */ if (((uint8_t*)record_key - node < HFS_FIRST_REC) || ((uint8_t*)record_key - node >= PED_SECTOR_SIZE_DEFAULT - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); return 0; } if (hfs_extent_key_cmp(record_key, key) <= 0) break; } if (!i) return 0; if (desc->type == HFS_IDX_NODE) { unsigned int skip; skip = (1 + record_key->key_length + 1) & ~1; node_number = PED_BE32_TO_CPU (*((uint32_t *) (((uint8_t *) record_key) + skip))); if (!hfs_file_read_sector(b_tree_file, node, node_number)) return 0; } else break; } /* copy the result if needed */ if (record_size) memcpy (record_out, record_key, record_size); /* send record reference if needed */ if (record_ref) { record_ref->node_size = 1; /* in sectors */ record_ref->node_number = node_number; record_ref->record_pos = (uint8_t*)record_key - node; record_ref->record_number = i; } /* success */ return 1; }
static int hfsplus_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPCatalogKey* catalog_key; HfsPCatalog* catalog_data; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; uint32_t jib = priv_data->jib_start_block, jl = priv_data->jl_start_block; if (!priv_data->catalog_file->sect_nb) { ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, _("This HFS+ volume has no catalog file. " "This is very unusual!")); return 1; } /* Search the extent starting at *ptr_block in the catalog file */ if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0)) return 0; header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc(bsize); if (!node) return 0; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->catalog_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { unsigned int skip; uint8_t where; catalog_key = (HfsPCatalogKey*) ( node + PED_BE16_TO_CPU (*((uint16_t *) (node+(bsize - 2*i)))) ); skip = ( 2 + PED_BE16_TO_CPU (catalog_key->key_length) + 1) & ~1; catalog_data = (HfsPCatalog*) (((uint8_t*)catalog_key) + skip); /* check for obvious error in FS */ if (((uint8_t*)catalog_key - node < HFS_FIRST_REC) || ((uint8_t*)catalog_data - node >= (signed) bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return 0; } if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE) continue; extent = catalog_data->sel.file.data_fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; where = CR_BTREE_CAT; if ( PED_BE32_TO_CPU(extent[j].start_block) == jib ) { jib = 0; where = CR_BTREE_CAT_JIB; } else if ( PED_BE32_TO_CPU(extent[j].start_block) == jl ) { jl = 0; where = CR_BTREE_CAT_JL; } if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, where, j ) ) { free (node); return 0; } } extent = catalog_data->sel.file.res_fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, CR_BTREE_CAT, j ) ) { free (node); return 0; } } } } free (node); return 1; }
PedFileSystem * hfs_open (PedGeometry* geom) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; PedFileSystem* fs; HfsMasterDirectoryBlock* mdb; HfsPrivateFSData* priv_data; if (!hfsc_can_use_geom (geom)) return NULL; /* Read MDB */ if (!ped_geometry_read (geom, buf, 2, 1)) return NULL; /* Allocate memory */ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); if (!fs) goto ho; mdb = (HfsMasterDirectoryBlock*) ped_malloc (sizeof (HfsMasterDirectoryBlock)); if (!mdb) goto ho_fs; priv_data = (HfsPrivateFSData*) ped_malloc (sizeof (HfsPrivateFSData)); if (!priv_data) goto ho_mdb; memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock)); /* init structures */ priv_data->mdb = mdb; priv_data->bad_blocks_loaded = 0; priv_data->bad_blocks_xtent_nb = 0; priv_data->bad_blocks_xtent_list = NULL; priv_data->extent_file = hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID), mdb->extents_file_rec, PED_CPU_TO_BE32 (mdb->extents_file_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->extent_file) goto ho_pd; priv_data->catalog_file = hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID), mdb->catalog_file_rec, PED_CPU_TO_BE32 (mdb->catalog_file_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->catalog_file) goto ho_ce; /* Read allocation blocks */ if (!ped_geometry_read(geom, priv_data->alloc_map, PED_BE16_TO_CPU (mdb->volume_bitmap_block), ( PED_BE16_TO_CPU (mdb->total_blocks) + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8) ) ) goto ho_cf; fs->type = &hfs_type; fs->geom = ped_geometry_duplicate (geom); if (!fs->geom) goto ho_cf; fs->type_specific = (void*) priv_data; fs->checked = ( PED_BE16_TO_CPU (mdb->volume_attributes) >> HFS_UNMOUNTED ) & 1; return fs; /*--- clean error handling ---*/ ho_cf: hfs_file_close(priv_data->catalog_file); ho_ce: hfs_file_close(priv_data->extent_file); ho_pd: free(priv_data); ho_mdb: free(mdb); ho_fs: free(fs); ho: return NULL; }
static int hfsplus_cache_from_attributes(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPPrivateGenericKey* generic_key; HfsPForkDataAttr* fork_ext_data; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; /* attributes file is facultative */ if (!priv_data->attributes_file->sect_nb) return 1; /* Search the extent starting at *ptr_block in the catalog file */ if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0)) return 0; header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc(bsize); if (!node) return 0; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->attributes_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { unsigned int skip; generic_key = (HfsPPrivateGenericKey*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(bsize - 2*i))))); skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length) + 1 ) & ~1; fork_ext_data = (HfsPForkDataAttr*) (((uint8_t*)generic_key) + skip); /* check for obvious error in FS */ if (((uint8_t*)generic_key - node < HFS_FIRST_REC) || ((uint8_t*)fork_ext_data - node >= (signed) bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return 0; } if (fork_ext_data->record_type == PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) { extent = fork_ext_data->fork_res.fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU ( extent[j].start_block ), PED_BE32_TO_CPU ( extent[j].block_count ), leaf_node, (uint8_t*)extent-node, size, CR_BTREE_ATTR, j ) ) { free(node); return 0; } } } else if (fork_ext_data->record_type == PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) { extent = fork_ext_data->fork_res.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU ( extent[j].start_block ), PED_BE32_TO_CPU ( extent[j].block_count ), leaf_node, (uint8_t*)extent-node, size, CR_BTREE_ATTR, j ) ) { free(node); return 0; } } } else continue; } } free (node); return 1; }
static int dvh_read (PedDisk* disk) { DVHDiskData* dvh_disk_data = disk->disk_specific; int i; struct volume_header vh; char boot_name [BFNAMESIZE + 1]; #ifndef DISCOVER_ONLY int write_back = 0; #endif PED_ASSERT (dvh_disk_data != NULL); ped_disk_delete_all (disk); void *s0; if (!ptt_read_sector (disk->dev, 0, &s0)) return 0; memcpy (&vh, s0, sizeof vh); free (s0); if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) { if (ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, _("Checksum is wrong, indicating the partition " "table is corrupt.")) == PED_EXCEPTION_CANCEL) return 0; } PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC); dvh_disk_data->dev_params = vh.vh_dp; strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE); boot_name[BFNAMESIZE] = 0; /* normal partitions */ for (i = 0; i < NPARTAB; i++) { PedPartition* part; if (!vh.vh_pt[i].pt_nblks) continue; /* Skip the whole-disk partition, parted disklikes overlap */ if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME) continue; part = _parse_partition (disk, &vh.vh_pt[i]); if (!part) goto error_delete_all; part->fs_type = ped_file_system_probe (&part->geom); part->num = i + 1; if (PED_BE16_TO_CPU (vh.vh_rootpt) == i) ped_partition_set_flag (part, PED_PARTITION_ROOT, 1); if (PED_BE16_TO_CPU (vh.vh_swappt) == i) ped_partition_set_flag (part, PED_PARTITION_SWAP, 1); PedConstraint *constraint_exact = ped_constraint_exact (&part->geom); bool ok = ped_disk_add_partition (disk, part, constraint_exact); ped_constraint_destroy (constraint_exact); if (!ok) { ped_partition_destroy (part); goto error_delete_all; } } if (!ped_disk_extended_partition (disk)) { #ifdef DISCOVER_ONLY return 1; #else switch (_handle_no_volume_header (disk)) { case PED_EXCEPTION_CANCEL: return 0; case PED_EXCEPTION_IGNORE: return 1; case PED_EXCEPTION_FIX: write_back = 1; break; default: break; } #endif } /* boot partitions */ for (i = 0; i < NVDIR; i++) { PedPartition* part; if (!vh.vh_vd[i].vd_nbytes) continue; part = _parse_boot_file (disk, &vh.vh_vd[i]); if (!part) goto error_delete_all; part->fs_type = ped_file_system_probe (&part->geom); part->num = NPARTAB + i + 1; if (!strcmp (boot_name, ped_partition_get_name (part))) ped_partition_set_flag (part, PED_PARTITION_BOOT, 1); PedConstraint *constraint_exact = ped_constraint_exact (&part->geom); bool ok = ped_disk_add_partition (disk, part, constraint_exact); ped_constraint_destroy (constraint_exact); if (!ok) { ped_partition_destroy (part); goto error_delete_all; } } #ifndef DISCOVER_ONLY if (write_back) dvh_write (disk); #endif return 1; error_delete_all: ped_disk_delete_all (disk); return 0; }