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 ); }
static PedGeometry* jfs_probe (PedGeometry* geom) { union { struct superblock sb; char bytes[512]; } buf; /* FIXME: for now, don't even try to deal with larger sector size. */ if (geom->dev->sector_size != PED_SECTOR_SIZE_DEFAULT) return NULL; if (geom->length < JFS_SUPER_SECTOR + 1) return NULL; if (!ped_geometry_read (geom, &buf, JFS_SUPER_SECTOR, 1)) return NULL; if (strncmp (buf.sb.s_magic, JFS_MAGIC, 4) == 0) { PedSector block_size = PED_LE32_TO_CPU (buf.sb.s_pbsize) / 512; PedSector block_count = PED_LE64_TO_CPU (buf.sb.s_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } else { return NULL; } }
int hfsj_update_jl(PedFileSystem* fs, uint32_t block) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; PedSector sector; uint64_t offset; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsJJournalInfoBlock* jib; int binsect; binsect = HFS_32_TO_CPU(priv_data->vh->block_size, is_le) / PED_SECTOR_SIZE_DEFAULT; sector = (PedSector) priv_data->jib_start_block * binsect; if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1)) return 0; jib = (HfsJJournalInfoBlock*) buf; offset = (uint64_t)block * PED_SECTOR_SIZE_DEFAULT * binsect; jib->offset = HFS_CPU_TO_64(offset, is_le); if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1) || !ped_geometry_sync(priv_data->plus_geom)) return 0; priv_data->jl_start_block = block; return 1; }
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 PedGeometry* ufs_probe_sun (PedGeometry* geom) { int8_t buf[512 * 3]; struct ufs_super_block *sb; if (geom->length < 5) return 0; if (!ped_geometry_read (geom, buf, 16, 3)) return 0; sb = (struct ufs_super_block *)buf; if (PED_BE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) { PedSector block_size = PED_BE32_TO_CPU(sb->fs_bsize) / 512; PedSector block_count = PED_BE32_TO_CPU(sb->fs_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } if (PED_LE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) { PedSector block_size = PED_LE32_TO_CPU(sb->fs_bsize) / 512; PedSector block_count = PED_LE32_TO_CPU(sb->fs_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } return NULL; }
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; }
/* return 0 on error */ int hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector) { PedSector abs_sector; if (sector >= file->sect_nb) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Trying to read HFS file with CNID %X behind EOF."), PED_BE32_TO_CPU(file->CNID)); return 0; } abs_sector = hfs_file_find_sector (file, sector); if (!abs_sector) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Could not find sector %lli of HFS file with " "CNID %X."), sector, PED_BE32_TO_CPU(file->CNID)); return 0; } return ped_geometry_read (file->fs->geom, buf, abs_sector, 1); }
static PedGeometry *reiserfs_probe(PedGeometry *geom) { int i; reiserfs_super_block_t sb; PED_ASSERT(geom != NULL); for (i = 0; reiserfs_super_offset[i] != -1; i++) { if (reiserfs_super_offset[i] >= geom->length) continue; if (!ped_geometry_read (geom, &sb, reiserfs_super_offset[i], 1)) continue; if (strncmp(REISERFS_SIGNATURE, sb.s_magic, strlen(REISERFS_SIGNATURE)) == 0 || strncmp(REISER2FS_SIGNATURE, sb.s_magic, strlen(REISER2FS_SIGNATURE)) == 0 || strncmp(REISER3FS_SIGNATURE, sb.s_magic, strlen(REISER3FS_SIGNATURE)) == 0) { PedSector block_size; PedSector block_count; block_size = PED_LE16_TO_CPU(sb.s_blocksize) / PED_SECTOR_SIZE_DEFAULT; block_count = PED_LE32_TO_CPU(sb.s_block_count); return ped_geometry_new(geom->dev, geom->start, block_size * block_count); } } return NULL; }
/* copies the "hidden" sectors, between the boot sector and the FAT. Required, * for the Windows 98 FAT32 boot loader */ int _copy_hidden_sectors (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); PedSector first = 1; PedSector last; PedSector count; /* nothing to copy for FAT16 */ if (old_fs_info->fat_type == FAT_TYPE_FAT16 || new_fs_info->fat_type == FAT_TYPE_FAT16) return 1; last = PED_MIN (old_fs_info->fat_offset, new_fs_info->fat_offset) - 1; count = last - first + 1; PED_ASSERT (count < BUFFER_SIZE); if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer, first, count)) return 0; if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer, first, count)) return 0; return 1; }
FatTraverseInfo* fat_traverse_begin (PedFileSystem* fs, FatCluster start_cluster, const char* dir_name) { FatSpecific* fs_info = FAT_SPECIFIC (fs); FatTraverseInfo* trav_info; trav_info = (FatTraverseInfo*) ped_malloc (sizeof (FatTraverseInfo)); if (!trav_info) goto error; trav_info->dir_name = strdup (dir_name); if (!trav_info->dir_name) goto error_free_trav_info; trav_info->fs = fs; trav_info->is_legacy_root_dir = (fs_info->fat_type == FAT_TYPE_FAT16) && (start_cluster == 0); trav_info->dirty = 0; trav_info->eof = 0; trav_info->current_entry = -1; if (trav_info->is_legacy_root_dir) { trav_info->buffer_size = 512 * fs_info->root_dir_sector_count; } else { trav_info->next_buffer = start_cluster; trav_info->buffer_size = fs_info->cluster_size; } trav_info->dir_entries = (FatDirEntry*) ped_malloc (trav_info->buffer_size); if (!trav_info->dir_entries) goto error_free_dir_name; if (trav_info->is_legacy_root_dir) { if (!ped_geometry_read (fs->geom, trav_info->dir_entries, fs_info->root_dir_offset, fs_info->root_dir_sector_count)) goto error_free_dir_entries; } else { if (!read_next_dir_buffer (trav_info)) goto error_free_dir_entries; } return trav_info; error_free_dir_entries: free (trav_info->dir_entries); error_free_dir_name: free (trav_info->dir_name); error_free_trav_info: free (trav_info); error: return NULL; }
static int ufs_clobber (PedGeometry* geom) { char buf[1536]; if (!ped_geometry_read (geom, buf, 16, 3)) return 0; memset (buf, 0, sizeof(struct ufs_super_block)); return ped_geometry_write (geom, buf, 16, 3); }
/* Reads in the boot sector (superblock), and does a minimum of sanity * checking. The goals are: * - to detect fat file systems, even if they are damaged [i.e. not * return an error / throw an exception] * - to fail detection if there's not enough information for * fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero) */ int fat_boot_sector_read (FatBootSector* bs, const PedGeometry *geom) { PED_ASSERT (bs != NULL); PED_ASSERT (geom != NULL); if (!ped_geometry_read (geom, bs, 0, 1)) return 0; if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid signature for a FAT " "file system.")); return 0; } if (!bs->system_id[0]) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid signature for a FAT " "file system.")); return 0; } if (!bs->sector_size || PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid sector size for a FAT " "file system.")); return 0; } if (!bs->cluster_size) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid cluster size for a FAT " "file system.")); return 0; } if (!bs->reserved) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid number of reserved " "sectors for a FAT file system.")); return 0; } if (bs->fats < 1 || bs->fats > 4) { ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("File system has an invalid number of FATs.")); return 0; } return 1; }
int fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag, FatFragment count) { FatSpecific* fs_info = FAT_SPECIFIC (fs); PedSector sector = fat_frag_to_sector (fs, frag); PedSector sector_count = count * fs_info->frag_sectors; PED_ASSERT (frag >= 0 && frag < fs_info->frag_count); return ped_geometry_read (fs->geom, buf, sector, sector_count); }
int fat_read_clusters (PedFileSystem* fs, char *buf, FatCluster cluster, FatCluster count) { FatSpecific* fs_info = FAT_SPECIFIC (fs); PedSector sector = fat_cluster_to_sector (fs, cluster); PedSector sector_count = count * fs_info->cluster_sectors; PED_ASSERT (cluster >= 2 && cluster + count - 1 < fs_info->cluster_count + 2); return ped_geometry_read (fs->geom, buf, sector, sector_count); }
PyObject *py_ped_geometry_read(PyObject *s, PyObject *args) { PyObject *ret = NULL; PedGeometry *geom = NULL; char *out_buf = NULL; PedSector offset, count; if (!PyArg_ParseTuple(args, "LL", &offset, &count)) { return NULL; } geom = _ped_Geometry2PedGeometry(s); if (geom == NULL) { return NULL; } /* py_device_read will ASSERT if the device isn't open yet. */ if (geom->dev->open_count <= 0) { PyErr_SetString(IOException, "Attempting to read from a unopened device"); return NULL; } /* And then py_geometry_read will ASSERT on these things too. */ if (offset < 0 || count < 0) { PyErr_SetString(IOException, "offset and count cannot be negative."); return NULL; } if ((out_buf = malloc(geom->dev->sector_size * count)) == NULL) { return PyErr_NoMemory(); } if (ped_geometry_read(geom, out_buf, offset, count) == 0) { if (partedExnRaised) { partedExnRaised = 0; if (!PyErr_ExceptionMatches(PartedException) && !PyErr_ExceptionMatches(PyExc_NotImplementedError)) PyErr_SetString(IOException, partedExnMessage); } else PyErr_SetString(IOException, "Could not read from given region"); free(out_buf); return NULL; } ret = PyString_FromString(out_buf); free(out_buf); return ret; }
/* 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; }
static PedGeometry* ntfs_probe (PedGeometry* geom) { char buf[512]; if (!ped_geometry_read (geom, buf, 0, 1)) return 0; if (strncmp (NTFS_SIGNATURE, buf + 3, strlen (NTFS_SIGNATURE)) == 0) return ped_geometry_new (geom->dev, geom->start, PED_LE64_TO_CPU (*(uint64_t*) (buf + 0x28))); else return NULL; }
/* 1 on succes */ int hfsplus_update_vh (PedFileSystem *fs) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node[PED_SECTOR_SIZE_DEFAULT]; if (!ped_geometry_read (priv_data->plus_geom, node, 2, 1)) return 0; memcpy (node, priv_data->vh, sizeof (HfsPVolumeHeader)); if (!ped_geometry_write (priv_data->plus_geom, node, 2, 1) || !ped_geometry_write (priv_data->plus_geom, node, priv_data->plus_geom->length - 2, 1) || !ped_geometry_sync_fast (priv_data->plus_geom)) return 0; return 1; }
static int hfs_extract_mdb (const char* filename, PedFileSystem* fs) { FILE* fout; fout = fopen(filename, "w"); if (!fout) return 0; if (!ped_geometry_read(fs->geom, extract_buffer, 2, 1)) goto err_close; if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout)) goto err_close; return (fclose(fout) == 0 ? 1 : 0); err_close: fclose(fout); return 0; }
static int duplicate_legacy_root_dir (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); PED_ASSERT (old_fs_info->root_dir_sector_count == new_fs_info->root_dir_sector_count); if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer, old_fs_info->root_dir_offset, old_fs_info->root_dir_sector_count)) return 0; if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer, new_fs_info->root_dir_offset, new_fs_info->root_dir_sector_count)) return 0; return 1; }
/* or 0 on error */ static PedSector hfsj_journal_read(PedGeometry* geom, HfsJJournalHeader* jh, PedSector journ_sect, PedSector journ_length, PedSector read_sect, unsigned int nb_sect, void* buf) { int r; while (nb_sect--) { r = ped_geometry_read(geom, buf, journ_sect + read_sect, 1); if (!r) return 0; buf = ((uint8_t*)buf) + PED_SECTOR_SIZE_DEFAULT; read_sect++; if (read_sect == journ_length) read_sect = 1; /* skip journal header which is asserted to be 1 sector long */ } return read_sect; }
static PedGeometry* ufs_probe_hp (PedGeometry* geom) { int8_t buf[1536]; struct ufs_super_block *sb; PedSector block_size; PedSector block_count; if (geom->length < 5) return 0; if (!ped_geometry_read (geom, buf, 16, 3)) return 0; sb = (struct ufs_super_block *)buf; /* Try sane bytesex */ switch (PED_BE32_TO_CPU(sb->fs_magic)) { case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: block_size = PED_BE32_TO_CPU(sb->fs_bsize) / 512; block_count = PED_BE32_TO_CPU(sb->fs_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } /* Try perverted bytesex */ switch (PED_LE32_TO_CPU(sb->fs_magic)) { case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: block_size = PED_LE32_TO_CPU(sb->fs_bsize) / 512; block_count = PED_LE32_TO_CPU(sb->fs_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } return NULL; }
int fat_info_sector_read (FatInfoSector* is, const PedFileSystem* fs) { FatSpecific* fs_info = FAT_SPECIFIC (fs); int status; PED_ASSERT (is != NULL); if (!ped_geometry_read (fs->geom, is, fs_info->info_sector_offset, 1)) return 0; if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) { status = ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL, _("The information sector has the wrong " "signature (%x). Select cancel for now, " "and send in a bug report. If you're " "desperate, it's probably safe to ignore."), PED_LE32_TO_CPU (is->signature_2)); if (status == PED_EXCEPTION_CANCEL) return 0; } return 1; }
static PedGeometry* jfs_probe (PedGeometry* geom) { union { struct superblock sb; char bytes[512]; } buf; if (geom->length < JFS_SUPER_SECTOR + 1) return NULL; if (!ped_geometry_read (geom, &buf, JFS_SUPER_SECTOR, 1)) return NULL; if (strncmp (buf.sb.s_magic, JFS_MAGIC, 4) == 0) { PedSector block_size = PED_LE32_TO_CPU (buf.sb.s_pbsize) / 512; PedSector block_count = PED_LE64_TO_CPU (buf.sb.s_size); return ped_geometry_new (geom->dev, geom->start, block_size * block_count); } else { return NULL; } }
static int hfsplus_extract_vh (const char* filename, PedFileSystem* fs) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; FILE* fout; PedGeometry* geom = priv_data->plus_geom; fout = fopen(filename, "w"); if (!fout) return 0; if (!ped_geometry_read(geom, extract_buffer, 2, 1)) goto err_close; if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout)) goto err_close; return (fclose(fout) == 0 ? 1 : 0); err_close: fclose(fout); return 0; }
/* -1 is ok because there can only be 2^32-1 blocks, so the max possible last one is 2^32-2 (and anyway it contains Alternate VH), so -1 (== 2^32-1[2^32]) never represent a valid block */ static int hfsplus_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock, unsigned int *ptr_to_fblock, unsigned int size) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; unsigned int i, ok = 0; unsigned int next_to_fblock; unsigned int start, stop; PED_ASSERT (hfsp_block != NULL); PED_ASSERT (*ptr_to_fblock <= *ptr_fblock); /* quiet GCC */ start = stop = 0; /* Try to fit the extent AT or _BEFORE_ the wanted place, or then in the gap between dest and source. If failed try to fit the extent after source, for 2 pass relocation The extent is always copied in a non overlapping way */ /* Backward search */ /* 1 pass relocation AT or BEFORE *ptr_to_fblock */ if (*ptr_to_fblock != *ptr_fblock) { start = stop = *ptr_fblock < *ptr_to_fblock+size ? *ptr_fblock : *ptr_to_fblock+size; while (start && stop-start != size) { --start; if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start)) stop = start; } ok = (stop-start == size); } /* Forward search */ /* 1 pass relocation in the gap merged with 2 pass reloc after source */ if (!ok && *ptr_to_fblock != *ptr_fblock) { start = stop = *ptr_to_fblock+1; while (stop < PED_BE32_TO_CPU(priv_data->vh->total_blocks) && stop-start != size) { if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop)) start = stop + 1; ++stop; } ok = (stop-start == size); } /* new non overlapping room has been found ? */ if (ok) { /* enough room */ PedSector abs_sector; unsigned int ai, j, block; unsigned int block_sz = (PED_BE32_TO_CPU ( priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT); if (stop > *ptr_to_fblock && stop <= *ptr_fblock) /* Fit in the gap */ next_to_fblock = stop; else /* Before or after the gap */ next_to_fblock = *ptr_to_fblock; /* move blocks */ for (i = 0; i < size; /*i++*/) { j = size - i; j = (j < hfsp_block_count) ? j : hfsp_block_count ; abs_sector = (PedSector) (*ptr_fblock + i) * block_sz; if (!ped_geometry_read (priv_data->plus_geom, hfsp_block, abs_sector, block_sz * j)) return -1; abs_sector = (PedSector) (start + i) * block_sz; if (!ped_geometry_write (priv_data->plus_geom, hfsp_block, abs_sector, block_sz * j)) return -1; for (ai = i+j; i < ai; i++) { /* free source block */ block = *ptr_fblock + i; CLR_BLOC_OCCUPATION(priv_data->alloc_map,block); SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map, block/(PED_SECTOR_SIZE_DEFAULT*8)); /* set dest block */ block = start + i; SET_BLOC_OCCUPATION(priv_data->alloc_map,block); SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map, block/(PED_SECTOR_SIZE_DEFAULT*8)); } } if (!ped_geometry_sync_fast (priv_data->plus_geom)) return -1; *ptr_fblock += size; *ptr_to_fblock = next_to_fblock; } else { if (*ptr_fblock != *ptr_to_fblock) /* not enough room */ ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE, _("An extent has not been relocated.")); start = *ptr_fblock; *ptr_fblock = *ptr_to_fblock = start + size; } return start; }
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_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; unsigned int nblock, nfree, mblock; unsigned int block, to_free, old_blocks; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsPVolumeHeader* vh = priv_data->vh; int resize = 1; unsigned int hfsp_sect_block = ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT ); unsigned int map_sectors; old_blocks = PED_BE32_TO_CPU (vh->total_blocks); /* Flush caches */ if (!ped_geometry_sync(priv_data->plus_geom)) return 0; /* Clear the unmounted bit */ /* and set the implementation code (Apple Creator Code) */ vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED )); vh->last_mounted_version = PED_CPU_TO_BE32(HFSP_IMPL_Shnk); if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) return 0; memcpy (buf, vh, sizeof (HfsPVolumeHeader)); if ( !ped_geometry_write (priv_data->plus_geom, buf, 2, 1) || !ped_geometry_sync (priv_data->plus_geom)) return 0; ped_timer_reset (timer); ped_timer_set_state_name(timer, _("shrinking")); ped_timer_update(timer, 0.0); /* relocate data */ to_free = ( priv_data->plus_geom->length - geom->length + hfsp_sect_block - 1 ) / hfsp_sect_block; block = hfsplus_find_start_pack (fs, to_free); if (!hfsplus_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_VH; } /* Calculate new block number and other VH field */ /* nblock must be rounded _down_ */ nblock = geom->length / hfsp_sect_block; nfree = PED_BE32_TO_CPU (vh->free_blocks) - (old_blocks - nblock); /* free block readjustement is only needed when incorrect nblock was used by my previous implementation, so detect the case */ if (priv_data->plus_geom->length < old_blocks * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT) ) { if (priv_data->plus_geom->length % hfsp_sect_block == 1) nfree++; } /* Check that all block after future end are really free */ mblock = ( priv_data->plus_geom->length - 2 ) / hfsp_sect_block; if (mblock > old_blocks - 1) mblock = old_blocks - 1; for ( block = nblock; block < mblock; 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 at the end " "of the volume.")); goto write_VH; } } /* Mark out of volume blocks as used */ map_sectors = ( ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8) ) * (PED_SECTOR_SIZE_DEFAULT * 8); for ( block = nblock; block < map_sectors; ++block) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); /* Update geometry */ if (resize) { /* update in fs structure */ if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock) vh->next_allocation = PED_CPU_TO_BE32 (0); vh->total_blocks = PED_CPU_TO_BE32 (nblock); vh->free_blocks = PED_CPU_TO_BE32 (nfree); /* update parted structure */ priv_data->plus_geom->length = geom->length; priv_data->plus_geom->end = priv_data->plus_geom->start + geom->length - 1; } /* Effective write */ write_VH: /* lasts two sectors are allocated by the alternate VH and a reserved sector, and last block is always reserved */ block = (priv_data->plus_geom->length - 1) / hfsp_sect_block; if (block < PED_BE32_TO_CPU (vh->total_blocks)) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); block = (priv_data->plus_geom->length - 2) / hfsp_sect_block; if (block < PED_BE32_TO_CPU (vh->total_blocks)) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); SET_BLOC_OCCUPATION(priv_data->alloc_map, PED_BE32_TO_CPU (vh->total_blocks) - 1); /* Write the _old_ area to set out of volume blocks as used */ map_sectors = ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); if (!hfsplus_file_write (priv_data->allocation_file, priv_data->alloc_map, 0, map_sectors)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Error while writing the allocation file.")); } else { /* Write remaining part of allocation bitmap */ /* This is necessary to handle pre patch-11 and third party */ /* implementations */ memset(buf, 0xFF, PED_SECTOR_SIZE_DEFAULT); for (block = map_sectors; block < priv_data->allocation_file->sect_nb; ++block) { if (!hfsplus_file_write_sector ( priv_data->allocation_file, buf, block)) { ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE, _("Error while writing the " "compatibility part of the " "allocation file.")); break; } } } ped_geometry_sync (priv_data->plus_geom); if (resize) { /* Set the unmounted bit and clear the inconsistent bit */ vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED ); vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT ); } ped_timer_set_state_name(timer, _("writing HFS+ Volume Header")); if (!hfsplus_update_vh(fs)) { ped_geometry_sync(priv_data->plus_geom); return 0; } if (!ped_geometry_sync(priv_data->plus_geom)) return 0; ped_timer_update(timer, 1.0); return (resize); }
/* 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; }