static PedGeometry* xfs_probe (PedGeometry* geom) { PedSector block_size; PedSector block_count; union { struct xfs_sb sb; char bytes [512]; } buf; if (geom->length < XFS_SB_DADDR + 1) return NULL; if (!ped_geometry_read (geom, &buf, XFS_SB_DADDR, 1)) return NULL; if (PED_LE32_TO_CPU (buf.sb.sb_magicnum) == XFS_SB_MAGIC) { block_size = PED_LE32_TO_CPU (buf.sb.sb_blocksize) / 512; block_count = PED_LE64_TO_CPU (buf.sb.sb_dblocks); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } if (PED_BE32_TO_CPU (buf.sb.sb_magicnum) == XFS_SB_MAGIC) { block_size = PED_BE32_TO_CPU (buf.sb.sb_blocksize) / 512; block_count = PED_BE64_TO_CPU (buf.sb.sb_dblocks); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } return NULL; }
/* TODO : use exceptions to report errors */ static int hfsplus_extract (PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsPVolumeHeader* vh = priv_data->vh; HfsPPrivateFile* startup_file; if (priv_data->wrapper) { /* TODO : create nested timer */ hfs_extract (priv_data->wrapper, timer); } ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, _("This is not a real %s check. This is going to extract " "special low level files for debugging purposes."), "HFS+"); extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT); if (!extract_buffer) return 0; hfsplus_extract_vh(HFSP_VH_FILENAME, fs); hfsplus_extract_file(HFSP_CATALOG_FILENAME, priv_data->catalog_file); hfsplus_extract_file(HFSP_EXTENTS_FILENAME, priv_data->extents_file); hfsplus_extract_file(HFSP_ATTRIB_FILENAME, priv_data->attributes_file); hfsplus_extract_file(HFSP_BITMAP_FILENAME, priv_data->allocation_file); startup_file = hfsplus_file_open(fs, PED_CPU_TO_BE32(HFSP_STARTUP_ID), vh->startup_file.extents, PED_BE64_TO_CPU ( vh->startup_file.logical_size) / PED_SECTOR_SIZE_DEFAULT); if (startup_file) { hfsplus_extract_file(HFSP_STARTUP_FILENAME, startup_file); hfsplus_file_close(startup_file); startup_file = NULL; } free(extract_buffer); extract_buffer = NULL; return 0; /* nothing has been fixed by us ! */ }
/* 1 => Success, the journal has been completly replayed, or don't need to */ int hfsj_replay_journal(PedFileSystem* fs) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; PedSector sector, length; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsJJournalInfoBlock* jib; HfsJJournalHeader* jh; int binsect; uint32_t cksum; binsect = PED_BE32_TO_CPU(priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT; priv_data->jib_start_block = PED_BE32_TO_CPU(priv_data->vh->journal_info_block); sector = (PedSector) priv_data->jib_start_block * binsect; if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1)) return 0; jib = (HfsJJournalInfoBlock*) buf; if ( (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS)) && !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) { priv_data->jl_start_block = HFS_64_TO_CPU(jib->offset, is_le) / ( PED_SECTOR_SIZE_DEFAULT * binsect ); } if (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_NEED_INIT)) return 1; if ( !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS)) || (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) { ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_CANCEL, _("Journal stored outside of the volume are " "not supported. Try to desactivate the " "journal and run Parted again.")); return 0; } if ( (PED_BE64_TO_CPU(jib->offset) % PED_SECTOR_SIZE_DEFAULT) || (PED_BE64_TO_CPU(jib->size) % PED_SECTOR_SIZE_DEFAULT) ) { ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_CANCEL, _("Journal offset or size is not multiple of " "the sector size.")); return 0; } sector = PED_BE64_TO_CPU(jib->offset) / PED_SECTOR_SIZE_DEFAULT; length = PED_BE64_TO_CPU(jib->size) / PED_SECTOR_SIZE_DEFAULT; jib = NULL; if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1)) return 0; jh = (HfsJJournalHeader*) buf; if (jh->endian == PED_LE32_TO_CPU(HFSJ_ENDIAN_MAGIC)) is_le = 1; if ( (jh->magic != HFS_32_TO_CPU(HFSJ_HEADER_MAGIC, is_le)) || (jh->endian != HFS_32_TO_CPU(HFSJ_ENDIAN_MAGIC, is_le)) ) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Incorrect magic values in the journal header.")); return 0; } if ( (HFS_64_TO_CPU(jh->size, is_le)%PED_SECTOR_SIZE_DEFAULT) || (HFS_64_TO_CPU(jh->size, is_le)/PED_SECTOR_SIZE_DEFAULT != (uint64_t)length) ) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Journal size mismatch between journal info block " "and journal header.")); return 0; } if ( (HFS_64_TO_CPU(jh->start, is_le) % PED_SECTOR_SIZE_DEFAULT) || (HFS_64_TO_CPU(jh->end, is_le) % PED_SECTOR_SIZE_DEFAULT) || (HFS_32_TO_CPU(jh->blhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT) || (HFS_32_TO_CPU(jh->jhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT) ) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Some header fields are not multiple of the sector " "size.")); return 0; } if (HFS_32_TO_CPU(jh->jhdr_size, is_le) != PED_SECTOR_SIZE_DEFAULT) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The sector size stored in the journal is not 512 " "bytes. Parted only supports 512 bytes length " "sectors.")); return 0; } cksum = HFS_32_TO_CPU(jh->checksum, is_le); jh->checksum = 0; if (cksum != hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Bad journal checksum.")); return 0; } jh->checksum = HFS_CPU_TO_32(cksum, is_le); /* The 2 following test are in the XNU Darwin source code */ /* so I assume they're needed */ if (jh->start == jh->size) jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le); if (jh->end == jh->size) jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le); if (jh->start == jh->end) return 1; if (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL, _("The journal is not empty. Parted must replay the " "transactions before opening the file system. This will " "modify the file system.")) != PED_EXCEPTION_FIX) return 0; while (jh->start != jh->end) { /* Replay one complete transaction */ if (!hfsj_replay_transaction(fs, jh, sector, length)) return 0; /* Recalculate cksum of the journal header */ jh->checksum = 0; /* need to be 0 while calculating the cksum */ cksum = hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh)); jh->checksum = HFS_CPU_TO_32(cksum, is_le); /* Update the Journal Header */ if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1) || !ped_geometry_sync(priv_data->plus_geom)) return 0; } if (hfsj_vh_replayed) { /* probe could have reported incorrect info ! */ /* is there a way to ask parted to quit ? */ ped_exception_throw( PED_EXCEPTION_WARNING, PED_EXCEPTION_OK, _("The volume header or the master directory block has " "changed while replaying the journal. You should " "restart Parted.")); return 0; } return 1; }
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; }
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; }