pmt: revert 7f8090b
This commit is contained in:
@@ -1,441 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2002, 2004, 2007, 2009-2014, 2019-2023 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* 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** bsp, const PedGeometry *geom)
|
||||
{
|
||||
PED_ASSERT (bsp != NULL);
|
||||
PED_ASSERT (geom != NULL);
|
||||
|
||||
if (!ped_geometry_read_alloc (geom, (void **)bsp, 0, 1))
|
||||
return 0;
|
||||
FatBootSector *bs = *bsp;
|
||||
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->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;
|
||||
}
|
||||
|
||||
/*
|
||||
Don't trust the FAT12, FAT16 or FAT32 label string.
|
||||
*/
|
||||
FatType _GL_ATTRIBUTE_PURE
|
||||
fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
|
||||
{
|
||||
PedSector logical_sector_size;
|
||||
PedSector first_cluster_sector;
|
||||
FatCluster cluster_count;
|
||||
|
||||
if (!PED_LE16_TO_CPU (bs->dir_entries))
|
||||
return FAT_TYPE_FAT32;
|
||||
|
||||
logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
|
||||
|
||||
first_cluster_sector
|
||||
= PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
|
||||
+ 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
|
||||
+ PED_LE16_TO_CPU (bs->dir_entries)
|
||||
/ (512 / sizeof (FatDirEntry));
|
||||
cluster_count = (geom->length - first_cluster_sector)
|
||||
/ bs->cluster_size / logical_sector_size;
|
||||
if (cluster_count > MAX_FAT12_CLUSTERS)
|
||||
return FAT_TYPE_FAT16;
|
||||
else
|
||||
return FAT_TYPE_FAT12;
|
||||
}
|
||||
|
||||
/* Analyses the boot sector, and sticks appropriate numbers in
|
||||
fs->type_specific.
|
||||
|
||||
Note: you need to subtract (2 * cluster_sectors) off cluster offset,
|
||||
because the first cluster is number 2. (0 and 1 are not real clusters,
|
||||
and referencing them is a bug)
|
||||
*/
|
||||
int
|
||||
fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
int fat_entry_size;
|
||||
|
||||
PED_ASSERT (bs != NULL);
|
||||
|
||||
fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
|
||||
|
||||
fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
|
||||
fs_info->heads = PED_LE16_TO_CPU (bs->heads);
|
||||
if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
|
||||
|| fs_info->heads < 1 || fs_info->heads > 255) {
|
||||
PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
|
||||
int cyl_count = 0;
|
||||
|
||||
if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
|
||||
cyl_count = fs->geom->dev->length / fs_info->heads
|
||||
/ fs_info->sectors_per_track;
|
||||
|
||||
switch (ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE
|
||||
+ PED_EXCEPTION_CANCEL,
|
||||
_("The file system's CHS geometry is (%d, %d, %d), "
|
||||
"which is invalid. The partition table's CHS "
|
||||
"geometry is (%d, %d, %d). If you select Ignore, "
|
||||
"the file system's CHS geometry will be left "
|
||||
"unchanged. If you select Fix, the file system's "
|
||||
"CHS geometry will be set to match the partition "
|
||||
"table's CHS geometry."),
|
||||
cyl_count, fs_info->heads, fs_info->sectors_per_track,
|
||||
bios_geom->cylinders, bios_geom->heads,
|
||||
bios_geom->sectors)) {
|
||||
|
||||
case PED_EXCEPTION_FIX:
|
||||
fs_info->sectors_per_track = bios_geom->sectors;
|
||||
fs_info->heads = bios_geom->heads;
|
||||
bs->secs_track
|
||||
= PED_CPU_TO_LE16 (fs_info->sectors_per_track);
|
||||
bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
|
||||
if (!fat_boot_sector_write (bs, fs))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case PED_EXCEPTION_CANCEL:
|
||||
return 0;
|
||||
|
||||
case PED_EXCEPTION_IGNORE:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bs->sectors)
|
||||
fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
|
||||
* fs_info->logical_sector_size;
|
||||
else
|
||||
fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
|
||||
* fs_info->logical_sector_size;
|
||||
|
||||
fs_info->fat_table_count = bs->fats;
|
||||
fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
|
||||
fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->cluster_sectors = bs->cluster_size
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->cluster_size = fs_info->cluster_sectors * 512;
|
||||
|
||||
if (fs_info->logical_sector_size == 0) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("FAT boot sector says logical sector size is 0. "
|
||||
"This is weird. "));
|
||||
return 0;
|
||||
}
|
||||
if (fs_info->fat_table_count == 0) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("FAT boot sector says there are no FAT tables. This "
|
||||
"is weird. "));
|
||||
return 0;
|
||||
}
|
||||
if (fs_info->cluster_sectors == 0) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("FAT boot sector says clusters are 0 sectors. This "
|
||||
"is weird. "));
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT12) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_NO_FEATURE,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("File system is FAT12, which is unsupported."));
|
||||
return 0;
|
||||
}
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16) {
|
||||
fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->serial_number
|
||||
= PED_LE32_TO_CPU (bs->u.fat16.serial_number);
|
||||
fs_info->root_cluster = 0;
|
||||
fs_info->root_dir_offset
|
||||
= fs_info->fat_offset
|
||||
+ fs_info->fat_sectors * fs_info->fat_table_count;
|
||||
fs_info->root_dir_sector_count
|
||||
= fs_info->root_dir_entry_count * sizeof (FatDirEntry)
|
||||
/ (512 * fs_info->logical_sector_size);
|
||||
fs_info->cluster_offset
|
||||
= fs_info->root_dir_offset
|
||||
+ fs_info->root_dir_sector_count;
|
||||
}
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->serial_number
|
||||
= PED_LE32_TO_CPU (bs->u.fat32.serial_number);
|
||||
fs_info->info_sector_offset
|
||||
= PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.info_sector)
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->boot_sector_backup_offset
|
||||
= PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.backup_sector)
|
||||
* fs_info->logical_sector_size;
|
||||
fs_info->root_cluster
|
||||
= PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
|
||||
fs_info->root_dir_offset = 0;
|
||||
fs_info->root_dir_sector_count = 0;
|
||||
fs_info->cluster_offset
|
||||
= fs_info->fat_offset
|
||||
+ fs_info->fat_sectors * fs_info->fat_table_count;
|
||||
}
|
||||
|
||||
fs_info->cluster_count
|
||||
= (fs_info->sector_count - fs_info->cluster_offset)
|
||||
/ fs_info->cluster_sectors;
|
||||
|
||||
fat_entry_size = fat_table_entry_size (fs_info->fat_type);
|
||||
if (fs_info->cluster_count + 2
|
||||
> fs_info->fat_sectors * 512 / fat_entry_size)
|
||||
fs_info->cluster_count
|
||||
= fs_info->fat_sectors * 512 / fat_entry_size - 2;
|
||||
|
||||
fs_info->dir_entries_per_cluster
|
||||
= fs_info->cluster_size / sizeof (FatDirEntry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
int
|
||||
fat_boot_sector_set_boot_code (FatBootSector** bsp, const PedFileSystem* fs)
|
||||
{
|
||||
PED_ASSERT (bsp != NULL);
|
||||
*bsp = ped_malloc (fs->geom->dev->sector_size);
|
||||
FatBootSector *bs = *bsp;
|
||||
PED_ASSERT (bs != NULL);
|
||||
|
||||
memset (bs, 0, 512);
|
||||
memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3);
|
||||
PED_ASSERT (sizeof(FAT_BOOT_CODE) < sizeof(bs->u.fat32.boot_code));
|
||||
strcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_boot_sector_generate (FatBootSector** bsp, const PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (bsp != NULL);
|
||||
FatBootSector *bs = *bsp;
|
||||
PED_ASSERT (bs != NULL);
|
||||
|
||||
memcpy (bs->system_id, "MSWIN4.1", 8);
|
||||
bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512);
|
||||
bs->cluster_size = fs_info->cluster_sectors
|
||||
/ fs_info->logical_sector_size;
|
||||
bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset
|
||||
/ fs_info->logical_sector_size);
|
||||
bs->fats = fs_info->fat_table_count;
|
||||
|
||||
bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16)
|
||||
? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count)
|
||||
: 0;
|
||||
|
||||
if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff
|
||||
|| fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
bs->sectors = 0;
|
||||
bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count
|
||||
/ fs_info->logical_sector_size);
|
||||
} else {
|
||||
bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count
|
||||
/ fs_info->logical_sector_size);
|
||||
bs->sector_count = 0;
|
||||
}
|
||||
|
||||
bs->media = 0xf8;
|
||||
|
||||
bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
|
||||
bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
|
||||
bs->hidden = PED_CPU_TO_LE32 (fs->geom->start);
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
bs->fat_length = 0;
|
||||
bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors
|
||||
/ fs_info->logical_sector_size);
|
||||
bs->u.fat32.flags = 0; /* FIXME: what the hell are these? */
|
||||
bs->u.fat32.version = 0; /* must be 0, for Win98 bootstrap */
|
||||
bs->u.fat32.root_dir_cluster
|
||||
= PED_CPU_TO_LE32 (fs_info->root_cluster);
|
||||
bs->u.fat32.info_sector
|
||||
= PED_CPU_TO_LE16 (fs_info->info_sector_offset
|
||||
/ fs_info->logical_sector_size);
|
||||
bs->u.fat32.backup_sector
|
||||
= PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset
|
||||
/ fs_info->logical_sector_size);
|
||||
|
||||
bs->u.fat32.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
|
||||
|
||||
memset (bs->u.fat32.empty_1, 0, 12);
|
||||
|
||||
bs->u.fat32.ext_signature = 0x29;
|
||||
bs->u.fat32.serial_number
|
||||
= PED_CPU_TO_LE32 (fs_info->serial_number);
|
||||
memcpy (bs->u.fat32.volume_name, "NO NAME ", 11);
|
||||
memcpy (bs->u.fat32.fat_name, "FAT32 ", 8);
|
||||
} else {
|
||||
bs->fat_length
|
||||
= PED_CPU_TO_LE16 (fs_info->fat_sectors
|
||||
/ fs_info->logical_sector_size);
|
||||
|
||||
bs->u.fat16.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
|
||||
|
||||
bs->u.fat16.ext_signature = 0x29;
|
||||
bs->u.fat16.serial_number
|
||||
= PED_CPU_TO_LE32 (fs_info->serial_number);
|
||||
memcpy (bs->u.fat16.volume_name, "NO NAME ", 11);
|
||||
memcpy (bs->u.fat16.fat_name, "FAT16 ", 8);
|
||||
}
|
||||
|
||||
bs->boot_sign = PED_CPU_TO_LE16 (0xaa55);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (bs != NULL);
|
||||
|
||||
if (!ped_geometry_write (fs->geom, bs, 0, 1))
|
||||
return 0;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
if (!ped_geometry_write (fs->geom, bs,
|
||||
fs_info->boot_sector_backup_offset, 1))
|
||||
return 0;
|
||||
}
|
||||
return ped_geometry_sync (fs->geom);
|
||||
}
|
||||
|
||||
int
|
||||
fat_info_sector_read (FatInfoSector** isp, const PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
int status;
|
||||
|
||||
PED_ASSERT (isp != NULL);
|
||||
|
||||
if (!ped_geometry_read_alloc (fs->geom, (void **)isp, fs_info->info_sector_offset, 1))
|
||||
return 0;
|
||||
FatInfoSector *is = *isp;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
fat_info_sector_generate (FatInfoSector** isp, const PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (isp != NULL);
|
||||
*isp = ped_malloc (fs->geom->dev->sector_size);
|
||||
FatInfoSector *is = *isp;
|
||||
|
||||
fat_table_count_stats (fs_info->fat);
|
||||
|
||||
memset (is, 0, 512);
|
||||
|
||||
is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1);
|
||||
is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2);
|
||||
is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count);
|
||||
is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc);
|
||||
is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (is != NULL);
|
||||
|
||||
if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
|
||||
return 0;
|
||||
return ped_geometry_sync (fs->geom);
|
||||
}
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PED_FAT_BOOTSECTOR_H
|
||||
#define PED_FAT_BOOTSECTOR_H
|
||||
|
||||
typedef struct _FatBootSector FatBootSector;
|
||||
typedef struct _FatInfoSector FatInfoSector;
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
#define FAT32_INFO_MAGIC1 0x41615252
|
||||
#define FAT32_INFO_MAGIC2 0x61417272
|
||||
#define FAT32_INFO_MAGIC3 0xaa55
|
||||
|
||||
/* stolen from mkdosfs, by Dave Hudson */
|
||||
|
||||
#define FAT_BOOT_MESSAGE \
|
||||
"This partition does not have an operating system loader installed on it.\n\r"\
|
||||
"Press a key to reboot..."
|
||||
|
||||
#define FAT_BOOT_JUMP "\xeb\x58\x90" /* jmp +5a */
|
||||
|
||||
#define FAT_BOOT_CODE "\x0e" /* push cs */ \
|
||||
"\x1f" /* pop ds */ \
|
||||
"\xbe\x74\x7e" /* mov si, offset message */ \
|
||||
/* write_msg_loop: */ \
|
||||
"\xac" /* lodsb */ \
|
||||
"\x22\xc0" /* and al, al */ \
|
||||
"\x74\x06" /* jz done (+8) */ \
|
||||
"\xb4\x0e" /* mov ah, 0x0e */ \
|
||||
"\xcd\x10" /* int 0x10 */ \
|
||||
"\xeb\xf5" /* jmp write_msg_loop */ \
|
||||
/* done: */ \
|
||||
"\xb4\x00" /* mov ah, 0x00 */ \
|
||||
"\xcd\x16" /* int 0x16 */ \
|
||||
"\xb4\x00" /* mov ah, 0x00 */ \
|
||||
"\xcd\x19" /* int 0x19 */ \
|
||||
"\xeb\xfe" /* jmp +0 - in case int 0x19 */ \
|
||||
/* doesn't work */ \
|
||||
/* message: */ \
|
||||
FAT_BOOT_MESSAGE
|
||||
|
||||
struct __attribute__ ((packed)) _FatBootSector {
|
||||
uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */
|
||||
uint8_t system_id[8]; /* 03: system name */
|
||||
uint16_t sector_size; /* 0b: bytes per logical sector */
|
||||
uint8_t cluster_size; /* 0d: sectors/cluster */
|
||||
uint16_t reserved; /* 0e: reserved sectors */
|
||||
uint8_t fats; /* 10: number of FATs */
|
||||
uint16_t dir_entries; /* 11: number of root directory entries */
|
||||
uint16_t sectors; /* 13: if 0, total_sect supersedes */
|
||||
uint8_t media; /* 15: media code */
|
||||
uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */
|
||||
uint16_t secs_track; /* 18: sectors per track */
|
||||
uint16_t heads; /* 1a: number of heads */
|
||||
uint32_t hidden; /* 1c: hidden sectors (partition start) */
|
||||
uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */
|
||||
|
||||
union __attribute__ ((packed)) {
|
||||
/* FAT16 fields */
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t drive_num; /* 24: */
|
||||
uint8_t empty_1; /* 25: */
|
||||
uint8_t ext_signature; /* 26: always 0x29 */
|
||||
uint32_t serial_number; /* 27: */
|
||||
uint8_t volume_name [11]; /* 2b: */
|
||||
uint8_t fat_name [8]; /* 36: */
|
||||
uint8_t boot_code[448]; /* 3f: Boot code (or message) */
|
||||
} fat16;
|
||||
/* FAT32 fields */
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t fat_length; /* 24: size of FAT in sectors */
|
||||
uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */
|
||||
uint16_t version; /* 2a: minor * 256 + major */
|
||||
uint32_t root_dir_cluster; /* 2c: */
|
||||
uint16_t info_sector; /* 30: */
|
||||
uint16_t backup_sector; /* 32: */
|
||||
uint8_t empty_1 [12]; /* 34: */
|
||||
uint16_t drive_num; /* 40: */
|
||||
uint8_t ext_signature; /* 42: always 0x29 */
|
||||
uint32_t serial_number; /* 43: */
|
||||
uint8_t volume_name [11]; /* 47: */
|
||||
uint8_t fat_name [8]; /* 52: */
|
||||
uint8_t boot_code[420]; /* 5a: Boot code (or message) */
|
||||
} fat32;
|
||||
} u;
|
||||
|
||||
uint16_t boot_sign; /* 1fe: always 0xAA55 */
|
||||
};
|
||||
|
||||
struct __attribute__ ((packed)) _FatInfoSector {
|
||||
uint32_t signature_1; /* should be 0x41615252 */
|
||||
uint8_t unused [480];
|
||||
uint32_t signature_2; /* should be 0x61417272 */
|
||||
uint32_t free_clusters;
|
||||
uint32_t next_cluster; /* most recently allocated cluster */
|
||||
uint8_t unused2 [0xe];
|
||||
uint16_t signature_3; /* should be 0xaa55 */
|
||||
};
|
||||
|
||||
int fat_boot_sector_read (FatBootSector** bs, const PedGeometry* geom);
|
||||
FatType fat_boot_sector_probe_type (const FatBootSector* bs,
|
||||
const PedGeometry* geom);
|
||||
int fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs);
|
||||
int fat_boot_sector_set_boot_code (FatBootSector** bs, const PedFileSystem* fs);
|
||||
int fat_boot_sector_generate (FatBootSector** bs, const PedFileSystem* fs);
|
||||
int fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs);
|
||||
|
||||
int fat_info_sector_read (FatInfoSector** is, const PedFileSystem* fs);
|
||||
int fat_info_sector_generate (FatInfoSector** is, const PedFileSystem* fs);
|
||||
int fat_info_sector_write (const FatInfoSector* is, PedFileSystem* fs);
|
||||
|
||||
#endif /* PED_FAT_BOOTSECTOR_H */
|
||||
@@ -1,433 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2002, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
/* returns the minimum size of clusters for a given file system type */
|
||||
PedSector _GL_ATTRIBUTE_CONST
|
||||
fat_min_cluster_size (FatType fat_type) {
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12: return 1;
|
||||
case FAT_TYPE_FAT16: return 1024/512;
|
||||
case FAT_TYPE_FAT32: return 4096/512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PedSector _GL_ATTRIBUTE_CONST
|
||||
_smallest_power2_over (PedSector ceiling)
|
||||
{
|
||||
PedSector result = 1;
|
||||
|
||||
while (result < ceiling)
|
||||
result *= 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns the minimum size of clusters for a given file system type */
|
||||
PedSector _GL_ATTRIBUTE_CONST
|
||||
fat_recommend_min_cluster_size (FatType fat_type, PedSector size) {
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12: return 1;
|
||||
case FAT_TYPE_FAT16: return fat_min_cluster_size(fat_type);
|
||||
case FAT_TYPE_FAT32:
|
||||
return PED_MAX(_smallest_power2_over(size
|
||||
/ MAX_FAT32_CLUSTERS),
|
||||
fat_min_cluster_size (fat_type));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the maxmimum size of clusters for a given file system type */
|
||||
PedSector _GL_ATTRIBUTE_CONST
|
||||
fat_max_cluster_size (FatType fat_type) {
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12: return 1; /* dunno... who cares? */
|
||||
case FAT_TYPE_FAT16: return 65536/512;
|
||||
case FAT_TYPE_FAT32: return 65536/512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the minimum number of clusters for a given file system type */
|
||||
FatCluster _GL_ATTRIBUTE_CONST
|
||||
fat_min_cluster_count (FatType fat_type) {
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
case FAT_TYPE_FAT16:
|
||||
return fat_max_cluster_count (fat_type) / 2;
|
||||
|
||||
case FAT_TYPE_FAT32: return 0xfff0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the maximum number of clusters for a given file system type */
|
||||
FatCluster _GL_ATTRIBUTE_CONST
|
||||
fat_max_cluster_count (FatType fat_type) {
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12: return 0xff0;
|
||||
case FAT_TYPE_FAT16: return 0xfff0;
|
||||
case FAT_TYPE_FAT32: return 0x0ffffff0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* what is this supposed to be? What drugs are M$ on? (Can I have some? :-) */
|
||||
PedSector _GL_ATTRIBUTE_CONST
|
||||
fat_min_reserved_sector_count (FatType fat_type)
|
||||
{
|
||||
return (fat_type == FAT_TYPE_FAT32) ? 32 : 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_check_resize_geometry (const PedFileSystem* fs,
|
||||
const PedGeometry* geom,
|
||||
PedSector new_cluster_sectors,
|
||||
FatCluster new_cluster_count)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedSector free_space;
|
||||
PedSector min_free_space;
|
||||
PedSector total_space;
|
||||
PedSector new_total_space;
|
||||
PedSector dir_space;
|
||||
|
||||
PED_ASSERT (geom != NULL);
|
||||
|
||||
dir_space = fs_info->total_dir_clusters * fs_info->cluster_sectors;
|
||||
free_space = fs_info->fat->free_cluster_count
|
||||
* fs_info->cluster_sectors;
|
||||
total_space = fs_info->fat->cluster_count * fs_info->cluster_sectors;
|
||||
new_total_space = new_cluster_count * new_cluster_sectors;
|
||||
min_free_space = total_space - new_total_space + dir_space;
|
||||
|
||||
PED_ASSERT (new_cluster_count
|
||||
<= fat_max_cluster_count (FAT_TYPE_FAT32));
|
||||
|
||||
if (free_space < min_free_space) {
|
||||
char* needed = ped_unit_format (geom->dev, min_free_space);
|
||||
char* have = ped_unit_format (geom->dev, free_space);
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("You need %s of free disk space to shrink this "
|
||||
"partition to this size. Currently, only %s is "
|
||||
"free."),
|
||||
needed, have);
|
||||
free (needed);
|
||||
free (have);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* DO NOT EDIT THIS ALGORITHM!
|
||||
* As far as I can tell, this is the same algorithm used by Microsoft to
|
||||
* calculate the size of the file allocaion tables, and the number of clusters.
|
||||
* I have not verified this by dissassembling Microsoft code - I came to this
|
||||
* conclusion by empirical analysis (i.e. trial and error - this was HORRIBLE).
|
||||
*
|
||||
* If you think this code makes no sense, then you are right. I will restrain
|
||||
* the urge to inflict serious bodily harm on Microsoft people.
|
||||
*/
|
||||
|
||||
static int
|
||||
entries_per_sector (FatType fat_type)
|
||||
{
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
return 512 * 3 / 2;
|
||||
case FAT_TYPE_FAT16:
|
||||
return 512 / 2;
|
||||
case FAT_TYPE_FAT32:
|
||||
return 512 / 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
calc_sizes (PedSector size, PedSector align, FatType fat_type,
|
||||
PedSector root_dir_sectors, PedSector cluster_sectors,
|
||||
FatCluster* out_cluster_count, PedSector* out_fat_size)
|
||||
{
|
||||
PedSector data_fat_space; /* space available to clusters + FAT */
|
||||
PedSector fat_space; /* space taken by each FAT */
|
||||
PedSector cluster_space; /* space taken by clusters */
|
||||
FatCluster cluster_count;
|
||||
int i;
|
||||
|
||||
PED_ASSERT (out_cluster_count != NULL);
|
||||
PED_ASSERT (out_fat_size != NULL);
|
||||
|
||||
data_fat_space = size - fat_min_reserved_sector_count (fat_type)
|
||||
- align;
|
||||
if (fat_type == FAT_TYPE_FAT16)
|
||||
data_fat_space -= root_dir_sectors;
|
||||
|
||||
fat_space = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (fat_type == FAT_TYPE_FAT32)
|
||||
cluster_space = data_fat_space - fat_space;
|
||||
else
|
||||
cluster_space = data_fat_space - 2 * fat_space;
|
||||
|
||||
cluster_count = cluster_space / cluster_sectors;
|
||||
fat_space = ped_div_round_up (cluster_count + 2,
|
||||
entries_per_sector (fat_type));
|
||||
}
|
||||
|
||||
cluster_space = data_fat_space - 2 * fat_space;
|
||||
cluster_count = cluster_space / cluster_sectors;
|
||||
|
||||
/* looks like this should be part of the loop condition?
|
||||
* Need to build the Big Table TM again to check
|
||||
*/
|
||||
if (fat_space < ped_div_round_up (cluster_count + 2,
|
||||
entries_per_sector (fat_type))) {
|
||||
fat_space = ped_div_round_up (cluster_count + 2,
|
||||
entries_per_sector (fat_type));
|
||||
}
|
||||
|
||||
if (cluster_count > fat_max_cluster_count (fat_type)
|
||||
|| cluster_count < fat_min_cluster_count (fat_type))
|
||||
return 0;
|
||||
|
||||
*out_cluster_count = cluster_count;
|
||||
*out_fat_size = fat_space;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int
|
||||
fat_calc_sizes (PedSector size, PedSector align, FatType fat_type,
|
||||
PedSector root_dir_sectors,
|
||||
PedSector* out_cluster_sectors, FatCluster* out_cluster_count,
|
||||
PedSector* out_fat_size)
|
||||
{
|
||||
PedSector cluster_sectors;
|
||||
|
||||
PED_ASSERT (out_cluster_sectors != NULL);
|
||||
PED_ASSERT (out_cluster_count != NULL);
|
||||
PED_ASSERT (out_fat_size != NULL);
|
||||
|
||||
for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
|
||||
cluster_sectors <= fat_max_cluster_size (fat_type);
|
||||
cluster_sectors *= 2) {
|
||||
if (calc_sizes (size, align, fat_type, root_dir_sectors,
|
||||
cluster_sectors,
|
||||
out_cluster_count, out_fat_size)) {
|
||||
*out_cluster_sectors = cluster_sectors;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
|
||||
cluster_sectors >= fat_min_cluster_size (fat_type);
|
||||
cluster_sectors /= 2) {
|
||||
if (calc_sizes (size, align, fat_type, root_dir_sectors,
|
||||
cluster_sectors,
|
||||
out_cluster_count, out_fat_size)) {
|
||||
*out_cluster_sectors = cluster_sectors;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* only make the cluster size really small (<4k) if a bigger one is
|
||||
* isn't possible. Windows never makes FS's like this, but it
|
||||
* seems to work... (do more tests!)
|
||||
*/
|
||||
for (cluster_sectors = 4; cluster_sectors > 0; cluster_sectors /= 2) {
|
||||
if (calc_sizes (size, align, fat_type, root_dir_sectors,
|
||||
cluster_sectors,
|
||||
out_cluster_count, out_fat_size)) {
|
||||
*out_cluster_sectors = cluster_sectors;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Same as fat_calc_sizes, except it only attempts to match a particular
|
||||
* cluster size. This is useful, because the FAT resizer can only shrink the
|
||||
* cluster size.
|
||||
*/
|
||||
int
|
||||
fat_calc_resize_sizes (
|
||||
const PedGeometry* geom,
|
||||
PedSector align,
|
||||
FatType fat_type,
|
||||
PedSector root_dir_sectors,
|
||||
PedSector cluster_sectors,
|
||||
PedSector* out_cluster_sectors,
|
||||
FatCluster* out_cluster_count,
|
||||
PedSector* out_fat_size)
|
||||
{
|
||||
PED_ASSERT (geom != NULL);
|
||||
PED_ASSERT (out_cluster_sectors != NULL);
|
||||
PED_ASSERT (out_cluster_count != NULL);
|
||||
PED_ASSERT (out_fat_size != NULL);
|
||||
|
||||
/* libparted can only reduce the cluster size at this point */
|
||||
for (*out_cluster_sectors = cluster_sectors;
|
||||
*out_cluster_sectors >= fat_min_cluster_size (fat_type);
|
||||
*out_cluster_sectors /= 2) {
|
||||
if (calc_sizes (geom->length, align, fat_type, root_dir_sectors,
|
||||
*out_cluster_sectors,
|
||||
out_cluster_count, out_fat_size))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculates the number of sectors needed to be added to cluster_offset,
|
||||
to make the cluster on the new file system match up with the ones
|
||||
on the old file system.
|
||||
However, some space is reserved by fat_calc_resize_sizes() and
|
||||
friends, to allow room for this space. If too much of this space is left
|
||||
over, everyone will complain, so we have to be greedy, and use it all up...
|
||||
*/
|
||||
PedSector _GL_ATTRIBUTE_PURE
|
||||
fat_calc_align_sectors (const PedFileSystem* new_fs,
|
||||
const PedFileSystem* old_fs)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
|
||||
PedSector raw_old_meta_data_end;
|
||||
PedSector new_meta_data_size;
|
||||
PedSector min_new_meta_data_end;
|
||||
PedSector new_data_size;
|
||||
PedSector new_clusters_size;
|
||||
PedSector align;
|
||||
|
||||
new_meta_data_size
|
||||
= fat_min_reserved_sector_count (new_fs_info->fat_type)
|
||||
+ new_fs_info->fat_sectors * 2;
|
||||
|
||||
if (new_fs_info->fat_type == FAT_TYPE_FAT16)
|
||||
new_meta_data_size += new_fs_info->root_dir_sector_count;
|
||||
|
||||
raw_old_meta_data_end = old_fs->geom->start
|
||||
+ old_fs_info->cluster_offset;
|
||||
|
||||
min_new_meta_data_end = new_fs->geom->start + new_meta_data_size;
|
||||
|
||||
if (raw_old_meta_data_end > min_new_meta_data_end)
|
||||
align = (raw_old_meta_data_end - min_new_meta_data_end)
|
||||
% new_fs_info->cluster_sectors;
|
||||
else
|
||||
align = (new_fs_info->cluster_sectors
|
||||
- ( (min_new_meta_data_end - raw_old_meta_data_end)
|
||||
% new_fs_info->cluster_sectors ))
|
||||
% new_fs_info->cluster_sectors;
|
||||
|
||||
new_data_size = new_fs->geom->length - new_meta_data_size;
|
||||
new_clusters_size = new_fs_info->cluster_count
|
||||
* new_fs_info->cluster_sectors;
|
||||
|
||||
while (new_clusters_size + align + new_fs_info->cluster_sectors
|
||||
<= new_data_size)
|
||||
align += new_fs_info->cluster_sectors;
|
||||
|
||||
return align;
|
||||
}
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
return sector >= fs_info->cluster_offset
|
||||
&& sector < fs_info->cluster_offset
|
||||
+ fs_info->cluster_sectors * fs_info->cluster_count;
|
||||
}
|
||||
|
||||
FatFragment _GL_ATTRIBUTE_PURE
|
||||
fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
|
||||
|
||||
return (cluster - 2) * fs_info->cluster_frags;
|
||||
}
|
||||
|
||||
FatCluster _GL_ATTRIBUTE_PURE
|
||||
fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
|
||||
|
||||
return frag / fs_info->cluster_frags + 2;
|
||||
}
|
||||
|
||||
PedSector _GL_ATTRIBUTE_PURE
|
||||
fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
|
||||
|
||||
return frag * fs_info->frag_sectors + fs_info->cluster_offset;
|
||||
}
|
||||
|
||||
FatFragment _GL_ATTRIBUTE_PURE
|
||||
fat_sector_to_frag (const PedFileSystem* fs, PedSector sector)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (sector >= fs_info->cluster_offset);
|
||||
|
||||
return (sector - fs_info->cluster_offset) / fs_info->frag_sectors;
|
||||
}
|
||||
|
||||
PedSector _GL_ATTRIBUTE_PURE
|
||||
fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
|
||||
|
||||
return (cluster - 2) * fs_info->cluster_sectors
|
||||
+ fs_info->cluster_offset;
|
||||
}
|
||||
|
||||
FatCluster _GL_ATTRIBUTE_PURE
|
||||
fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (sector >= fs_info->cluster_offset);
|
||||
|
||||
return (sector - fs_info->cluster_offset) / fs_info->cluster_sectors
|
||||
+ 2;
|
||||
}
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PED_FAT_CALC_H
|
||||
#define PED_FAT_CALC_H
|
||||
|
||||
extern PedSector fat_min_cluster_size (FatType fat_type);
|
||||
extern PedSector fat_max_cluster_size (FatType fat_type);
|
||||
extern FatCluster fat_min_cluster_count (FatType fat_type);
|
||||
extern FatCluster fat_max_cluster_count (FatType fat_type);
|
||||
|
||||
extern PedSector fat_min_reserved_sector_count (FatType fat_type);
|
||||
|
||||
extern int fat_check_resize_geometry (const PedFileSystem* fs,
|
||||
const PedGeometry* geom,
|
||||
PedSector new_cluster_sectors,
|
||||
FatCluster new_cluster_count);
|
||||
|
||||
extern int fat_calc_sizes (PedSector size,
|
||||
PedSector align,
|
||||
FatType fat_type,
|
||||
PedSector root_dir_sectors,
|
||||
PedSector* out_cluster_sectors,
|
||||
FatCluster* out_cluster_count,
|
||||
PedSector* out_fat_size);
|
||||
|
||||
extern int fat_calc_resize_sizes (const PedGeometry* geom,
|
||||
PedSector align,
|
||||
FatType fat_type,
|
||||
PedSector root_dir_sectors,
|
||||
PedSector cluster_sectors,
|
||||
PedSector* out_cluster_sectors,
|
||||
FatCluster* out_cluster_count,
|
||||
PedSector* out_fat_size);
|
||||
|
||||
extern PedSector
|
||||
fat_calc_align_sectors (const PedFileSystem* new_fs,
|
||||
const PedFileSystem* old_fs);
|
||||
|
||||
extern int
|
||||
fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector);
|
||||
|
||||
extern FatFragment
|
||||
fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster);
|
||||
|
||||
extern FatCluster
|
||||
fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag);
|
||||
|
||||
extern PedSector
|
||||
fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag);
|
||||
|
||||
extern FatFragment
|
||||
fat_sector_to_frag (const PedFileSystem* fs, PedSector sector);
|
||||
|
||||
extern PedSector
|
||||
fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster);
|
||||
|
||||
extern FatCluster
|
||||
fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector);
|
||||
|
||||
#endif /* PED_FAT_CALC_H */
|
||||
@@ -1,423 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2001, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
static int
|
||||
needs_duplicating (const FatOpContext* ctx, FatFragment frag)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatCluster cluster = fat_frag_to_cluster (ctx->old_fs, frag);
|
||||
FatClusterFlag flag;
|
||||
|
||||
PED_ASSERT (cluster >= 2 && cluster < old_fs_info->cluster_count + 2);
|
||||
|
||||
flag = fat_get_fragment_flag (ctx->old_fs, frag);
|
||||
switch (flag) {
|
||||
case FAT_FLAG_FREE:
|
||||
return 0;
|
||||
|
||||
case FAT_FLAG_DIRECTORY:
|
||||
return 1;
|
||||
|
||||
case FAT_FLAG_FILE:
|
||||
return fat_op_context_map_static_fragment (ctx, frag) == -1;
|
||||
|
||||
case FAT_FLAG_BAD:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
search_next_fragment (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
|
||||
for (; ctx->buffer_offset < fs_info->frag_count; ctx->buffer_offset++) {
|
||||
if (needs_duplicating (ctx, ctx->buffer_offset))
|
||||
return 1;
|
||||
}
|
||||
return 0; /* all done! */
|
||||
}
|
||||
|
||||
static int
|
||||
read_marked_fragments (FatOpContext* ctx, FatFragment length)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
int status;
|
||||
FatFragment i;
|
||||
|
||||
ped_exception_fetch_all ();
|
||||
status = fat_read_fragments (ctx->old_fs, fs_info->buffer,
|
||||
ctx->buffer_offset, length);
|
||||
ped_exception_leave_all ();
|
||||
if (status)
|
||||
return 1;
|
||||
|
||||
ped_exception_catch ();
|
||||
|
||||
/* something bad happened, so read fragments one by one. (The error may
|
||||
have occurred on an unused fragment: who cares) */
|
||||
for (i = 0; i < length; i++) {
|
||||
if (ctx->buffer_map [i]) {
|
||||
if (!fat_read_fragment (ctx->old_fs,
|
||||
fs_info->buffer + i * fs_info->frag_size,
|
||||
ctx->buffer_offset + i))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
fetch_fragments (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatFragment fetch_length = 0;
|
||||
FatFragment frag;
|
||||
|
||||
for (frag = 0; frag < ctx->buffer_frags; frag++)
|
||||
ctx->buffer_map [frag] = -1;
|
||||
|
||||
for (frag = 0;
|
||||
frag < ctx->buffer_frags
|
||||
&& ctx->buffer_offset + frag < old_fs_info->frag_count;
|
||||
frag++) {
|
||||
if (needs_duplicating (ctx, ctx->buffer_offset + frag)) {
|
||||
ctx->buffer_map [frag] = 1;
|
||||
fetch_length = frag + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_marked_fragments (ctx, fetch_length))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* here starts the write code. All assumes that ctx->buffer_map [first] and
|
||||
* ctx->buffer_map [last] are occupied by fragments that need to be duplicated.
|
||||
*****************************************************************************/
|
||||
|
||||
/* finds the first fragment that is not going to get overwritten (that needs to
|
||||
get read in) */
|
||||
static FatFragment _GL_ATTRIBUTE_PURE
|
||||
get_first_underlay (const FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
int old;
|
||||
FatFragment new;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
new = ctx->buffer_map [first];
|
||||
for (old = first + 1; old <= last; old++) {
|
||||
if (ctx->buffer_map [old] == -1)
|
||||
continue;
|
||||
new++;
|
||||
if (ctx->buffer_map [old] != new)
|
||||
return new;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* finds the last fragment that is not going to get overwritten (that needs to
|
||||
get read in) */
|
||||
static FatFragment _GL_ATTRIBUTE_PURE
|
||||
get_last_underlay (const FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
int old;
|
||||
FatFragment new;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
new = ctx->buffer_map [last];
|
||||
for (old = last - 1; old >= first; old--) {
|
||||
if (ctx->buffer_map [old] == -1)
|
||||
continue;
|
||||
new--;
|
||||
if (ctx->buffer_map [old] != new)
|
||||
return new;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* "underlay" refers to the "static" fragments, that remain unchanged.
|
||||
* when writing large chunks at a time, we don't want to clobber these,
|
||||
* so we read them in, and write them back again. MUCH quicker that way.
|
||||
*/
|
||||
static int
|
||||
quick_group_write_read_underlay (FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatFragment first_underlay;
|
||||
FatFragment last_underlay;
|
||||
FatFragment underlay_length;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
first_underlay = get_first_underlay (ctx, first, last);
|
||||
if (first_underlay == -1)
|
||||
return 1;
|
||||
last_underlay = get_last_underlay (ctx, first, last);
|
||||
|
||||
PED_ASSERT (first_underlay <= last_underlay);
|
||||
|
||||
underlay_length = last_underlay - first_underlay + 1;
|
||||
if (!fat_read_fragments (ctx->new_fs,
|
||||
new_fs_info->buffer
|
||||
+ (first_underlay - ctx->buffer_map [first])
|
||||
* new_fs_info->frag_size,
|
||||
first_underlay,
|
||||
underlay_length))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* quick_group_write() makes no attempt to recover from errors - just
|
||||
* does things fast. If there is an error, slow_group_write() is
|
||||
* called.
|
||||
* Note: we do syncing writes, to make sure there isn't any
|
||||
* error writing out. It's rather difficult recovering from errors
|
||||
* further on.
|
||||
*/
|
||||
static int
|
||||
quick_group_write (FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
int active_length;
|
||||
int i;
|
||||
int offset;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
ped_exception_fetch_all ();
|
||||
if (!quick_group_write_read_underlay (ctx, first, last))
|
||||
goto error;
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
if (ctx->buffer_map [i] == -1)
|
||||
continue;
|
||||
|
||||
offset = ctx->buffer_map [i] - ctx->buffer_map [first];
|
||||
memcpy (new_fs_info->buffer + offset * new_fs_info->frag_size,
|
||||
old_fs_info->buffer + i * new_fs_info->frag_size,
|
||||
new_fs_info->frag_size);
|
||||
}
|
||||
|
||||
active_length = ctx->buffer_map [last] - ctx->buffer_map [first] + 1;
|
||||
if (!fat_write_sync_fragments (ctx->new_fs, new_fs_info->buffer,
|
||||
ctx->buffer_map [first], active_length))
|
||||
goto error;
|
||||
|
||||
ped_exception_leave_all ();
|
||||
return 1;
|
||||
|
||||
error:
|
||||
ped_exception_catch ();
|
||||
ped_exception_leave_all ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Writes fragments out, one at a time, avoiding errors on redundant writes
|
||||
* on damaged parts of the disk we already know about. If there's an error
|
||||
* on one of the required fragments, it gets marked as bad, and a replacement
|
||||
* is found.
|
||||
*/
|
||||
static int
|
||||
slow_group_write (FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
int i;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
if (ctx->buffer_map [i] == -1)
|
||||
continue;
|
||||
|
||||
while (!fat_write_sync_fragment (ctx->new_fs,
|
||||
old_fs_info->buffer + i * old_fs_info->frag_size,
|
||||
ctx->buffer_map [i])) {
|
||||
fat_table_set_bad (new_fs_info->fat,
|
||||
ctx->buffer_map [i]);
|
||||
ctx->buffer_map [i] = fat_table_alloc_cluster
|
||||
(new_fs_info->fat);
|
||||
if (ctx->buffer_map [i] == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
update_remap (FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
int i;
|
||||
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
if (ctx->buffer_map [i] == -1)
|
||||
continue;
|
||||
ctx->remap [ctx->buffer_offset + i] = ctx->buffer_map [i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
group_write (FatOpContext* ctx, int first, int last)
|
||||
{
|
||||
PED_ASSERT (first <= last);
|
||||
|
||||
if (!quick_group_write (ctx, first, last)) {
|
||||
if (!slow_group_write (ctx, first, last))
|
||||
return 0;
|
||||
}
|
||||
if (!update_remap (ctx, first, last))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* assumes fragment size and new_fs's cluster size are equal */
|
||||
static int
|
||||
write_fragments (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
int group_start;
|
||||
int group_end = -1; /* shut gcc up! */
|
||||
FatFragment mapped_length;
|
||||
FatFragment i;
|
||||
FatCluster new_cluster;
|
||||
|
||||
PED_ASSERT (ctx->buffer_offset < old_fs_info->frag_count);
|
||||
|
||||
group_start = -1;
|
||||
for (i = 0; i < ctx->buffer_frags; i++) {
|
||||
if (ctx->buffer_map [i] == -1)
|
||||
continue;
|
||||
|
||||
ctx->frags_duped++;
|
||||
|
||||
new_cluster = fat_table_alloc_cluster (new_fs_info->fat);
|
||||
if (!new_cluster)
|
||||
return 0;
|
||||
fat_table_set_eof (new_fs_info->fat, new_cluster);
|
||||
ctx->buffer_map [i] = fat_cluster_to_frag (ctx->new_fs,
|
||||
new_cluster);
|
||||
|
||||
if (group_start == -1)
|
||||
group_start = group_end = i;
|
||||
|
||||
PED_ASSERT (ctx->buffer_map [i]
|
||||
>= ctx->buffer_map [group_start]);
|
||||
|
||||
mapped_length = ctx->buffer_map [i]
|
||||
- ctx->buffer_map [group_start] + 1;
|
||||
if (mapped_length <= ctx->buffer_frags) {
|
||||
group_end = i;
|
||||
} else {
|
||||
/* ran out of room in the buffer, so write this group,
|
||||
* and start a new one...
|
||||
*/
|
||||
if (!group_write (ctx, group_start, group_end))
|
||||
return 0;
|
||||
group_start = group_end = i;
|
||||
}
|
||||
}
|
||||
|
||||
PED_ASSERT (group_start != -1);
|
||||
|
||||
if (!group_write (ctx, group_start, group_end))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* default all fragments to unmoved
|
||||
*/
|
||||
static void
|
||||
init_remap (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatFragment i;
|
||||
|
||||
for (i = 0; i < old_fs_info->frag_count; i++)
|
||||
ctx->remap[i] = fat_op_context_map_static_fragment (ctx, i);
|
||||
}
|
||||
|
||||
static FatFragment
|
||||
count_frags_to_dup (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatFragment i;
|
||||
FatFragment total;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i = 0; i < fs_info->frag_count; i++) {
|
||||
if (needs_duplicating (ctx, i))
|
||||
total++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/* duplicates unreachable file clusters, and all directory clusters
|
||||
*/
|
||||
int
|
||||
fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer)
|
||||
{
|
||||
FatFragment total_frags_to_dup;
|
||||
|
||||
init_remap (ctx);
|
||||
total_frags_to_dup = count_frags_to_dup (ctx);
|
||||
|
||||
ped_timer_reset (timer);
|
||||
ped_timer_set_state_name (timer, "moving data");
|
||||
|
||||
ctx->buffer_offset = 0;
|
||||
ctx->frags_duped = 0;
|
||||
while (search_next_fragment (ctx)) {
|
||||
ped_timer_update (
|
||||
timer, 1.0 * ctx->frags_duped / total_frags_to_dup);
|
||||
|
||||
if (!fetch_fragments (ctx))
|
||||
return 0;
|
||||
if (!write_fragments (ctx))
|
||||
return 0;
|
||||
ctx->buffer_offset += ctx->buffer_frags;
|
||||
}
|
||||
|
||||
ped_timer_update (timer, 1.0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1999, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PED_FAT_CLSTDUP_H_INCLUDED
|
||||
#define PED_FAT_CLSTDUP_H_INCLUDED
|
||||
|
||||
#include "context.h"
|
||||
|
||||
/* the big important one :-) */
|
||||
extern int fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer);
|
||||
|
||||
#endif /* PED_FAT_CLSTDUP_H_INCLUDED */
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
/* Note: this deals with file system start and end sectors, even if the physical
|
||||
* devices are different (eg for fat_copy()) Perhaps this is a hack, but it
|
||||
* works ;-)
|
||||
*/
|
||||
static int
|
||||
calc_deltas (FatOpContext* ctx)
|
||||
{
|
||||
PedFileSystem* old_fs = ctx->old_fs;
|
||||
PedFileSystem* new_fs = ctx->new_fs;
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
|
||||
PedSector old_cluster_ofs;
|
||||
PedSector new_cluster_ofs;
|
||||
PedSector sector_delta;
|
||||
|
||||
old_cluster_ofs = old_fs->geom->start + old_fs_info->cluster_offset;
|
||||
new_cluster_ofs = new_fs->geom->start + new_fs_info->cluster_offset;
|
||||
|
||||
if (new_cluster_ofs > old_cluster_ofs) {
|
||||
ctx->start_move_dir = FAT_DIR_FORWARD;
|
||||
sector_delta = new_cluster_ofs - old_cluster_ofs;
|
||||
} else {
|
||||
ctx->start_move_dir = FAT_DIR_BACKWARD;
|
||||
sector_delta = old_cluster_ofs - new_cluster_ofs;
|
||||
}
|
||||
|
||||
if (sector_delta % new_fs_info->cluster_sectors) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
|
||||
_("Cluster start delta = %d, which is not a multiple "
|
||||
"of the cluster size %d."),
|
||||
(int) sector_delta,
|
||||
(int) new_fs_info->cluster_sectors);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->start_move_delta = sector_delta / ctx->frag_sectors;
|
||||
|
||||
#ifdef PED_VERBOSE
|
||||
printf ("Start move delta is: %d %s.\n",
|
||||
(int) ctx->start_move_delta,
|
||||
(ctx->start_move_dir == FAT_DIR_FORWARD)?
|
||||
"forwards" : "backwards");
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FatOpContext*
|
||||
fat_op_context_new (PedFileSystem* new_fs, PedFileSystem* old_fs)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
|
||||
FatOpContext* ctx;
|
||||
|
||||
ctx = (FatOpContext*) ped_malloc (sizeof (FatOpContext));
|
||||
if (!ctx)
|
||||
goto error;
|
||||
|
||||
ctx->frag_sectors = PED_MIN (old_fs_info->cluster_sectors,
|
||||
new_fs_info->cluster_sectors);
|
||||
if (!fat_set_frag_sectors (new_fs, ctx->frag_sectors))
|
||||
goto error;
|
||||
if (!fat_set_frag_sectors (old_fs, ctx->frag_sectors))
|
||||
goto error;
|
||||
|
||||
ctx->buffer_frags = old_fs_info->buffer_sectors / ctx->frag_sectors;
|
||||
ctx->buffer_map = (FatFragment*) ped_malloc (sizeof (FatFragment)
|
||||
* ctx->buffer_frags);
|
||||
if (!ctx->buffer_map)
|
||||
goto error_free_ctx;
|
||||
|
||||
ctx->remap = (FatFragment*) ped_malloc (sizeof (FatFragment)
|
||||
* old_fs_info->frag_count);
|
||||
if (!ctx->remap)
|
||||
goto error_free_buffer_map;
|
||||
|
||||
ctx->new_fs = new_fs;
|
||||
ctx->old_fs = old_fs;
|
||||
if (!calc_deltas (ctx))
|
||||
goto error_free_buffer_map;
|
||||
|
||||
return ctx;
|
||||
|
||||
error_free_buffer_map:
|
||||
free (ctx->buffer_map);
|
||||
error_free_ctx:
|
||||
free (ctx);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
fat_op_context_destroy (FatOpContext* ctx)
|
||||
{
|
||||
free (ctx->buffer_map);
|
||||
free (ctx->remap);
|
||||
free (ctx);
|
||||
}
|
||||
|
||||
FatFragment _GL_ATTRIBUTE_PURE
|
||||
fat_op_context_map_static_fragment (const FatOpContext* ctx, FatFragment frag)
|
||||
{
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatFragment result;
|
||||
|
||||
if (ctx->new_fs->geom->dev != ctx->old_fs->geom->dev)
|
||||
return -1;
|
||||
|
||||
if (ctx->start_move_dir == FAT_DIR_FORWARD) {
|
||||
if (frag < ctx->start_move_delta)
|
||||
return -1;
|
||||
result = frag - ctx->start_move_delta;
|
||||
} else {
|
||||
result = frag + ctx->start_move_delta;
|
||||
}
|
||||
|
||||
if (result >= new_fs_info->frag_count)
|
||||
return -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FatCluster
|
||||
fat_op_context_map_static_cluster (const FatOpContext* ctx, FatCluster clst)
|
||||
{
|
||||
FatFragment mapped_frag;
|
||||
|
||||
mapped_frag = fat_op_context_map_static_fragment (ctx,
|
||||
fat_cluster_to_frag (ctx->old_fs, clst));
|
||||
if (mapped_frag != -1)
|
||||
return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
FatFragment _GL_ATTRIBUTE_PURE
|
||||
fat_op_context_map_fragment (const FatOpContext* ctx, FatFragment frag)
|
||||
{
|
||||
return ctx->remap [frag];
|
||||
}
|
||||
|
||||
FatCluster
|
||||
fat_op_context_map_cluster (const FatOpContext* ctx, FatCluster clst)
|
||||
{
|
||||
FatFragment mapped_frag;
|
||||
|
||||
mapped_frag = fat_op_context_map_fragment (ctx,
|
||||
fat_cluster_to_frag (ctx->old_fs, clst));
|
||||
if (mapped_frag != -1)
|
||||
return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function sets the initial fat for the new resized file system.
|
||||
This is in *NO WAY* a proper FAT table - all it does is:
|
||||
a) mark bad clusters as bad.
|
||||
b) mark used clusters (that is, clusters from the original FS that are
|
||||
reachable from the resized one). Marks as EOF (i.e. used, end of
|
||||
file chain).
|
||||
c) mark original file system metadata as EOF (i.e. used), to prevent
|
||||
it from being clobbered. This will leave the original file system
|
||||
intact, until the partition table is modified, if the start of
|
||||
the partition is moved.
|
||||
|
||||
The FATs are rebuilt *properly* after cluster relocation. This here is
|
||||
only to mark clusters as used, so when cluster relocation occurs, clusters
|
||||
aren't relocated on top of ones marked in a, b or c.
|
||||
*/
|
||||
int
|
||||
fat_op_context_create_initial_fat (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatCluster clst;
|
||||
FatCluster new_clst;
|
||||
PedSector sect;
|
||||
PedSector new_sect;
|
||||
FatFragment frag;
|
||||
FatFragment new_frag;
|
||||
FatClusterFlag frag_flag;
|
||||
|
||||
new_fs_info->fat = fat_table_new (
|
||||
new_fs_info->fat_type,
|
||||
new_fs_info->fat_sectors * 512
|
||||
/ fat_table_entry_size (new_fs_info->fat_type));
|
||||
if (!new_fs_info->fat)
|
||||
return 0;
|
||||
|
||||
if (!fat_table_set_cluster_count (new_fs_info->fat,
|
||||
new_fs_info->cluster_count))
|
||||
return 0;
|
||||
|
||||
/* mark bad and used clusters */
|
||||
for (frag = 0; frag < old_fs_info->frag_count; frag++) {
|
||||
frag_flag = fat_get_fragment_flag (ctx->old_fs, frag);
|
||||
if (frag_flag == FAT_FLAG_FREE)
|
||||
continue;
|
||||
|
||||
new_frag = fat_op_context_map_static_fragment (ctx, frag);
|
||||
if (new_frag == -1)
|
||||
continue;
|
||||
|
||||
new_clst = fat_frag_to_cluster (ctx->new_fs, new_frag);
|
||||
PED_ASSERT (new_clst != 0);
|
||||
|
||||
if (frag_flag == FAT_FLAG_BAD) {
|
||||
if (!fat_table_set_bad (new_fs_info->fat, new_clst))
|
||||
return 0;
|
||||
} else {
|
||||
if (!fat_table_set_eof (new_fs_info->fat, new_clst))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark metadata regions that map to clusters on the new FS */
|
||||
for (sect = 0; sect < old_fs_info->cluster_offset; sect++) {
|
||||
new_sect = ped_geometry_map (ctx->new_fs->geom,
|
||||
ctx->old_fs->geom, sect);
|
||||
if (new_sect == -1
|
||||
|| !fat_is_sector_in_clusters (ctx->new_fs, new_sect))
|
||||
continue;
|
||||
|
||||
clst = fat_sector_to_cluster (ctx->new_fs, new_sect);
|
||||
PED_ASSERT (clst != 0);
|
||||
|
||||
if (!fat_table_set_eof (new_fs_info->fat, clst))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1999-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PED_FAT_CONTEXT_H_INCLUDED
|
||||
#define PED_FAT_CONTEXT_H_INCLUDED
|
||||
|
||||
#include "count.h"
|
||||
|
||||
enum _FatDirection {
|
||||
FAT_DIR_FORWARD,
|
||||
FAT_DIR_BACKWARD
|
||||
};
|
||||
typedef enum _FatDirection FatDirection;
|
||||
|
||||
struct _FatOpContext {
|
||||
PedFileSystem* old_fs;
|
||||
PedFileSystem* new_fs;
|
||||
|
||||
PedSector frag_sectors; /* should equal old_fs and
|
||||
new_fs's frag_sectors */
|
||||
|
||||
FatDirection start_move_dir;
|
||||
FatFragment start_move_delta;
|
||||
|
||||
FatFragment buffer_offset;
|
||||
FatFragment buffer_frags;
|
||||
FatFragment* buffer_map;
|
||||
|
||||
FatFragment frags_duped;
|
||||
|
||||
FatFragment* remap;
|
||||
|
||||
FatCluster new_root_dir [32];
|
||||
};
|
||||
typedef struct _FatOpContext FatOpContext;
|
||||
|
||||
extern FatOpContext* fat_op_context_new (PedFileSystem* new_fs,
|
||||
PedFileSystem* old_fs);
|
||||
|
||||
extern void fat_op_context_destroy (FatOpContext* ctx);
|
||||
|
||||
extern FatFragment fat_op_context_map_static_fragment (const FatOpContext* ctx,
|
||||
FatFragment frag);
|
||||
extern FatCluster fat_op_context_map_static_cluster (const FatOpContext* ctx,
|
||||
FatCluster clst);
|
||||
|
||||
extern FatFragment fat_op_context_map_fragment (const FatOpContext* ctx,
|
||||
FatFragment frag);
|
||||
extern FatCluster fat_op_context_map_cluster (const FatOpContext* ctx,
|
||||
FatCluster clst);
|
||||
|
||||
extern int fat_op_context_create_initial_fat (FatOpContext* ctx);
|
||||
|
||||
#endif /* PED_FAT_CONTEXT_H_INCLUDED */
|
||||
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
#include "traverse.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
/*
|
||||
prints out the sequence of clusters for a given file chain, beginning
|
||||
at start_cluster.
|
||||
*/
|
||||
#ifdef PED_VERBOSE
|
||||
static void
|
||||
print_chain (PedFileSystem* fs, FatCluster start)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster clst;
|
||||
int this_row;
|
||||
|
||||
this_row = 0;
|
||||
for (clst = start; !fat_table_is_eof (fs_info->fat, clst);
|
||||
clst = fat_table_get (fs_info->fat, clst)) {
|
||||
printf (" %d", (int) clst);
|
||||
if (++this_row == 7) {
|
||||
putchar ('\n');
|
||||
this_row = 0;
|
||||
}
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
#endif /* PED_VERBOSE */
|
||||
|
||||
static PedSector
|
||||
remainder_round_up (PedSector a, PedSector b)
|
||||
{
|
||||
PedSector result;
|
||||
|
||||
result = a % b;
|
||||
if (!result)
|
||||
result = b;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
traverse the FAT for a file/directory, marking each entry's flag
|
||||
to "flag".
|
||||
*/
|
||||
static int
|
||||
flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
|
||||
FatClusterFlag flag, PedSector size)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster clst;
|
||||
FatCluster prev_clst;
|
||||
int last_cluster_usage;
|
||||
FatCluster chain_length = 0;
|
||||
|
||||
if (fat_table_is_eof (fs_info->fat, start)) {
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("Bad directory entry for %s: first cluster is the "
|
||||
"end of file marker."),
|
||||
chain_name)
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (prev_clst = clst = start; !fat_table_is_eof (fs_info->fat, clst);
|
||||
prev_clst = clst, clst = fat_table_get (fs_info->fat, clst)) {
|
||||
chain_length++;
|
||||
if (!clst) {
|
||||
ped_exception_throw (PED_EXCEPTION_FATAL,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad FAT: unterminated chain for %s. You "
|
||||
"should run dosfsck or scandisk."),
|
||||
chain_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (clst >= fs_info->fat->cluster_count + 2) {
|
||||
ped_exception_throw (PED_EXCEPTION_FATAL,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad FAT: cluster %d outside file system "
|
||||
"in chain for %s. You should run dosfsck "
|
||||
"or scandisk."),
|
||||
(int) clst, chain_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fs_info->cluster_info [clst].flag != FAT_FLAG_FREE ) {
|
||||
ped_exception_throw (PED_EXCEPTION_FATAL,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad FAT: cluster %d is cross-linked for "
|
||||
"%s. You should run dosfsck or scandisk."),
|
||||
(int) clst, chain_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flag == FAT_FLAG_DIRECTORY)
|
||||
fs_info->total_dir_clusters++;
|
||||
|
||||
fs_info->cluster_info [clst].flag = flag;
|
||||
fs_info->cluster_info [clst].units_used = 0; /* 0 == 64 */
|
||||
}
|
||||
|
||||
if (size
|
||||
&& chain_length
|
||||
!= ped_div_round_up (size, fs_info->cluster_sectors)) {
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("%s is %dk, but it has %d clusters (%dk)."),
|
||||
chain_name,
|
||||
(int) size / 2,
|
||||
(int) chain_length,
|
||||
(int) chain_length * fs_info->cluster_sectors / 2)
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
last_cluster_usage
|
||||
= ped_div_round_up (64 * remainder_round_up (size,
|
||||
fs_info->cluster_sectors),
|
||||
fs_info->cluster_sectors);
|
||||
|
||||
fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
recursively traverses a directory, flagging all clusters in the process.
|
||||
It frees the traverse_info structure before returning.
|
||||
*/
|
||||
static int
|
||||
flag_traverse_dir (FatTraverseInfo* trav_info) {
|
||||
PedFileSystem* fs = trav_info->fs;
|
||||
FatDirEntry* this_entry;
|
||||
FatTraverseInfo* subdir_trav_info;
|
||||
char file_name [4096];
|
||||
char* file_name_start;
|
||||
FatCluster first_cluster;
|
||||
PedSector size;
|
||||
|
||||
PED_ASSERT (trav_info != NULL);
|
||||
|
||||
strcpy (file_name, trav_info->dir_name);
|
||||
file_name_start = file_name + strlen (file_name);
|
||||
|
||||
while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
|
||||
if (fat_dir_entry_is_null_term (this_entry))
|
||||
break;
|
||||
if (!fat_dir_entry_has_first_cluster (this_entry, fs))
|
||||
continue;
|
||||
if (this_entry->name [0] == '.')
|
||||
continue; /* skip . and .. entries */
|
||||
|
||||
fat_dir_entry_get_name (this_entry, file_name_start);
|
||||
first_cluster = fat_dir_entry_get_first_cluster(this_entry, fs);
|
||||
size = ped_div_round_up (fat_dir_entry_get_length (this_entry),
|
||||
512);
|
||||
|
||||
#ifdef PED_VERBOSE
|
||||
printf ("%s: ", file_name);
|
||||
print_chain (fs, first_cluster);
|
||||
#endif
|
||||
|
||||
if (fat_dir_entry_is_directory (this_entry)) {
|
||||
if (!flag_traverse_fat (fs, file_name, first_cluster,
|
||||
FAT_FLAG_DIRECTORY, size))
|
||||
return 0;
|
||||
|
||||
subdir_trav_info = fat_traverse_directory (trav_info,
|
||||
this_entry);
|
||||
if (!subdir_trav_info)
|
||||
return 0;
|
||||
if (!flag_traverse_dir (subdir_trav_info))
|
||||
return 0;
|
||||
} else if (fat_dir_entry_is_file (this_entry)) {
|
||||
if (!flag_traverse_fat (fs, file_name, first_cluster,
|
||||
FAT_FLAG_FILE, size))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fat_traverse_complete (trav_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_mark_bad_clusters (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster cluster;
|
||||
|
||||
for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
|
||||
if (fat_table_is_bad (fs_info->fat, cluster))
|
||||
fs_info->cluster_info [cluster].flag = FAT_FLAG_BAD;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fills in cluster_info. Each FAT entry (= cluster) is flagged as either
|
||||
FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.
|
||||
|
||||
Also, the fraction of each cluster (x/64) is recorded
|
||||
*/
|
||||
int
|
||||
fat_collect_cluster_info (PedFileSystem* fs) {
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatTraverseInfo* trav_info;
|
||||
|
||||
/* set all clusters to unused as a default */
|
||||
memset (fs_info->cluster_info, 0, fs_info->fat->cluster_count + 2);
|
||||
fs_info->total_dir_clusters = 0;
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
|
||||
"\\");
|
||||
if (!flag_traverse_dir (trav_info))
|
||||
return 0;
|
||||
if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
|
||||
FAT_FLAG_DIRECTORY, 0))
|
||||
return 0;
|
||||
} else {
|
||||
trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
|
||||
if (!flag_traverse_dir (trav_info))
|
||||
return 0;
|
||||
}
|
||||
|
||||
_mark_bad_clusters (fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FatClusterFlag _GL_ATTRIBUTE_PURE
|
||||
fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
return fs_info->cluster_info [cluster].flag;
|
||||
}
|
||||
|
||||
PedSector _GL_ATTRIBUTE_PURE
|
||||
fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
int fraction;
|
||||
|
||||
if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
|
||||
return 0;
|
||||
|
||||
fraction = fs_info->cluster_info [cluster].units_used;
|
||||
if (fraction == 0)
|
||||
fraction = 64;
|
||||
|
||||
return fraction * fs_info->cluster_sectors / 64;
|
||||
}
|
||||
|
||||
FatClusterFlag
|
||||
fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster cluster = fat_frag_to_cluster (fs, frag);
|
||||
FatFragment offset = frag % fs_info->cluster_frags;
|
||||
FatFragment last_frag_used;
|
||||
FatClusterFlag flag;
|
||||
|
||||
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
|
||||
|
||||
flag = fat_get_cluster_flag (fs, cluster);
|
||||
if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
|
||||
return flag;
|
||||
last_frag_used = (fat_get_cluster_usage (fs, cluster) - 1)
|
||||
/ fs_info->frag_sectors;
|
||||
if (offset > last_frag_used)
|
||||
return FAT_FLAG_FREE;
|
||||
else
|
||||
return flag;
|
||||
}
|
||||
|
||||
int
|
||||
fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
|
||||
{
|
||||
switch (fat_get_fragment_flag (fs, frag)) {
|
||||
case FAT_FLAG_FREE:
|
||||
case FAT_FLAG_BAD:
|
||||
return 0;
|
||||
|
||||
case FAT_FLAG_FILE:
|
||||
case FAT_FLAG_DIRECTORY:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1999-2000, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COUNT_H_INCLUDED
|
||||
#define COUNT_H_INCLUDED
|
||||
|
||||
typedef enum _FatClusterFlag FatClusterFlag;
|
||||
typedef struct _FatClusterInfo FatClusterInfo;
|
||||
|
||||
enum _FatClusterFlag {
|
||||
FAT_FLAG_FREE=0,
|
||||
FAT_FLAG_FILE=1,
|
||||
FAT_FLAG_DIRECTORY=2,
|
||||
FAT_FLAG_BAD=3
|
||||
};
|
||||
|
||||
struct __attribute__ ((packed)) _FatClusterInfo {
|
||||
unsigned int units_used:6; /* 1 unit = cluster_size / 64 */
|
||||
FatClusterFlag flag:2;
|
||||
};
|
||||
|
||||
extern int fat_collect_cluster_info (PedFileSystem *fs);
|
||||
extern FatClusterFlag fat_get_cluster_flag (PedFileSystem* fs,
|
||||
FatCluster cluster);
|
||||
extern PedSector fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster);
|
||||
extern FatClusterFlag fat_get_fragment_flag (PedFileSystem* fs,
|
||||
FatFragment frag);
|
||||
extern int fat_is_fragment_active (PedFileSystem* fs, FatFragment frag);
|
||||
|
||||
#endif /* COUNT_H_INCLUDED */
|
||||
@@ -1,652 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2001, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fat.h"
|
||||
#include "calc.h"
|
||||
#include "../../../labels/misc.h"
|
||||
|
||||
PedFileSystem*
|
||||
fat_alloc (const PedGeometry* geom)
|
||||
{
|
||||
PedFileSystem* fs;
|
||||
|
||||
fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
|
||||
if (!fs)
|
||||
goto error;
|
||||
|
||||
fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
|
||||
if (!fs->type_specific)
|
||||
goto error_free_fs;
|
||||
FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
|
||||
fs_info->boot_sector = NULL;
|
||||
fs_info->info_sector = NULL;
|
||||
fs->geom = ped_geometry_duplicate (geom);
|
||||
if (!fs->geom)
|
||||
goto error_free_type_specific;
|
||||
|
||||
fs->checked = 0;
|
||||
return fs;
|
||||
|
||||
error_free_type_specific:
|
||||
free (fs->type_specific);
|
||||
error_free_fs:
|
||||
free (fs);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Requires the boot sector to be analysed */
|
||||
int
|
||||
fat_alloc_buffers (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
fs_info->buffer_sectors = BUFFER_SIZE;
|
||||
fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
|
||||
if (!fs_info->buffer)
|
||||
goto error;
|
||||
|
||||
fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
|
||||
if (!fs_info->cluster_info)
|
||||
goto error_free_buffer;
|
||||
|
||||
return 1;
|
||||
|
||||
error_free_buffer:
|
||||
free (fs_info->buffer);
|
||||
error:
|
||||
return 0;
|
||||
};
|
||||
|
||||
void
|
||||
fat_free_buffers (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
free (fs_info->cluster_info);
|
||||
free (fs_info->buffer);
|
||||
}
|
||||
|
||||
void
|
||||
fat_free (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
|
||||
free (fs_info->boot_sector);
|
||||
ped_geometry_destroy (fs->geom);
|
||||
free (fs->type_specific);
|
||||
free (fs);
|
||||
}
|
||||
|
||||
int
|
||||
fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
|
||||
&& frag_sectors <= fs_info->cluster_sectors);
|
||||
|
||||
fs_info->frag_size = frag_sectors * 512;
|
||||
fs_info->frag_sectors = frag_sectors;
|
||||
fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
|
||||
fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
|
||||
fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
int
|
||||
fat_clobber (PedGeometry* geom)
|
||||
{
|
||||
FatBootSector *boot_sector;
|
||||
int ok;
|
||||
|
||||
if (!fat_boot_sector_read (&boot_sector, geom))
|
||||
return 1;
|
||||
|
||||
boot_sector->system_id[0] = 0;
|
||||
boot_sector->boot_sign = 0;
|
||||
if (boot_sector->u.fat16.fat_name[0] == 'F')
|
||||
boot_sector->u.fat16.fat_name[0] = 0;
|
||||
if (boot_sector->u.fat32.fat_name[0] == 'F')
|
||||
boot_sector->u.fat32.fat_name[0] = 0;
|
||||
|
||||
ok = ped_geometry_write (geom, boot_sector, 0, 1);
|
||||
free (boot_sector);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
_init_fats (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster table_size;
|
||||
|
||||
table_size = fs_info->fat_sectors * 512
|
||||
/ fat_table_entry_size (fs_info->fat_type);
|
||||
fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
|
||||
if (!fs_info->fat)
|
||||
goto error;
|
||||
|
||||
if (!fat_table_read (fs_info->fat, fs, 0))
|
||||
goto error_free_fat;
|
||||
|
||||
return 1;
|
||||
|
||||
error_free_fat:
|
||||
fat_table_destroy (fs_info->fat);
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
PedFileSystem*
|
||||
fat_open (PedGeometry* geom)
|
||||
{
|
||||
PedFileSystem* fs;
|
||||
FatSpecific* fs_info;
|
||||
|
||||
fs = fat_alloc (geom);
|
||||
if (!fs)
|
||||
goto error;
|
||||
fs_info = (FatSpecific*) fs->type_specific;
|
||||
|
||||
if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
|
||||
goto error_free_fs;
|
||||
if (!fat_boot_sector_analyse (fs_info->boot_sector, fs))
|
||||
goto error_free_fs;
|
||||
fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
|
||||
? &fat16_type
|
||||
: &fat32_type;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
if (!fat_info_sector_read (&fs_info->info_sector, fs))
|
||||
goto error_free_fs;
|
||||
}
|
||||
|
||||
if (!_init_fats (fs))
|
||||
goto error_free_fs;
|
||||
if (!fat_alloc_buffers (fs))
|
||||
goto error_free_fat_table;
|
||||
if (!fat_collect_cluster_info (fs))
|
||||
goto error_free_buffers;
|
||||
|
||||
return fs;
|
||||
|
||||
error_free_buffers:
|
||||
fat_free_buffers (fs);
|
||||
error_free_fat_table:
|
||||
fat_table_destroy (fs_info->fat);
|
||||
error_free_fs:
|
||||
fat_free (fs);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
fat_root_dir_clear (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
|
||||
return ped_geometry_write (fs->geom, fs_info->buffer,
|
||||
fs_info->root_dir_offset,
|
||||
fs_info->root_dir_sector_count);
|
||||
}
|
||||
|
||||
PedFileSystem*
|
||||
fat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
|
||||
{
|
||||
PedFileSystem* fs;
|
||||
FatSpecific* fs_info;
|
||||
FatCluster table_size;
|
||||
|
||||
fs = fat_alloc (geom);
|
||||
if (!fs)
|
||||
goto error;
|
||||
fs_info = (FatSpecific*) fs->type_specific;
|
||||
|
||||
fs_info->logical_sector_size = 1;
|
||||
fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
|
||||
fs_info->heads = geom->dev->bios_geom.heads;
|
||||
fs_info->sector_count = fs->geom->length;
|
||||
fs_info->fat_table_count = 2;
|
||||
/* some initial values, to be changed later */
|
||||
fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
|
||||
/ (512 / sizeof (FatDirEntry));
|
||||
fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
|
||||
|
||||
fs_info->fat_type = fat_type;
|
||||
if (!fat_calc_sizes (fs->geom->length, 0,
|
||||
fs_info->fat_type,
|
||||
fs_info->root_dir_sector_count,
|
||||
&fs_info->cluster_sectors,
|
||||
&fs_info->cluster_count,
|
||||
&fs_info->fat_sectors)) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Partition too big/small for a %s file system."),
|
||||
(fat_type == FAT_TYPE_FAT16)
|
||||
? fat16_type.name
|
||||
: fat32_type.name);
|
||||
goto error_free_fs;
|
||||
}
|
||||
|
||||
fs_info->cluster_size = fs_info->cluster_sectors * 512;
|
||||
|
||||
fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
|
||||
fs_info->dir_entries_per_cluster
|
||||
= fs_info->cluster_size / sizeof (FatDirEntry);
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16) {
|
||||
/* FAT16 */
|
||||
fs->type = &fat16_type;
|
||||
|
||||
if (fs_info->cluster_count
|
||||
> fat_max_cluster_count (fs_info->fat_type)) {
|
||||
fs_info->cluster_count
|
||||
= fat_max_cluster_count (fs_info->fat_type);
|
||||
}
|
||||
|
||||
fs_info->root_dir_sector_count
|
||||
= FAT_ROOT_DIR_ENTRY_COUNT
|
||||
/ (512 / sizeof (FatDirEntry));
|
||||
fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
|
||||
fs_info->root_dir_offset
|
||||
= fs_info->fat_offset
|
||||
+ fs_info->fat_sectors * fs_info->fat_table_count;
|
||||
fs_info->cluster_offset
|
||||
= fs_info->root_dir_offset
|
||||
+ fs_info->root_dir_sector_count;
|
||||
} else {
|
||||
/* FAT32 */
|
||||
fs->type = &fat32_type;
|
||||
|
||||
fs_info->info_sector_offset = 1;
|
||||
fs_info->boot_sector_backup_offset = 6;
|
||||
|
||||
fs_info->root_dir_sector_count = 0;
|
||||
fs_info->root_dir_entry_count = 0;
|
||||
fs_info->root_dir_offset = 0;
|
||||
|
||||
fs_info->cluster_offset
|
||||
= fs_info->fat_offset
|
||||
+ fs_info->fat_sectors * fs_info->fat_table_count;
|
||||
}
|
||||
|
||||
table_size = fs_info->fat_sectors * 512
|
||||
/ fat_table_entry_size (fs_info->fat_type);
|
||||
fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
|
||||
if (!fs_info->fat)
|
||||
goto error_free_fs;
|
||||
fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
|
||||
if (!fat_alloc_buffers (fs))
|
||||
goto error_free_fat_table;
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
fs_info->root_cluster
|
||||
= fat_table_alloc_cluster (fs_info->fat);
|
||||
fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
|
||||
memset (fs_info->buffer, 0, fs_info->cluster_size);
|
||||
if (!fat_write_cluster (fs, fs_info->buffer,
|
||||
fs_info->root_cluster))
|
||||
goto error_free_buffers;
|
||||
}
|
||||
|
||||
fs_info->serial_number = generate_random_uint32 ();
|
||||
|
||||
if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector, fs))
|
||||
goto error_free_buffers;
|
||||
if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
|
||||
goto error_free_buffers;
|
||||
if (!fat_boot_sector_write (fs_info->boot_sector, fs))
|
||||
goto error_free_buffers;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
if (!fat_info_sector_generate (&fs_info->info_sector, fs))
|
||||
goto error_free_buffers;
|
||||
if (!fat_info_sector_write (fs_info->info_sector, fs))
|
||||
goto error_free_buffers;
|
||||
}
|
||||
|
||||
if (!fat_table_write_all (fs_info->fat, fs))
|
||||
goto error_free_buffers;
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16) {
|
||||
if (!fat_root_dir_clear (fs))
|
||||
goto error_free_buffers;
|
||||
}
|
||||
|
||||
return fs;
|
||||
|
||||
error_free_buffers:
|
||||
fat_free_buffers (fs);
|
||||
error_free_fat_table:
|
||||
fat_table_destroy (fs_info->fat);
|
||||
error_free_fs:
|
||||
fat_free (fs);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PedFileSystem*
|
||||
fat_create_fat16 (PedGeometry* geom, PedTimer* timer)
|
||||
{
|
||||
return fat_create (geom, FAT_TYPE_FAT16, timer);
|
||||
}
|
||||
|
||||
PedFileSystem*
|
||||
fat_create_fat32 (PedGeometry* geom, PedTimer* timer)
|
||||
{
|
||||
return fat_create (geom, FAT_TYPE_FAT32, timer);
|
||||
}
|
||||
|
||||
int
|
||||
fat_close (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
fat_free_buffers (fs);
|
||||
fat_table_destroy (fs_info->fat);
|
||||
fat_free (fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Hack: just resize the file system outside of its boundaries! */
|
||||
PedFileSystem*
|
||||
fat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
|
||||
{
|
||||
PedFileSystem* new_fs;
|
||||
|
||||
new_fs = ped_file_system_open (fs->geom);
|
||||
if (!new_fs)
|
||||
goto error;
|
||||
if (!ped_file_system_resize (new_fs, geom, timer))
|
||||
goto error_close_new_fs;
|
||||
return new_fs;
|
||||
|
||||
error_close_new_fs:
|
||||
ped_file_system_close (new_fs);
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_fats (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatTable* table_copy;
|
||||
FatCluster table_size;
|
||||
int i;
|
||||
|
||||
table_size = fs_info->fat_sectors * 512
|
||||
/ fat_table_entry_size (fs_info->fat_type);
|
||||
|
||||
table_copy = fat_table_new (fs_info->fat_type, table_size);
|
||||
if (!table_copy)
|
||||
goto error;
|
||||
|
||||
for (i = 1; i < fs_info->fat_table_count; i++) {
|
||||
if (!fat_table_read (table_copy, fs, i))
|
||||
goto error_free_table_copy;
|
||||
if (!fat_table_compare (fs_info->fat, table_copy)) {
|
||||
if (ped_exception_throw (PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("The FATs don't match. If you don't know "
|
||||
"what this means, then select cancel, run "
|
||||
"scandisk on the file system, and then come "
|
||||
"back."))
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
goto error_free_table_copy;
|
||||
}
|
||||
}
|
||||
|
||||
fat_table_destroy (table_copy);
|
||||
return 1;
|
||||
|
||||
error_free_table_copy:
|
||||
fat_table_destroy (table_copy);
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fat_check (PedFileSystem* fs, PedTimer* timer)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedSector cluster_sectors;
|
||||
FatCluster cluster_count;
|
||||
PedSector fat_sectors;
|
||||
PedSector align_sectors;
|
||||
FatCluster info_free_clusters;
|
||||
|
||||
align_sectors = fs_info->fat_offset
|
||||
- fat_min_reserved_sector_count (fs_info->fat_type);
|
||||
|
||||
if (!fat_calc_sizes (fs->geom->length,
|
||||
align_sectors,
|
||||
fs_info->fat_type,
|
||||
fs_info->root_dir_sector_count,
|
||||
&cluster_sectors,
|
||||
&cluster_count,
|
||||
&fat_sectors)) {
|
||||
if (ped_exception_throw (PED_EXCEPTION_BUG,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("There are no possible configurations for this FAT "
|
||||
"type."))
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16) {
|
||||
if (cluster_sectors != fs_info->cluster_sectors
|
||||
|| cluster_count != fs_info->cluster_count
|
||||
|| fat_sectors != fs_info->fat_sectors) {
|
||||
if (ped_exception_throw (PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("File system doesn't have expected sizes for "
|
||||
"Windows to like it. "
|
||||
"Cluster size is %dk (%dk expected); "
|
||||
"number of clusters is %d (%d expected); "
|
||||
"size of FATs is %d sectors (%d expected)."),
|
||||
(int) fs_info->cluster_sectors / 2,
|
||||
(int) cluster_sectors / 2,
|
||||
(int) fs_info->cluster_count,
|
||||
(int) cluster_count,
|
||||
(int) fs_info->fat_sectors,
|
||||
(int) fat_sectors)
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
info_free_clusters
|
||||
= PED_LE32_TO_CPU (fs_info->info_sector->free_clusters);
|
||||
if (info_free_clusters != (FatCluster) -1
|
||||
&& info_free_clusters != fs_info->fat->free_cluster_count) {
|
||||
if (ped_exception_throw (PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("File system is reporting the free space as "
|
||||
"%d clusters, not %d clusters."),
|
||||
info_free_clusters,
|
||||
fs_info->fat->free_cluster_count)
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_compare_fats (fs))
|
||||
goto error;
|
||||
|
||||
fs->checked = 1;
|
||||
return 1; /* existence of fs implies consistency ;-) */
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculates how much space there will be in clusters in:
|
||||
* old_fs intersect the-new-fs
|
||||
*/
|
||||
static PedSector
|
||||
_calc_resize_data_size (
|
||||
const PedFileSystem* old_fs,
|
||||
PedSector new_cluster_sectors,
|
||||
FatCluster new_cluster_count,
|
||||
PedSector new_fat_size)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
|
||||
PedSector fat_size_delta;
|
||||
|
||||
fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
|
||||
return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
|
||||
}
|
||||
|
||||
static int
|
||||
_test_resize_size (const PedFileSystem* fs,
|
||||
PedSector length, PedSector min_data_size)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedGeometry geom;
|
||||
PedSector _cluster_sectors;
|
||||
FatCluster _cluster_count;
|
||||
PedSector _fat_size;
|
||||
|
||||
ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
|
||||
|
||||
if (fat_calc_resize_sizes (
|
||||
&geom,
|
||||
fs_info->cluster_sectors,
|
||||
FAT_TYPE_FAT16,
|
||||
fs_info->root_dir_sector_count,
|
||||
fs_info->cluster_sectors,
|
||||
&_cluster_sectors,
|
||||
&_cluster_count,
|
||||
&_fat_size)
|
||||
&& _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
|
||||
_fat_size)
|
||||
>= min_data_size)
|
||||
return 1;
|
||||
|
||||
if (fat_calc_resize_sizes (
|
||||
&geom,
|
||||
fs_info->cluster_sectors,
|
||||
FAT_TYPE_FAT32,
|
||||
0,
|
||||
fs_info->cluster_sectors,
|
||||
&_cluster_sectors,
|
||||
&_cluster_count,
|
||||
&_fat_size)
|
||||
&& _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
|
||||
_fat_size)
|
||||
>= min_data_size)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* does a binary search (!) for the mininum size. Too hard to compute directly
|
||||
* (see calc_sizes() for why!)
|
||||
*/
|
||||
static PedSector
|
||||
_get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
|
||||
{
|
||||
PedSector min_length = 0;
|
||||
PedSector max_length = fs->geom->length;
|
||||
PedSector length;
|
||||
|
||||
while (min_length < max_length - 1) {
|
||||
length = (min_length + max_length) / 2;
|
||||
if (_test_resize_size (fs, length, min_data_size))
|
||||
max_length = length;
|
||||
else
|
||||
min_length = length;
|
||||
}
|
||||
|
||||
/* adds a bit of leeway (64 sectors), for resolving extra issues, like root
|
||||
* directory allocation, that aren't covered here.
|
||||
*/
|
||||
return max_length + 64;
|
||||
}
|
||||
|
||||
PedConstraint*
|
||||
fat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedGeometry full_dev;
|
||||
PedSector min_cluster_count;
|
||||
FatCluster used_clusters;
|
||||
PedSector min_data_size;
|
||||
|
||||
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
|
||||
return NULL;
|
||||
|
||||
used_clusters = fs_info->fat->cluster_count
|
||||
- fs_info->fat->free_cluster_count;
|
||||
min_cluster_count = used_clusters + fs_info->total_dir_clusters;
|
||||
min_data_size = min_cluster_count * fs_info->cluster_sectors;
|
||||
|
||||
return ped_constraint_new (ped_alignment_any, ped_alignment_any,
|
||||
&full_dev, &full_dev,
|
||||
_get_min_resize_size (fs, min_data_size),
|
||||
dev->length);
|
||||
}
|
||||
|
||||
PedConstraint*
|
||||
fat_get_resize_constraint (const PedFileSystem* fs)
|
||||
{
|
||||
return fat_get_copy_constraint (fs, fs->geom->dev);
|
||||
}
|
||||
|
||||
PedConstraint*
|
||||
fat_get_create_constraint_fat16 (const PedDevice* dev)
|
||||
{
|
||||
PedGeometry full_dev;
|
||||
PedSector min_size;
|
||||
PedSector max_size;
|
||||
|
||||
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
|
||||
return NULL;
|
||||
|
||||
min_size = 65794;
|
||||
max_size = 2097153;
|
||||
|
||||
return ped_constraint_new (
|
||||
ped_alignment_any, ped_alignment_any,
|
||||
&full_dev, &full_dev,
|
||||
min_size, max_size);
|
||||
}
|
||||
|
||||
PedConstraint*
|
||||
fat_get_create_constraint_fat32 (const PedDevice* dev)
|
||||
{
|
||||
PedGeometry full_dev;
|
||||
PedSector min_size;
|
||||
|
||||
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
|
||||
return NULL;
|
||||
|
||||
min_size = 525224;
|
||||
|
||||
return ped_constraint_new (
|
||||
ped_alignment_any, ped_alignment_any,
|
||||
&full_dev, &full_dev,
|
||||
min_size, dev->length);
|
||||
}
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2001, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FAT_H_INCLUDED
|
||||
#define FAT_H_INCLUDED
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define BUFFER_SIZE 1024 /* buffer size in sectors (512 bytes) */
|
||||
|
||||
typedef uint32_t FatCluster;
|
||||
typedef int32_t FatFragment;
|
||||
|
||||
enum _FatType {
|
||||
FAT_TYPE_FAT12,
|
||||
FAT_TYPE_FAT16,
|
||||
FAT_TYPE_FAT32
|
||||
};
|
||||
typedef enum _FatType FatType;
|
||||
|
||||
typedef struct _FatSpecific FatSpecific;
|
||||
typedef struct _FatDirEntry FatDirEntry;
|
||||
|
||||
/* FIXME: YUCKY */
|
||||
#include "table.h"
|
||||
#include "bootsector.h"
|
||||
#include "context.h"
|
||||
#include "fatio.h"
|
||||
#include "traverse.h"
|
||||
#include "calc.h"
|
||||
#include "count.h"
|
||||
#include "clstdup.h"
|
||||
|
||||
struct __attribute__ ((packed)) _FatDirEntry {
|
||||
char name[8];
|
||||
uint8_t extension[3];
|
||||
uint8_t attributes;
|
||||
uint8_t is_upper_case_name;
|
||||
uint8_t creation_time_low; /* milliseconds */
|
||||
uint16_t creation_time_high;
|
||||
uint16_t creation_date;
|
||||
uint16_t access_date;
|
||||
uint16_t first_cluster_high; /* for FAT32 */
|
||||
uint16_t time;
|
||||
uint16_t date;
|
||||
uint16_t first_cluster;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct _FatSpecific {
|
||||
FatBootSector *boot_sector; /* structure of boot sector */
|
||||
FatInfoSector *info_sector; /* fat32-only information sector */
|
||||
|
||||
int logical_sector_size; /* illogical sector size :-) */
|
||||
PedSector sector_count;
|
||||
|
||||
int sectors_per_track; /* BIOS CHS stuff (S) */
|
||||
int heads; /* BIOS CHS stuff (H) */
|
||||
|
||||
int cluster_size;
|
||||
PedSector cluster_sectors;
|
||||
FatCluster cluster_count;
|
||||
int dir_entries_per_cluster;
|
||||
|
||||
FatType fat_type;
|
||||
int fat_table_count;
|
||||
PedSector fat_sectors;
|
||||
|
||||
uint32_t serial_number;
|
||||
|
||||
PedSector info_sector_offset; /* FAT32 only */
|
||||
PedSector fat_offset;
|
||||
PedSector root_dir_offset; /* non-FAT32 */
|
||||
PedSector cluster_offset;
|
||||
PedSector boot_sector_backup_offset;
|
||||
|
||||
FatCluster root_cluster; /* FAT32 only */
|
||||
int root_dir_entry_count; /* non-FAT32 */
|
||||
PedSector root_dir_sector_count; /* non-FAT32 */
|
||||
FatCluster total_dir_clusters;
|
||||
|
||||
FatTable* fat;
|
||||
FatClusterInfo* cluster_info;
|
||||
|
||||
PedSector buffer_sectors;
|
||||
char* buffer;
|
||||
|
||||
int frag_size;
|
||||
PedSector frag_sectors;
|
||||
FatFragment frag_count;
|
||||
FatFragment buffer_frags;
|
||||
FatFragment cluster_frags;
|
||||
};
|
||||
|
||||
#define FAT_SPECIFIC(fs) ((FatSpecific*) fs->type_specific)
|
||||
|
||||
#define FAT_ROOT 0
|
||||
|
||||
#define DELETED_FLAG 0xe5
|
||||
|
||||
#define READONLY_ATTR 0x01
|
||||
#define HIDDEN_ATTR 0x02
|
||||
#define SYSTEM_ATTR 0x04
|
||||
#define VOLUME_LABEL_ATTR 0x08
|
||||
#define VFAT_ATTR 0x0f
|
||||
#define DIRECTORY_ATTR 0x10
|
||||
#define ARCH_ATTR 0x20
|
||||
|
||||
#define MAX_FAT12_CLUSTERS 4086
|
||||
#define MAX_FAT16_CLUSTERS 65526
|
||||
#define MAX_FAT32_CLUSTERS 2000000
|
||||
|
||||
#define FAT_ROOT_DIR_ENTRY_COUNT 512
|
||||
|
||||
extern PedFileSystemType fat16_type;
|
||||
extern PedFileSystemType fat32_type;
|
||||
|
||||
extern void fat_print (const PedFileSystem* fs);
|
||||
|
||||
extern PedFileSystem* fat_alloc (const PedGeometry* geom);
|
||||
extern void fat_free (PedFileSystem* fs);
|
||||
extern int fat_alloc_buffers (PedFileSystem* fs);
|
||||
extern void fat_free_buffers (PedFileSystem* fs);
|
||||
|
||||
extern int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer);
|
||||
|
||||
extern int fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors);
|
||||
|
||||
#endif /* FAT_H_INCLUDED */
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
#include "fatio.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
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_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
|
||||
{
|
||||
return fat_read_fragments (fs, buf, frag, 1);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_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_write (fs->geom, buf, sector, sector_count);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
|
||||
{
|
||||
return fat_write_fragments (fs, buf, frag, 1);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_sync_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
|
||||
FatFragment count)
|
||||
{
|
||||
if (!fat_write_fragments (fs, buf, frag, count))
|
||||
return 0;
|
||||
if (!ped_geometry_sync (fs->geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_sync_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
|
||||
{
|
||||
return fat_write_sync_fragments (fs, buf, frag, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int
|
||||
fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
|
||||
{
|
||||
return fat_read_clusters (fs, buf, cluster, 1);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_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_write (fs->geom, buf, sector, sector_count);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
|
||||
{
|
||||
return fat_write_clusters (fs, buf, cluster, 1);
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_sync_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
|
||||
FatCluster count)
|
||||
{
|
||||
if (!fat_write_clusters (fs, buf, cluster, count))
|
||||
return 0;
|
||||
if (!ped_geometry_sync (fs->geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_write_sync_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
|
||||
{
|
||||
if (!fat_write_cluster (fs, buf, cluster))
|
||||
return 0;
|
||||
if (!ped_geometry_sync (fs->geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FATIO_H_INCLUDED
|
||||
#define FATIO_H_INCLUDED
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
extern int fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
|
||||
FatFragment count);
|
||||
extern int fat_write_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
|
||||
FatFragment count);
|
||||
extern int fat_write_sync_fragments (PedFileSystem* fs, char* buf,
|
||||
FatFragment frag, FatFragment count);
|
||||
|
||||
extern int fat_read_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
|
||||
extern int fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
|
||||
extern int fat_write_sync_fragment (PedFileSystem* fs, char* buf,
|
||||
FatFragment frag);
|
||||
|
||||
extern int fat_read_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
|
||||
FatCluster count);
|
||||
extern int fat_write_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
|
||||
FatCluster count);
|
||||
extern int fat_write_sync_clusters (PedFileSystem* fs, char* buf,
|
||||
FatCluster cluster, FatCluster count);
|
||||
|
||||
extern int fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
|
||||
extern int fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
|
||||
extern int fat_write_sync_cluster (PedFileSystem* fs, char *buf,
|
||||
FatCluster cluster);
|
||||
|
||||
#endif /* FATIO_H_INCLUDED */
|
||||
@@ -1,876 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
#include "traverse.h"
|
||||
#include "count.h"
|
||||
#include "fatio.h"
|
||||
#include "calc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
/* Recursively builds (i.e. makes consistent) the duplicated directory tree
|
||||
* (leaving the original directory tree in tact)
|
||||
*/
|
||||
static int
|
||||
fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info)
|
||||
{
|
||||
FatTraverseInfo* sub_dir_info;
|
||||
FatDirEntry* dir_entry;
|
||||
FatCluster old_first_cluster;
|
||||
|
||||
while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) {
|
||||
if (fat_dir_entry_is_null_term (dir_entry))
|
||||
break;
|
||||
if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs))
|
||||
continue;
|
||||
|
||||
fat_traverse_mark_dirty (trav_info);
|
||||
|
||||
old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry,
|
||||
ctx->old_fs);
|
||||
fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs,
|
||||
fat_op_context_map_cluster (ctx, old_first_cluster));
|
||||
|
||||
if (fat_dir_entry_is_directory (dir_entry)
|
||||
&& dir_entry->name [0] != '.') {
|
||||
sub_dir_info
|
||||
= fat_traverse_directory (trav_info, dir_entry);
|
||||
if (!sub_dir_info)
|
||||
return 0;
|
||||
if (!fat_construct_directory (ctx, sub_dir_info))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* remove "stale" entries at the end */
|
||||
while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) {
|
||||
memset (dir_entry, 0, sizeof (FatDirEntry));
|
||||
fat_traverse_mark_dirty (trav_info);
|
||||
}
|
||||
fat_traverse_complete (trav_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs the new directory tree for legacy (FAT16) file systems.
|
||||
*/
|
||||
static int
|
||||
fat_construct_legacy_root (FatOpContext* ctx)
|
||||
{
|
||||
FatTraverseInfo* trav_info;
|
||||
|
||||
if (!duplicate_legacy_root_dir (ctx))
|
||||
return 0;
|
||||
trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\");
|
||||
return fat_construct_directory (ctx, trav_info);
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs the new directory tree for new (FAT32) file systems.
|
||||
*/
|
||||
static int
|
||||
fat_construct_root (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatTraverseInfo* trav_info;
|
||||
|
||||
trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster,
|
||||
"\\");
|
||||
fat_construct_directory (ctx, trav_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Converts the root directory between FAT16 and FAT32. NOTE: this code
|
||||
* can also do no conversion. I'm leaving fat_construct_directory(), because
|
||||
* it's really pretty :-) It also leaves a higher chance of deleted file
|
||||
* recovery, because it doesn't remove redundant entries. (We do this here,
|
||||
* because brain-damaged FAT16 has an arbitary limit on root directory entries,
|
||||
* so we save room)
|
||||
*/
|
||||
static int
|
||||
fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav,
|
||||
FatTraverseInfo* new_trav)
|
||||
{
|
||||
FatTraverseInfo* sub_old_dir_trav;
|
||||
FatTraverseInfo* sub_new_dir_trav;
|
||||
FatDirEntry* new_dir_entry;
|
||||
FatDirEntry* old_dir_entry;
|
||||
FatCluster old_first_cluster;
|
||||
|
||||
while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) {
|
||||
if (fat_dir_entry_is_null_term (old_dir_entry))
|
||||
break;
|
||||
if (!fat_dir_entry_is_active (old_dir_entry))
|
||||
continue;
|
||||
|
||||
new_dir_entry = fat_traverse_next_dir_entry (new_trav);
|
||||
if (!new_dir_entry) {
|
||||
return ped_exception_throw (PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("There's not enough room in the root "
|
||||
"directory for all of the files. Either "
|
||||
"cancel, or ignore to lose the files."))
|
||||
== PED_EXCEPTION_IGNORE;
|
||||
}
|
||||
|
||||
*new_dir_entry = *old_dir_entry;
|
||||
fat_traverse_mark_dirty (new_trav);
|
||||
|
||||
if (!fat_dir_entry_has_first_cluster (old_dir_entry,
|
||||
ctx->old_fs))
|
||||
continue;
|
||||
|
||||
old_first_cluster = fat_dir_entry_get_first_cluster (
|
||||
old_dir_entry, ctx->old_fs);
|
||||
fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs,
|
||||
fat_op_context_map_cluster (ctx, old_first_cluster));
|
||||
|
||||
if (fat_dir_entry_is_directory (old_dir_entry)
|
||||
&& old_dir_entry->name [0] != '.') {
|
||||
sub_old_dir_trav
|
||||
= fat_traverse_directory (old_trav, old_dir_entry);
|
||||
if (!sub_old_dir_trav) return 0;
|
||||
sub_new_dir_trav
|
||||
= fat_traverse_directory (new_trav, new_dir_entry);
|
||||
if (!sub_new_dir_trav) {
|
||||
fat_traverse_complete (sub_old_dir_trav);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fat_convert_directory (ctx, sub_old_dir_trav,
|
||||
sub_new_dir_trav))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove "stale" entries at the end, just in case there is some
|
||||
* overlap
|
||||
*/
|
||||
while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) {
|
||||
memset (new_dir_entry, 0, sizeof (FatDirEntry));
|
||||
fat_traverse_mark_dirty (new_trav);
|
||||
}
|
||||
|
||||
fat_traverse_complete (old_trav);
|
||||
fat_traverse_complete (new_trav);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_cluster (PedFileSystem* fs, FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
memset (fs_info->buffer, 0, fs_info->cluster_size);
|
||||
fat_write_cluster (fs, fs_info->buffer, cluster);
|
||||
}
|
||||
|
||||
/* This MUST be called BEFORE the fat_construct_new_fat(), because cluster
|
||||
* allocation depend on the old FAT. The reason is, old clusters may
|
||||
* still be needed during the resize, (particularly clusters in the directory
|
||||
* tree) even if they will be discarded later.
|
||||
*/
|
||||
static int
|
||||
alloc_root_dir (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatCluster i;
|
||||
FatCluster cluster;
|
||||
FatCluster cluster_count;
|
||||
|
||||
PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT32);
|
||||
|
||||
cluster_count = ped_div_round_up (
|
||||
PED_MAX (16, old_fs_info->root_dir_sector_count),
|
||||
new_fs_info->cluster_sectors);
|
||||
|
||||
for (i = 0; i < cluster_count; i++) {
|
||||
cluster = fat_table_alloc_check_cluster (new_fs_info->fat,
|
||||
ctx->new_fs);
|
||||
if (!cluster)
|
||||
return 0;
|
||||
ctx->new_root_dir [i] = cluster;
|
||||
clear_cluster (ctx->new_fs, cluster);
|
||||
}
|
||||
ctx->new_root_dir [i] = 0;
|
||||
new_fs_info->root_cluster = ctx->new_root_dir [0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* when converting FAT32 -> FAT16
|
||||
* fat_duplicate clusters() duplicated the root directory unnecessarily.
|
||||
* Let's free it.
|
||||
*
|
||||
* This must be called AFTER fat_construct_new_fat(). (otherwise, our
|
||||
* changes just get overwritten)
|
||||
*/
|
||||
static int
|
||||
free_root_dir (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatCluster old_cluster;
|
||||
FatFragment i;
|
||||
|
||||
PED_ASSERT (old_fs_info->fat_type == FAT_TYPE_FAT32);
|
||||
PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT16);
|
||||
|
||||
for (old_cluster = old_fs_info->root_cluster;
|
||||
!fat_table_is_eof (old_fs_info->fat, old_cluster);
|
||||
old_cluster = fat_table_get (old_fs_info->fat, old_cluster)) {
|
||||
FatFragment old_frag;
|
||||
old_frag = fat_cluster_to_frag (ctx->old_fs, old_cluster);
|
||||
for (i = 0; i < new_fs_info->cluster_frags; i++) {
|
||||
FatFragment new_frag;
|
||||
FatCluster new_clst;
|
||||
new_frag = fat_op_context_map_fragment (ctx,
|
||||
old_frag + i);
|
||||
new_clst = fat_frag_to_cluster (ctx->old_fs, new_frag);
|
||||
if (!fat_table_set_avail (new_fs_info->fat, new_clst))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
fat_clear_root_dir (PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
int i;
|
||||
|
||||
PED_ASSERT (fs_info->fat_type == FAT_TYPE_FAT16);
|
||||
PED_ASSERT (fs_info->root_dir_sector_count);
|
||||
|
||||
memset (fs_info->buffer, 0, 512);
|
||||
|
||||
for (i = 0; i < fs_info->root_dir_sector_count; i++) {
|
||||
if (!ped_geometry_write (fs->geom, fs_info->buffer,
|
||||
fs_info->root_dir_offset + i, 1)) {
|
||||
if (ped_exception_throw (PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("Error writing to the root directory."))
|
||||
== PED_EXCEPTION_CANCEL)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
fat_construct_converted_tree (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatTraverseInfo* old_trav_info;
|
||||
FatTraverseInfo* new_trav_info;
|
||||
|
||||
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
new_trav_info = fat_traverse_begin (ctx->new_fs,
|
||||
new_fs_info->root_cluster, "\\");
|
||||
if (!new_trav_info) return 0;
|
||||
old_trav_info = fat_traverse_begin (ctx->old_fs, FAT_ROOT,
|
||||
"\\");
|
||||
} else {
|
||||
fat_clear_root_dir (ctx->new_fs);
|
||||
new_trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT,
|
||||
"\\");
|
||||
if (!new_trav_info) return 0;
|
||||
old_trav_info = fat_traverse_begin (ctx->old_fs,
|
||||
old_fs_info->root_cluster, "\\");
|
||||
}
|
||||
if (!old_trav_info) {
|
||||
fat_traverse_complete (new_trav_info);
|
||||
return 0;
|
||||
}
|
||||
if (!fat_convert_directory (ctx, old_trav_info, new_trav_info))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs the new directory tree to match the new file locations.
|
||||
*/
|
||||
static int
|
||||
fat_construct_dir_tree (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
|
||||
if (new_fs_info->fat_type == old_fs_info->fat_type) {
|
||||
switch (old_fs_info->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
return fat_construct_legacy_root (ctx);
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return fat_construct_root (ctx);
|
||||
}
|
||||
} else {
|
||||
return fat_construct_converted_tree (ctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FatFragment
|
||||
_get_next_old_frag (FatOpContext* ctx, FatFragment frag)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatCluster cluster;
|
||||
FatCluster next_cluster;
|
||||
|
||||
if ((frag + 1) % old_fs_info->cluster_frags != 0) {
|
||||
if (fat_is_fragment_active (ctx->old_fs, frag + 1))
|
||||
return frag + 1;
|
||||
else
|
||||
return -1;
|
||||
} else {
|
||||
cluster = fat_frag_to_cluster (ctx->old_fs, frag);
|
||||
next_cluster = fat_table_get (old_fs_info->fat, cluster);
|
||||
|
||||
if (fat_table_is_eof (old_fs_info->fat, next_cluster))
|
||||
return -1;
|
||||
else
|
||||
return fat_cluster_to_frag (ctx->old_fs, next_cluster);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs the new fat for the resized file system.
|
||||
*/
|
||||
static int
|
||||
fat_construct_new_fat (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
FatFragment old_frag;
|
||||
FatCluster new_cluster;
|
||||
FatFragment new_frag;
|
||||
FatFragment old_next_frag;
|
||||
FatFragment new_next_frag;
|
||||
FatCluster new_next_cluster;
|
||||
FatClusterFlag flag;
|
||||
int i;
|
||||
|
||||
fat_table_clear (new_fs_info->fat);
|
||||
if (!fat_table_set_cluster_count (new_fs_info->fat,
|
||||
new_fs_info->cluster_count))
|
||||
return 0;
|
||||
|
||||
for (old_frag = 0; old_frag < old_fs_info->frag_count; old_frag++) {
|
||||
flag = fat_get_fragment_flag (ctx->old_fs, old_frag);
|
||||
if (flag == FAT_FLAG_FREE)
|
||||
continue;
|
||||
if (flag == FAT_FLAG_BAD) {
|
||||
new_frag = fat_op_context_map_static_fragment (
|
||||
ctx, old_frag);
|
||||
if (new_frag == -1)
|
||||
continue;
|
||||
new_cluster = fat_frag_to_cluster (ctx->new_fs,
|
||||
new_frag);
|
||||
fat_table_set_bad (new_fs_info->fat, new_cluster);
|
||||
continue;
|
||||
}
|
||||
|
||||
new_frag = fat_op_context_map_fragment (ctx, old_frag);
|
||||
new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag);
|
||||
|
||||
old_next_frag = _get_next_old_frag (ctx, old_frag);
|
||||
if (old_next_frag == -1) {
|
||||
fat_table_set_eof (new_fs_info->fat, new_cluster);
|
||||
continue;
|
||||
}
|
||||
|
||||
new_next_frag = fat_op_context_map_fragment (ctx,
|
||||
old_next_frag);
|
||||
PED_ASSERT (new_next_frag != -1);
|
||||
|
||||
new_next_cluster = fat_frag_to_cluster (ctx->new_fs,
|
||||
new_next_frag);
|
||||
PED_ASSERT (new_next_cluster != new_cluster);
|
||||
|
||||
fat_table_set (new_fs_info->fat, new_cluster, new_next_cluster);
|
||||
}
|
||||
|
||||
if (old_fs_info->fat_type == FAT_TYPE_FAT32
|
||||
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
new_fs_info->root_cluster
|
||||
= fat_op_context_map_cluster (ctx,
|
||||
old_fs_info->root_cluster);
|
||||
}
|
||||
|
||||
if (old_fs_info->fat_type == FAT_TYPE_FAT16
|
||||
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
for (i=0; ctx->new_root_dir[i+1]; i++) {
|
||||
fat_table_set (new_fs_info->fat,
|
||||
ctx->new_root_dir[i],
|
||||
ctx->new_root_dir[i+1]);
|
||||
}
|
||||
fat_table_set_eof (new_fs_info->fat, ctx->new_root_dir[i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ask_type (PedFileSystem* fs, int fat16_ok, int fat32_ok, FatType* out_fat_type)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedExceptionOption status;
|
||||
const char* fat16_msg;
|
||||
const char* fat32_msg;
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16)
|
||||
fat16_msg = _("If you leave your file system as FAT16, "
|
||||
"then you will have no problems.");
|
||||
else
|
||||
fat16_msg = _("If you convert to FAT16, and MS Windows "
|
||||
"is installed on this partition, then "
|
||||
"you must re-install the MS Windows boot "
|
||||
"loader. If you want to do this, you "
|
||||
"should consult the Parted manual (or "
|
||||
"your distribution's manual).");
|
||||
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32)
|
||||
fat32_msg = _("If you leave your file system as FAT32, "
|
||||
"then you will not introduce any new "
|
||||
"problems.");
|
||||
else
|
||||
fat32_msg = _("If you convert to FAT32, and MS Windows "
|
||||
"is installed on this partition, then "
|
||||
"you must re-install the MS Windows boot "
|
||||
"loader. If you want to do this, you "
|
||||
"should consult the Parted manual (or "
|
||||
"your distribution's manual). Also, "
|
||||
"converting to FAT32 will make the file "
|
||||
"system unreadable by MS DOS, MS Windows "
|
||||
"95a, and MS Windows NT.");
|
||||
|
||||
if (fat16_ok && fat32_ok) {
|
||||
status = ped_exception_throw (
|
||||
PED_EXCEPTION_INFORMATION,
|
||||
PED_EXCEPTION_YES_NO_CANCEL,
|
||||
_("%s %s %s"),
|
||||
_("Would you like to use FAT32?"),
|
||||
fat16_msg,
|
||||
fat32_msg);
|
||||
|
||||
switch (status) {
|
||||
case PED_EXCEPTION_YES:
|
||||
*out_fat_type = FAT_TYPE_FAT32;
|
||||
return 1;
|
||||
|
||||
case PED_EXCEPTION_NO:
|
||||
*out_fat_type = FAT_TYPE_FAT16;
|
||||
return 1;
|
||||
|
||||
case PED_EXCEPTION_UNHANDLED:
|
||||
*out_fat_type = fs_info->fat_type;
|
||||
return 1;
|
||||
|
||||
case PED_EXCEPTION_CANCEL:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fat16_ok) {
|
||||
if (fs_info->fat_type != FAT_TYPE_FAT16) {
|
||||
status = ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_OK_CANCEL,
|
||||
_("%s %s"),
|
||||
_("The file system can only be resized to this "
|
||||
"size by converting to FAT16."),
|
||||
fat16_msg);
|
||||
if (status == PED_EXCEPTION_CANCEL)
|
||||
return 0;
|
||||
}
|
||||
*out_fat_type = FAT_TYPE_FAT16;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fat32_ok) {
|
||||
if (fs_info->fat_type != FAT_TYPE_FAT32) {
|
||||
status = ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_OK_CANCEL,
|
||||
_("%s %s"),
|
||||
_("The file system can only be resized to this "
|
||||
"size by converting to FAT32."),
|
||||
fat32_msg);
|
||||
if (status == PED_EXCEPTION_CANCEL)
|
||||
return 0;
|
||||
}
|
||||
*out_fat_type = FAT_TYPE_FAT32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_NO_FEATURE,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("GNU Parted cannot resize this partition to this size. "
|
||||
"We're working on it!"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For resize operations: determine if the file system must be FAT16 or FAT32,
|
||||
* or either. If the new file system must be FAT32, then query for
|
||||
* confirmation. If either file system can be used, query for which one.
|
||||
*/
|
||||
static int
|
||||
get_fat_type (PedFileSystem* fs, const PedGeometry* new_geom,
|
||||
FatType* out_fat_type)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
PedSector fat16_cluster_sectors;
|
||||
PedSector fat32_cluster_sectors;
|
||||
FatCluster dummy_cluster_count;
|
||||
PedSector dummy_fat_sectors;
|
||||
int fat16_ok;
|
||||
int fat32_ok;
|
||||
|
||||
fat16_ok = fat_calc_resize_sizes (
|
||||
new_geom,
|
||||
fs_info->cluster_sectors,
|
||||
FAT_TYPE_FAT16,
|
||||
fs_info->root_dir_sector_count,
|
||||
fs_info->cluster_sectors,
|
||||
&fat16_cluster_sectors,
|
||||
&dummy_cluster_count,
|
||||
&dummy_fat_sectors);
|
||||
|
||||
fat32_ok = fat_calc_resize_sizes (
|
||||
new_geom,
|
||||
fs_info->cluster_sectors,
|
||||
FAT_TYPE_FAT32,
|
||||
fs_info->root_dir_sector_count,
|
||||
fs_info->cluster_sectors,
|
||||
&fat32_cluster_sectors,
|
||||
&dummy_cluster_count,
|
||||
&dummy_fat_sectors);
|
||||
|
||||
return ask_type (fs, fat16_ok, fat32_ok, out_fat_type);
|
||||
}
|
||||
|
||||
/* Creates the PedFileSystem struct for the new resized file system, and
|
||||
sticks it in a FatOpContext. At the end of the process, the original
|
||||
(ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs).
|
||||
*/
|
||||
static FatOpContext*
|
||||
create_resize_context (PedFileSystem* fs, const PedGeometry* new_geom)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatSpecific* new_fs_info;
|
||||
PedFileSystem* new_fs;
|
||||
PedSector new_cluster_sectors;
|
||||
FatCluster new_cluster_count;
|
||||
PedSector new_fat_sectors;
|
||||
FatType new_fat_type;
|
||||
PedSector root_dir_sector_count;
|
||||
FatOpContext* context;
|
||||
|
||||
/* hypothetical number of root dir sectors, if we end up using
|
||||
* FAT16
|
||||
*/
|
||||
if (fs_info->root_dir_sector_count)
|
||||
root_dir_sector_count = fs_info->root_dir_sector_count;
|
||||
else
|
||||
root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
|
||||
* sizeof (FatDirEntry) / 512;
|
||||
|
||||
if (!get_fat_type (fs, new_geom, &new_fat_type))
|
||||
return 0;
|
||||
|
||||
fat_calc_resize_sizes (new_geom, fs_info->cluster_sectors, new_fat_type,
|
||||
root_dir_sector_count, fs_info->cluster_sectors,
|
||||
&new_cluster_sectors, &new_cluster_count, &new_fat_sectors);
|
||||
|
||||
if (!fat_check_resize_geometry (fs, new_geom, new_cluster_sectors,
|
||||
new_cluster_count))
|
||||
goto error;
|
||||
|
||||
new_fs = fat_alloc (new_geom);
|
||||
if (!new_fs)
|
||||
goto error;
|
||||
|
||||
new_fs_info = FAT_SPECIFIC (new_fs);
|
||||
if (!new_fs_info)
|
||||
goto error_free_new_fs;
|
||||
|
||||
/* preserve boot code, etc. */
|
||||
new_fs_info->boot_sector = ped_malloc (new_geom->dev->sector_size);
|
||||
memcpy (new_fs_info->boot_sector, fs_info->boot_sector,
|
||||
new_geom->dev->sector_size);
|
||||
new_fs_info->info_sector = NULL;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32)
|
||||
{
|
||||
PED_ASSERT (fs_info->info_sector != NULL);
|
||||
new_fs_info->info_sector =
|
||||
ped_malloc (new_geom->dev->sector_size);
|
||||
memcpy (new_fs_info->info_sector, fs_info->info_sector,
|
||||
new_geom->dev->sector_size);
|
||||
}
|
||||
|
||||
new_fs_info->logical_sector_size = fs_info->logical_sector_size;
|
||||
new_fs_info->sector_count = new_geom->length;
|
||||
|
||||
new_fs_info->sectors_per_track = fs_info->sectors_per_track;
|
||||
new_fs_info->heads = fs_info->heads;
|
||||
|
||||
new_fs_info->cluster_size = new_cluster_sectors * 512;
|
||||
new_fs_info->cluster_sectors = new_cluster_sectors;
|
||||
new_fs_info->cluster_count = new_cluster_count;
|
||||
new_fs_info->dir_entries_per_cluster = fs_info->dir_entries_per_cluster;
|
||||
|
||||
new_fs_info->fat_type = new_fat_type;
|
||||
new_fs_info->fat_table_count = 2;
|
||||
new_fs_info->fat_sectors = new_fat_sectors;
|
||||
|
||||
/* what about copying? */
|
||||
new_fs_info->serial_number = fs_info->serial_number;
|
||||
|
||||
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
new_fs_info->info_sector_offset = 1;
|
||||
new_fs_info->boot_sector_backup_offset = 6;
|
||||
|
||||
new_fs_info->root_dir_offset = 0;
|
||||
new_fs_info->root_dir_entry_count = 0;
|
||||
new_fs_info->root_dir_sector_count = 0;
|
||||
|
||||
/* we add calc_align_sectors to push the cluster_offset
|
||||
forward, to keep the clusters aligned between the new
|
||||
and old file systems
|
||||
*/
|
||||
new_fs_info->fat_offset
|
||||
= fat_min_reserved_sector_count (FAT_TYPE_FAT32)
|
||||
+ fat_calc_align_sectors (new_fs, fs);
|
||||
|
||||
new_fs_info->cluster_offset
|
||||
= new_fs_info->fat_offset
|
||||
+ 2 * new_fs_info->fat_sectors;
|
||||
} else {
|
||||
new_fs_info->root_dir_sector_count = root_dir_sector_count;
|
||||
new_fs_info->root_dir_entry_count
|
||||
= root_dir_sector_count * 512 / sizeof (FatDirEntry);
|
||||
|
||||
new_fs_info->fat_offset
|
||||
= fat_min_reserved_sector_count (FAT_TYPE_FAT16)
|
||||
+ fat_calc_align_sectors (new_fs, fs);
|
||||
|
||||
new_fs_info->root_dir_offset = new_fs_info->fat_offset
|
||||
+ 2 * new_fs_info->fat_sectors;
|
||||
|
||||
new_fs_info->cluster_offset = new_fs_info->root_dir_offset
|
||||
+ new_fs_info->root_dir_sector_count;
|
||||
}
|
||||
|
||||
new_fs_info->total_dir_clusters = fs_info->total_dir_clusters;
|
||||
|
||||
context = fat_op_context_new (new_fs, fs);
|
||||
if (!context)
|
||||
goto error_free_new_fs_info;
|
||||
|
||||
if (!fat_op_context_create_initial_fat (context))
|
||||
goto error_free_context;
|
||||
|
||||
if (!fat_alloc_buffers (new_fs))
|
||||
goto error_free_fat;
|
||||
|
||||
return context;
|
||||
|
||||
error_free_fat:
|
||||
fat_table_destroy (new_fs_info->fat);
|
||||
error_free_context:
|
||||
free (context);
|
||||
error_free_new_fs_info:
|
||||
free (new_fs_info);
|
||||
error_free_new_fs:
|
||||
free (new_fs);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
resize_context_assimilate (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
|
||||
fat_free_buffers (ctx->old_fs);
|
||||
fat_table_destroy (old_fs_info->fat);
|
||||
free (old_fs_info);
|
||||
ped_geometry_destroy (ctx->old_fs->geom);
|
||||
|
||||
ctx->old_fs->type_specific = ctx->new_fs->type_specific;
|
||||
ctx->old_fs->geom = ctx->new_fs->geom;
|
||||
ctx->old_fs->type = (new_fs_info->fat_type == FAT_TYPE_FAT16)
|
||||
? &fat16_type
|
||||
: &fat32_type;
|
||||
|
||||
free (ctx->new_fs);
|
||||
|
||||
fat_op_context_destroy (ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
resize_context_abort (FatOpContext* ctx)
|
||||
{
|
||||
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
|
||||
|
||||
fat_free_buffers (ctx->new_fs);
|
||||
fat_table_destroy (new_fs_info->fat);
|
||||
free (new_fs_info);
|
||||
ped_geometry_destroy (ctx->new_fs->geom);
|
||||
free (ctx->new_fs);
|
||||
|
||||
fat_op_context_destroy (ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int
|
||||
fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatSpecific* new_fs_info;
|
||||
FatOpContext* ctx;
|
||||
PedFileSystem* new_fs;
|
||||
|
||||
ctx = create_resize_context (fs, geom);
|
||||
if (!ctx)
|
||||
goto error;
|
||||
new_fs = ctx->new_fs;
|
||||
new_fs_info = FAT_SPECIFIC (new_fs);
|
||||
|
||||
if (!fat_duplicate_clusters (ctx, timer))
|
||||
goto error_abort_ctx;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT16
|
||||
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
if (!alloc_root_dir (ctx))
|
||||
goto error_abort_ctx;
|
||||
}
|
||||
if (!fat_construct_new_fat (ctx))
|
||||
goto error_abort_ctx;
|
||||
if (fs_info->fat_type == FAT_TYPE_FAT32
|
||||
&& new_fs_info->fat_type == FAT_TYPE_FAT16) {
|
||||
if (!free_root_dir (ctx))
|
||||
goto error_abort_ctx;
|
||||
}
|
||||
if (!fat_construct_dir_tree (ctx))
|
||||
goto error_abort_ctx;
|
||||
if (!fat_table_write_all (new_fs_info->fat, new_fs))
|
||||
goto error_abort_ctx;
|
||||
|
||||
_copy_hidden_sectors (ctx);
|
||||
fat_boot_sector_generate (&new_fs_info->boot_sector, new_fs);
|
||||
fat_boot_sector_write (new_fs_info->boot_sector, new_fs);
|
||||
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
|
||||
fat_info_sector_generate (&new_fs_info->info_sector, new_fs);
|
||||
fat_info_sector_write (new_fs_info->info_sector, new_fs);
|
||||
}
|
||||
|
||||
if (!resize_context_assimilate (ctx))
|
||||
goto error;
|
||||
|
||||
return 1;
|
||||
|
||||
error_abort_ctx:
|
||||
resize_context_abort (ctx);
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,481 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <parted/endian.h>
|
||||
#include "fat.h"
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
FatTable*
|
||||
fat_table_new (FatType fat_type, FatCluster size)
|
||||
{
|
||||
FatTable* ft;
|
||||
int entry_size = fat_table_entry_size (fat_type);
|
||||
|
||||
ft = (FatTable*) ped_malloc (sizeof (FatTable));
|
||||
if (!ft) return NULL;
|
||||
|
||||
ft->cluster_count = ft->free_cluster_count = size - 2;
|
||||
|
||||
/* ensure there's some free room on the end, to finish off the sector */
|
||||
ft->size = ped_div_round_up (size * entry_size, 512) * 512 / entry_size;
|
||||
ft->fat_type = fat_type;
|
||||
ft->raw_size = ft->size * entry_size;
|
||||
|
||||
ft->table = ped_malloc (ft->raw_size);
|
||||
if (!ft->table) {
|
||||
free (ft);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fat_table_clear (ft);
|
||||
return ft;
|
||||
}
|
||||
|
||||
void
|
||||
fat_table_destroy (FatTable* ft)
|
||||
{
|
||||
free (ft->table);
|
||||
free (ft);
|
||||
}
|
||||
|
||||
FatTable*
|
||||
fat_table_duplicate (const FatTable* ft)
|
||||
{
|
||||
FatTable* dup_ft;
|
||||
|
||||
dup_ft = fat_table_new (ft->fat_type, ft->size);
|
||||
if (!dup_ft) return NULL;
|
||||
|
||||
dup_ft->cluster_count = ft->cluster_count;
|
||||
dup_ft->free_cluster_count = ft->free_cluster_count;
|
||||
dup_ft->bad_cluster_count = ft->bad_cluster_count;
|
||||
dup_ft->last_alloc = ft->last_alloc;
|
||||
|
||||
memcpy (dup_ft->table, ft->table, ft->raw_size);
|
||||
|
||||
return dup_ft;
|
||||
}
|
||||
|
||||
void
|
||||
fat_table_clear (FatTable* ft)
|
||||
{
|
||||
memset (ft->table, 0, ft->raw_size);
|
||||
|
||||
fat_table_set (ft, 0, 0x0ffffff8);
|
||||
fat_table_set (ft, 1, 0x0fffffff);
|
||||
|
||||
ft->free_cluster_count = ft->cluster_count;
|
||||
ft->bad_cluster_count = 0;
|
||||
ft->last_alloc = 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_set_cluster_count (FatTable* ft, FatCluster new_cluster_count)
|
||||
{
|
||||
PED_ASSERT (new_cluster_count + 2 <= ft->size);
|
||||
|
||||
ft->cluster_count = new_cluster_count;
|
||||
return fat_table_count_stats (ft);
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_count_stats (FatTable* ft)
|
||||
{
|
||||
FatCluster i;
|
||||
|
||||
PED_ASSERT (ft->cluster_count + 2 <= ft->size);
|
||||
|
||||
ft->free_cluster_count = 0;
|
||||
ft->bad_cluster_count = 0;
|
||||
|
||||
for (i=2; i < ft->cluster_count + 2; i++) {
|
||||
if (fat_table_is_available (ft, i))
|
||||
ft->free_cluster_count++;
|
||||
if (fat_table_is_bad (ft, i))
|
||||
ft->bad_cluster_count++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_read (FatTable* ft, const PedFileSystem* fs, int table_num)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
|
||||
|
||||
memset (ft->table, 0, ft->raw_size);
|
||||
|
||||
if (!ped_geometry_read (fs->geom, (void *) ft->table,
|
||||
fs_info->fat_offset
|
||||
+ table_num * fs_info->fat_sectors,
|
||||
fs_info->fat_sectors))
|
||||
return 0;
|
||||
|
||||
if ( *((unsigned char*) ft->table) != fs_info->boot_sector->media) {
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("FAT %d media %x doesn't match the boot sector's "
|
||||
"media %x. You should probably run scandisk."),
|
||||
(int) table_num + 1,
|
||||
(int) *((unsigned char*) ft->table),
|
||||
(int) fs_info->boot_sector->media)
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ft->cluster_count = fs_info->cluster_count;
|
||||
|
||||
fat_table_count_stats (ft);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_write (const FatTable* ft, PedFileSystem* fs, int table_num)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
|
||||
|
||||
if (!ped_geometry_write (fs->geom, (void *) ft->table,
|
||||
fs_info->fat_offset
|
||||
+ table_num * fs_info->fat_sectors,
|
||||
fs_info->fat_sectors))
|
||||
return 0;
|
||||
if (!ped_geometry_sync (fs->geom))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_write_all (const FatTable* ft, PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fs_info->fat_table_count; i++) {
|
||||
if (!fat_table_write (ft, fs, i))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_compare (const FatTable* a, const FatTable* b)
|
||||
{
|
||||
FatCluster i;
|
||||
|
||||
if (a->cluster_count != b->cluster_count)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < a->cluster_count + 2; i++) {
|
||||
if (fat_table_get (a, i) != fat_table_get (b, i))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_test_code_available (const FatTable* ft, FatCluster code)
|
||||
{
|
||||
return code == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_test_code_bad (const FatTable* ft, FatCluster code)
|
||||
{
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
if (code == 0xff7) return 1;
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
if (code == 0xfff7) return 1;
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
if (code == 0x0ffffff7) return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_test_code_eof (const FatTable* ft, FatCluster code)
|
||||
{
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
if (code >= 0xff7) return 1;
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
if (code >= 0xfff7) return 1;
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
if (code >= 0x0ffffff7) return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_update_stats (FatTable* ft, FatCluster cluster, FatCluster value)
|
||||
{
|
||||
if (_test_code_available (ft, value)
|
||||
&& !fat_table_is_available (ft, cluster)) {
|
||||
ft->free_cluster_count++;
|
||||
if (fat_table_is_bad (ft, cluster))
|
||||
ft->bad_cluster_count--;
|
||||
}
|
||||
|
||||
if (!_test_code_available (ft, value)
|
||||
&& fat_table_is_available (ft, cluster)) {
|
||||
ft->free_cluster_count--;
|
||||
if (_test_code_bad (ft, cluster))
|
||||
ft->bad_cluster_count--;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value)
|
||||
{
|
||||
if (cluster >= ft->cluster_count + 2) {
|
||||
ped_exception_throw (PED_EXCEPTION_BUG,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("fat_table_set: cluster %ld outside "
|
||||
"file system"),
|
||||
(long) cluster);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_update_stats (ft, cluster, value);
|
||||
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
((unsigned short *) ft->table) [cluster]
|
||||
= PED_CPU_TO_LE16 (value);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
((unsigned int *) ft->table) [cluster]
|
||||
= PED_CPU_TO_LE32 (value);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
FatCluster
|
||||
fat_table_get (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
if (cluster >= ft->cluster_count + 2) {
|
||||
ped_exception_throw (PED_EXCEPTION_BUG,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("fat_table_get: cluster %ld outside "
|
||||
"file system"),
|
||||
(long) cluster);
|
||||
exit (EXIT_FAILURE); /* FIXME */
|
||||
}
|
||||
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
return PED_LE16_TO_CPU
|
||||
(((unsigned short *) ft->table) [cluster]);
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return PED_LE32_TO_CPU
|
||||
(((unsigned int *) ft->table) [cluster]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FatCluster
|
||||
fat_table_alloc_cluster (FatTable* ft)
|
||||
{
|
||||
FatCluster i;
|
||||
FatCluster cluster;
|
||||
|
||||
/* hack: assumes the first two FAT entries are marked as used (which they
|
||||
* always should be)
|
||||
*/
|
||||
for (i=1; i < ft->cluster_count + 1; i++) {
|
||||
cluster = (i + ft->last_alloc) % ft->cluster_count;
|
||||
if (fat_table_is_available (ft, cluster)) {
|
||||
ft->last_alloc = cluster;
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("fat_table_alloc_cluster: no free clusters"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FatCluster
|
||||
fat_table_alloc_check_cluster (FatTable* ft, PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster result;
|
||||
|
||||
while (1) {
|
||||
result = fat_table_alloc_cluster (ft);
|
||||
if (!result)
|
||||
return 0;
|
||||
if (fat_read_cluster (fs, fs_info->buffer, result))
|
||||
return result;
|
||||
fat_table_set_bad (ft, result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
returns true if <cluster> is marked as bad
|
||||
*/
|
||||
int
|
||||
fat_table_is_bad (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return _test_code_bad (ft, fat_table_get (ft, cluster));
|
||||
}
|
||||
|
||||
/*
|
||||
returns true if <cluster> represents an EOF marker
|
||||
*/
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_table_is_eof (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return _test_code_eof (ft, cluster);
|
||||
}
|
||||
|
||||
/*
|
||||
returns true if <cluster> is available.
|
||||
*/
|
||||
int
|
||||
fat_table_is_available (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return _test_code_available (ft, fat_table_get (ft, cluster));
|
||||
}
|
||||
|
||||
/*
|
||||
returns true if <cluster> is empty. Note that this includes bad clusters.
|
||||
*/
|
||||
int
|
||||
fat_table_is_empty (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return fat_table_is_available (ft, cluster)
|
||||
|| fat_table_is_bad (ft, cluster);
|
||||
}
|
||||
|
||||
/*
|
||||
returns true if <cluster> is being used for something constructive.
|
||||
*/
|
||||
int
|
||||
fat_table_is_active (const FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return !fat_table_is_bad (ft, cluster)
|
||||
&& !fat_table_is_available (ft, cluster);
|
||||
}
|
||||
|
||||
/*
|
||||
marks <cluster> as the last cluster in the chain
|
||||
*/
|
||||
int
|
||||
fat_table_set_eof (FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
return fat_table_set (ft, cluster, 0xfff8);
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return fat_table_set (ft, cluster, 0x0fffffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Marks a clusters as unusable, due to physical disk damage.
|
||||
*/
|
||||
int
|
||||
fat_table_set_bad (FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
if (!fat_table_is_bad (ft, cluster))
|
||||
ft->bad_cluster_count++;
|
||||
|
||||
switch (ft->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
return fat_table_set (ft, cluster, 0xff7);
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
return fat_table_set (ft, cluster, 0xfff7);
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return fat_table_set (ft, cluster, 0x0ffffff7);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
marks <cluster> as unused/free/available
|
||||
*/
|
||||
int
|
||||
fat_table_set_avail (FatTable* ft, FatCluster cluster)
|
||||
{
|
||||
return fat_table_set (ft, cluster, 0);
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
|
||||
int _GL_ATTRIBUTE_CONST
|
||||
fat_table_entry_size (FatType fat_type)
|
||||
{
|
||||
switch (fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
return 2; /* FIXME: how? */
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
return 2;
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PED_FAT_TABLE_H_INCLUDED
|
||||
#define PED_FAT_TABLE_H_INCLUDED
|
||||
|
||||
typedef struct _FatTable FatTable;
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
struct _FatTable {
|
||||
void* table;
|
||||
FatCluster size;
|
||||
int raw_size;
|
||||
|
||||
FatType fat_type;
|
||||
FatCluster cluster_count;
|
||||
FatCluster free_cluster_count;
|
||||
FatCluster bad_cluster_count;
|
||||
|
||||
FatCluster last_alloc;
|
||||
};
|
||||
|
||||
extern FatTable* fat_table_new (FatType fat_type, FatCluster size);
|
||||
extern FatTable* fat_table_duplicate (const FatTable* ft);
|
||||
extern void fat_table_destroy (FatTable* ft);
|
||||
extern void fat_table_clear (FatTable* ft);
|
||||
extern int fat_table_set_cluster_count (FatTable* ft,
|
||||
FatCluster new_cluster_count);
|
||||
|
||||
extern int fat_table_read (FatTable* ft, const PedFileSystem* fs,
|
||||
int table_num);
|
||||
extern int fat_table_write (const FatTable* ft, PedFileSystem* fs,
|
||||
int table_num);
|
||||
extern int fat_table_write_all (const FatTable* ft, PedFileSystem* fs);
|
||||
extern int fat_table_compare (const FatTable* a, const FatTable* b);
|
||||
extern int fat_table_count_stats (FatTable* ft);
|
||||
|
||||
extern FatCluster fat_table_get (const FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value);
|
||||
|
||||
extern FatCluster fat_table_alloc_cluster (FatTable* ft);
|
||||
extern FatCluster fat_table_alloc_check_cluster (FatTable* ft,
|
||||
PedFileSystem* fs);
|
||||
|
||||
extern int fat_table_is_bad (const FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_is_eof (const FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_is_empty (const FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_is_available (const FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_is_active (const FatTable* ft, FatCluster cluster);
|
||||
|
||||
extern int fat_table_set_eof (FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_set_avail (FatTable* ft, FatCluster cluster);
|
||||
extern int fat_table_set_bad (FatTable* ft, FatCluster cluster);
|
||||
|
||||
extern int fat_table_entry_size (FatType fat_type);
|
||||
|
||||
#endif /* PED_FAT_TABLE_H_INCLUDED */
|
||||
@@ -1,368 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2005, 2007-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fat.h"
|
||||
#include "traverse.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#define NO_CLUSTER -1
|
||||
|
||||
static char tmp_buffer [4096];
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info)
|
||||
{
|
||||
return trav_info->buffer_size / sizeof (FatDirEntry);
|
||||
}
|
||||
|
||||
/* returns 1 if there are no more directory entries in the directory being
|
||||
* traversed, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
is_last_buffer (FatTraverseInfo* trav_info) {
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
|
||||
|
||||
if (trav_info->is_legacy_root_dir)
|
||||
return 1;
|
||||
else
|
||||
return fat_table_is_eof (fs_info->fat, trav_info->next_buffer);
|
||||
}
|
||||
|
||||
static int
|
||||
write_root_dir (FatTraverseInfo* trav_info)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
|
||||
|
||||
if (!ped_geometry_write (trav_info->fs->geom, trav_info->dir_entries,
|
||||
fs_info->root_dir_offset,
|
||||
fs_info->root_dir_sector_count))
|
||||
return 0;
|
||||
if (!ped_geometry_sync (trav_info->fs->geom))
|
||||
return 0;
|
||||
trav_info->dirty = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
write_dir_cluster (FatTraverseInfo* trav_info)
|
||||
{
|
||||
if (!fat_write_sync_cluster (trav_info->fs,
|
||||
(void*) trav_info->dir_entries,
|
||||
trav_info->this_buffer))
|
||||
return 0;
|
||||
trav_info->dirty = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
write_dir_buffer (FatTraverseInfo* trav_info)
|
||||
{
|
||||
if (trav_info->is_legacy_root_dir)
|
||||
return write_root_dir (trav_info);
|
||||
else
|
||||
return write_dir_cluster (trav_info);
|
||||
}
|
||||
|
||||
static int
|
||||
read_next_dir_buffer (FatTraverseInfo* trav_info)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
|
||||
|
||||
PED_ASSERT (!trav_info->is_legacy_root_dir);
|
||||
|
||||
trav_info->this_buffer = trav_info->next_buffer;
|
||||
|
||||
if (trav_info->this_buffer < 2
|
||||
|| trav_info->this_buffer >= fs_info->cluster_count + 2) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
"Cluster %ld in directory %s is outside file system!",
|
||||
(long) trav_info->this_buffer,
|
||||
trav_info->dir_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trav_info->next_buffer
|
||||
= fat_table_get (fs_info->fat, trav_info->this_buffer);
|
||||
|
||||
return fat_read_cluster (trav_info->fs, (void *) trav_info->dir_entries,
|
||||
trav_info->this_buffer);
|
||||
}
|
||||
|
||||
/* FIXME: put into fat_dir_entry_* operations */
|
||||
void
|
||||
fat_traverse_mark_dirty (FatTraverseInfo* trav_info)
|
||||
{
|
||||
trav_info->dirty = 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;
|
||||
}
|
||||
|
||||
int
|
||||
fat_traverse_complete (FatTraverseInfo* trav_info)
|
||||
{
|
||||
if (trav_info->dirty) {
|
||||
if (!write_dir_buffer (trav_info))
|
||||
return 0;
|
||||
}
|
||||
free (trav_info->dir_entries);
|
||||
free (trav_info->dir_name);
|
||||
free (trav_info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FatTraverseInfo*
|
||||
fat_traverse_directory (FatTraverseInfo *trav_info, FatDirEntry* parent)
|
||||
{
|
||||
strcpy (tmp_buffer, trav_info->dir_name);
|
||||
fat_dir_entry_get_name (parent,
|
||||
tmp_buffer + strlen (trav_info->dir_name));
|
||||
strcat (tmp_buffer, "\\");
|
||||
|
||||
return fat_traverse_begin (trav_info->fs,
|
||||
fat_dir_entry_get_first_cluster (parent, trav_info->fs),
|
||||
tmp_buffer);
|
||||
}
|
||||
|
||||
FatDirEntry*
|
||||
fat_traverse_next_dir_entry (FatTraverseInfo *trav_info)
|
||||
{
|
||||
if (trav_info->eof)
|
||||
return NULL;
|
||||
|
||||
trav_info->current_entry++;
|
||||
if (trav_info->current_entry
|
||||
>= fat_traverse_entries_per_buffer (trav_info)) {
|
||||
if (trav_info->dirty) {
|
||||
if (!write_dir_buffer (trav_info))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
trav_info->current_entry = 0;
|
||||
if (is_last_buffer (trav_info)) {
|
||||
trav_info->eof = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (!read_next_dir_buffer (trav_info))
|
||||
return NULL;
|
||||
}
|
||||
return trav_info->dir_entries + trav_info->current_entry;
|
||||
}
|
||||
|
||||
FatCluster _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry, PedFileSystem *fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
switch (fs_info->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
case FAT_TYPE_FAT16:
|
||||
return PED_LE16_TO_CPU (dir_entry->first_cluster);
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
return PED_LE16_TO_CPU (dir_entry->first_cluster_high)
|
||||
* 65536L
|
||||
+ PED_LE16_TO_CPU (dir_entry->first_cluster);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs,
|
||||
FatCluster cluster)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
|
||||
switch (fs_info->fat_type) {
|
||||
case FAT_TYPE_FAT12:
|
||||
PED_ASSERT (0);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT16:
|
||||
dir_entry->first_cluster = PED_CPU_TO_LE16 (cluster);
|
||||
break;
|
||||
|
||||
case FAT_TYPE_FAT32:
|
||||
dir_entry->first_cluster
|
||||
= PED_CPU_TO_LE16 (cluster & 0xffff);
|
||||
dir_entry->first_cluster_high
|
||||
= PED_CPU_TO_LE16 (cluster / 0x10000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_get_length (FatDirEntry* dir_entry)
|
||||
{
|
||||
return PED_LE32_TO_CPU (dir_entry->length);
|
||||
}
|
||||
|
||||
int
|
||||
fat_dir_entry_is_null_term (const FatDirEntry* dir_entry)
|
||||
{
|
||||
FatDirEntry null_entry;
|
||||
|
||||
memset (&null_entry, 0, sizeof (null_entry));
|
||||
return memcmp (&null_entry, dir_entry, sizeof (null_entry)) == 0;
|
||||
}
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_is_active (FatDirEntry* dir_entry)
|
||||
{
|
||||
if ((unsigned char) dir_entry->name[0] == DELETED_FLAG) return 0;
|
||||
if ((unsigned char) dir_entry->name[0] == 0) return 0;
|
||||
if ((unsigned char) dir_entry->name[0] == 0xF6) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_is_file (FatDirEntry* dir_entry) {
|
||||
if (dir_entry->attributes == VFAT_ATTR) return 0;
|
||||
if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
|
||||
if (!fat_dir_entry_is_active (dir_entry)) return 0;
|
||||
if ((dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_is_system_file (FatDirEntry* dir_entry)
|
||||
{
|
||||
if (!fat_dir_entry_is_file (dir_entry)) return 0;
|
||||
return (dir_entry->attributes & SYSTEM_ATTR)
|
||||
|| (dir_entry->attributes & HIDDEN_ATTR);
|
||||
}
|
||||
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
fat_dir_entry_is_directory (FatDirEntry* dir_entry)
|
||||
{
|
||||
if (dir_entry->attributes == VFAT_ATTR) return 0;
|
||||
if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
|
||||
if (!fat_dir_entry_is_active (dir_entry)) return 0;
|
||||
return (dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR;
|
||||
}
|
||||
|
||||
int
|
||||
fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs)
|
||||
{
|
||||
FatSpecific* fs_info = FAT_SPECIFIC (fs);
|
||||
FatCluster first_cluster;
|
||||
|
||||
if (!fat_dir_entry_is_file (dir_entry)
|
||||
&& !fat_dir_entry_is_directory (dir_entry))
|
||||
return 0;
|
||||
|
||||
first_cluster = fat_dir_entry_get_first_cluster (dir_entry, fs);
|
||||
if (first_cluster == 0
|
||||
|| fat_table_is_eof (fs_info->fat, first_cluster))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
decrypts silly DOS names to FILENAME.EXT
|
||||
*/
|
||||
void
|
||||
fat_dir_entry_get_name (const FatDirEntry *dir_entry, char *result) {
|
||||
size_t i;
|
||||
const char *src;
|
||||
const char *ext;
|
||||
|
||||
src = dir_entry->name;
|
||||
|
||||
for (i=0; i < sizeof dir_entry->name; i++) {
|
||||
if (src[i] == ' ' || src[i] == 0) break;
|
||||
*result++ = src[i];
|
||||
}
|
||||
|
||||
ext = (const char *) dir_entry->extension;
|
||||
if (ext[0] != ' ' && ext[0] != 0) {
|
||||
*result++ = '.';
|
||||
for (i=0; i < sizeof dir_entry->extension; i++) {
|
||||
if (ext[i] == ' ' || ext[i] == 0) break;
|
||||
*result++ = ext[i];
|
||||
}
|
||||
}
|
||||
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
libparted
|
||||
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRAVERSE_H_INCLUDED
|
||||
#define TRAVERSE_H_INCLUDED
|
||||
|
||||
#include "fatio.h"
|
||||
|
||||
typedef struct _FatTraverseInfo FatTraverseInfo;
|
||||
|
||||
struct _FatTraverseInfo {
|
||||
PedFileSystem* fs;
|
||||
char* dir_name;
|
||||
|
||||
int is_legacy_root_dir;
|
||||
int dirty;
|
||||
int eof;
|
||||
|
||||
FatDirEntry* dir_entries;
|
||||
int current_entry;
|
||||
FatCluster this_buffer, next_buffer;
|
||||
int buffer_size;
|
||||
};
|
||||
|
||||
extern int fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info);
|
||||
|
||||
/* starts traversal at an arbitary cluster. if start_cluster==0, then uses
|
||||
root directory */
|
||||
extern FatTraverseInfo* fat_traverse_begin (PedFileSystem* fs,
|
||||
FatCluster start_cluster,
|
||||
const char* dir_name);
|
||||
|
||||
extern int fat_traverse_complete (FatTraverseInfo* trav_info);
|
||||
|
||||
extern FatTraverseInfo* fat_traverse_directory (FatTraverseInfo* trav_info,
|
||||
FatDirEntry* parent);
|
||||
|
||||
extern void fat_traverse_mark_dirty (FatTraverseInfo* trav_info);
|
||||
|
||||
extern FatDirEntry* fat_traverse_next_dir_entry (FatTraverseInfo* trav_info);
|
||||
|
||||
extern FatCluster fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry,
|
||||
PedFileSystem* fs);
|
||||
|
||||
extern void fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry,
|
||||
PedFileSystem* fs, FatCluster cluster);
|
||||
|
||||
extern uint32_t fat_dir_entry_get_length (FatDirEntry* dir_entry);
|
||||
|
||||
extern int fat_dir_entry_is_null_term (const FatDirEntry* dir_entry);
|
||||
extern int fat_dir_entry_is_file (FatDirEntry* dir_entry);
|
||||
extern int fat_dir_entry_is_system_file (FatDirEntry* dir_entry);
|
||||
extern int fat_dir_entry_is_directory (FatDirEntry* dir_entry);
|
||||
extern void fat_dir_entry_get_name (const FatDirEntry* dir_entry, char* result);
|
||||
extern int fat_dir_entry_is_active (FatDirEntry* dir_entry);
|
||||
extern int fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry,
|
||||
PedFileSystem* fs);
|
||||
|
||||
#endif /* TRAVERSE_H_INCLUDED */
|
||||
@@ -1,320 +0,0 @@
|
||||
/* libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 1999-2001, 2007-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file filesys.c */
|
||||
|
||||
/**
|
||||
* \addtogroup PedFileSystem
|
||||
*
|
||||
* \note File systems exist on a PedGeometry - NOT a PedPartition.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/debug.h>
|
||||
#include "pt-tools.h"
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#define STREQ(a, b) (strcmp (a, b) == 0)
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
typedef PedFileSystem * (*open_fn_t) (PedGeometry *);
|
||||
extern PedFileSystem *hfsplus_open (PedGeometry *);
|
||||
extern PedFileSystem *hfs_open (PedGeometry *);
|
||||
extern PedFileSystem *fat_open (PedGeometry *);
|
||||
|
||||
typedef int (*close_fn_t) (PedFileSystem *);
|
||||
extern int hfsplus_close (PedFileSystem *);
|
||||
extern int hfs_close (PedFileSystem *);
|
||||
extern int fat_close (PedFileSystem *);
|
||||
|
||||
typedef int (*resize_fn_t) (PedFileSystem *fs, PedGeometry *geom,
|
||||
PedTimer *timer);
|
||||
extern int hfsplus_resize (PedFileSystem *fs, PedGeometry *geom,
|
||||
PedTimer *timer);
|
||||
extern int hfs_resize (PedFileSystem *fs, PedGeometry *geom,
|
||||
PedTimer *timer);
|
||||
extern int fat_resize (PedFileSystem *fs, PedGeometry *geom,
|
||||
PedTimer *timer);
|
||||
|
||||
typedef PedConstraint * (*resize_constraint_fn_t) (PedFileSystem const *fs);
|
||||
extern PedConstraint *hfsplus_get_resize_constraint (PedFileSystem const *fs);
|
||||
extern PedConstraint *hfs_get_resize_constraint (PedFileSystem const *fs);
|
||||
extern PedConstraint *fat_get_resize_constraint (PedFileSystem const *fs);
|
||||
|
||||
static bool
|
||||
is_hfs_plus (char const *fs_type_name)
|
||||
{
|
||||
return STREQ (fs_type_name, "hfsx") || STREQ (fs_type_name, "hfs+");
|
||||
}
|
||||
|
||||
static open_fn_t
|
||||
open_fn (char const *fs_type_name)
|
||||
{
|
||||
if (is_hfs_plus (fs_type_name))
|
||||
return hfsplus_open;
|
||||
if (STREQ (fs_type_name, "hfs"))
|
||||
return hfs_open;
|
||||
if (strncmp (fs_type_name, "fat", 3) == 0)
|
||||
return fat_open;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static close_fn_t
|
||||
close_fn (char const *fs_type_name)
|
||||
{
|
||||
if (is_hfs_plus (fs_type_name))
|
||||
return hfsplus_close;
|
||||
if (STREQ (fs_type_name, "hfs"))
|
||||
return hfs_close;
|
||||
if (strncmp (fs_type_name, "fat", 3) == 0)
|
||||
return fat_close;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static resize_fn_t
|
||||
resize_fn (char const *fs_type_name)
|
||||
{
|
||||
if (is_hfs_plus (fs_type_name))
|
||||
return hfsplus_resize;
|
||||
if (STREQ (fs_type_name, "hfs"))
|
||||
return hfs_resize;
|
||||
if (strncmp (fs_type_name, "fat", 3) == 0)
|
||||
return fat_resize;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static resize_constraint_fn_t
|
||||
resize_constraint_fn (char const *fs_type_name)
|
||||
{
|
||||
if (is_hfs_plus (fs_type_name))
|
||||
return hfsplus_get_resize_constraint;
|
||||
if (STREQ (fs_type_name, "hfs"))
|
||||
return hfs_get_resize_constraint;
|
||||
if (strncmp (fs_type_name, "fat", 3) == 0)
|
||||
return fat_get_resize_constraint;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function opens the file system stored on \p geom, if it
|
||||
* can find one.
|
||||
* It is often called in the following manner:
|
||||
* \code
|
||||
* fs = ped_file_system_open (&part.geom)
|
||||
* \endcode
|
||||
*
|
||||
* \throws PED_EXCEPTION_ERROR if file system could not be detected
|
||||
* \throws PED_EXCEPTION_ERROR if the file system is bigger than its volume
|
||||
* \throws PED_EXCEPTION_NO_FEATURE if opening of a file system stored on
|
||||
* \p geom is not implemented
|
||||
*
|
||||
* \return a PedFileSystem on success, \c NULL on failure.
|
||||
*/
|
||||
PedFileSystem *
|
||||
ped_file_system_open (PedGeometry* geom)
|
||||
{
|
||||
PED_ASSERT (geom != NULL);
|
||||
|
||||
if (!ped_device_open (geom->dev))
|
||||
goto error;
|
||||
|
||||
PedFileSystemType *type = ped_file_system_probe (geom);
|
||||
if (!type) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("Could not detect file system."));
|
||||
goto error_close_dev;
|
||||
}
|
||||
|
||||
open_fn_t open_f = open_fn (type->name);
|
||||
if (open_f == NULL) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("resizing %s file systems is not supported"),
|
||||
type->name);
|
||||
goto error_close_dev;
|
||||
}
|
||||
|
||||
PedGeometry *probed_geom = ped_file_system_probe_specific (type, geom);
|
||||
if (!probed_geom)
|
||||
goto error_close_dev;
|
||||
if (!ped_geometry_test_inside (geom, probed_geom)) {
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("The file system is bigger than its volume!"))
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
goto error_destroy_probed_geom;
|
||||
}
|
||||
|
||||
PedFileSystem *fs = (*open_f) (probed_geom);
|
||||
if (!fs)
|
||||
goto error_destroy_probed_geom;
|
||||
ped_geometry_destroy (probed_geom);
|
||||
fs->type = type;
|
||||
return fs;
|
||||
|
||||
error_destroy_probed_geom:
|
||||
ped_geometry_destroy (probed_geom);
|
||||
error_close_dev:
|
||||
ped_device_close (geom->dev);
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close file system \p fs.
|
||||
*
|
||||
* \return \c 1 on success, \c 0 on failure
|
||||
*/
|
||||
int
|
||||
ped_file_system_close (PedFileSystem* fs)
|
||||
{
|
||||
PED_ASSERT (fs != NULL);
|
||||
PedDevice *dev = fs->geom->dev;
|
||||
close_fn_t fn = close_fn (fs->type->name);
|
||||
|
||||
if (!fn || !(fn (fs)))
|
||||
goto error_close_dev;
|
||||
ped_device_close (dev);
|
||||
return 1;
|
||||
|
||||
error_close_dev:
|
||||
ped_device_close (dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function erases all file system signatures that indicate that a
|
||||
* file system occupies a given region described by \p geom.
|
||||
* After this operation ped_file_system_probe() won't detect any file system.
|
||||
*
|
||||
* \return \c 1 on success, \c 0 on failure
|
||||
*/
|
||||
static int
|
||||
ped_file_system_clobber (PedGeometry* geom)
|
||||
{
|
||||
PED_ASSERT (geom != NULL);
|
||||
|
||||
if (!ped_device_open (geom->dev))
|
||||
return 0;
|
||||
|
||||
/* Clear the first three and the last two sectors, albeit fewer
|
||||
when GEOM is too small. */
|
||||
PedSector len = MIN (geom->length, geom->dev->length);
|
||||
|
||||
int ok = (len <= 5
|
||||
? ptt_geom_clear_sectors (geom, 0, len)
|
||||
: (ptt_geom_clear_sectors (geom, 0, 3)
|
||||
&& ptt_geom_clear_sectors (geom, geom->dev->length - 2, 2)));
|
||||
|
||||
ped_device_close (geom->dev);
|
||||
return !!ok;
|
||||
}
|
||||
|
||||
/* This function erases all signatures that indicate the presence of
|
||||
* a file system in a particular region, without erasing any data
|
||||
* contained inside the "exclude" region.
|
||||
*/
|
||||
static int
|
||||
ped_file_system_clobber_exclude (PedGeometry* geom,
|
||||
const PedGeometry* exclude)
|
||||
{
|
||||
PedGeometry* clobber_geom;
|
||||
int status;
|
||||
|
||||
if (ped_geometry_test_sector_inside (exclude, geom->start))
|
||||
return 1;
|
||||
|
||||
clobber_geom = ped_geometry_duplicate (geom);
|
||||
if (ped_geometry_test_overlap (clobber_geom, exclude))
|
||||
ped_geometry_set_end (clobber_geom, exclude->start - 1);
|
||||
|
||||
status = ped_file_system_clobber (clobber_geom);
|
||||
ped_geometry_destroy (clobber_geom);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize \p fs to new geometry \p geom.
|
||||
*
|
||||
* \p geom should satisfy the ped_file_system_get_resize_constraint().
|
||||
* (This isn't asserted, so it's not a bug not to... just it's likely
|
||||
* to fail ;) If \p timer is non-NULL, it is used as the progress meter.
|
||||
*
|
||||
* \throws PED_EXCEPTION_NO_FEATURE if resizing of file system \p fs
|
||||
* is not implemented yet
|
||||
*
|
||||
* \return \c 0 on failure
|
||||
*/
|
||||
int
|
||||
ped_file_system_resize (PedFileSystem *fs, PedGeometry *geom, PedTimer *timer)
|
||||
{
|
||||
PED_ASSERT (fs != NULL);
|
||||
PED_ASSERT (geom != NULL);
|
||||
|
||||
resize_fn_t resize_f = resize_fn (fs->type->name);
|
||||
if (resize_f == NULL) {
|
||||
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
|
||||
_("resizing %s file systems is not supported"),
|
||||
fs->type->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ped_file_system_clobber_exclude (geom, fs->geom))
|
||||
return 0;
|
||||
|
||||
return resize_f (fs, geom, timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a constraint that represents all of the possible ways the
|
||||
* file system \p fs can be resized with ped_file_system_resize().
|
||||
* This takes into account the amount of used space on
|
||||
* the filesystem \p fs and the capabilities of the resize algorithm.
|
||||
* Hints:
|
||||
* -# if constraint->start_align->grain_size == 0, or
|
||||
* constraint->start_geom->length == 1, then the start cannot be moved
|
||||
* -# constraint->min_size is the minimum size you can resize the partition
|
||||
* to. You might want to tell the user this ;-).
|
||||
*
|
||||
* \return a PedConstraint on success, \c NULL on failure
|
||||
*/
|
||||
PedConstraint *
|
||||
ped_file_system_get_resize_constraint (const PedFileSystem *fs)
|
||||
{
|
||||
PED_ASSERT (fs != NULL);
|
||||
|
||||
resize_constraint_fn_t resize_constraint_f =
|
||||
resize_constraint_fn (fs->type->name);
|
||||
if (resize_constraint_f == NULL)
|
||||
return NULL;
|
||||
|
||||
return resize_constraint_f (fs);
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "file.h"
|
||||
|
||||
#include "advfs.h"
|
||||
|
||||
/* - if a < b, 0 if a == b, + if a > b */
|
||||
/* Comparaison is done in the following order : */
|
||||
/* CNID, then fork type, then start block */
|
||||
/* Note that HFS implementation in linux has a bug */
|
||||
/* 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) );
|
||||
}
|
||||
|
||||
/* do a B-Tree lookup */
|
||||
/* read the first record immediatly inferior or egal to the given key */
|
||||
/* return 0 on error */
|
||||
/* record_out _must_ be large enough to receive record_size bytes */
|
||||
/* WARNING : the compare function called only handle Extents BTree */
|
||||
/* so modify this function if you want to do lookup in */
|
||||
/* 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;
|
||||
uint16_t record_pos;
|
||||
|
||||
/* Read the header node */
|
||||
if (!hfs_file_read_sector(b_tree_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
/* 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--) {
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
record_pos = PED_BE16_TO_CPU(value);
|
||||
record_key = (HfsPrivateGenericKey*) (node + record_pos);
|
||||
/* check for obvious error in FS */
|
||||
if ((record_pos< HFS_FIRST_REC)
|
||||
|| (record_pos>= 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;
|
||||
uint32_t value;
|
||||
memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
|
||||
node_number = PED_BE32_TO_CPU(value);
|
||||
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 = record_pos;
|
||||
record_ref->record_number = i;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* free the bad blocks linked list */
|
||||
void
|
||||
hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first)
|
||||
{
|
||||
HfsPrivateLinkExtent* next;
|
||||
|
||||
while (first) {
|
||||
next = first->next;
|
||||
free (first);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* This function check if fblock is a bad block */
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
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;
|
||||
}
|
||||
|
||||
/* This function returns the first sector of the last free block of an
|
||||
HFS volume we can get after a hfs_pack_free_space_from_block call */
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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 _GL_ATTRIBUTE_PURE
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ADVFS_H
|
||||
#define _ADVFS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref);
|
||||
|
||||
void
|
||||
hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first);
|
||||
|
||||
int
|
||||
hfs_read_bad_blocks (const PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
PedSector
|
||||
hfs_get_empty_end (const PedFileSystem *fs);
|
||||
|
||||
unsigned int
|
||||
hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
#endif /* _ADVFS_H */
|
||||
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs.h"
|
||||
#include "file_plus.h"
|
||||
|
||||
#include "advfs_plus.h"
|
||||
|
||||
/* - if a < b, 0 if a == b, + if a > b */
|
||||
/* Comparaison is done in the following order : */
|
||||
/* CNID, then fork type, then start block */
|
||||
static int
|
||||
hfsplus_extent_key_cmp(HfsPPrivateGenericKey* a, HfsPPrivateGenericKey* b)
|
||||
{
|
||||
HfsPExtentKey* key1 = (HfsPExtentKey*) a;
|
||||
HfsPExtentKey* key2 = (HfsPExtentKey*) b;
|
||||
|
||||
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;
|
||||
return PED_BE32_TO_CPU(key1->start) <
|
||||
PED_BE32_TO_CPU(key2->start) ?
|
||||
-1 : +1;
|
||||
}
|
||||
|
||||
/* do a B-Tree lookup */
|
||||
/* read the first record immediatly inferior or egal to the given key */
|
||||
/* return 0 on error */
|
||||
/* record_out _must_ be large enough to receive the whole record (key + data) */
|
||||
/* WARNING : the search function called only handle Extents BTree */
|
||||
/* so modify this function if you want to do lookup in */
|
||||
/* other BTrees has well */
|
||||
int
|
||||
hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref)
|
||||
{
|
||||
uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
|
||||
uint8_t* node;
|
||||
HfsPHeaderRecord* header;
|
||||
HfsPPrivateGenericKey* record_key = NULL;
|
||||
unsigned int node_number, record_number, size, bsize;
|
||||
int i;
|
||||
uint16_t record_pos;
|
||||
|
||||
/* Read the header node */
|
||||
if (!hfsplus_file_read_sector(b_tree_file, node_1, 0))
|
||||
return 0;
|
||||
header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC);
|
||||
|
||||
/* Get the node number of the root */
|
||||
node_number = PED_BE32_TO_CPU (header->root_node);
|
||||
if (!node_number)
|
||||
return 0;
|
||||
|
||||
/* Get the size of a node in sectors and allocate buffer */
|
||||
size = (bsize = PED_BE16_TO_CPU (header->node_size)) / PED_SECTOR_SIZE_DEFAULT;
|
||||
node = ped_malloc (bsize);
|
||||
if (!node)
|
||||
return 0;
|
||||
HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
|
||||
|
||||
/* Read the root node */
|
||||
if (!hfsplus_file_read (b_tree_file, node,
|
||||
(PedSector) node_number * size, size))
|
||||
return 0;
|
||||
|
||||
/* Follow the white rabbit */
|
||||
while (1) {
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = record_number; i; i--) {
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
record_pos = PED_BE16_TO_CPU(value);
|
||||
record_key = (HfsPPrivateGenericKey*) (node + record_pos);
|
||||
/* check for obvious error in FS */
|
||||
if ((record_pos < HFS_FIRST_REC)
|
||||
|| (record_pos >= (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 (hfsplus_extent_key_cmp(record_key, key) <= 0)
|
||||
break;
|
||||
}
|
||||
if (!i) { free (node); return 0; }
|
||||
if (desc->type == HFS_IDX_NODE) {
|
||||
unsigned int skip;
|
||||
|
||||
skip = ( 2 + PED_BE16_TO_CPU (record_key->key_length)
|
||||
+ 1 ) & ~1;
|
||||
uint32_t value;
|
||||
memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
|
||||
node_number = PED_BE32_TO_CPU(value);
|
||||
if (!hfsplus_file_read(b_tree_file, node,
|
||||
(PedSector) node_number * size,
|
||||
size)) {
|
||||
free (node);
|
||||
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 = size; /* in sectors */
|
||||
record_ref->node_number = node_number;
|
||||
record_ref->record_pos = record_pos;
|
||||
record_ref->record_number = i;
|
||||
}
|
||||
|
||||
/* success */
|
||||
free (node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* free the bad blocks linked list */
|
||||
void
|
||||
hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first)
|
||||
{
|
||||
HfsPPrivateLinkExtent* next;
|
||||
|
||||
while (first) {
|
||||
next = first->next;
|
||||
free (first);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function reads bad blocks extents in the extents file
|
||||
and store it in f.s. specific data of fs */
|
||||
int
|
||||
hfsplus_read_bad_blocks (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
|
||||
if (priv_data->bad_blocks_loaded)
|
||||
return 1;
|
||||
|
||||
{
|
||||
uint8_t record[sizeof (HfsPExtentKey)
|
||||
+ sizeof (HfsPExtDataRec)];
|
||||
HfsPExtentKey search;
|
||||
HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
|
||||
HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
|
||||
(record + sizeof (HfsPExtentKey));
|
||||
int block, first_pass = 1;
|
||||
unsigned int last_start;
|
||||
|
||||
search.key_length = sizeof (HfsExtentKey) - 2;
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.pad = 0;
|
||||
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_BE32 (block);
|
||||
if (!hfsplus_btree_search (priv_data->extents_file,
|
||||
(HfsPPrivateGenericKey*) &search,
|
||||
record, sizeof (record), NULL)
|
||||
|| ret_key->file_ID != search.file_ID
|
||||
|| ret_key->type != search.type) {
|
||||
if (first_pass)
|
||||
break;
|
||||
else
|
||||
goto errbbp;
|
||||
}
|
||||
if (PED_BE32_TO_CPU (ret_key->start) == last_start)
|
||||
break;
|
||||
|
||||
last_start = PED_BE32_TO_CPU (ret_key->start);
|
||||
for (i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if (ret_cache[i].block_count) {
|
||||
HfsPPrivateLinkExtent* new_xt =
|
||||
(HfsPPrivateLinkExtent*) ped_malloc (
|
||||
sizeof (HfsPPrivateLinkExtent));
|
||||
if (!new_xt)
|
||||
goto errbbp;
|
||||
new_xt->next = priv_data->bad_blocks_xtent_list;
|
||||
memcpy (&(new_xt->extent), ret_cache+i,
|
||||
sizeof (HfsPExtDescriptor));
|
||||
priv_data->bad_blocks_xtent_list = new_xt;
|
||||
priv_data->bad_blocks_xtent_nb++;
|
||||
block += PED_BE32_TO_CPU (
|
||||
ret_cache[i].block_count);
|
||||
}
|
||||
}
|
||||
first_pass = 0;
|
||||
}
|
||||
|
||||
priv_data->bad_blocks_loaded = 1;
|
||||
return 1;}
|
||||
|
||||
errbbp: hfsplus_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;
|
||||
}
|
||||
|
||||
/* This function check if fblock is a bad block */
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPPrivateLinkExtent* 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_BE32_TO_CPU (walk->extent.start_block)) &&
|
||||
(fblock < (unsigned int)(PED_BE32_TO_CPU (
|
||||
walk->extent.start_block)
|
||||
+ PED_BE32_TO_CPU (walk->extent.block_count))))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns the first sector of the last free block of
|
||||
an HFS+ volume we can get after a hfsplus_pack_free_space_from_block call */
|
||||
PedSector
|
||||
hfsplus_get_empty_end (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPVolumeHeader* vh = priv_data->vh;
|
||||
unsigned int block, last_bad, end_free_blocks;
|
||||
|
||||
/* find the next block to the last bad block of the volume */
|
||||
if (!hfsplus_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks could not be read."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
HfsPPrivateLinkExtent* l;
|
||||
last_bad = 0;
|
||||
for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
|
||||
if ((unsigned int) PED_BE32_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE32_TO_CPU (l->extent.block_count) > last_bad)
|
||||
last_bad = PED_BE32_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE32_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_BE32_TO_CPU (vh->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_BE32_TO_CPU (vh->total_blocks) - end_free_blocks;
|
||||
|
||||
return (PedSector) block * ( PED_BE32_TO_CPU (vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT );
|
||||
}
|
||||
|
||||
/* On error, returns 0 */
|
||||
PedSector
|
||||
hfsplus_get_min_size (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
PedSector min_size;
|
||||
|
||||
/* don't need to add anything because every sector
|
||||
can be part of allocation blocks in HFS+, and
|
||||
the last block _must_ be reserved */
|
||||
min_size = hfsplus_get_empty_end(fs);
|
||||
if (!min_size) return 0;
|
||||
|
||||
if (priv_data->wrapper) {
|
||||
HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
|
||||
priv_data->wrapper->type_specific;
|
||||
unsigned int hfs_sect_block;
|
||||
PedSector hgee;
|
||||
hfs_sect_block =
|
||||
PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT;
|
||||
/*
|
||||
* if hfs+ is embedded in an hfs wrapper then the new size is :
|
||||
* the new size of the hfs+ volume rounded up to the size
|
||||
* of hfs blocks
|
||||
* + the minimum size of the hfs wrapper without any hfs+
|
||||
* modification
|
||||
* - the current size of the hfs+ volume in the hfs wrapper
|
||||
*/
|
||||
hgee = hfs_get_empty_end(priv_data->wrapper);
|
||||
if (!hgee) return 0;
|
||||
min_size = ((min_size + hfs_sect_block - 1) / hfs_sect_block)
|
||||
* hfs_sect_block
|
||||
+ hgee + 2
|
||||
- (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb
|
||||
->old_new.embedded
|
||||
.location.block_count )
|
||||
* hfs_sect_block;
|
||||
}
|
||||
|
||||
return min_size;
|
||||
}
|
||||
|
||||
/* 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 _GL_ATTRIBUTE_PURE
|
||||
hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int block;
|
||||
|
||||
for (block = PED_BE32_TO_CPU (priv_data->vh->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;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ADVFS_PLUS_H
|
||||
#define _ADVFS_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref);
|
||||
|
||||
void
|
||||
hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first);
|
||||
|
||||
int
|
||||
hfsplus_read_bad_blocks (const PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
PedSector
|
||||
hfsplus_get_empty_end (const PedFileSystem *fs);
|
||||
|
||||
PedSector
|
||||
hfsplus_get_min_size (const PedFileSystem *fs);
|
||||
|
||||
unsigned int
|
||||
hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
#endif /* _ADVFS_PLUS_H */
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
static HfsCPrivateCacheTable*
|
||||
hfsc_new_cachetable(unsigned int size)
|
||||
{
|
||||
HfsCPrivateCacheTable* ret;
|
||||
|
||||
ret = (HfsCPrivateCacheTable*) ped_malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
|
||||
ret->next_cache = NULL;
|
||||
ret->table_size = size;
|
||||
ret->table_first_free = 0;
|
||||
|
||||
ret->table = ped_malloc(sizeof(*ret->table)*size);
|
||||
if (!ret->table) { free(ret); return NULL; }
|
||||
memset(ret->table, 0, sizeof(*ret->table)*size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HfsCPrivateCache*
|
||||
hfsc_new_cache(unsigned int block_number, unsigned int file_number)
|
||||
{
|
||||
unsigned int cachetable_size, i;
|
||||
HfsCPrivateCache* ret;
|
||||
|
||||
ret = (HfsCPrivateCache*) ped_malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
ret->block_number = block_number;
|
||||
/* following code avoid integer overflow */
|
||||
ret->linked_ref_size = block_number > block_number + ((1<<CR_SHIFT)-1) ?
|
||||
( block_number >> CR_SHIFT ) + 1 :
|
||||
( block_number + ((1<<CR_SHIFT)-1) ) >> CR_SHIFT
|
||||
;
|
||||
|
||||
ret->linked_ref = (HfsCPrivateExtent**)
|
||||
ped_malloc( sizeof(*ret->linked_ref)
|
||||
* ret->linked_ref_size );
|
||||
if (!ret->linked_ref) { free(ret); return NULL; }
|
||||
|
||||
cachetable_size = file_number + file_number / CR_OVER_DIV + CR_ADD_CST;
|
||||
if (cachetable_size < file_number) cachetable_size = (unsigned) -1;
|
||||
ret->first_cachetable_size = cachetable_size;
|
||||
ret->table_list = hfsc_new_cachetable(cachetable_size);
|
||||
if (!ret->table_list) {
|
||||
free(ret->linked_ref);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->last_table = ret->table_list;
|
||||
|
||||
for (i = 0; i < ret->linked_ref_size; ++i)
|
||||
ret->linked_ref[i] = NULL;
|
||||
|
||||
ret->needed_alloc_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
hfsc_delete_cachetable(HfsCPrivateCacheTable* list)
|
||||
{
|
||||
HfsCPrivateCacheTable* next;
|
||||
|
||||
while (list) {
|
||||
free (list->table);
|
||||
next = list->next_cache;
|
||||
free (list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hfsc_delete_cache(HfsCPrivateCache* cache)
|
||||
{
|
||||
hfsc_delete_cachetable(cache->table_list);
|
||||
free(cache->linked_ref);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
|
||||
uint32_t block, uint16_t offset, uint8_t sbb,
|
||||
uint8_t where, uint8_t ref_index)
|
||||
{
|
||||
HfsCPrivateExtent* ext;
|
||||
unsigned int idx = start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx < cache->linked_ref_size);
|
||||
|
||||
for (ext = cache->linked_ref[idx];
|
||||
ext && start != ext->ext_start;
|
||||
ext = ext->next);
|
||||
|
||||
if (ext) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to register an extent starting at block "
|
||||
"0x%X, but another one already exists at this "
|
||||
"position. You should check the file system!"),
|
||||
start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( cache->last_table->table_first_free
|
||||
== cache->last_table->table_size ) {
|
||||
cache->last_table->next_cache =
|
||||
hfsc_new_cachetable( ( cache->first_cachetable_size
|
||||
/ CR_NEW_ALLOC_DIV )
|
||||
+ CR_ADD_CST );
|
||||
if (!cache->last_table->next_cache)
|
||||
return NULL;
|
||||
cache->last_table = cache->last_table->next_cache;
|
||||
}
|
||||
|
||||
ext = cache->last_table->table+(cache->last_table->table_first_free++);
|
||||
|
||||
ext->ext_start = start;
|
||||
ext->ext_length = length;
|
||||
ext->ref_block = block;
|
||||
ext->ref_offset = offset;
|
||||
ext->sect_by_block = sbb;
|
||||
ext->where = where;
|
||||
ext->ref_index = ref_index;
|
||||
|
||||
ext->next = cache->linked_ref[idx];
|
||||
cache->linked_ref[idx] = ext;
|
||||
|
||||
cache->needed_alloc_size = cache->needed_alloc_size >
|
||||
(unsigned) PED_SECTOR_SIZE_DEFAULT * sbb ?
|
||||
cache->needed_alloc_size :
|
||||
(unsigned) PED_SECTOR_SIZE_DEFAULT * sbb;
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
HfsCPrivateExtent* _GL_ATTRIBUTE_PURE
|
||||
hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start)
|
||||
{
|
||||
HfsCPrivateExtent* ret;
|
||||
unsigned int idx = start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx < cache->linked_ref_size);
|
||||
|
||||
for (ret = cache->linked_ref[idx];
|
||||
ret && start != ret->ext_start;
|
||||
ret = ret->next);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Can't fail if extent begining at old_start exists */
|
||||
/* Returns 0 if no such extent, or on error */
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
|
||||
uint32_t new_start)
|
||||
{
|
||||
HfsCPrivateExtent** ppext;
|
||||
HfsCPrivateExtent* pext;
|
||||
|
||||
unsigned int idx1 = old_start >> CR_SHIFT;
|
||||
unsigned int idx2 = new_start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx1 < cache->linked_ref_size);
|
||||
PED_ASSERT(idx2 < cache->linked_ref_size);
|
||||
|
||||
for (pext = cache->linked_ref[idx2];
|
||||
pext && new_start != pext->ext_start;
|
||||
pext = pext->next);
|
||||
|
||||
if (pext) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_BUG,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to move an extent from block 0x%X to block "
|
||||
"0x%X, but another one already exists at this "
|
||||
"position. This should not happen!"),
|
||||
old_start, new_start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ppext = &(cache->linked_ref[idx1]);
|
||||
(*ppext) && old_start != (*ppext)->ext_start;
|
||||
ppext = &((*ppext)->next));
|
||||
|
||||
if (!(*ppext)) return NULL;
|
||||
|
||||
/* removing the extent from the cache */
|
||||
pext = *ppext;
|
||||
(*ppext) = pext->next;
|
||||
|
||||
/* change ext_start and insert the extent again */
|
||||
pext->ext_start = new_start;
|
||||
pext->next = cache->linked_ref[idx2];
|
||||
cache->linked_ref[idx2] = pext;
|
||||
|
||||
return pext;
|
||||
}
|
||||
|
||||
#endif /* DISCOVER_ONLY */
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CACHE_H
|
||||
#define _CACHE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
/* CR => CACHE REF */
|
||||
#define CR_NULL 0 /* reserved */
|
||||
#define CR_PRIM_CAT 1
|
||||
#define CR_PRIM_EXT 2
|
||||
#define CR_PRIM_ATTR 3
|
||||
#define CR_PRIM_ALLOC 4
|
||||
#define CR_PRIM_START 5
|
||||
#define CR_BTREE_CAT 6
|
||||
#define CR_BTREE_ATTR 7
|
||||
#define CR_BTREE_EXT_0 8
|
||||
#define CR_BTREE_EXT_CAT 9
|
||||
#define CR_BTREE_EXT_EXT 10 /* should not happen ! */
|
||||
#define CR_BTREE_EXT_ATTR 11
|
||||
#define CR_BTREE_EXT_ALLOC 12
|
||||
#define CR_BTREE_EXT_START 13 /* unneeded in current code */
|
||||
#define CR_BTREE_CAT_JIB 14 /* journal info block */
|
||||
#define CR_BTREE_CAT_JL 15 /* journal */
|
||||
/* 16 -> 31 || high order bit */ /* reserved */
|
||||
|
||||
/* tuning */
|
||||
#define CR_SHIFT 8 /* number of bits to shift start_block by */
|
||||
/* to get the index of the linked list */
|
||||
#define CR_OVER_DIV 16 /* alloc a table for (1+1/CR_OVER_DIV) *
|
||||
file_number + CR_ADD_CST */
|
||||
#define CR_ADD_CST 16
|
||||
#define CR_NEW_ALLOC_DIV 4 /* divide the size of the first alloc table
|
||||
by this value to allocate next tables */
|
||||
|
||||
/* See DOC for an explaination of this structure */
|
||||
/* Access read only from outside cache.c */
|
||||
struct _HfsCPrivateExtent {
|
||||
struct _HfsCPrivateExtent* next;
|
||||
uint32_t ext_start;
|
||||
uint32_t ext_length;
|
||||
uint32_t ref_block;
|
||||
uint16_t ref_offset;
|
||||
uint8_t sect_by_block;
|
||||
unsigned where : 5;
|
||||
unsigned ref_index : 3; /* 0 -> 7 */
|
||||
};
|
||||
typedef struct _HfsCPrivateExtent HfsCPrivateExtent;
|
||||
|
||||
/* Internaly used by cache.c for custom memory managment only */
|
||||
struct _HfsCPrivateCacheTable {
|
||||
struct _HfsCPrivateCacheTable* next_cache;
|
||||
HfsCPrivateExtent* table;
|
||||
unsigned int table_size;
|
||||
unsigned int table_first_free;
|
||||
/* first_elemt ? */
|
||||
};
|
||||
typedef struct _HfsCPrivateCacheTable HfsCPrivateCacheTable;
|
||||
|
||||
/* Internaly used by cache.c for custom memory managment
|
||||
and cache handling only */
|
||||
struct _HfsCPrivateCache {
|
||||
HfsCPrivateCacheTable* table_list;
|
||||
HfsCPrivateCacheTable* last_table;
|
||||
HfsCPrivateExtent** linked_ref;
|
||||
unsigned int linked_ref_size;
|
||||
unsigned int block_number;
|
||||
unsigned int first_cachetable_size;
|
||||
unsigned int needed_alloc_size;
|
||||
};
|
||||
typedef struct _HfsCPrivateCache HfsCPrivateCache;
|
||||
|
||||
HfsCPrivateCache*
|
||||
hfsc_new_cache(unsigned int block_number, unsigned int file_number);
|
||||
|
||||
void
|
||||
hfsc_delete_cache(HfsCPrivateCache* cache);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
|
||||
uint32_t block, uint16_t offset, uint8_t sbb,
|
||||
uint8_t where, uint8_t index);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
|
||||
uint32_t new_start);
|
||||
|
||||
static __inline__ unsigned int
|
||||
hfsc_cache_needed_buffer(HfsCPrivateCache* cache)
|
||||
{
|
||||
return cache->needed_alloc_size;
|
||||
}
|
||||
|
||||
#endif /* _CACHE_H */
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
/* Open the data fork of a file with its first three extents and its CNID */
|
||||
HfsPrivateFile*
|
||||
hfs_file_open (PedFileSystem *fs, uint32_t CNID,
|
||||
HfsExtDataRec ext_desc, PedSector sect_nb)
|
||||
{
|
||||
HfsPrivateFile* file;
|
||||
|
||||
file = (HfsPrivateFile*) ped_malloc (sizeof (HfsPrivateFile));
|
||||
if (!file) return NULL;
|
||||
|
||||
file->fs = fs;
|
||||
file->sect_nb = sect_nb;
|
||||
file->CNID = CNID;
|
||||
memcpy(file->first, ext_desc, sizeof (HfsExtDataRec));
|
||||
file->start_cache = 0;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Close an HFS file */
|
||||
void
|
||||
hfs_file_close (HfsPrivateFile* file)
|
||||
{
|
||||
free (file);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* find and return the nth sector of a file */
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Read the nth sector of a file */
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Write the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
int
|
||||
hfs_file_write_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 write 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_write (file->fs->geom, buf, abs_sector, 1);
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_H
|
||||
#define _FILE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
HfsPrivateFile*
|
||||
hfs_file_open (PedFileSystem *fs, uint32_t CNID,
|
||||
HfsExtDataRec ext_desc, PedSector sect_nb);
|
||||
|
||||
void
|
||||
hfs_file_close (HfsPrivateFile* file);
|
||||
|
||||
int
|
||||
hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector);
|
||||
|
||||
int
|
||||
hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector);
|
||||
|
||||
#endif /* _FILE_H */
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs_plus.h"
|
||||
|
||||
#include "file_plus.h"
|
||||
|
||||
/* Open the data fork of a file with its first eight extents and its CNID */
|
||||
/* CNID and ext_desc must be in disc order, sect_nb in CPU order */
|
||||
/* return null on failure */
|
||||
HfsPPrivateFile*
|
||||
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
|
||||
HfsPExtDataRec ext_desc, PedSector sect_nb)
|
||||
{
|
||||
HfsPPrivateFile* file;
|
||||
|
||||
file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
|
||||
if (!file) return NULL;
|
||||
|
||||
file->fs = fs;
|
||||
file->sect_nb = sect_nb;
|
||||
file->CNID = CNID;
|
||||
memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
|
||||
file->start_cache = 0;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Close an HFS+ file */
|
||||
void
|
||||
hfsplus_file_close (HfsPPrivateFile* file)
|
||||
{
|
||||
free (file);
|
||||
}
|
||||
|
||||
/* warning : only works on data forks */
|
||||
static int
|
||||
hfsplus_get_extent_containing (HfsPPrivateFile* file, unsigned int block,
|
||||
HfsPExtDataRec cache, uint32_t* ptr_start_cache)
|
||||
{
|
||||
uint8_t record[sizeof (HfsPExtentKey)
|
||||
+ sizeof (HfsPExtDataRec)];
|
||||
HfsPExtentKey search;
|
||||
HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
|
||||
HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
|
||||
(record + sizeof (HfsPExtentKey));
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
|
||||
search.key_length = PED_CPU_TO_BE16 (sizeof (HfsPExtentKey) - 2);
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.pad = 0;
|
||||
search.file_ID = file->CNID;
|
||||
search.start = PED_CPU_TO_BE32 (block);
|
||||
|
||||
if (!hfsplus_btree_search (priv_data->extents_file,
|
||||
(HfsPPrivateGenericKey*) &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(HfsPExtDataRec));
|
||||
*ptr_start_cache = PED_BE32_TO_CPU (ret_key->start);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find a sub extent contained in the desired area */
|
||||
/* and with the same starting point */
|
||||
/* return 0 in sector_count on error, or the physical area */
|
||||
/* on the volume corresponding to the logical area in the file */
|
||||
static HfsPPrivateExtent
|
||||
hfsplus_file_find_extent (HfsPPrivateFile* file, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent ret = {0,0};
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
unsigned int sect_by_block = PED_BE32_TO_CPU (
|
||||
priv_data->vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT;
|
||||
unsigned int i, s, vol_block, size;
|
||||
PedSector sect_size;
|
||||
unsigned int block = sector / sect_by_block;
|
||||
unsigned int offset = sector % sect_by_block;
|
||||
|
||||
/* in the 8 first extent */
|
||||
for (s = 0, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->first[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->first[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->first[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->first[i].block_count);
|
||||
}
|
||||
|
||||
/* in the 8 cached extent */
|
||||
if (file->start_cache && block >= file->start_cache)
|
||||
for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->cache[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->cache[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
/* update cache */
|
||||
if (!hfsplus_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 ret; /* ret == {0,0} */
|
||||
}
|
||||
|
||||
/* ret == {0,0} */
|
||||
PED_ASSERT(file->start_cache && block >= file->start_cache);
|
||||
|
||||
for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->cache[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->cache[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
plus_sector_found:
|
||||
sect_size = (PedSector) size * sect_by_block - offset;
|
||||
ret.start_sector = vol_block * sect_by_block + offset;
|
||||
ret.sector_count = (sect_size < nb) ? sect_size : nb;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent phy_area;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
char *b = buf;
|
||||
|
||||
if (sector+nb < sector /* detect overflow */
|
||||
|| sector+nb > file->sect_nb) /* out of file */ {
|
||||
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;
|
||||
}
|
||||
|
||||
while (nb) {
|
||||
phy_area = hfsplus_file_find_extent(file, sector, nb);
|
||||
if (phy_area.sector_count == 0) {
|
||||
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;
|
||||
}
|
||||
if (!ped_geometry_read(priv_data->plus_geom, b,
|
||||
phy_area.start_sector,
|
||||
phy_area.sector_count))
|
||||
return 0;
|
||||
|
||||
nb -= phy_area.sector_count; /* < nb anyway ... */
|
||||
sector += phy_area.sector_count;
|
||||
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
hfsplus_file_write(HfsPPrivateFile* file, void *buf, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent phy_area;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
char *b = buf;
|
||||
|
||||
if (sector+nb < sector /* detect overflow */
|
||||
|| sector+nb > file->sect_nb) /* out of file */ {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to write HFS+ file with CNID %X behind EOF."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (nb) {
|
||||
phy_area = hfsplus_file_find_extent(file, sector, nb);
|
||||
if (phy_area.sector_count == 0) {
|
||||
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;
|
||||
}
|
||||
if (!ped_geometry_write(priv_data->plus_geom, b,
|
||||
phy_area.start_sector,
|
||||
phy_area.sector_count))
|
||||
return 0;
|
||||
|
||||
nb -= phy_area.sector_count; /* < nb anyway ... */
|
||||
sector += phy_area.sector_count;
|
||||
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_PLUS_H
|
||||
#define _FILE_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
HfsPPrivateFile*
|
||||
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
|
||||
HfsPExtDataRec ext_desc, PedSector sect_nb);
|
||||
|
||||
void
|
||||
hfsplus_file_close (HfsPPrivateFile* file);
|
||||
|
||||
int
|
||||
hfsplus_file_read(HfsPPrivateFile* file, void *buf,
|
||||
PedSector sector, unsigned int nb);
|
||||
|
||||
int
|
||||
hfsplus_file_write(HfsPPrivateFile* file, void *buf,
|
||||
PedSector sector, unsigned int nb);
|
||||
|
||||
/* Read the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
static __inline__ int
|
||||
hfsplus_file_read_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
return hfsplus_file_read(file, buf, sector, 1);
|
||||
}
|
||||
|
||||
/* Write the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
static __inline__ int
|
||||
hfsplus_file_write_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
return hfsplus_file_write(file, buf, sector, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _FILE_PLUS_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,648 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2003-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _HFS_H
|
||||
#define _HFS_H
|
||||
|
||||
/* WARNING : bn is used 2 times in theses macro */
|
||||
/* so _never_ use side effect operators when using them */
|
||||
#define TST_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) & (1<<(7-((bn)&7))))
|
||||
#define SET_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) |= (1<<(7-((bn)&7))))
|
||||
#define CLR_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) &= ~(1<<(7-((bn)&7))))
|
||||
|
||||
/* Maximum number of blocks for the copy buffers */
|
||||
#define BLOCK_MAX_BUFF 256
|
||||
/* Maximum size of the copy buffers, in bytes */
|
||||
#define BYTES_MAX_BUFF 8388608
|
||||
|
||||
/* Apple Creator Codes follow */
|
||||
#define HFSP_IMPL_Shnk 0x53686e6b /* in use */
|
||||
#define HFSP_IMPL_Xpnd 0x58706e64 /* reserved */
|
||||
#define HFSP_IMPL_Resz 0x5265737a /* reserved */
|
||||
#define HFSP_IMPL_PHpx 0x50482b78 /* reserved */
|
||||
#define HFSP_IMPL_traP 0x74726150 /* reserved */
|
||||
#define HFSP_IMPL_GnuP 0x476e7550 /* reserved */
|
||||
|
||||
#define HFS_SIGNATURE 0x4244 /* 'BD' */
|
||||
#define HFSP_SIGNATURE 0x482B /* 'H+' */
|
||||
#define HFSX_SIGNATURE 0x4858 /* 'HX' */
|
||||
|
||||
#define HFSP_VERSION 4
|
||||
#define HFSX_VERSION 5
|
||||
|
||||
#define HFS_HARD_LOCK 7
|
||||
#define HFS_UNMOUNTED 8
|
||||
#define HFS_BAD_SPARED 9
|
||||
#define HFS_SOFT_LOCK 15
|
||||
#define HFSP_NO_CACHE 10
|
||||
#define HFSP_INCONSISTENT 11
|
||||
#define HFSP_REUSE_CNID 12
|
||||
#define HFSP_JOURNALED 13
|
||||
|
||||
#define HFS_IDX_NODE 0x00
|
||||
#define HFS_HDR_NODE 0x01
|
||||
#define HFS_MAP_NODE 0x02
|
||||
#define HFS_LEAF_NODE 0xFF
|
||||
|
||||
#define HFS_FIRST_REC 0x0E
|
||||
#define HFS_NSD_HD_REC 0x78
|
||||
#define HFS_MAP_REC 0xF8
|
||||
|
||||
#define HFS_DATA_FORK 0x00
|
||||
#define HFS_RES_FORK 0xFF
|
||||
|
||||
#define HFS_CAT_DIR 0x01
|
||||
#define HFS_CAT_FILE 0x02
|
||||
#define HFS_CAT_DIR_TH 0x03
|
||||
#define HFS_CAT_FILE_TH 0x04
|
||||
|
||||
#define HFSP_ATTR_INLINE 0x10
|
||||
#define HFSP_ATTR_FORK 0x20
|
||||
#define HFSP_ATTR_EXTENTS 0x30
|
||||
|
||||
#define HFS_ROOT_PAR_ID 0x01
|
||||
#define HFS_ROOT_DIR_ID 0x02
|
||||
#define HFS_XTENT_ID 0x03
|
||||
#define HFS_CATALOG_ID 0x04
|
||||
#define HFS_BAD_BLOCK_ID 0x05
|
||||
#define HFSP_ALLOC_ID 0x06
|
||||
#define HFSP_STARTUP_ID 0x07
|
||||
#define HFSP_ATTRIB_ID 0x08
|
||||
#define HFSP_BOGUS_ID 0x0F
|
||||
#define HFSP_FIRST_AV_ID 0x10
|
||||
|
||||
#define HFSJ_JOURN_IN_FS 0x00
|
||||
#define HFSJ_JOURN_OTHER_DEV 0x01
|
||||
#define HFSJ_JOURN_NEED_INIT 0x02
|
||||
|
||||
#define HFSJ_HEADER_MAGIC 0x4a4e4c78
|
||||
#define HFSJ_ENDIAN_MAGIC 0x12345678
|
||||
|
||||
#define HFSX_CASE_FOLDING 0xCF /* case insensitive HFSX */
|
||||
#define HFSX_BINARY_COMPARE 0xBC /* case sensitive HFSX */
|
||||
|
||||
#define HFS_EXT_NB 3
|
||||
#define HFSP_EXT_NB 8
|
||||
|
||||
/* Define the filenames used by the FS extractor */
|
||||
#ifdef HFS_EXTRACT_FS
|
||||
|
||||
#define HFS_MDB_FILENAME "mdb.hfs"
|
||||
#define HFS_CATALOG_FILENAME "catalog.hfs"
|
||||
#define HFS_EXTENTS_FILENAME "extents.hfs"
|
||||
#define HFS_BITMAP_FILENAME "bitmap.hfs"
|
||||
|
||||
#define HFSP_VH_FILENAME "vh.hfsplus"
|
||||
#define HFSP_CATALOG_FILENAME "catalog.hfsplus"
|
||||
#define HFSP_EXTENTS_FILENAME "extents.hfsplus"
|
||||
#define HFSP_BITMAP_FILENAME "bitmap.hfsplus"
|
||||
#define HFSP_ATTRIB_FILENAME "attributes.hfsplus"
|
||||
#define HFSP_STARTUP_FILENAME "startup.hfsplus"
|
||||
|
||||
#endif /* HFS_EXTRACT_FS */
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------- */
|
||||
/* -- HFS DATA STRUCTURES -- */
|
||||
/* ----------------------------------- */
|
||||
|
||||
/* Extent descriptor */
|
||||
struct __attribute__ ((packed)) _HfsExtDescriptor {
|
||||
uint16_t start_block;
|
||||
uint16_t block_count;
|
||||
};
|
||||
typedef struct _HfsExtDescriptor HfsExtDescriptor;
|
||||
typedef HfsExtDescriptor HfsExtDataRec[HFS_EXT_NB];
|
||||
|
||||
/* Volume header */
|
||||
struct __attribute__ ((packed)) _HfsMasterDirectoryBlock {
|
||||
uint16_t signature;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint16_t volume_attributes;
|
||||
uint16_t files_in_root;
|
||||
uint16_t volume_bitmap_block; /* in sectors */
|
||||
uint16_t next_allocation;
|
||||
uint16_t total_blocks;
|
||||
uint32_t block_size; /* in bytes */
|
||||
uint32_t def_clump_size; /* in bytes */
|
||||
uint16_t start_block; /* in sectors */
|
||||
uint32_t next_free_node;
|
||||
uint16_t free_blocks;
|
||||
uint8_t name_length;
|
||||
char name[27];
|
||||
uint32_t backup_date;
|
||||
uint16_t backup_number;
|
||||
uint32_t write_count;
|
||||
uint32_t extents_clump;
|
||||
uint32_t catalog_clump;
|
||||
uint16_t dirs_in_root;
|
||||
uint32_t file_count;
|
||||
uint32_t dir_count;
|
||||
uint32_t finder_info[8];
|
||||
union __attribute__ ((packed)) {
|
||||
struct __attribute__ ((packed)) {
|
||||
uint16_t volume_cache_size; /* in blocks */
|
||||
uint16_t bitmap_cache_size; /* in blocks */
|
||||
uint16_t common_cache_size; /* in blocks */
|
||||
} legacy;
|
||||
struct __attribute__ ((packed)) {
|
||||
uint16_t signature;
|
||||
HfsExtDescriptor location;
|
||||
} embedded;
|
||||
} old_new;
|
||||
uint32_t extents_file_size; /* in bytes, block size multiple */
|
||||
HfsExtDataRec extents_file_rec;
|
||||
uint32_t catalog_file_size; /* in bytes, block size multiple */
|
||||
HfsExtDataRec catalog_file_rec;
|
||||
};
|
||||
typedef struct _HfsMasterDirectoryBlock HfsMasterDirectoryBlock;
|
||||
|
||||
/* B*-Tree Node Descriptor */
|
||||
struct __attribute__ ((packed)) _HfsNodeDescriptor {
|
||||
uint32_t next;
|
||||
uint32_t previous;
|
||||
int8_t type;
|
||||
uint8_t height;
|
||||
uint16_t rec_nb;
|
||||
uint16_t reserved;
|
||||
};
|
||||
typedef struct _HfsNodeDescriptor HfsNodeDescriptor;
|
||||
|
||||
/* Header record of a whole B*-Tree */
|
||||
struct __attribute__ ((packed)) _HfsHeaderRecord {
|
||||
uint16_t depth;
|
||||
uint32_t root_node;
|
||||
uint32_t leaf_records;
|
||||
uint32_t first_leaf_node;
|
||||
uint32_t last_leaf_node;
|
||||
uint16_t node_size;
|
||||
uint16_t max_key_len;
|
||||
uint32_t total_nodes;
|
||||
uint32_t free_nodes;
|
||||
int8_t reserved[76];
|
||||
};
|
||||
typedef struct _HfsHeaderRecord HfsHeaderRecord;
|
||||
|
||||
/* Catalog key for B*-Tree lookup in the catalog file */
|
||||
struct __attribute__ ((packed)) _HfsCatalogKey {
|
||||
uint8_t key_length; /* length of the key without key_length */
|
||||
uint8_t reserved;
|
||||
uint32_t parent_ID;
|
||||
uint8_t name_length;
|
||||
char name[31]; /* in fact physicaly 1 upto 31 */
|
||||
};
|
||||
typedef struct _HfsCatalogKey HfsCatalogKey;
|
||||
|
||||
/* Extents overflow key for B*-Tree lookup */
|
||||
struct __attribute__ ((packed)) _HfsExtentKey {
|
||||
uint8_t key_length; /* length of the key without key_length */
|
||||
uint8_t type; /* data or ressource fork */
|
||||
uint32_t file_ID;
|
||||
uint16_t start;
|
||||
};
|
||||
typedef struct _HfsExtentKey HfsExtentKey;
|
||||
|
||||
/* Catalog subdata case directory */
|
||||
struct __attribute__ ((packed)) _HfsDir {
|
||||
uint16_t flags;
|
||||
uint16_t valence; /* number of files in this directory */
|
||||
uint32_t dir_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
int8_t DInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t DXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t reserved[4];
|
||||
};
|
||||
typedef struct _HfsDir HfsDir;
|
||||
|
||||
/* Catalog subdata case file */
|
||||
struct __attribute__ ((packed)) _HfsFile {
|
||||
int8_t flags;
|
||||
int8_t type; /* should be 0 */
|
||||
int8_t FInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t file_ID;
|
||||
uint16_t data_start_block;
|
||||
uint32_t data_sz_byte;
|
||||
uint32_t data_sz_block;
|
||||
uint16_t res_start_block;
|
||||
uint32_t res_sz_byte;
|
||||
uint32_t res_sz_block;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
int8_t FXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint16_t clump_size;
|
||||
HfsExtDataRec extents_data;
|
||||
HfsExtDataRec extents_res;
|
||||
uint32_t reserved;
|
||||
};
|
||||
typedef struct _HfsFile HfsFile;
|
||||
|
||||
/* Catalog subdata case directory thread */
|
||||
struct __attribute__ ((packed)) _HfsDirTh {
|
||||
uint32_t reserved[2];
|
||||
uint32_t parent_ID;
|
||||
int8_t name_length;
|
||||
char name[31];
|
||||
};
|
||||
typedef struct _HfsDirTh HfsDirTh;
|
||||
|
||||
/* Catalog subdata case file thread */
|
||||
typedef struct _HfsDirTh HfsFileTh; /* same as directory thread */
|
||||
|
||||
/* Catalog data */
|
||||
struct __attribute__ ((packed)) _HfsCatalog {
|
||||
int8_t type;
|
||||
int8_t reserved;
|
||||
union {
|
||||
HfsDir dir;
|
||||
HfsFile file;
|
||||
HfsDirTh dir_th;
|
||||
HfsFileTh file_th;
|
||||
} sel;
|
||||
};
|
||||
typedef struct _HfsCatalog HfsCatalog;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------ */
|
||||
/* -- HFS+ DATA STRUCTURES -- */
|
||||
/* ------------------------------------ */
|
||||
|
||||
/* documented since 2004 in tn1150 */
|
||||
struct __attribute__ ((packed)) _HfsPPerms {
|
||||
uint32_t owner_ID;
|
||||
uint32_t group_ID;
|
||||
uint32_t permissions;
|
||||
uint32_t special_devices;
|
||||
};
|
||||
typedef struct _HfsPPerms HfsPPerms;
|
||||
|
||||
/* HFS+ extent descriptor*/
|
||||
struct __attribute__ ((packed)) _HfsPExtDescriptor {
|
||||
uint32_t start_block;
|
||||
uint32_t block_count;
|
||||
};
|
||||
typedef struct _HfsPExtDescriptor HfsPExtDescriptor;
|
||||
typedef HfsPExtDescriptor HfsPExtDataRec[HFSP_EXT_NB];
|
||||
|
||||
/* HFS+ fork data structure */
|
||||
struct __attribute__ ((packed)) _HfsPForkData {
|
||||
uint64_t logical_size;
|
||||
uint32_t clump_size;
|
||||
uint32_t total_blocks;
|
||||
HfsPExtDataRec extents;
|
||||
};
|
||||
typedef struct _HfsPForkData HfsPForkData;
|
||||
|
||||
/* HFS+ catalog node ID */
|
||||
typedef uint32_t HfsPNodeID;
|
||||
|
||||
/* HFS+ file names */
|
||||
typedef uint16_t unichar;
|
||||
struct __attribute__ ((packed)) _HfsPUniStr255 {
|
||||
uint16_t length;
|
||||
unichar unicode[255]; /* 1 upto 255 */
|
||||
};
|
||||
typedef struct _HfsPUniStr255 HfsPUniStr255;
|
||||
|
||||
/* HFS+ volume header */
|
||||
struct __attribute__ ((packed)) _HfsPVolumeHeader {
|
||||
uint16_t signature;
|
||||
uint16_t version;
|
||||
uint32_t attributes;
|
||||
uint32_t last_mounted_version;
|
||||
uint32_t journal_info_block;
|
||||
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
uint32_t checked_date;
|
||||
|
||||
uint32_t file_count;
|
||||
uint32_t dir_count;
|
||||
|
||||
uint32_t block_size;
|
||||
uint32_t total_blocks;
|
||||
uint32_t free_blocks;
|
||||
|
||||
uint32_t next_allocation;
|
||||
uint32_t res_clump_size;
|
||||
uint32_t data_clump_size;
|
||||
HfsPNodeID next_catalog_ID;
|
||||
|
||||
uint32_t write_count;
|
||||
uint64_t encodings_bitmap;
|
||||
|
||||
uint8_t finder_info[32];
|
||||
|
||||
HfsPForkData allocation_file;
|
||||
HfsPForkData extents_file;
|
||||
HfsPForkData catalog_file;
|
||||
HfsPForkData attributes_file;
|
||||
HfsPForkData startup_file;
|
||||
};
|
||||
typedef struct _HfsPVolumeHeader HfsPVolumeHeader;
|
||||
|
||||
/* HFS+ B-Tree Node Descriptor. Same as HFS btree. */
|
||||
struct __attribute__ ((packed)) _HfsPNodeDescriptor {
|
||||
uint32_t next;
|
||||
uint32_t previous;
|
||||
int8_t type;
|
||||
uint8_t height;
|
||||
uint16_t rec_nb;
|
||||
uint16_t reserved;
|
||||
};
|
||||
typedef struct _HfsPNodeDescriptor HfsPNodeDescriptor;
|
||||
|
||||
/* Header record of a whole HFS+ B-Tree. */
|
||||
struct __attribute__ ((packed)) _HfsPHeaderRecord {
|
||||
uint16_t depth;
|
||||
uint32_t root_node;
|
||||
uint32_t leaf_records;
|
||||
uint32_t first_leaf_node;
|
||||
uint32_t last_leaf_node;
|
||||
uint16_t node_size;
|
||||
uint16_t max_key_len;
|
||||
uint32_t total_nodes;
|
||||
uint32_t free_nodes; /* same as hfs btree until here */
|
||||
uint16_t reserved1;
|
||||
|
||||
uint32_t clump_size;
|
||||
uint8_t btree_type; /* must be 0 for HFS+ B-Tree */
|
||||
uint8_t key_compare_type; /* hfsx => 0xCF = case folding */
|
||||
/* 0xBC = binary compare */
|
||||
/* otherwise, reserved */
|
||||
uint32_t attributes;
|
||||
uint32_t reserved3[16];
|
||||
};
|
||||
typedef struct _HfsPHeaderRecord HfsPHeaderRecord;
|
||||
|
||||
/* Catalog key for B-Tree lookup in the HFS+ catalog file */
|
||||
struct __attribute__ ((packed)) _HfsPCatalogKey {
|
||||
uint16_t key_length;
|
||||
HfsPNodeID parent_ID;
|
||||
HfsPUniStr255 node_name;
|
||||
};
|
||||
typedef struct _HfsPCatalogKey HfsPCatalogKey;
|
||||
|
||||
/* HFS+ catalog subdata case dir */
|
||||
struct __attribute__ ((packed)) _HfsPDir {
|
||||
uint16_t flags;
|
||||
uint32_t valence;
|
||||
HfsPNodeID dir_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t attrib_mod_date;
|
||||
uint32_t access_date;
|
||||
uint32_t backup_date;
|
||||
HfsPPerms permissions;
|
||||
int8_t DInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t DXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t text_encoding;
|
||||
uint32_t reserved;
|
||||
};
|
||||
typedef struct _HfsPDir HfsPDir;
|
||||
|
||||
/* HFS+ catalog subdata case file */
|
||||
struct __attribute__ ((packed)) _HfsPFile {
|
||||
uint16_t flags;
|
||||
uint32_t reserved1;
|
||||
HfsPNodeID file_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t attrib_mod_date;
|
||||
uint32_t access_date;
|
||||
uint32_t backup_date;
|
||||
HfsPPerms permissions;
|
||||
int8_t FInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t FXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t text_encoding;
|
||||
uint32_t reserved2;
|
||||
|
||||
HfsPForkData data_fork;
|
||||
HfsPForkData res_fork;
|
||||
};
|
||||
typedef struct _HfsPFile HfsPFile;
|
||||
|
||||
/* HFS+ catalog subdata case thread */
|
||||
struct __attribute__ ((packed)) _HfsPThread {
|
||||
int16_t reserved;
|
||||
HfsPNodeID parent_ID;
|
||||
HfsPUniStr255 node_name;
|
||||
};
|
||||
typedef struct _HfsPThread HfsPDirTh;
|
||||
typedef struct _HfsPThread HfsPFileTh;
|
||||
|
||||
/* HFS+ Catalog leaf data */
|
||||
struct __attribute__ ((packed)) _HfsPCatalog {
|
||||
int16_t type;
|
||||
union {
|
||||
HfsPDir dir;
|
||||
HfsPFile file;
|
||||
HfsPDirTh dir_th;
|
||||
HfsPFileTh file_th;
|
||||
} sel;
|
||||
};
|
||||
typedef struct _HfsPCatalog HfsPCatalog;
|
||||
|
||||
/* HFS+ extents file key */
|
||||
struct __attribute__ ((packed)) _HfsPExtentKey {
|
||||
uint16_t key_length;
|
||||
uint8_t type;
|
||||
uint8_t pad;
|
||||
HfsPNodeID file_ID;
|
||||
uint32_t start;
|
||||
};
|
||||
typedef struct _HfsPExtentKey HfsPExtentKey;
|
||||
|
||||
/* extent file data is HfsPExtDataRec */
|
||||
|
||||
/* Fork data attribute file */
|
||||
struct __attribute__ ((packed)) _HfsPForkDataAttr {
|
||||
uint32_t record_type;
|
||||
uint32_t reserved;
|
||||
union __attribute__ ((packed)) {
|
||||
HfsPForkData fork;
|
||||
HfsPExtDataRec extents;
|
||||
} fork_res;
|
||||
};
|
||||
typedef struct _HfsPForkDataAttr HfsPForkDataAttr;
|
||||
|
||||
|
||||
/* ----------- Journal data structures ----------- */
|
||||
|
||||
/* Info block : stored in a block # defined in the VH */
|
||||
struct __attribute__ ((packed)) _HfsJJournalInfoBlock {
|
||||
uint32_t flags;
|
||||
uint32_t device_signature[8];
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t reserved[32];
|
||||
};
|
||||
typedef struct _HfsJJournalInfoBlock HfsJJournalInfoBlock;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJJournalHeader {
|
||||
uint32_t magic;
|
||||
uint32_t endian;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
uint64_t size;
|
||||
uint32_t blhdr_size;
|
||||
uint32_t checksum;
|
||||
uint32_t jhdr_size;
|
||||
};
|
||||
typedef struct _HfsJJournalHeader HfsJJournalHeader;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJBlockInfo {
|
||||
uint64_t bnum; /* sector number */
|
||||
uint32_t bsize; /* size in bytes */
|
||||
uint32_t next;
|
||||
};
|
||||
typedef struct _HfsJBlockInfo HfsJBlockInfo;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJBlockListHeader {
|
||||
uint16_t max_blocks; /* reserved */
|
||||
uint16_t num_blocks;
|
||||
uint32_t bytes_used;
|
||||
uint32_t checksum;
|
||||
uint32_t pad;
|
||||
HfsJBlockInfo binfo[];
|
||||
};
|
||||
typedef struct _HfsJBlockListHeader HfsJBlockListHeader;
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* -- INTERNAL DATA STRUCTURES -- */
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/* Data of an opened HFS file */
|
||||
struct _HfsPrivateFile {
|
||||
PedSector sect_nb;
|
||||
PedFileSystem* fs;
|
||||
uint32_t CNID; /* disk order (BE) */
|
||||
HfsExtDataRec first; /* disk order (BE) */
|
||||
HfsExtDataRec cache; /* disk order (BE) */
|
||||
uint16_t start_cache; /* CPU order */
|
||||
};
|
||||
typedef struct _HfsPrivateFile HfsPrivateFile;
|
||||
|
||||
/* To store bad block list */
|
||||
struct _HfsPrivateLinkExtent {
|
||||
HfsExtDescriptor extent;
|
||||
struct _HfsPrivateLinkExtent* next;
|
||||
};
|
||||
typedef struct _HfsPrivateLinkExtent HfsPrivateLinkExtent;
|
||||
|
||||
/* HFS Filesystem specific data */
|
||||
struct _HfsPrivateFSData {
|
||||
uint8_t alloc_map[(1<<16) / 8];
|
||||
HfsMasterDirectoryBlock* mdb;
|
||||
HfsPrivateFile* extent_file;
|
||||
HfsPrivateFile* catalog_file;
|
||||
HfsPrivateLinkExtent* bad_blocks_xtent_list;
|
||||
unsigned int bad_blocks_xtent_nb;
|
||||
char bad_blocks_loaded;
|
||||
};
|
||||
typedef struct _HfsPrivateFSData HfsPrivateFSData;
|
||||
|
||||
/* Generic btree key */
|
||||
struct __attribute__ ((packed)) _HfsPrivateGenericKey {
|
||||
uint8_t key_length;
|
||||
uint8_t key_content[1]; /* we use 1 as a minimum size */
|
||||
};
|
||||
typedef struct _HfsPrivateGenericKey HfsPrivateGenericKey;
|
||||
|
||||
/* ----- HFS+ ----- */
|
||||
|
||||
/* Data of an opened HFS file */
|
||||
struct _HfsPPrivateFile {
|
||||
PedSector sect_nb;
|
||||
PedFileSystem* fs;
|
||||
HfsPNodeID CNID; /* disk order (BE) */
|
||||
HfsPExtDataRec first; /* disk order (BE) */
|
||||
HfsPExtDataRec cache; /* disk order (BE) */
|
||||
uint32_t start_cache; /* CPU order */
|
||||
};
|
||||
typedef struct _HfsPPrivateFile HfsPPrivateFile;
|
||||
|
||||
struct _HfsPPrivateExtent {
|
||||
PedSector start_sector;
|
||||
PedSector sector_count;
|
||||
};
|
||||
typedef struct _HfsPPrivateExtent HfsPPrivateExtent;
|
||||
|
||||
/* To store bad block list */
|
||||
struct _HfsPPrivateLinkExtent {
|
||||
HfsPExtDescriptor extent;
|
||||
struct _HfsPPrivateLinkExtent* next;
|
||||
};
|
||||
typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
|
||||
|
||||
/* HFS+ file system specific data */
|
||||
struct _HfsPPrivateFSData {
|
||||
PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
|
||||
PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
|
||||
uint8_t* alloc_map;
|
||||
uint8_t* dirty_alloc_map;
|
||||
HfsPVolumeHeader* vh;
|
||||
HfsPPrivateFile* extents_file;
|
||||
HfsPPrivateFile* catalog_file;
|
||||
HfsPPrivateFile* attributes_file;
|
||||
HfsPPrivateFile* allocation_file;
|
||||
HfsPPrivateLinkExtent* bad_blocks_xtent_list;
|
||||
uint32_t jib_start_block;
|
||||
uint32_t jl_start_block;
|
||||
unsigned int bad_blocks_xtent_nb;
|
||||
char bad_blocks_loaded;
|
||||
char free_geom; /* 1 = plus_geom must be freed */
|
||||
};
|
||||
typedef struct _HfsPPrivateFSData HfsPPrivateFSData;
|
||||
|
||||
/* Generic + btree key */
|
||||
struct __attribute__ ((packed)) _HfsPPrivateGenericKey {
|
||||
uint16_t key_length;
|
||||
uint8_t key_content[1]; /* we use 1 as a minimum size */
|
||||
};
|
||||
typedef struct _HfsPPrivateGenericKey HfsPPrivateGenericKey;
|
||||
|
||||
/* ---- common ---- */
|
||||
|
||||
/* node and lead record reference for a BTree search */
|
||||
struct _HfsCPrivateLeafRec {
|
||||
unsigned int node_size; /* in sectors */
|
||||
unsigned int node_number;
|
||||
unsigned int record_pos;
|
||||
unsigned int record_number;
|
||||
};
|
||||
typedef struct _HfsCPrivateLeafRec HfsCPrivateLeafRec;
|
||||
|
||||
extern uint8_t* hfs_block;
|
||||
extern uint8_t* hfsp_block;
|
||||
extern unsigned hfs_block_count;
|
||||
extern unsigned hfsp_block_count;
|
||||
|
||||
#endif /* _HFS_H */
|
||||
@@ -1,392 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "reloc_plus.h"
|
||||
|
||||
#include "journal.h"
|
||||
|
||||
static int hfsj_vh_replayed = 0;
|
||||
static int is_le = 0;
|
||||
|
||||
static uint32_t
|
||||
hfsj_calc_checksum(uint8_t *ptr, int len)
|
||||
{
|
||||
int i;
|
||||
uint32_t cksum=0;
|
||||
|
||||
for (i=0; i < len; i++, ptr++) {
|
||||
cksum = (cksum << 8) ^ (cksum + *ptr);
|
||||
}
|
||||
|
||||
return (~cksum);
|
||||
}
|
||||
|
||||
int
|
||||
hfsj_update_jib(PedFileSystem* fs, uint32_t block)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
|
||||
priv_data->vh->journal_info_block = PED_CPU_TO_BE32(block);
|
||||
|
||||
if (!hfsplus_update_vh (fs))
|
||||
return 0;
|
||||
|
||||
priv_data->jib_start_block = block;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Return the sector in the journal that is after the area read */
|
||||
/* 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 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 = HFS_32_TO_CPU(jh->blhdr_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
|
||||
blhdr = (HfsJBlockListHeader*)
|
||||
ped_malloc (blhdr_nbsect * PED_SECTOR_SIZE_DEFAULT);
|
||||
if (!blhdr) return 0;
|
||||
|
||||
start = HFS_64_TO_CPU(jh->start, is_le) / 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 = HFS_32_TO_CPU(blhdr->checksum, is_le);
|
||||
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 = HFS_CPU_TO_32(cksum, is_le);
|
||||
|
||||
for (i=1; i < HFS_16_TO_CPU(blhdr->num_blocks, is_le); ++i) {
|
||||
size = HFS_32_TO_CPU(blhdr->binfo[i].bsize, is_le);
|
||||
sector = HFS_64_TO_CPU(blhdr->binfo[i].bnum, is_le);
|
||||
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) {
|
||||
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;
|
||||
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 = HFS_CPU_TO_64(start * PED_SECTOR_SIZE_DEFAULT, is_le);
|
||||
|
||||
free (blhdr);
|
||||
return (ped_geometry_sync (fs->geom));
|
||||
|
||||
err_replay:
|
||||
free (blhdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 0 => Failure, don't continue to open ! */
|
||||
/* 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 deactivate 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);
|
||||
|
||||
/* https://github.com/apple-opensource/hfs/blob/master/core/hfs_journal.c#L1167
|
||||
* indicates that this is:
|
||||
* wrap the start ptr if it points to the very end of the journal
|
||||
*/
|
||||
if (jh->start == jh->size)
|
||||
jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
|
||||
if (jh->end == jh->size)
|
||||
jh->end = 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;
|
||||
}
|
||||
|
||||
#endif /* DISCOVER_ONLY */
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _JOURNAL_H
|
||||
#define _JOURNAL_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsj_replay_journal(PedFileSystem* fs);
|
||||
|
||||
int
|
||||
hfsj_update_jib(PedFileSystem* fs, uint32_t block);
|
||||
|
||||
int
|
||||
hfsj_update_jl(PedFileSystem* fs, uint32_t block);
|
||||
|
||||
#define HFS_16_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_LE16_TO_CPU(x) : (uint16_t)PED_BE16_TO_CPU(x))
|
||||
#define HFS_32_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_LE32_TO_CPU(x) : (uint32_t)PED_BE32_TO_CPU(x))
|
||||
#define HFS_64_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_LE64_TO_CPU(x) : (uint64_t)PED_BE64_TO_CPU(x))
|
||||
#define HFS_CPU_TO_16(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_CPU_TO_LE16(x) : (uint16_t)PED_CPU_TO_BE16(x))
|
||||
#define HFS_CPU_TO_32(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_CPU_TO_LE32(x) : (uint32_t)PED_CPU_TO_BE32(x))
|
||||
#define HFS_CPU_TO_64(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_CPU_TO_LE64(x) : (uint64_t)PED_CPU_TO_BE64(x))
|
||||
|
||||
#endif /* _JOURNAL_H */
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
#include "probe.h"
|
||||
|
||||
int
|
||||
hfsc_can_use_geom (PedGeometry* geom)
|
||||
{
|
||||
PedDevice* dev;
|
||||
|
||||
dev = geom->dev;
|
||||
PED_ASSERT (geom != NULL);
|
||||
PED_ASSERT (dev != NULL);
|
||||
|
||||
if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Parted can't use HFS file systems on disks "
|
||||
"with a sector size not equal to %d bytes."),
|
||||
(int)PED_SECTOR_SIZE_DEFAULT );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Probe an HFS volume, detecting it even if
|
||||
it is in fact a wrapper to an HFS+ volume */
|
||||
/* 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;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PROBE_H
|
||||
#define _PROBE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsc_can_use_geom (PedGeometry* geom);
|
||||
|
||||
PedGeometry*
|
||||
hfs_and_wrapper_probe (PedGeometry* geom);
|
||||
|
||||
#endif /* _PROBE_H */
|
||||
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "file.h"
|
||||
#include "advfs.h"
|
||||
#include "cache.h"
|
||||
|
||||
#include "reloc.h"
|
||||
|
||||
/* This function moves data of size blocks starting
|
||||
at block *ptr_fblock to block *ptr_to_fblock */
|
||||
/* return new start or -1 on failure */
|
||||
static int
|
||||
hfs_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock, unsigned int size)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int i, ok = 0;
|
||||
unsigned int next_to_fblock;
|
||||
unsigned int start, stop;
|
||||
|
||||
PED_ASSERT (hfs_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_BE16_TO_CPU(priv_data->mdb->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 */
|
||||
unsigned int j;
|
||||
unsigned int start_block =
|
||||
PED_BE16_TO_CPU (priv_data->mdb->start_block );
|
||||
unsigned int block_sz =
|
||||
(PED_BE32_TO_CPU (priv_data->mdb->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*/) {
|
||||
PedSector abs_sector;
|
||||
unsigned int ai;
|
||||
|
||||
j = size - i; j = (j < hfs_block_count) ?
|
||||
j : hfs_block_count ;
|
||||
|
||||
abs_sector = start_block
|
||||
+ (PedSector) (*ptr_fblock + i) * block_sz;
|
||||
if (!ped_geometry_read (fs->geom, hfs_block, abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
abs_sector = start_block
|
||||
+ (PedSector) (start + i) * block_sz;
|
||||
if (!ped_geometry_write (fs->geom,hfs_block,abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
for (ai = i+j; i < ai; i++) {
|
||||
/* free source block */
|
||||
CLR_BLOC_OCCUPATION(priv_data->alloc_map,
|
||||
*ptr_fblock + i);
|
||||
|
||||
/* set dest block */
|
||||
SET_BLOC_OCCUPATION(priv_data->alloc_map,
|
||||
start + i);
|
||||
}
|
||||
}
|
||||
if (!ped_geometry_sync_fast (fs->geom))
|
||||
return -1;
|
||||
|
||||
*ptr_fblock += size;
|
||||
*ptr_to_fblock = next_to_fblock;
|
||||
} else {
|
||||
if (*ptr_fblock != *ptr_to_fblock)
|
||||
/* not enough room, but try to continue */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Update MDB */
|
||||
/* Return 0 if an error occurred */
|
||||
/* Return 1 if everything ok */
|
||||
int
|
||||
hfs_update_mdb (PedFileSystem *fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
|
||||
if (!ped_geometry_read (fs->geom, node, 2, 1))
|
||||
return 0;
|
||||
memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
|
||||
if ( !ped_geometry_write (fs->geom, node, 2, 1)
|
||||
|| !ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1)
|
||||
|| !ped_geometry_sync_fast (fs->geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generic relocator */
|
||||
/* replace previous hfs_do_move_* */
|
||||
static int
|
||||
hfs_do_move (PedFileSystem* fs, unsigned int *ptr_src,
|
||||
unsigned int *ptr_dest, HfsCPrivateCache* cache,
|
||||
HfsCPrivateExtent* ref)
|
||||
{
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPrivateFile* file;
|
||||
HfsExtDescriptor* extent;
|
||||
HfsCPrivateExtent* move;
|
||||
int new_start;
|
||||
|
||||
new_start = hfs_effect_move_extent (fs, ptr_src, ptr_dest,
|
||||
ref->ext_length);
|
||||
if (new_start == -1) return -1;
|
||||
|
||||
if (ref->ext_start != (unsigned) new_start) {
|
||||
/* Load, modify & save */
|
||||
switch (ref->where) {
|
||||
/******** MDB *********/
|
||||
case CR_PRIM_CAT :
|
||||
priv_data->catalog_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_EXT :
|
||||
priv_data->extent_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
CR_PRIM :
|
||||
extent = ( HfsExtDescriptor* )
|
||||
( (uint8_t*)priv_data->mdb + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
if (!hfs_update_mdb(fs)) return -1;
|
||||
break;
|
||||
|
||||
/********* BTREE *******/
|
||||
case CR_BTREE_EXT_CAT :
|
||||
if (priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE16(ref->ext_start))
|
||||
priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
/* FALLTHROUGH */
|
||||
case CR_BTREE_EXT_0 :
|
||||
file = priv_data->extent_file;
|
||||
goto CR_BTREE;
|
||||
case CR_BTREE_CAT :
|
||||
file = priv_data->catalog_file;
|
||||
CR_BTREE:
|
||||
PED_ASSERT(ref->sect_by_block == 1
|
||||
&& ref->ref_offset < PED_SECTOR_SIZE_DEFAULT);
|
||||
if (!hfs_file_read_sector(file, node, ref->ref_block))
|
||||
return -1;
|
||||
extent = ( HfsExtDescriptor* ) (node + ref->ref_offset);
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
if (!hfs_file_write_sector(file, node, ref->ref_block)
|
||||
|| !ped_geometry_sync_fast (fs->geom))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/********** BUG ********/
|
||||
default :
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("A reference to an extent comes from a place "
|
||||
"it should not. You should check the file "
|
||||
"system!"));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the cache */
|
||||
move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
|
||||
if (!move) return -1; /* "cleanly" fail */
|
||||
PED_ASSERT(move == ref); /* generate a bug */
|
||||
}
|
||||
|
||||
return new_start;
|
||||
}
|
||||
|
||||
/* 0 error, 1 ok */
|
||||
static int
|
||||
hfs_save_allocation(PedFileSystem* fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int map_sectors;
|
||||
|
||||
map_sectors = ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
|
||||
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
|
||||
/ (PED_SECTOR_SIZE_DEFAULT * 8);
|
||||
return ( ped_geometry_write (fs->geom, priv_data->alloc_map,
|
||||
PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
|
||||
map_sectors) );
|
||||
}
|
||||
|
||||
/* This function moves an extent starting at block fblock to block to_fblock
|
||||
if there's enough room */
|
||||
/* Return 1 if everything was fine */
|
||||
/* Return -1 if an error occurred */
|
||||
/* Return 0 if no extent was found */
|
||||
/* Generic search thanks to the file system cache */
|
||||
static int
|
||||
hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock,
|
||||
HfsCPrivateCache* cache)
|
||||
{
|
||||
HfsCPrivateExtent* ref;
|
||||
unsigned int old_start, new_start;
|
||||
|
||||
/* Reference search powered by the cache... */
|
||||
/* This is the optimisation secret :) */
|
||||
ref = hfsc_cache_search_extent(cache, *ptr_fblock);
|
||||
if (!ref) return 0; /* not found */
|
||||
|
||||
old_start = *ptr_fblock;
|
||||
new_start = hfs_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
|
||||
if (new_start == (unsigned int) -1) return -1;
|
||||
if (new_start > old_start) { /* detect 2 pass reloc */
|
||||
new_start = hfs_do_move(fs,&new_start,ptr_to_fblock,cache,ref);
|
||||
if (new_start == (unsigned int) -1 || new_start > old_start)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocation bitmap save is not atomic with data relocation */
|
||||
/* so we only do it a few times, and without syncing */
|
||||
/* The unmounted bit protect us anyway */
|
||||
hfs_save_allocation(fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_mdb(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int j;
|
||||
|
||||
extent = priv_data->mdb->extents_file_rec;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for mdb */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
|
||||
1, /* load/save only 1 sector */
|
||||
CR_PRIM_EXT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->mdb->catalog_file_rec;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
0,
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
|
||||
1,
|
||||
CR_PRIM_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsHeaderRecord* header;
|
||||
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
|
||||
HfsCatalogKey* catalog_key;
|
||||
HfsCatalog* catalog_data;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j;
|
||||
uint16_t catalog_pos;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!hfs_file_read_sector (priv_data->catalog_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
leaf_node;
|
||||
leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfs_file_read_sector (priv_data->catalog_file,
|
||||
node, leaf_node))
|
||||
return 0;
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; ++i) {
|
||||
/* undocumented alignement */
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
catalog_pos = PED_BE16_TO_CPU(value);
|
||||
catalog_key = (HfsCatalogKey*) (node + catalog_pos);
|
||||
unsigned int skip;
|
||||
skip = (1 + catalog_key->key_length + 1) & ~1;
|
||||
catalog_data = (HfsCatalog*)(node+catalog_pos+skip);
|
||||
/* check for obvious error in FS */
|
||||
if ((catalog_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)catalog_data - 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 (catalog_data->type != HFS_CAT_FILE) continue;
|
||||
|
||||
extent = catalog_data->sel.file.extents_data;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
CR_BTREE_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = catalog_data->sel.file.extents_res;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
CR_BTREE_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsHeaderRecord* header;
|
||||
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
|
||||
HfsExtentKey* extent_key;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j;
|
||||
uint16_t extent_pos;
|
||||
|
||||
if (!priv_data->extent_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 (!hfs_file_read_sector (priv_data->extent_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
leaf_node;
|
||||
leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfs_file_read_sector (priv_data->extent_file, node,
|
||||
leaf_node))
|
||||
return 0;
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; i++) {
|
||||
uint8_t where;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
extent_pos = PED_BE16_TO_CPU(value);
|
||||
extent_key = (HfsExtentKey*)(node + extent_pos);
|
||||
/* size is cst */
|
||||
extent = (HfsExtDescriptor*)(node+extent_pos+sizeof(HfsExtentKey));
|
||||
/* check for obvious error in FS */
|
||||
if ((extent_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)extent - 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;
|
||||
}
|
||||
|
||||
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;
|
||||
default :
|
||||
where = CR_BTREE_EXT_0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
where,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function cache every extents start and length stored in any
|
||||
fs structure into the adt defined in cache.[ch]
|
||||
Returns NULL on failure */
|
||||
static HfsCPrivateCache*
|
||||
hfs_cache_extents(PedFileSystem *fs, PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsCPrivateCache* ret;
|
||||
unsigned int file_number, block_number;
|
||||
|
||||
file_number = PED_BE32_TO_CPU(priv_data->mdb->file_count);
|
||||
block_number = PED_BE16_TO_CPU(priv_data->mdb->total_blocks);
|
||||
ret = hfsc_new_cache(block_number, file_number);
|
||||
if (!ret) return NULL;
|
||||
|
||||
if (!hfs_cache_from_mdb(ret, fs, timer) ||
|
||||
!hfs_cache_from_catalog(ret, fs, timer) ||
|
||||
!hfs_cache_from_extent(ret, fs, timer)) {
|
||||
ped_exception_throw(
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not cache the file system in memory."));
|
||||
hfsc_delete_cache(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function moves file's data to compact used and free space,
|
||||
starting at fblock block */
|
||||
/* return 0 on error */
|
||||
int
|
||||
hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free)
|
||||
{
|
||||
PedSector bytes_buff;
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsMasterDirectoryBlock* mdb = priv_data->mdb;
|
||||
HfsCPrivateCache* cache;
|
||||
unsigned int to_fblock = fblock;
|
||||
unsigned int start = fblock;
|
||||
unsigned int divisor = PED_BE16_TO_CPU (mdb->total_blocks)
|
||||
+ 1 - start - to_free;
|
||||
int ret;
|
||||
|
||||
PED_ASSERT (!hfs_block);
|
||||
|
||||
cache = hfs_cache_extents (fs, timer);
|
||||
if (!cache)
|
||||
return 0;
|
||||
|
||||
/* Calculate the size of the copy buffer :
|
||||
* Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
|
||||
* takes the maximum number of HFS blocks so that the buffer
|
||||
* will remain smaller than or equal to BYTES_MAX_BUFF, with
|
||||
* a minimum of 1 HFS block */
|
||||
bytes_buff = PED_BE32_TO_CPU (priv_data->mdb->block_size)
|
||||
* (PedSector) BLOCK_MAX_BUFF;
|
||||
if (bytes_buff > BYTES_MAX_BUFF) {
|
||||
hfs_block_count = BYTES_MAX_BUFF
|
||||
/ PED_BE32_TO_CPU (priv_data->mdb->block_size);
|
||||
if (!hfs_block_count)
|
||||
hfs_block_count = 1;
|
||||
bytes_buff = (PedSector) hfs_block_count
|
||||
* PED_BE32_TO_CPU (priv_data->mdb->block_size);
|
||||
} else
|
||||
hfs_block_count = BLOCK_MAX_BUFF;
|
||||
|
||||
/* If the cache code requests more space, give it to him */
|
||||
if (bytes_buff < hfsc_cache_needed_buffer (cache))
|
||||
bytes_buff = hfsc_cache_needed_buffer (cache);
|
||||
|
||||
hfs_block = (uint8_t*) ped_malloc (bytes_buff);
|
||||
if (!hfs_block)
|
||||
goto error_cache;
|
||||
|
||||
if (!hfs_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks list could not be loaded."));
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) {
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,fblock)
|
||||
&& (!hfs_is_bad_block (fs, fblock))) {
|
||||
if (!(ret = hfs_move_extent_starting_at (fs, &fblock,
|
||||
&to_fblock, cache)))
|
||||
to_fblock = ++fblock;
|
||||
else if (ret == -1) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("An error occurred during extent "
|
||||
"relocation."));
|
||||
goto error_alloc;
|
||||
}
|
||||
} else {
|
||||
fblock++;
|
||||
}
|
||||
|
||||
ped_timer_update(timer, (float)(to_fblock - start)/divisor);
|
||||
}
|
||||
|
||||
free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
|
||||
hfsc_delete_cache (cache);
|
||||
return 1;
|
||||
|
||||
error_alloc:
|
||||
free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
|
||||
error_cache:
|
||||
hfsc_delete_cache (cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _RELOC_H
|
||||
#define _RELOC_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfs_update_mdb (PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free);
|
||||
|
||||
#endif /* _RELOC_H */
|
||||
@@ -1,948 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISCOVER_ONLY
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "file_plus.h"
|
||||
#include "advfs_plus.h"
|
||||
#include "cache.h"
|
||||
#include "journal.h"
|
||||
|
||||
#include "reloc_plus.h"
|
||||
|
||||
/* This function moves data of size blocks starting at block *ptr_fblock
|
||||
to block *ptr_to_fblock */
|
||||
/* return new start or -1 on failure */
|
||||
/* -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;
|
||||
}
|
||||
|
||||
/* Returns 0 on error */
|
||||
/* 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
|
||||
hfsplus_do_move (PedFileSystem* fs, unsigned int *ptr_src,
|
||||
unsigned int *ptr_dest, HfsCPrivateCache* cache,
|
||||
HfsCPrivateExtent* ref)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPPrivateFile* file;
|
||||
HfsPExtDescriptor* extent;
|
||||
HfsCPrivateExtent* move;
|
||||
int new_start;
|
||||
|
||||
new_start = hfsplus_effect_move_extent (fs, ptr_src, ptr_dest,
|
||||
ref->ext_length);
|
||||
|
||||
if (new_start == -1) return -1;
|
||||
|
||||
if (ref->ext_start != (unsigned) new_start) {
|
||||
switch (ref->where) {
|
||||
/************ VH ************/
|
||||
case CR_PRIM_CAT :
|
||||
priv_data->catalog_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_EXT :
|
||||
priv_data->extents_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_ATTR :
|
||||
priv_data->attributes_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_ALLOC :
|
||||
priv_data->allocation_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_START :
|
||||
/* No startup file opened */
|
||||
CR_PRIM :
|
||||
extent = ( HfsPExtDescriptor* )
|
||||
( (uint8_t*)priv_data->vh + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
if (!hfsplus_update_vh(fs))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/************** BTREE *************/
|
||||
case CR_BTREE_CAT_JIB :
|
||||
if (!hfsj_update_jib(fs, new_start))
|
||||
return -1;
|
||||
goto BTREE_CAT;
|
||||
|
||||
case CR_BTREE_CAT_JL :
|
||||
if (!hfsj_update_jl(fs, new_start))
|
||||
return -1;
|
||||
goto BTREE_CAT;
|
||||
|
||||
BTREE_CAT:
|
||||
case CR_BTREE_CAT :
|
||||
file = priv_data->catalog_file;
|
||||
goto CR_BTREE;
|
||||
|
||||
case CR_BTREE_ATTR :
|
||||
file = priv_data->attributes_file;
|
||||
goto CR_BTREE;
|
||||
|
||||
case CR_BTREE_EXT_ATTR :
|
||||
if (priv_data->attributes_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->attributes_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_CAT :
|
||||
if (priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_ALLOC :
|
||||
if (priv_data->allocation_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->allocation_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_START :
|
||||
/* No startup file opened */
|
||||
CR_BTREE_EXT :
|
||||
case CR_BTREE_EXT_0 :
|
||||
file = priv_data->extents_file;
|
||||
|
||||
CR_BTREE :
|
||||
PED_ASSERT(PED_SECTOR_SIZE_DEFAULT * ref->sect_by_block
|
||||
> ref->ref_offset);
|
||||
if (!hfsplus_file_read(file, hfsp_block,
|
||||
(PedSector)ref->ref_block * ref->sect_by_block,
|
||||
ref->sect_by_block))
|
||||
return -1;
|
||||
extent = ( HfsPExtDescriptor* )
|
||||
( hfsp_block + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
if (!hfsplus_file_write(file, hfsp_block,
|
||||
(PedSector)ref->ref_block * ref->sect_by_block,
|
||||
ref->sect_by_block)
|
||||
|| !ped_geometry_sync_fast (priv_data->plus_geom))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/********** BUG *********/
|
||||
default :
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("A reference to an extent comes from a place "
|
||||
"it should not. You should check the file "
|
||||
"system!"));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
|
||||
if (!move) return -1;
|
||||
PED_ASSERT(move == ref);
|
||||
}
|
||||
|
||||
return new_start;
|
||||
}
|
||||
|
||||
/* save any dirty sector of the allocation bitmap file */
|
||||
static int
|
||||
hfsplus_save_allocation(PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int map_sectors, i, j;
|
||||
int ret = 1;
|
||||
|
||||
map_sectors = ( PED_BE32_TO_CPU (priv_data->vh->total_blocks)
|
||||
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8);
|
||||
|
||||
for (i = 0; i < map_sectors;) {
|
||||
for (j = i;
|
||||
(TST_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j));
|
||||
++j)
|
||||
CLR_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j);
|
||||
if (j-i) {
|
||||
ret = hfsplus_file_write(priv_data->allocation_file,
|
||||
priv_data->alloc_map + i * PED_SECTOR_SIZE_DEFAULT,
|
||||
i, j-i) && ret;
|
||||
i = j;
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function moves an extent starting at block fblock
|
||||
to block to_fblock if there's enough room */
|
||||
/* Return 1 if everything was fine */
|
||||
/* Return -1 if an error occurred */
|
||||
/* Return 0 if no extent was found */
|
||||
static int
|
||||
hfsplus_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock,
|
||||
HfsCPrivateCache* cache)
|
||||
{
|
||||
HfsCPrivateExtent* ref;
|
||||
unsigned int old_start, new_start;
|
||||
|
||||
ref = hfsc_cache_search_extent(cache, *ptr_fblock);
|
||||
if (!ref) return 0;
|
||||
|
||||
old_start = *ptr_fblock;
|
||||
new_start = hfsplus_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
|
||||
if (new_start == (unsigned)-1) return -1;
|
||||
if (new_start > old_start) {
|
||||
new_start = hfsplus_do_move(fs, &new_start, ptr_to_fblock,
|
||||
cache, ref);
|
||||
if (new_start == (unsigned)-1 || new_start > old_start)
|
||||
return -1;
|
||||
}
|
||||
|
||||
hfsplus_save_allocation(fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_cache_from_vh(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPExtDescriptor* extent;
|
||||
unsigned int j;
|
||||
|
||||
extent = priv_data->vh->allocation_file.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),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_ALLOC,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->extents_file.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),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_EXT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->catalog_file.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),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->attributes_file.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),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_ATTR,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->startup_file.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),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_START,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
uint16_t catalog_pos;
|
||||
|
||||
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;
|
||||
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
catalog_pos = PED_BE16_TO_CPU(value);
|
||||
catalog_key = (HfsPCatalogKey*)(node + catalog_pos);
|
||||
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 ((catalog_pos < 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;
|
||||
}
|
||||
|
||||
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;
|
||||
uint16_t extent_pos;
|
||||
|
||||
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;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
extent_pos = PED_BE16_TO_CPU(value);
|
||||
extent_key = (HfsPExtentKey*)(node + extent_pos);
|
||||
extent = (HfsPExtDescriptor*)
|
||||
(((uint8_t*)extent_key) + sizeof (HfsPExtentKey));
|
||||
/* check for obvious error in FS */
|
||||
if ((extent_pos < 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;
|
||||
}
|
||||
|
||||
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;
|
||||
uint16_t generic_pos;
|
||||
|
||||
/* 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;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
generic_pos = PED_BE16_TO_CPU(value);
|
||||
generic_key = (HfsPPrivateGenericKey*)(node + generic_pos);
|
||||
skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length)
|
||||
+ 1 ) & ~1;
|
||||
fork_ext_data = (HfsPForkDataAttr*)(node+generic_pos+skip);
|
||||
/* check for obvious error in FS */
|
||||
if ((generic_pos < 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 HfsCPrivateCache*
|
||||
hfsplus_cache_extents(PedFileSystem* fs, PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsCPrivateCache* ret;
|
||||
unsigned int file_number, block_number;
|
||||
|
||||
file_number = PED_BE32_TO_CPU(priv_data->vh->file_count);
|
||||
block_number = PED_BE32_TO_CPU(priv_data->vh->total_blocks);
|
||||
ret = hfsc_new_cache(block_number, file_number);
|
||||
if (!ret) return NULL;
|
||||
|
||||
if (!hfsplus_cache_from_vh(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_catalog(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_extent(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_attributes(ret, fs, timer)) {
|
||||
ped_exception_throw(
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not cache the file system in memory."));
|
||||
hfsc_delete_cache(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function moves file's data to compact used and free space,
|
||||
starting at fblock block */
|
||||
/* return 0 on error */
|
||||
int
|
||||
hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free)
|
||||
{
|
||||
PedSector bytes_buff;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPVolumeHeader* vh = priv_data->vh;
|
||||
HfsCPrivateCache* cache;
|
||||
unsigned int to_fblock = fblock;
|
||||
unsigned int start = fblock;
|
||||
unsigned int divisor = PED_BE32_TO_CPU (vh->total_blocks)
|
||||
+ 1 - start - to_free;
|
||||
int ret;
|
||||
|
||||
PED_ASSERT (!hfsp_block);
|
||||
|
||||
cache = hfsplus_cache_extents (fs, timer);
|
||||
if (!cache)
|
||||
return 0;
|
||||
|
||||
/* Calculate the size of the copy buffer :
|
||||
* Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
|
||||
* takes the maximum number of HFS blocks so that the buffer
|
||||
* will remain smaller than or equal to BYTES_MAX_BUFF, with
|
||||
* a minimum of 1 HFS block */
|
||||
bytes_buff = PED_BE32_TO_CPU (priv_data->vh->block_size)
|
||||
* (PedSector) BLOCK_MAX_BUFF;
|
||||
if (bytes_buff > BYTES_MAX_BUFF) {
|
||||
hfsp_block_count = BYTES_MAX_BUFF
|
||||
/ PED_BE32_TO_CPU (priv_data->vh->block_size);
|
||||
if (!hfsp_block_count)
|
||||
hfsp_block_count = 1;
|
||||
bytes_buff = (PedSector) hfsp_block_count
|
||||
* PED_BE32_TO_CPU (priv_data->vh->block_size);
|
||||
} else
|
||||
hfsp_block_count = BLOCK_MAX_BUFF;
|
||||
|
||||
/* If the cache code requests more space, give it to him */
|
||||
if (bytes_buff < hfsc_cache_needed_buffer (cache))
|
||||
bytes_buff = hfsc_cache_needed_buffer (cache);
|
||||
|
||||
hfsp_block = (uint8_t*) ped_malloc (bytes_buff);
|
||||
if (!hfsp_block)
|
||||
goto error_cache;
|
||||
|
||||
if (!hfsplus_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks list could not be loaded."));
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
while ( fblock < ( priv_data->plus_geom->length - 2 )
|
||||
/ ( PED_BE32_TO_CPU (vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT ) ) {
|
||||
if (TST_BLOC_OCCUPATION (priv_data->alloc_map, fblock)
|
||||
&& (!hfsplus_is_bad_block (fs, fblock))) {
|
||||
if (!(ret = hfsplus_move_extent_starting_at (fs,
|
||||
&fblock, &to_fblock, cache)))
|
||||
to_fblock = ++fblock;
|
||||
else if (ret == -1) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("An error occurred during extent "
|
||||
"relocation."));
|
||||
goto error_alloc;
|
||||
}
|
||||
} else {
|
||||
fblock++;
|
||||
}
|
||||
|
||||
ped_timer_update(timer, (float)(to_fblock - start) / divisor);
|
||||
}
|
||||
|
||||
free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
|
||||
hfsc_delete_cache (cache);
|
||||
return 1;
|
||||
|
||||
error_alloc:
|
||||
free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
|
||||
error_cache:
|
||||
hfsc_delete_cache (cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _RELOC_PLUS_H
|
||||
#define _RELOC_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsplus_update_vh (PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free);
|
||||
|
||||
|
||||
#endif /* _RELOC_PLUS_H */
|
||||
Reference in New Issue
Block a user