pmt: initial 3.0.2 update

This commit is contained in:
2024-12-14 10:25:23 +03:00
parent 686ef38598
commit 7f8090bb1f
1292 changed files with 500876 additions and 2823 deletions

View File

@@ -0,0 +1,88 @@
/*
interface.c -- parted support amiga file systems
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 <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
extern PedFileSystemType _affs0_type;
extern PedFileSystemType _affs1_type;
extern PedFileSystemType _affs2_type;
extern PedFileSystemType _affs3_type;
extern PedFileSystemType _affs4_type;
extern PedFileSystemType _affs5_type;
extern PedFileSystemType _affs6_type;
extern PedFileSystemType _affs7_type;
extern PedFileSystemType _amufs_type;
extern PedFileSystemType _amufs0_type;
extern PedFileSystemType _amufs1_type;
extern PedFileSystemType _amufs2_type;
extern PedFileSystemType _amufs3_type;
extern PedFileSystemType _amufs4_type;
extern PedFileSystemType _amufs5_type;
extern PedFileSystemType _asfs_type;
extern PedFileSystemType _apfs1_type;
extern PedFileSystemType _apfs2_type;
void ped_file_system_amiga_init ()
{
ped_file_system_type_register (&_affs0_type);
ped_file_system_type_register (&_affs1_type);
ped_file_system_type_register (&_affs2_type);
ped_file_system_type_register (&_affs3_type);
ped_file_system_type_register (&_affs4_type);
ped_file_system_type_register (&_affs5_type);
ped_file_system_type_register (&_affs6_type);
ped_file_system_type_register (&_affs7_type);
ped_file_system_type_register (&_amufs_type);
ped_file_system_type_register (&_amufs0_type);
ped_file_system_type_register (&_amufs1_type);
ped_file_system_type_register (&_amufs2_type);
ped_file_system_type_register (&_amufs3_type);
ped_file_system_type_register (&_amufs4_type);
ped_file_system_type_register (&_amufs5_type);
ped_file_system_type_register (&_asfs_type);
ped_file_system_type_register (&_apfs1_type);
ped_file_system_type_register (&_apfs2_type);
}
void ped_file_system_amiga_done ()
{
ped_file_system_type_unregister (&_affs0_type);
ped_file_system_type_unregister (&_affs1_type);
ped_file_system_type_unregister (&_affs2_type);
ped_file_system_type_unregister (&_affs3_type);
ped_file_system_type_unregister (&_affs4_type);
ped_file_system_type_unregister (&_affs5_type);
ped_file_system_type_unregister (&_affs6_type);
ped_file_system_type_unregister (&_affs7_type);
ped_file_system_type_unregister (&_amufs_type);
ped_file_system_type_unregister (&_amufs0_type);
ped_file_system_type_unregister (&_amufs1_type);
ped_file_system_type_unregister (&_amufs2_type);
ped_file_system_type_unregister (&_amufs3_type);
ped_file_system_type_unregister (&_amufs4_type);
ped_file_system_type_unregister (&_amufs5_type);
ped_file_system_type_unregister (&_asfs_type);
ped_file_system_type_unregister (&_apfs1_type);
ped_file_system_type_unregister (&_apfs2_type);
}

View File

@@ -0,0 +1,292 @@
/*
affs.c -- parted support for affs file systems
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 <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#include "amiga.h"
#include "affs.h"
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
static int
_affs_probe_root (uint32_t *block, int blocksize) {
int i;
uint32_t sum;
if (PED_BE32_TO_CPU (block[0]) != 2) return 0;
if (PED_BE32_TO_CPU (block[128*blocksize-1]) != 1) return 0;
for (i = 0, sum = 0; i < 128*blocksize; i++)
sum += PED_BE32_TO_CPU (block[i]);
if (sum) return 0;
return 1;
}
static PedGeometry*
_generic_affs_probe (PedGeometry* geom, uint32_t kind)
{
uint32_t *block;
PedSector root, len, pos;
struct PartitionBlock * part;
int blocksize = 1, reserved = 2;
PED_ASSERT (geom != NULL);
PED_ASSERT (geom->dev != NULL);
if (geom->dev->sector_size != 512)
return NULL;
/* Finds the blocksize and reserved values of the partition block */
if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate partition block\n"), __func__);
goto error_part;
}
if (amiga_find_part(geom, part) != NULL) {
reserved = PED_BE32_TO_CPU (part->de_Reserved);
reserved = reserved == 0 ? 1 : reserved;
blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
* PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
}
free (part);
/* Test boot block */
if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate block\n"), __func__);
goto error_block;
}
if (!ped_device_read (geom->dev, block, geom->start, blocksize)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read boot block %llu\n"), __func__, geom->start);
goto error;
}
if (PED_BE32_TO_CPU (block[0]) != kind) {
goto error;
}
/* Find and test the root block */
len = geom->length / blocksize - reserved;
pos = (len - 1) / 2;
root = geom->start + (pos + reserved) * blocksize;
if (!ped_device_read (geom->dev, block, root, blocksize)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read root block %llu\n"), __func__, root);
goto error;
}
if (_affs_probe_root(block, blocksize) == 1) {
free (block);
return ped_geometry_duplicate (geom);
}
error:
free (block);
error_block:
error_part:
return NULL;
}
static PedGeometry*
_affs0_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5300);
}
static PedGeometry*
_affs1_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5301);
}
static PedGeometry*
_affs2_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5302);
}
static PedGeometry*
_affs3_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5303);
}
static PedGeometry*
_affs4_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5304);
}
static PedGeometry*
_affs5_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5305);
}
static PedGeometry*
_affs6_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5306);
}
static PedGeometry*
_affs7_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x444f5307);
}
static PedGeometry*
_amufs_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754653);
}
static PedGeometry*
_amufs0_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754600);
}
static PedGeometry*
_amufs1_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754601);
}
static PedGeometry*
_amufs2_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754602);
}
static PedGeometry*
_amufs3_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754603);
}
static PedGeometry*
_amufs4_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754604);
}
static PedGeometry*
_amufs5_probe (PedGeometry* geom) {
return _generic_affs_probe (geom, 0x6d754605);
}
static PedFileSystemOps _affs0_ops = {
probe: _affs0_probe,
};
static PedFileSystemOps _affs1_ops = {
probe: _affs1_probe,
};
static PedFileSystemOps _affs2_ops = {
probe: _affs2_probe,
};
static PedFileSystemOps _affs3_ops = {
probe: _affs3_probe,
};
static PedFileSystemOps _affs4_ops = {
probe: _affs4_probe,
};
static PedFileSystemOps _affs5_ops = {
probe: _affs5_probe,
};
static PedFileSystemOps _affs6_ops = {
probe: _affs6_probe,
};
static PedFileSystemOps _affs7_ops = {
probe: _affs7_probe,
};
static PedFileSystemOps _amufs_ops = {
probe: _amufs_probe,
};
static PedFileSystemOps _amufs0_ops = {
probe: _amufs0_probe,
};
static PedFileSystemOps _amufs1_ops = {
probe: _amufs1_probe,
};
static PedFileSystemOps _amufs2_ops = {
probe: _amufs2_probe,
};
static PedFileSystemOps _amufs3_ops = {
probe: _amufs3_probe,
};
static PedFileSystemOps _amufs4_ops = {
probe: _amufs4_probe,
};
static PedFileSystemOps _amufs5_ops = {
probe: _amufs5_probe,
};
PedFileSystemType _affs0_type = {
next: NULL,
ops: &_affs0_ops,
name: "affs0",
};
PedFileSystemType _affs1_type = {
next: NULL,
ops: &_affs1_ops,
name: "affs1",
};
PedFileSystemType _affs2_type = {
next: NULL,
ops: &_affs2_ops,
name: "affs2",
};
PedFileSystemType _affs3_type = {
next: NULL,
ops: &_affs3_ops,
name: "affs3",
};
PedFileSystemType _affs4_type = {
next: NULL,
ops: &_affs4_ops,
name: "affs4",
};
PedFileSystemType _affs5_type = {
next: NULL,
ops: &_affs5_ops,
name: "affs5",
};
PedFileSystemType _affs6_type = {
next: NULL,
ops: &_affs6_ops,
name: "affs6",
};
PedFileSystemType _affs7_type = {
next: NULL,
ops: &_affs7_ops,
name: "affs7",
};
PedFileSystemType _amufs_type = {
next: NULL,
ops: &_amufs_ops,
name: "amufs",
};
PedFileSystemType _amufs0_type = {
next: NULL,
ops: &_amufs0_ops,
name: "amufs0",
};
PedFileSystemType _amufs1_type = {
next: NULL,
ops: &_amufs1_ops,
name: "amufs1",
};
PedFileSystemType _amufs2_type = {
next: NULL,
ops: &_amufs2_ops,
name: "amufs2",
};
PedFileSystemType _amufs3_type = {
next: NULL,
ops: &_amufs3_ops,
name: "amufs3",
};
PedFileSystemType _amufs4_type = {
next: NULL,
ops: &_amufs4_ops,
name: "amufs4",
};
PedFileSystemType _amufs5_type = {
next: NULL,
ops: &_amufs5_ops,
name: "amufs5",
};

View File

@@ -0,0 +1,19 @@
/*
affs.h -- parted suppoer for affs filesystems header files
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/>.
*/

View File

@@ -0,0 +1,351 @@
/*
libparted/fs_amiga - amiga file system support.
Copyright (C) 2000-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/>.
Contributor: Sven Luther <luther@debian.org>
*/
#include <config.h>
#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#include "amiga.h"
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#define IDNAME_RIGIDDISK (uint32_t)0x5244534B /* 'RDSK' */
#define IDNAME_BADBLOCK (uint32_t)0x42414442 /* 'BADB' */
#define IDNAME_PARTITION (uint32_t)0x50415254 /* 'PART' */
#define IDNAME_FILESYSHEADER (uint32_t)0x46534844 /* 'FSHD' */
#define IDNAME_LOADSEG (uint32_t)0x4C534547 /* 'LSEG' */
#define IDNAME_BOOT (uint32_t)0x424f4f54 /* 'BOOT' */
#define IDNAME_FREE (uint32_t)0xffffffff
static const char *
_amiga_block_id (uint32_t id) {
switch (id) {
case IDNAME_RIGIDDISK :
return "RDSK";
case IDNAME_BADBLOCK :
return "BADB";
case IDNAME_PARTITION :
return "PART";
case IDNAME_FILESYSHEADER :
return "FSHD";
case IDNAME_LOADSEG :
return "LSEG";
case IDNAME_BOOT :
return "BOOT";
case IDNAME_FREE :
return "<free>";
default :
return "<unknown>";
}
}
struct AmigaIds *
_amiga_add_id (uint32_t id, struct AmigaIds *ids) {
struct AmigaIds *newid;
if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate id list element\n"), __func__);
return 0;
}
newid->ID = id;
newid->next = ids;
return newid;
}
void
_amiga_free_ids (struct AmigaIds *ids) {
struct AmigaIds *current, *next;
for (current = ids; current != NULL; current = next) {
next = current->next;
free (current);
}
}
int
_amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
struct AmigaIds *current;
for (current = ids; current != NULL; current = current->next) {
if (id == current->ID)
return 1;
}
return 0;
}
#define AMIGA_RDB_NOT_FOUND ((uint32_t)0xffffffff)
struct AmigaBlock {
uint32_t amiga_ID; /* Identifier 32 bit word */
uint32_t amiga_SummedLongss; /* Size of the structure for checksums */
int32_t amiga_ChkSum; /* Checksum of the structure */
};
#define AMIGA(pos) ((struct AmigaBlock *)(pos))
struct RigidDiskBlock {
uint32_t rdb_ID; /* Identifier 32 bit word : 'RDSK' */
uint32_t rdb_SummedLongs; /* Size of the structure for checksums */
int32_t rdb_ChkSum; /* Checksum of the structure */
uint32_t rdb_HostID; /* SCSI Target ID of host, not really used */
uint32_t rdb_BlockBytes; /* Size of disk blocks */
uint32_t rdb_Flags; /* RDB Flags */
/* block list heads */
uint32_t rdb_BadBlockList; /* Bad block list */
uint32_t rdb_PartitionList; /* Partition list */
uint32_t rdb_FileSysHeaderList; /* File system header list */
uint32_t rdb_DriveInit; /* Drive specific init code */
uint32_t rdb_BootBlockList; /* Amiga OS 4 Boot Blocks */
uint32_t rdb_Reserved1[5]; /* Unused word, need to be set to $ffffffff */
/* physical drive characteristics */
uint32_t rdb_Cylinders; /* Number of the cylinders of the drive */
uint32_t rdb_Sectors; /* Number of sectors of the drive */
uint32_t rdb_Heads; /* Number of heads of the drive */
uint32_t rdb_Interleave; /* Interleave */
uint32_t rdb_Park; /* Head parking cylinder */
uint32_t rdb_Reserved2[3]; /* Unused word, need to be set to $ffffffff */
uint32_t rdb_WritePreComp; /* Starting cylinder of write precompensation */
uint32_t rdb_ReducedWrite; /* Starting cylinder of reduced write current */
uint32_t rdb_StepRate; /* Step rate of the drive */
uint32_t rdb_Reserved3[5]; /* Unused word, need to be set to $ffffffff */
/* logical drive characteristics */
uint32_t rdb_RDBBlocksLo; /* low block of range reserved for hardblocks */
uint32_t rdb_RDBBlocksHi; /* high block of range for these hardblocks */
uint32_t rdb_LoCylinder; /* low cylinder of partitionable disk area */
uint32_t rdb_HiCylinder; /* high cylinder of partitionable data area */
uint32_t rdb_CylBlocks; /* number of blocks available per cylinder */
uint32_t rdb_AutoParkSeconds; /* zero for no auto park */
uint32_t rdb_HighRDSKBlock; /* highest block used by RDSK */
/* (not including replacement bad blocks) */
uint32_t rdb_Reserved4;
/* drive identification */
char rdb_DiskVendor[8];
char rdb_DiskProduct[16];
char rdb_DiskRevision[4];
char rdb_ControllerVendor[8];
char rdb_ControllerProduct[16];
char rdb_ControllerRevision[4];
uint32_t rdb_Reserved5[10];
};
#define AMIGA_MAX_PARTITIONS 128
#define RDB_LOCATION_LIMIT 16
#define RDSK(pos) ((struct RigidDiskBlock *)(pos))
static int
_amiga_checksum (struct AmigaBlock *blk) {
uint32_t *rdb = (uint32_t *) blk;
uint32_t sum;
int i, end;
sum = PED_BE32_TO_CPU (rdb[0]);
end = PED_BE32_TO_CPU (rdb[1]);
if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
return sum;
}
static void
_amiga_calculate_checksum (struct AmigaBlock *blk) {
blk->amiga_ChkSum = PED_CPU_TO_BE32(
PED_BE32_TO_CPU(blk->amiga_ChkSum) -
_amiga_checksum((struct AmigaBlock *) blk));
return;
}
static struct AmigaBlock *
_amiga_read_block (PedDevice *dev, struct AmigaBlock *blk, PedSector block, struct AmigaIds *ids) {
if (!ped_device_read (dev, blk, block, 1)) {
switch (ped_exception_throw(PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("%s : Couldn't read block %llu\n"), __func__, block))
{
case PED_EXCEPTION_CANCEL :
case PED_EXCEPTION_UNHANDLED :
default :
return NULL;
}
}
if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
return NULL;
if (_amiga_checksum (blk) != 0) {
switch (ped_exception_throw(PED_EXCEPTION_ERROR,
PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
_("%s : Bad checksum on block %llu of type %s\n"),
__func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID))))
{
case PED_EXCEPTION_CANCEL :
return NULL;
case PED_EXCEPTION_FIX :
_amiga_calculate_checksum(AMIGA(blk));
if (!ped_device_write (dev, blk, block, 1)) {
switch (ped_exception_throw(PED_EXCEPTION_FATAL,
PED_EXCEPTION_CANCEL,
_("%s : Couldn't write block %d\n"), __func__, block))
{
case PED_EXCEPTION_CANCEL :
case PED_EXCEPTION_UNHANDLED :
default :
return NULL;
}
}
/* FALLTHROUGH */
case PED_EXCEPTION_IGNORE :
case PED_EXCEPTION_UNHANDLED :
default :
return blk;
}
}
return blk;
}
static uint32_t
_amiga_find_rdb (PedDevice *dev, struct RigidDiskBlock *rdb) {
int i;
struct AmigaIds *ids;
ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
continue;
}
if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
_amiga_free_ids (ids);
return i;
}
}
_amiga_free_ids (ids);
return AMIGA_RDB_NOT_FOUND;
}
static int
_amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
{
uint32_t i;
for (i = 0; i < max; i++)
if (block == blocklist[i]) {
/* We are looping, let's stop. */
return 1;
}
blocklist[max] = block;
return 0;
}
/* We have already allocated a rdb, we are now reading it from the disk */
struct PartitionBlock *
amiga_find_part (PedGeometry *geom, struct PartitionBlock *part)
{
struct RigidDiskBlock *rdb;
uint32_t partblock;
uint32_t partlist[AMIGA_MAX_PARTITIONS];
int i;
PED_ASSERT(geom!= NULL);
PED_ASSERT(geom->dev!= NULL);
if (!(rdb = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
switch (ped_exception_throw(PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate disk_specific rdb block\n"), __func__))
{
case PED_EXCEPTION_CANCEL :
case PED_EXCEPTION_UNHANDLED :
default :
return NULL;
}
}
if (_amiga_find_rdb (geom->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
switch (ped_exception_throw(PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("%s : Didn't find rdb block, should never happen\n"), __func__))
{
case PED_EXCEPTION_CANCEL :
case PED_EXCEPTION_UNHANDLED :
default :
free(rdb);
return NULL;
}
}
/* We initialize the hardblock free list to detect loops */
for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = IDNAME_FREE;
for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
i < AMIGA_MAX_PARTITIONS && partblock != IDNAME_FREE;
i++, partblock = PED_BE32_TO_CPU(part->pb_Next))
{
PedSector start, end;
PedSector cylblocks;
/* Let's look for loops in the partition table */
if (_amiga_loop_check(partblock, partlist, i)) {
free (rdb);
return NULL;
}
/* Let's read a partition block to get its geometry*/
if (!ped_device_read (geom->dev, part, (PedSector)partblock, 1)) {
switch (ped_exception_throw(PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("%s : Failed to read partition block %llu\n"),
__func__, (PedSector)partblock))
{
case PED_EXCEPTION_CANCEL :
case PED_EXCEPTION_UNHANDLED :
default :
free(rdb);
return NULL;
}
}
/* Current block is not a Partition Block */
if (part->pb_ID != IDNAME_PARTITION) {
free (rdb);
return NULL;
}
/* Calculate the geometry of the partition */
cylblocks = ((PedSector) PED_BE32_TO_CPU (part->de_Surfaces)) *
((PedSector) PED_BE32_TO_CPU (part->de_BlocksPerTrack));
start = ((PedSector) PED_BE32_TO_CPU (part->de_LowCyl)) * cylblocks;
end = ((((PedSector) PED_BE32_TO_CPU (part->de_HighCyl))+1) * (cylblocks))-1;
/* And check if it is the one we are searching for */
if (start == geom->start && end == geom->end) {
free (rdb);
return part;
}
}
free (rdb);
return NULL;
}

View File

@@ -0,0 +1,70 @@
/*
util.h -- amiga partition table headers.
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/>.
*/
struct PartitionBlock {
uint32_t pb_ID; /* Identifier 32 bit word : 'PART' */
uint32_t pb_SummedLongs; /* Size of the structure for checksums */
int32_t pb_ChkSum; /* Checksum of the structure */
uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
uint32_t pb_Next; /* Block number of the next PartitionBlock */
uint32_t pb_Flags; /* Part Flags (NOMOUNT and BOOTABLE) */
uint32_t pb_Reserved1[2];
uint32_t pb_DevFlags; /* Preferred flags for OpenDevice */
uint8_t pb_DriveName[32]; /* Preferred DOS device name: BSTR form */
uint32_t pb_Reserved2[15];
uint32_t de_TableSize; /* Size of Environment vector */
uint32_t de_SizeBlock; /* Size of the blocks in 32 bit words, usually 128 */
uint32_t de_SecOrg; /* Not used; must be 0 */
uint32_t de_Surfaces; /* Number of heads (surfaces) */
uint32_t de_SectorPerBlock; /* Disk sectors per block, used with SizeBlock, usually 1 */
uint32_t de_BlocksPerTrack; /* Blocks per track. drive specific */
uint32_t de_Reserved; /* DOS reserved blocks at start of partition. */
uint32_t de_PreAlloc; /* DOS reserved blocks at end of partition */
uint32_t de_Interleave; /* Not used, usually 0 */
uint32_t de_LowCyl; /* First cylinder of the partition */
uint32_t de_HighCyl; /* Last cylinder of the partition */
uint32_t de_NumBuffers; /* Initial # DOS of buffers. */
uint32_t de_BufMemType; /* Type of mem to allocate for buffers */
uint32_t de_MaxTransfer; /* Max number of bytes to transfer at a time */
uint32_t de_Mask; /* Address Mask to block out certain memory */
int32_t de_BootPri; /* Boot priority for autoboot */
uint32_t de_DosType; /* Dostype of the file system */
uint32_t de_Baud; /* Baud rate for serial handler */
uint32_t de_Control; /* Control word for handler/filesystem */
uint32_t de_BootBlocks; /* Number of blocks containing boot code */
uint32_t pb_EReserved[12];
};
#define PART(pos) ((struct PartitionBlock *)(pos))
#define PBFB_BOOTABLE 0 /* this partition is intended to be bootable */
#define PBFF_BOOTABLE 1L /* (expected directories and files exist) */
#define PBFB_NOMOUNT 1 /* do not mount this partition (e.g. manually */
#define PBFF_NOMOUNT 2L /* mounted, but space reserved here) */
struct PartitionBlock * amiga_find_part (PedGeometry *geom, struct PartitionBlock *part);
struct AmigaIds {
uint32_t ID;
struct AmigaIds *next;
};
struct AmigaIds * _amiga_add_id (uint32_t id, struct AmigaIds *ids);
void _amiga_free_ids (struct AmigaIds *ids);
int _amiga_id_in_list (uint32_t id, struct AmigaIds *ids) _GL_ATTRIBUTE_PURE;

View File

@@ -0,0 +1,128 @@
/*
apfs.c -- parted support for apfs file systems
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 <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#include "amiga.h"
#include "apfs.h"
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
static int
_apfs_probe_root (uint32_t *block, uint32_t blocksize, uint32_t kind) {
if (PED_BE32_TO_CPU (block[0]) != kind) return 0;
return 1;
}
static PedGeometry*
_generic_apfs_probe (PedGeometry* geom, uint32_t kind)
{
uint32_t *block;
PedSector root;
struct PartitionBlock * part;
uint32_t blocksize = 1, reserved = 2;
PED_ASSERT (geom != NULL);
PED_ASSERT (geom->dev != NULL);
if (geom->dev->sector_size != 512)
return NULL;
/* Finds the blocksize and reserved values of the partition block */
if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate partition block\n"), __func__);
goto error_part;
}
if (amiga_find_part(geom, part) != NULL) {
reserved = PED_BE32_TO_CPU (part->de_Reserved);
blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
* PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
}
free (part);
/* Test boot block */
if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate block\n"), __func__);
goto error_block;
}
if (!ped_device_read (geom->dev, block, geom->start, blocksize)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read boot block %llu\n"), __func__, geom->start);
goto error;
}
if (PED_BE32_TO_CPU (block[0]) != kind) {
goto error;
}
/* Find and test the root block */
root = geom->start+reserved*blocksize;
if (!ped_device_read (geom->dev, block, root, blocksize)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read root block %llu\n"), __func__, root);
goto error;
}
if (_apfs_probe_root(block, blocksize, kind) == 1) {
free(block);
return ped_geometry_duplicate (geom);
}
error:
free (block);
error_block:
error_part:
return NULL;
}
static PedGeometry*
_apfs1_probe (PedGeometry* geom) {
return _generic_apfs_probe (geom, 0x50463101);
}
static PedGeometry*
_apfs2_probe (PedGeometry* geom) {
return _generic_apfs_probe (geom, 0x50463102);
}
static PedFileSystemOps _apfs1_ops = {
probe: _apfs1_probe,
};
static PedFileSystemOps _apfs2_ops = {
probe: _apfs2_probe,
};
PedFileSystemType _apfs1_type = {
next: NULL,
ops: &_apfs1_ops,
name: "apfs1",
};
PedFileSystemType _apfs2_type = {
next: NULL,
ops: &_apfs2_ops,
name: "apfs2",
};

View File

@@ -0,0 +1,18 @@
/*
apfs.h -- parted support for apfs file systems header files
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/>.
*/

View File

@@ -0,0 +1,130 @@
/*
asfs.c -- parted asfs filesystem support
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 <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#include "amiga.h"
#include "asfs.h"
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
static int
_asfs_probe_root (PedGeometry *geom, uint32_t *block, int blocksize, PedSector root) {
int i, sum;
PedSector start, end;
if (PED_BE32_TO_CPU (block[0]) != 0x53465300) return 0;
for (i = 0, sum = 1; i < 128*blocksize; i++) sum += PED_BE32_TO_CPU (block[i]);
if (sum != 0) return 0;
if (PED_BE32_TO_CPU (block[2]) * blocksize + geom->start != root) {
return 0;
}
start = ((((PedSector) PED_BE32_TO_CPU (block[8])) << 32)
+ (PedSector) PED_BE32_TO_CPU (block[9])) / 512;
end = (((((PedSector) PED_BE32_TO_CPU (block[10])) << 32)
+ (PedSector) PED_BE32_TO_CPU (block[11])) / 512) - 1;
if (start != geom->start || end != geom->end) return 0;
return 1;
}
static PedGeometry*
_asfs_probe (PedGeometry* geom)
{
uint32_t *block;
struct PartitionBlock * part;
int blocksize = 1;
PedSector root;
int found = 0;
PED_ASSERT (geom != NULL);
PED_ASSERT (geom->dev != NULL);
if (geom->dev->sector_size != 512)
return NULL;
/* Finds the blocksize of the partition block */
if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate partition block\n"), __func__);
goto error_part;
}
if (amiga_find_part(geom, part) != NULL) {
blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
* PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
}
free (part);
/* Test boot block */
if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Failed to allocate block\n"), __func__);
goto error_block;
}
root = geom->start;
if (!ped_device_read (geom->dev, block, root, blocksize)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read root block %llu\n"), __func__, root);
goto error;
}
if (PED_BE32_TO_CPU (block[0]) != 0x53465300) {
goto error;
}
/* Find and test the root blocks */
if (_asfs_probe_root(geom, block, blocksize, root)) {
found++;
}
root = geom->end - blocksize - (geom->length % blocksize) + 1;
if (!ped_device_read (geom->dev, block, root, 1)) {
ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("%s : Couldn't read root block %llu\n"), __func__, root);
goto error;
}
if (_asfs_probe_root(geom, block, blocksize, root)) {
found++;
}
if (found != 0) {
free (block);
return ped_geometry_duplicate (geom);
}
error:
free (block);
error_block:
error_part:
return NULL;
}
static PedFileSystemOps _asfs_ops = {
probe: _asfs_probe,
};
PedFileSystemType _asfs_type = {
next: NULL,
ops: &_asfs_ops,
name: "asfs",
};

View File

@@ -0,0 +1,18 @@
/*
asfs.h -- parted asfs filesystem support header files
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/>.
*/

View File

@@ -0,0 +1,77 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2013-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>
/* Located 64k inside the partition (start of the first btrfs superblock) */
#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
#define BTRFS_CSUM_SIZE 32
#define BTRFS_FSID_SIZE 16
static PedGeometry*
btrfs_probe (PedGeometry* geom)
{
union {
struct {
/* Just enough of the btrfs_super_block to get the magic */
uint8_t csum[BTRFS_CSUM_SIZE];
uint8_t fsid[BTRFS_FSID_SIZE];
uint64_t bytenr;
uint64_t flags;
uint64_t magic;
} sb;
int8_t sector[8192];
} buf;
PedSector offset = (64*1024)/geom->dev->sector_size;
if (geom->length < offset+1)
return 0;
if (!ped_geometry_read (geom, &buf, offset, 1))
return 0;
if (PED_LE64_TO_CPU(buf.sb.magic) == BTRFS_MAGIC) {
return ped_geometry_new (geom->dev, geom->start, geom->length);
}
return NULL;
}
static PedFileSystemOps btrfs_ops = {
probe: btrfs_probe,
};
static PedFileSystemType btrfs_type = {
next: NULL,
ops: &btrfs_ops,
name: "btrfs",
};
void
ped_file_system_btrfs_init ()
{
ped_file_system_type_register (&btrfs_type);
}
void
ped_file_system_btrfs_done ()
{
ped_file_system_type_unregister (&btrfs_type);
}

View File

@@ -0,0 +1,79 @@
/*
ext2.h -- ext2 header
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 _EXT2_H
#define _EXT2_H
#include <parted/parted.h>
#include <parted/debug.h>
#include <sys/types.h>
#include <inttypes.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
typedef u_int32_t blk_t;
#ifdef HAVE_LINUX_EXT2_FS_H__FAILS_TO_COMPILE
#include <linux/ext2_fs.h>
#else
#include "ext2_fs.h"
#endif
struct ext2_fs
{
struct ext2_dev_handle *devhandle;
struct ext2_super_block sb;
struct ext2_group_desc *gd;
struct ext2_buffer_cache *bc;
int metadirty; /* 0:all sb&gd copies clean
1:all sb&gd copies dirty
2:only first sb&gd copy clean */
int dynamic_version;
int sparse; /* sparse superblocks */
int has_journal; /* journal */
int has_internal_journal;
int blocksize;
int logsize;
blk_t adminblocks;
blk_t gdblocks;
blk_t itoffset;
blk_t inodeblocks;
int numgroups;
int r_frac; /* reserved % of blocks */
unsigned char *relocator_pool;
unsigned char *relocator_pool_end;
int opt_debug;
int opt_safe;
int opt_verbose;
void *journal;
};
#endif

View File

@@ -0,0 +1,329 @@
/*
* linux/include/linux/ext2_fs.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* EXT2_*_*() convienience macros added by Andrew Clausen <clausen@gnu.org>
* Copyright (C) 2000, 2009-2014, 2019-2023 Free Software Foundation, Inc.
*/
#ifndef _EXT2_FS_H
#define _EXT2_FS_H
#include <parted/endian.h>
#include <stdint.h>
/*
* The second extended file system constants/structures
*/
#define EXT2_SUPER_MAGIC_CONST 0xEF53
#define EXT2_MIN_BLOCK_SIZE 1024
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
#define EXT2_VALID_FS 0x0001
#define EXT2_ERROR_FS 0x0002
#define EXT2_RESERVED_INODE_COUNT 11
/*
* Codes for operating systems
*/
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
#define EXT2_OS_FREEBSD 3
#define EXT2_OS_LITES 4
/*
* Feature set definitions
*/
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT2_FEATURE_COMPAT_HAS_DIR_INDEX 0x0020
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
/*
* Special inodes numbers
*/
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
/*
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT2_FT_UNKNOWN 0
#define EXT2_FT_REG_FILE 1
#define EXT2_FT_DIR 2
#define EXT2_FT_CHRDEV 3
#define EXT2_FT_BLKDEV 4
#define EXT2_FT_FIFO 5
#define EXT2_FT_SOCK 6
#define EXT2_FT_SYMLINK 7
/*
* Behaviour when detecting errors
*/
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
#define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
struct ext2_dir_entry_2
{
uint32_t inode;
uint16_t rec_len;
uint8_t name_len;
uint8_t file_type;
char name[255];
};
struct ext2_group_desc
{
uint32_t bg_block_bitmap;
uint32_t bg_inode_bitmap;
uint32_t bg_inode_table;
uint16_t bg_free_blocks_count;
uint16_t bg_free_inodes_count;
uint16_t bg_used_dirs_count;
uint16_t bg_pad;
uint32_t bg_reserved[3];
};
struct ext2_inode
{
uint16_t i_mode; /* File mode */
uint16_t i_uid; /* Owner Uid */
uint32_t i_size; /* Size in bytes */
uint32_t i_atime; /* Access time */
uint32_t i_ctime; /* Creation time */
uint32_t i_mtime; /* Modification time */
uint32_t i_dtime; /* Deletion Time */
uint16_t i_gid; /* Group Id */
uint16_t i_links_count; /* Links count */
uint32_t i_blocks; /* Blocks count */
uint32_t i_flags; /* File flags */
union {
struct {
uint32_t l_i_reserved1;
} linux1;
struct {
uint32_t h_i_translator;
} hurd1;
struct {
uint32_t m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
uint32_t i_generation; /* File version (for NFS) */
uint32_t i_file_acl; /* File ACL */
uint32_t i_dir_acl; /* Directory ACL */
uint32_t i_faddr; /* Fragment address */
union {
struct {
uint8_t l_i_frag; /* Fragment number */
uint8_t l_i_fsize; /* Fragment size */
uint16_t i_pad1;
uint32_t l_i_reserved2[2];
} linux2;
struct {
uint8_t h_i_frag; /* Fragment number */
uint8_t h_i_fsize; /* Fragment size */
uint16_t h_i_mode_high;
uint16_t h_i_uid_high;
uint16_t h_i_gid_high;
uint32_t h_i_author;
} hurd2;
struct {
uint8_t m_i_frag; /* Fragment number */
uint8_t m_i_fsize; /* Fragment size */
uint16_t m_pad1;
uint32_t m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
#define i_size_high i_dir_acl
struct __attribute__ ((packed)) ext2_super_block
{
uint32_t s_inodes_count; /* Inodes count */
uint32_t s_blocks_count; /* Blocks count */
uint32_t s_r_blocks_count; /* Reserved blocks count */
uint32_t s_free_blocks_count; /* Free blocks count */
uint32_t s_free_inodes_count; /* Free inodes count */
uint32_t s_first_data_block; /* First Data Block */
uint32_t s_log_block_size; /* Block size */
int32_t s_log_frag_size; /* Fragment size */
uint32_t s_blocks_per_group; /* # Blocks per group */
uint32_t s_frags_per_group; /* # Fragments per group */
uint32_t s_inodes_per_group; /* # Inodes per group */
uint32_t s_mtime; /* Mount time */
uint32_t s_wtime; /* Write time */
uint16_t s_mnt_count; /* Mount count */
int16_t s_max_mnt_count; /* Maximal mount count */
uint16_t s_magic; /* Magic signature */
uint16_t s_state; /* File system state */
uint16_t s_errors; /* Behaviour when detecting errors */
uint16_t s_minor_rev_level; /* minor revision level */
uint32_t s_lastcheck; /* time of last check */
uint32_t s_checkinterval; /* max. time between checks */
uint32_t s_creator_os; /* OS */
uint32_t s_rev_level; /* Revision level */
uint16_t s_def_resuid; /* Default uid for reserved blocks */
uint16_t s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the file system.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
uint32_t s_first_ino; /* First non-reserved inode */
uint16_t s_inode_size; /* size of inode structure */
uint16_t s_block_group_nr; /* block group # of this superblock */
uint32_t s_feature_compat; /* compatible feature set */
uint32_t s_feature_incompat; /* incompatible feature set */
uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
uint8_t s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
uint32_t s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
uint16_t s_padding1;
/*
* Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
*/
uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
uint32_t s_journal_inum; /* inode number of journal file */
uint32_t s_journal_dev; /* device number of journal file */
uint32_t s_last_orphan; /* start of list of inodes to delete */
uint32_t s_reserved[197]; /* Padding to the end of the block */
};
#define EXT2_DIRENT_INODE(dir_ent) (PED_LE32_TO_CPU((dir_ent).inode))
#define EXT2_DIRENT_REC_LEN(dir_ent) (PED_LE16_TO_CPU((dir_ent).rec_len))
#define EXT2_DIRENT_NAME_LEN(dir_ent) ((dir_ent).name_len)
#define EXT2_DIRENT_FILE_TYPE(dir_ent) ((dir_ent).file_type)
#define EXT2_GROUP_BLOCK_BITMAP(gd) (PED_LE32_TO_CPU((gd).bg_block_bitmap))
#define EXT2_GROUP_INODE_BITMAP(gd) (PED_LE32_TO_CPU((gd).bg_inode_bitmap))
#define EXT2_GROUP_INODE_TABLE(gd) (PED_LE32_TO_CPU((gd).bg_inode_table))
#define EXT2_GROUP_FREE_BLOCKS_COUNT(gd) \
(PED_LE16_TO_CPU((gd).bg_free_blocks_count))
#define EXT2_GROUP_FREE_INODES_COUNT(gd) \
(PED_LE16_TO_CPU((gd).bg_free_inodes_count))
#define EXT2_GROUP_USED_DIRS_COUNT(gd) \
(PED_LE16_TO_CPU((gd).bg_used_dirs_count))
#define EXT2_INODE_MODE(inode) (PED_LE16_TO_CPU((inode).i_mode))
#define EXT2_INODE_UID(inode) (PED_LE16_TO_CPU((inode).i_uid))
#define EXT2_INODE_SIZE(inode) \
((uint64_t) PED_LE32_TO_CPU((inode).i_size) \
+ ((uint64_t) PED_LE32_TO_CPU((inode).i_size_high) << 32))
#define EXT2_INODE_ATIME(inode) (PED_LE32_TO_CPU((inode).i_atime))
#define EXT2_INODE_CTIME(inode) (PED_LE32_TO_CPU((inode).i_ctime))
#define EXT2_INODE_MTIME(inode) (PED_LE32_TO_CPU((inode).i_mtime))
#define EXT2_INODE_DTIME(inode) (PED_LE32_TO_CPU((inode).i_dtime))
#define EXT2_INODE_GID(inode) (PED_LE16_TO_CPU((inode).i_gid))
#define EXT2_INODE_LINKS_COUNT(inode) (PED_LE16_TO_CPU((inode).i_links_count))
#define EXT2_INODE_BLOCKS(inode) (PED_LE32_TO_CPU((inode).i_blocks))
#define EXT2_INODE_FLAGS(inode) (PED_LE32_TO_CPU((inode).i_flags))
#define EXT2_INODE_TRANSLATOR(inode) (PED_LE32_TO_CPU((inode).osd1.hurd1.h_i_translator))
#define EXT2_INODE_BLOCK(inode, blk) (PED_LE32_TO_CPU((inode).i_block[blk]))
#define EXT2_SUPER_INODES_COUNT(sb) (PED_LE32_TO_CPU((sb).s_inodes_count))
#define EXT2_SUPER_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_blocks_count))
#define EXT2_SUPER_R_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_r_blocks_count))
#define EXT2_SUPER_FREE_BLOCKS_COUNT(sb) \
(PED_LE32_TO_CPU((sb).s_free_blocks_count))
#define EXT2_SUPER_FREE_INODES_COUNT(sb) \
(PED_LE32_TO_CPU((sb).s_free_inodes_count))
#define EXT2_SUPER_FIRST_DATA_BLOCK(sb) \
(PED_LE32_TO_CPU((sb).s_first_data_block))
#define EXT2_SUPER_LOG_BLOCK_SIZE(sb) (PED_LE32_TO_CPU((sb).s_log_block_size))
#define EXT2_SUPER_LOG_FRAG_SIZE(sb) \
((int32_t) PED_LE32_TO_CPU((sb).s_log_frag_size))
#define EXT2_SUPER_BLOCKS_PER_GROUP(sb) \
(PED_LE32_TO_CPU((sb).s_blocks_per_group))
#define EXT2_SUPER_FRAGS_PER_GROUP(sb) \
(PED_LE32_TO_CPU((sb).s_frags_per_group))
#define EXT2_SUPER_INODES_PER_GROUP(sb) \
(PED_LE32_TO_CPU((sb).s_inodes_per_group))
#define EXT2_SUPER_MTIME(sb) (PED_LE32_TO_CPU((sb).s_mtime))
#define EXT2_SUPER_WTIME(sb) (PED_LE32_TO_CPU((sb).s_wtime))
#define EXT2_SUPER_MNT_COUNT(sb) (PED_LE16_TO_CPU((sb).s_mnt_count))
#define EXT2_SUPER_MAX_MNT_COUNT(sb) \
((int16_t) PED_LE16_TO_CPU((sb).s_max_mnt_count))
#define EXT2_SUPER_MAGIC(sb) (PED_LE16_TO_CPU((sb).s_magic))
#define EXT2_SUPER_STATE(sb) (PED_LE16_TO_CPU((sb).s_state))
#define EXT2_SUPER_ERRORS(sb) (PED_LE16_TO_CPU((sb).s_errors))
#define EXT2_SUPER_MINOR_REV_LEVEL(sb) \
(PED_LE16_TO_CPU((sb).s_minor_rev_level))
#define EXT2_SUPER_LASTCHECK(sb) (PED_LE32_TO_CPU((sb).s_lastcheck))
#define EXT2_SUPER_CHECKINTERVAL(sb) (PED_LE32_TO_CPU((sb).s_checkinterval))
#define EXT2_SUPER_CREATOR_OS(sb) (PED_LE32_TO_CPU((sb).s_creator_os))
#define EXT2_SUPER_REV_LEVEL(sb) (PED_LE32_TO_CPU((sb).s_rev_level))
#define EXT2_SUPER_DEF_RESUID(sb) (PED_LE16_TO_CPU((sb).s_def_resuid))
#define EXT2_SUPER_DEF_RESGID(sb) (PED_LE16_TO_CPU((sb).s_def_resgid))
#define EXT2_SUPER_FIRST_INO(sb) (PED_LE32_TO_CPU((sb).s_first_ino))
#define EXT2_SUPER_INODE_SIZE(sb) (PED_LE16_TO_CPU((sb).s_inode_size))
#define EXT2_SUPER_BLOCK_GROUP_NR(sb) (PED_LE16_TO_CPU((sb).s_block_group_nr))
#define EXT2_SUPER_FEATURE_COMPAT(sb) (PED_LE32_TO_CPU((sb).s_feature_compat))
#define EXT2_SUPER_FEATURE_INCOMPAT(sb) \
(PED_LE32_TO_CPU((sb).s_feature_incompat))
#define EXT2_SUPER_FEATURE_RO_COMPAT(sb) \
(PED_LE32_TO_CPU((sb).s_feature_ro_compat))
#define EXT2_SUPER_UUID(sb) ((sb).s_uuid)
#define EXT2_SUPER_VOLUME_NAME(sb) ((sb).s_volume_name)
#define EXT2_SUPER_LAST_MOUNTED(sb) ((sb).s_last_mounted)
#define EXT2_SUPER_ALGORITHM_USAGE_BITMAP(sb) \
(PED_LE32_TO_CPU((sb).s_algorithm_usage_bitmap))
#define EXT2_SUPER_JOURNAL_UUID(sb) ((sb).s_journal_uuid)
#define EXT2_SUPER_JOURNAL_INUM(sb) (PED_LE32_TO_CPU((sb).s_journal_inum))
#define EXT2_SUPER_JOURNAL_DEV(sb) (PED_LE32_TO_CPU((sb).s_journal_dev))
#define EXT2_SUPER_LAST_ORPHAN(sb) (PED_LE32_TO_CPU((sb).s_last_orphan))
#endif

View File

@@ -0,0 +1,163 @@
/*
interface.c -- parted binding glue to libext2resize
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/>.
*/
/* VERSION: libext2resize 1.1.6 (by Lennert)
* merged 1.1.11 changes (by Andrew)
*/
#include <config.h>
#include <parted/parted.h>
#include "ext2.h"
static PedFileSystemType _ext2_type;
static PedFileSystemType _ext3_type;
struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
static PedGeometry*
_ext2_generic_probe (PedGeometry* geom, int expect_ext_ver)
{
struct ext2_super_block *sb;
const int sectors = (4096 + geom->dev->sector_size - 1) /
geom->dev->sector_size;
uint8_t *buf = alloca (sectors * geom->dev->sector_size);
if (!ped_geometry_read(geom, buf, 0, sectors))
return NULL;
sb = (struct ext2_super_block *)(buf+1024);
if (EXT2_SUPER_MAGIC(*sb) == EXT2_SUPER_MAGIC_CONST) {
PedSector block_size = (EXT2_MIN_BLOCK_SIZE << (EXT2_SUPER_LOG_BLOCK_SIZE(*sb))) / geom->dev->sector_size;
PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(*sb);
PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(*sb);
PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(*sb);
PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(*sb);
int version = EXT2_SUPER_REV_LEVEL(*sb);
int is_ext3 = 0;
int is_ext4 = 0;
is_ext3 = (EXT2_SUPER_FEATURE_COMPAT (*sb)
& EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
if (is_ext3) {
is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
& EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
|| (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
& EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
|| (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
& EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
|| (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
& EXT4_FEATURE_INCOMPAT_EXTENTS)
|| (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
& EXT4_FEATURE_INCOMPAT_64BIT)
|| (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
& EXT4_FEATURE_INCOMPAT_FLEX_BG));
if (is_ext4)
is_ext3 = 0;
}
if (expect_ext_ver == 2 && (is_ext3 || is_ext4))
return NULL;
if (expect_ext_ver == 3 && !is_ext3)
return NULL;
else if (expect_ext_ver == 4 && !is_ext4)
return NULL;
if (version > 0 && group_nr > 0) {
PedSector start;
PedGeometry probe_geom;
start = geom->start
- group_blocks * group_nr
- first_data_block;
if (start < 0)
return NULL;
ped_geometry_init (&probe_geom, geom->dev,
start, block_count * block_size);
return _ext2_generic_probe (&probe_geom,
expect_ext_ver);
} else {
return ped_geometry_new (geom->dev, geom->start,
block_count * block_size);
}
}
return NULL;
}
static PedGeometry*
_ext2_probe (PedGeometry* geom)
{
return _ext2_generic_probe (geom, 2);
}
static PedGeometry*
_ext3_probe (PedGeometry* geom)
{
return _ext2_generic_probe (geom, 3);
}
static PedGeometry*
_ext4_probe (PedGeometry* geom)
{
return _ext2_generic_probe (geom, 4);
}
static PedFileSystemOps _ext2_ops = {
probe: _ext2_probe,
};
static PedFileSystemOps _ext3_ops = {
probe: _ext3_probe,
};
static PedFileSystemOps _ext4_ops = {
probe: _ext4_probe,
};
static PedFileSystemType _ext2_type = {
next: NULL,
ops: &_ext2_ops,
name: "ext2",
};
static PedFileSystemType _ext3_type = {
next: NULL,
ops: &_ext3_ops,
name: "ext3",
};
static PedFileSystemType _ext4_type = {
next: NULL,
ops: &_ext4_ops,
name: "ext4",
};
void ped_file_system_ext2_init ()
{
ped_file_system_type_register (&_ext2_type);
ped_file_system_type_register (&_ext3_type);
ped_file_system_type_register (&_ext4_type);
}
void ped_file_system_ext2_done ()
{
ped_file_system_type_unregister (&_ext2_type);
ped_file_system_type_unregister (&_ext3_type);
ped_file_system_type_unregister (&_ext4_type);
}

View File

@@ -0,0 +1,60 @@
/*
libparted/fs/f2fs - Flash-Friendly File System
Copyright (C) 2020-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 "f2fs.h"
static PedGeometry*
f2fs_probe (PedGeometry* geom)
{
struct f2fs_super_block *sb = alloca(geom->dev->sector_size);
if (!ped_geometry_read (geom, sb, F2FS_SB_OFFSET, 1))
return NULL;
if (PED_LE32_TO_CPU(sb->magic) == F2FS_MAGIC)
return ped_geometry_new (geom->dev, geom->start, geom->length);
return NULL;
}
static PedFileSystemOps f2fs_ops = {
probe: f2fs_probe,
};
static PedFileSystemType f2fs_type = {
next: NULL,
ops: &f2fs_ops,
name: "f2fs",
};
void
ped_file_system_f2fs_init ()
{
ped_file_system_type_register (&f2fs_type);
}
void
ped_file_system_f2fs_done ()
{
ped_file_system_type_unregister (&f2fs_type);
}

View File

@@ -0,0 +1,57 @@
/*
libparted/fs/f2fs - Flash-Friendly File System
Copyright (C) 2020-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 _F2FS_H
#define _F2FS_H
#define F2FS_MAGIC 0xF2F52010
#define F2FS_MAX_VOLUME_NAME 512
#define F2FS_SB_OFFSET 0x02
struct f2fs_super_block {
uint32_t magic; /* Magic Number */
uint16_t major_ver; /* Major Version */
uint16_t minor_ver; /* Minor Version */
uint32_t log_sectorsize; /* log2 sector size in bytes */
uint32_t log_sectors_per_block; /* log2 # of sectors per block */
uint32_t log_blocksize; /* log2 block size in bytes */
uint32_t log_blocks_per_seg; /* log2 # of blocks per segment */
uint32_t segs_per_sec; /* # of segments per section */
uint32_t secs_per_zone; /* # of sections per zone */
uint32_t checksum_offset; /* checksum offset inside super block */
uint64_t block_count; /* total # of user blocks */
uint32_t section_count; /* total # of sections */
uint32_t segment_count; /* total # of segments */
uint32_t segment_count_ckpt; /* # of segments for checkpoint */
uint32_t segment_count_sit; /* # of segments for SIT */
uint32_t segment_count_nat; /* # of segments for NAT */
uint32_t segment_count_ssa; /* # of segments for SSA */
uint32_t segment_count_main; /* # of segments for main area */
uint32_t segment0_blkaddr; /* start block address of segment 0 */
uint32_t cp_blkaddr; /* start block address of checkpoint */
uint32_t sit_blkaddr; /* start block address of SIT */
uint32_t nat_blkaddr; /* start block address of NAT */
uint32_t ssa_blkaddr; /* start block address of SSA */
uint32_t main_blkaddr; /* start block address of main area */
uint32_t root_ino; /* root inode number */
uint32_t node_ino; /* node inode number */
uint32_t meta_ino; /* meta inode number */
uint8_t uuid[16]; /* 128-bit uuid for volume */
uint16_t volume_name[F2FS_MAX_VOLUME_NAME]; /* volume name */
} __attribute__((packed));
#endif

View File

@@ -0,0 +1,271 @@
/*
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;
}
static int
_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;
}
/* 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_IGNORE_CANCEL,
_("The file system's CHS geometry is (%d, %d, %d), "
"which is invalid. The partition table's CHS "
"geometry is (%d, %d, %d)."),
cyl_count, fs_info->heads, fs_info->sectors_per_track,
bios_geom->cylinders, bios_geom->heads,
bios_geom->sectors)) {
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;
}

View File

@@ -0,0 +1,126 @@
/*
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
#define FAT_BOOT_CODE_LENGTH 128
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);
#endif /* PED_FAT_BOOTSECTOR_H */

View File

@@ -0,0 +1,46 @@
/*
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 */

162
jni/parted/libparted/fs/fat/fat.c Executable file
View File

@@ -0,0 +1,162 @@
/*
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 <uuid/uuid.h>
#include "fat.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;
}
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);
}
PedGeometry*
fat_probe (PedGeometry* geom, FatType* fat_type)
{
PedFileSystem* fs;
FatSpecific* fs_info;
PedGeometry* result;
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;
*fat_type = fs_info->fat_type;
result = ped_geometry_new (geom->dev, geom->start,
fs_info->sector_count);
fat_free (fs);
return result;
error_free_fs:
fat_free (fs);
error:
return NULL;
}
PedGeometry*
fat_probe_fat16 (PedGeometry* geom)
{
FatType fat_type;
PedGeometry* probed_geom = fat_probe (geom, &fat_type);
if (probed_geom) {
if (fat_type == FAT_TYPE_FAT16)
return probed_geom;
ped_geometry_destroy (probed_geom);
}
return NULL;
}
PedGeometry*
fat_probe_fat32 (PedGeometry* geom)
{
FatType fat_type;
PedGeometry* probed_geom = fat_probe (geom, &fat_type);
if (probed_geom) {
if (fat_type == FAT_TYPE_FAT32)
return probed_geom;
ped_geometry_destroy (probed_geom);
}
return NULL;
}
static PedFileSystemOps fat16_ops = {
probe: fat_probe_fat16,
};
static PedFileSystemOps fat32_ops = {
probe: fat_probe_fat32,
};
PedFileSystemType fat16_type = {
next: NULL,
ops: &fat16_ops,
name: "fat16",
};
PedFileSystemType fat32_type = {
next: NULL,
ops: &fat32_ops,
name: "fat32",
};
void
ped_file_system_fat_init ()
{
if (sizeof (FatBootSector) != 512) {
ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
_("GNU Parted was miscompiled: the FAT boot sector "
"should be 512 bytes. FAT support will be disabled."));
} else {
ped_file_system_type_register (&fat16_type);
ped_file_system_type_register (&fat32_type);
}
}
void
ped_file_system_fat_done ()
{
ped_file_system_type_unregister (&fat16_type);
ped_file_system_type_unregister (&fat32_type);
}

163
jni/parted/libparted/fs/fat/fat.h Executable file
View File

@@ -0,0 +1,163 @@
/*
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;
#include "bootsector.h"
#include "count.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;
};
typedef struct _FatTable FatTable;
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 int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer);
#endif /* FAT_H_INCLUDED */

92
jni/parted/libparted/fs/hfs/DOC Executable file
View File

@@ -0,0 +1,92 @@
WARNING : Both HFS and HFS+ implementations of Linux 2.4 are buggy, at
least when used before or after this implementation. Some workarounds
are used in this implementation, but there can still be incompatibilities.
Try Linux 2.6 if you want to play with HFS(+) resizing (though some bugs
might also be there in 2.6, there is of course no warranty)
---
Technical doc about Apple HFS and HFS+ file systems is available at :
* For HFS, section "Data Organization on Volumes",
"Chapter 2 - File Manager"
of the book "Inside Macintosh: Files"
http://developer.apple.com/documentation/mac/Files/Files-99.html
* For HFS+, "Technical Note TN1150", "HFS Plus Volume Format"
http://developer.apple.com/technotes/tn/tn1150.html
Some useful HFS precisions concerning alignement, bit ordering, and
order of fields for extent key comparaisons are only in the HFS+ TN
These Apple Creator Codes are reserved for us :
Shnk traP GP16 GnuP PH+x Xpnd Resz GP17 GP18 GP19 GP20
---
* Cache design *
Versions before HFS Patch 15 were very slow when data relocation was needed,
because every extent to relocate involved scanning the whole file system,
looking for a reference to its physical position on the volume (this was a
dummy algorithm, I know :)
HFS Patch 16 introduced a cache that allows to efficiently retrieve the place
of the reference in the file system given the physical position of an extent.
The cache is designed for : - efficiency
- scaling
- simplicity
- avoiding memory allocation while resizing
This cache involves quite big worst case memory consumption, but without it
the time needed to complete the operation in the worst case would be huge
anyway (maybe several years...) so this isn't really an issue. The cache size
is nearly proportional to the number of files you have, or if you have very few
files, to the size of your volume, so worst cases situations occure when you
fill a drive with millions of < 4 ko files :p For this very special usage you
will just need a very special amount of RAM (on typical systems about
(FS size) / 256 )... On a more "normal" volume it's about
(# of files) * 20 bytes. With very few files it's about (FS Size) / 1024 / 256.
At the beginning of the resize process, the cache is filed by scanning the FS.
The position of each extent is cut into 2 parts : high order is used as
an index into a table of pointer to a linked list which contains :
- the next ptr (sizeof struct *)
- the extent start (4 bytes)
- the extent size (4 bytes)
- number of BTree block or 0 if in prim (4 bytes)
- offset of the extent start reference
from the block beginning (2 bytes)
- sectors by BTree block, or
1 for VH/MDB (1 byte)
- FS special file / primary structure
where the extent reference is stored (1 byte)
(3 bits for the extent index, 5 for
the actual ref)
0 : dont exists --- reserved
1 : mdb / vh : catalog ---
2 : mdb / vh : extent ---
3 : vh : attributes X+-
4 : vh : allocation X+-
5 : vh : startup X+-
6 : catalog ---
7 : attributes X+-
8 : extent (nothing to update) ---
9 : extent (update catalog) ---
10 : extent (update extent !?!) --- should not exist
11 : extent (update attributes) X+-
12 : extent (update allocation) X+-
13 : extent (update startup) X+- reserved
14 : vh : journal info block X+J
15 : jib: journal X+J
16 - 31 : ---
mdb : Master Directory Block
vh : Volume Header
X+ : HFSX or HFS+ only
J : Journaled only
Large amount of memory is allocated at once (first enough memory to fit
every files if there isn't any fragmentation +6.25%, then this value / 4,
if this wasn't enough). On a typical FS, the first allocation should be enough.
---

View File

@@ -0,0 +1,115 @@
## modifications dd-mm-yyyy
---------------------- PATCH FOR PARTED 1.6.5 ----------------------------
1 initial revision 07-04-2003
2 one pass resizing, removal of debug info 08-04-2003
3 safe abort if resize failed, code cleanups, timer, 10-04-2003
source file split, won't resize if not unmounted,
only relocate data if needed, minimize disk operations
4 memory leaks removal, code cleanups, resize hfs+ code, 17-04-2003
more checks, minor hfs resize bugfix, probe code
returns real geometry
5 hfs+ resize bugfixes : 19-04-2003
* fragmented fs could be corrupted
* VH wasn't written on error during alloc map writing
* attributes file could be corrupted
6 Use PedSector to be able to use 2To+ HD 23-04-2003
Minor probe bugfix, Cleanups, HFS+ Timer tuning,
7 80 columns indentation 23-04-2003
8 Bugfix free blocks calculation in wrapper
(makes Mac OS boot !) 28-04-2003
---------------------- PATCH FOR PARTED 1.6.6 ----------------------------
9 Don't destroy the file being worked on in case of
interruption of Parted 28-10-2003
---------------------- PATCH FOR PARTED 1.6.10 ---------------------------
10 Regression tests, URL correction, In effect_move_extent :
corrected memory leak & corrected a bug in precondition checks
Added error messages, Check ped_alloc results
Use macro for test / set / clear in the allocation bitmap
Light probe correction, Check return value of get_empty_end
Moved dynamic memory allocation out of effect_move_extent
Check HFS+ version, Set implementation creator code
Check journal absence, Corrected a bug in HFS+ block number
calculation 24-04-2004
--------------------- PATCH FOR PARTED 1.6.11 ----------------------------
11-Some pointer dereference moved after non nul assertion
-Error messages for HFS(+) file IO
-Memory leak correction in hfs(plus)_read_bad_blocks
-Mark out of volume blocks as used
(improve compatibility with broken HFS+ Linux
implementation)
WARNING : this fix is not 100% tn1150 compatible :
"The allocation file may be larger than the minimum
number of bits required for the given volume size.
Any unused bits in the bitmap must be set to _zero_."
Anyway neither is the Linux implementation, nor was my
previous implementations
Maybe I should ask Apple to change the specifications
-HISTORY, DOC and TODO files 29-04-2004
12 Corrected a bug in hfsplus_volume_resize : size of alloc
bitmap could be miscalculated 29-04-2004
--------------------- PATCH FOR PARTED 1.6.12 ----------------------------
13-Finally partial rewrite of *_search_move_*
Easier to maintain and prepare for extent search and
relocation algorithm changes for better ones.
-"An extent has not been relocated!" message now only when
relocation requested
-Slightly better and simpler relocation algorithm
-Update of Makefile.in and Makefile.am in fs_hfs
-Sign correction for some 8bits HFS integers
-Added the option --enable-hfs-extract-fs in 'configure'
-Added every ped_geometry_sync where needed
-Bugfix : "A root node does not need to exist
(if the tree is empty)."
- now handled correctly in btree_search
-Bugfix : failure wasn't detected in some cases
during 2 pass relocation (*_search_move_*)
-Bugfix : The extent key comparaison was done in a wrong order
and a pad field was used during the comparaison
-Bugfix : in hfs_file_find_sector and hfsplus_file_find_sector
the absolute position of a file sector could be
miscalculated in case of fragmentation, resulting
in potential data corruption, or various errors
-Bugfix : The end of the HFS bitmap compatibility block was
miscalculated ( (1<<16)/8 instead of (1<<16) )
in hfs_resize
07-09-2004
--------------------- PATCH FOR PARTED 1.6.14 ----------------------------
14 Port of Patch 13 for Parted 1.6.14 (update timestamps)
08-09-2004
--------------------- PATCH FOR PARTED 1.6.15 ----------------------------
15-hfsplus_open : added a warning message if the "attributes"
special file exists
-hfsplus_open : added a test to check if the "allocation"
special file has been correctly opened
-optimisation of hfs+ block access : don't recalculate
the address of each sector, and avoid checking the cache if
obviously not useful
( hfsplus_file_read && hfsplus_file_write
&& hfsplus_file_find_extent && hfs_file_find_sector)
-cut the "hfs.c" file in several parts
-Bugfix: in hfsplus_do_move_primary, hfs_effect_move_extent
was called instead of hfsplus_effect_move_extent !!!
This could not produce data corruption, because of a welcome
ASSERT in *_effect_move_extent that would detect the bug :)
-Bugfix: in hfs_effect_move_extent, do
PED_ASSERT(*ptr_to_fblock <= *ptr_fblock, return -1);
instead of
PED_ASSERT(*ptr_to_fblock < *ptr_fblock, return -1);
and added that assertion to hfsplus_effect_move_extent
-Bugfix: bugs introduced in rewrite of hfsplus_file_read
&& hfsplus_file_write : last sector was incorrectly detected
as out of file.
-Cache the extent references (speed improvement ?)
23-09-2004
16-Bugfix: in hfsplus_do_move (reloc_plus.c), case CR_BTREE_EXT_ATTR
incorrectly updated the cached part of priv_data->catalog_file
instead of priv_data->attributes_file
-Bugfix: in hfs_read_bad_blocks && hfsplus_read_bad_blocks,
now generate an error if file_ID or type mismatch after the
first pass
Also check return value of ped_malloc
-Bugfix: in hfsplus_btree_search, check return value of ped_malloc
29-09-2004
---------------- INTEGRATION IN PARTED 1.6.22 (cvs) ----------------------
Futur changes will be described in ../../ChangeLog
02-02-2005

View File

@@ -0,0 +1,27 @@
--- TODO ---
* Continue to write regressions tests and try on 2.6 kernel -- (high)
* Fix timer progression calculation, according to the new
caching code -- (high)
* write doc, website, ... -- (high)
* Check block allocation in linux 2.4 and remove
compatibility code if possible -- (high)
* In hfs(plus)_btree_search , use a static variable to detect
illegal recursion and abort in that case. (find the right
number of recursion before reporting bug) -- easy -- (medium)
* Finish the HFS Extractor -- (medium)
(add mdb & vh extraction, and maybe journal)
* Write code to allow enlarging and moving HFS[+x] -- (low)
* Use a bitmap to internaly store the bad blocks -- (low)
* Less bitmap saves ? -- (low)
* Continue to change the relocation algorithm
for a better one :) -- (low)
--- NOT todo ---
* debug HFS(+) Linux implementation (block allocation for HFS+,
hard and sym links for HFS+, filename length for HFS, ...) -- (dont)
/// Linux 2.6 contains HFS(+) implementations with less bugs
/// Linux 2.4 should not be used anymore to access HFS(+)

View File

@@ -0,0 +1,92 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2000, 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/>.
*/
/*
Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
Report bug to <bug-parted@gnu.org>
*/
#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"
uint8_t* hfs_block = NULL;
uint8_t* hfsp_block = NULL;
unsigned hfs_block_count;
unsigned hfsp_block_count;
static PedFileSystemOps hfs_ops = {
probe: hfs_probe,
};
static PedFileSystemOps hfsplus_ops = {
probe: hfsplus_probe,
};
static PedFileSystemOps hfsx_ops = {
probe: hfsx_probe,
};
static PedFileSystemType hfs_type = {
next: NULL,
ops: &hfs_ops,
name: "hfs",
};
static PedFileSystemType hfsplus_type = {
next: NULL,
ops: &hfsplus_ops,
name: "hfs+",
};
static PedFileSystemType hfsx_type = {
next: NULL,
ops: &hfsx_ops,
name: "hfsx",
};
void
ped_file_system_hfs_init ()
{
ped_file_system_type_register (&hfs_type);
ped_file_system_type_register (&hfsplus_type);
ped_file_system_type_register (&hfsx_type);
}
void
ped_file_system_hfs_done ()
{
ped_file_system_type_unregister (&hfs_type);
ped_file_system_type_unregister (&hfsplus_type);
ped_file_system_type_unregister (&hfsx_type);
}

648
jni/parted/libparted/fs/hfs/hfs.h Executable file
View File

@@ -0,0 +1,648 @@
/*
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 */

View File

@@ -0,0 +1,238 @@
/*
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)
{
HfsMasterDirectoryBlock *mdb;
PedGeometry* geom_ret;
PedSector search, max;
PED_ASSERT (geom != NULL);
PED_ASSERT (hfsc_can_use_geom (geom));
const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
geom->dev->sector_size;
char * buf = alloca (sectors * geom->dev->sector_size);
mdb = (HfsMasterDirectoryBlock *)(buf+1024);
/* is 5 an intelligent value ? */
if ((geom->length < 5)
|| (!ped_geometry_read (geom, buf, 0, sectors))
|| (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) / geom->dev->sector_size)));
max = search + (PED_BE32_TO_CPU (mdb->block_size) / geom->dev->sector_size);
if ((search < 0)
|| !(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;
}
PedGeometry*
hfsplus_probe (PedGeometry* geom)
{
PedGeometry* geom_ret;
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
PED_ASSERT (geom != NULL);
if (!hfsc_can_use_geom (geom))
return NULL;
if ((geom_ret = hfs_and_wrapper_probe(geom))) {
/* HFS+ is embedded in an HFS volume ? */
HfsMasterDirectoryBlock *mdb;
mdb = (HfsMasterDirectoryBlock *) buf;
if (!ped_geometry_read (geom, buf, 2, 1)
|| (mdb->old_new.embedded.signature
!= PED_CPU_TO_BE16 (HFSP_SIGNATURE))) {
ped_geometry_destroy (geom_ret);
return NULL;
} else
return geom_ret;
} else {
/* This is a standalone HFS+ volume ? */
PedSector search, max;
HfsPVolumeHeader *vh;
vh = (HfsPVolumeHeader *) buf;
if ((geom->length < 5)
|| !ped_geometry_read (geom, buf, 2, 1)
|| (vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)))
return NULL;
/* Correct range is indeed [ blocks*sz-2;(blocs+1)*sz-2 ( */
/* But previous versions of my implementation used to */
/* assume range is [(blocks-1)*sz-1;(blocks*sz) ( */
/* (blocks-1)*sz-1 has to be scanned last, because */
/* it can belong to a regular file */
max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
* ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
- 2;
search = max - 2 * ( PED_BE32_TO_CPU (vh->block_size)
/ PED_SECTOR_SIZE_DEFAULT ) + 2;
if ((search < 0)
|| !(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 (vh->signature == PED_CPU_TO_BE16 (HFSP_SIGNATURE))
return geom_ret;
}
search = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) - 1)
* ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
- 1;
if ((search < 0)
|| !ped_geometry_set (geom_ret, geom_ret->start,
search + 2)
|| !ped_geometry_read (geom_ret, buf, search, 1)
|| vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)) {
ped_geometry_destroy (geom_ret);
return NULL;
} else
return geom_ret;
}
}
PedGeometry*
hfs_probe (PedGeometry* geom)
{
PedGeometry* geom_base;
PedGeometry* geom_plus = NULL;
PED_ASSERT (geom != NULL);
if (!hfsc_can_use_geom (geom))
return NULL;
if ((geom_base = hfs_and_wrapper_probe(geom))
&& (!(geom_plus = hfsplus_probe(geom_base))))
return geom_base;
else {
if (geom_base) ped_geometry_destroy (geom_base);
if (geom_plus) ped_geometry_destroy (geom_plus);
return NULL;
}
}
PedGeometry*
hfsx_probe (PedGeometry* geom)
{
PedGeometry* geom_ret;
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
PedSector search, max;
HfsPVolumeHeader *vh = (HfsPVolumeHeader *) buf;
PED_ASSERT (geom != NULL);
if (!hfsc_can_use_geom (geom))
return NULL;
if ((geom->length < 5)
|| !ped_geometry_read (geom, buf, 2, 1)
|| (vh->signature != PED_CPU_TO_BE16 (HFSX_SIGNATURE)))
return NULL;
/* unlike the hfs+ code, which should be kept compatible
with my old previous implementations, we only care here
about legal alternate VH positions, like TN1150 describes them */
max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
* ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
- 2;
search = max - ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT );
if ((search < 0)
|| !(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 (vh->signature == PED_CPU_TO_BE16 (HFSX_SIGNATURE))
return geom_ret;
}
ped_geometry_destroy (geom_ret);
return NULL;
}

View File

@@ -0,0 +1,44 @@
/*
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);
PedGeometry*
hfsplus_probe (PedGeometry* geom);
PedGeometry*
hfs_probe (PedGeometry* geom);
PedGeometry*
hfsx_probe (PedGeometry* geom);
#endif /* _PROBE_H */

View File

@@ -0,0 +1,80 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 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 <parted/parted.h>
#include <parted/endian.h>
#define _JFS_UTILITY
#include "jfs_types.h"
#include "jfs_superblock.h"
#define JFS_SUPER_OFFSET 32768
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
static PedGeometry*
jfs_probe (PedGeometry* geom)
{
struct superblock *sb = alloca (geom->dev->sector_size);
if (geom->length * geom->dev->sector_size < JFS_SUPER_OFFSET)
return NULL;
if (!ped_geometry_read (geom, sb, JFS_SUPER_OFFSET / geom->dev->sector_size, 1))
return NULL;
if (strncmp (sb->s_magic, JFS_MAGIC, 4) == 0) {
PedSector block_size = PED_LE32_TO_CPU (sb->s_pbsize);
PedSector block_count = PED_LE64_TO_CPU (sb->s_size);
/* apparently jfs is retarded and always claims 512 byte
sectors, with the block count as a multiple of that */
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count / geom->dev->sector_size);
} else {
return NULL;
}
}
static PedFileSystemOps jfs_ops = {
probe: jfs_probe,
};
static PedFileSystemType jfs_type = {
next: NULL,
ops: &jfs_ops,
name: "jfs",
};
void
ped_file_system_jfs_init ()
{
ped_file_system_type_register (&jfs_type);
}
void
ped_file_system_jfs_done ()
{
ped_file_system_type_unregister (&jfs_type);
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) International Business Machines Corp., 2000
*
* 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 _H_JFS_SUPERBLOCK
#define _H_JFS_SUPERBLOCK
/*
* jfs_superblock.h
*/
/*
* make the magic number something a human could read
*/
#define JFS_MAGIC "JFS1" /* Magic word: Version 1 */
#define JFS_VERSION 1 /* Version number: Version 1 */
#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
/*
* aggregate superblock
*
* The name superblock is too close to super_block, so the name has been
* changed to jfs_superblock. The utilities are still using the old name.
*/
#ifdef _JFS_UTILITY
struct superblock
#else
struct jfs_superblock
#endif
{
char s_magic[4]; /* 4: magic number */
u32 s_version; /* 4: version number */
s64 s_size; /* 8: aggregate size in hardware/LVM blocks;
* VFS: number of blocks
*/
s32 s_bsize; /* 4: aggregate block size in bytes;
* VFS: fragment size
*/
s16 s_l2bsize; /* 2: log2 of s_bsize */
s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
s32 s_pbsize; /* 4: hardware/LVM block size in bytes */
s16 s_l2pbsize; /* 2: log2 of s_pbsize */
s16 pad; /* 2: padding necessary for alignment */
u32 s_agsize; /* 4: allocation group size in aggr. blocks */
u32 s_flag; /* 4: aggregate attributes:
* see jfs_filsys.h
*/
u32 s_state; /* 4: mount/unmount/recovery state:
* see jfs_filsys.h
*/
s32 s_compress; /* 4: > 0 if data compression */
pxd_t s_ait2; /* 8: first extent of secondary
* aggregate inode table
*/
pxd_t s_aim2; /* 8: first extent of secondary
* aggregate inode map
*/
u32 s_logdev; /* 4: device address of log */
s32 s_logserial; /* 4: log serial number at aggregate mount */
pxd_t s_logpxd; /* 8: inline log extent */
pxd_t s_fsckpxd; /* 8: inline fsck work space extent */
struct timestruc_t s_time; /* 8: time last updated */
s32 s_fsckloglen; /* 4: Number of file system blocks reserved for
* the fsck service log.
* N.B. These blocks are divided among the
* versions kept. This is not a per
* version size.
* N.B. These blocks are included in the
* length field of s_fsckpxd.
*/
s8 s_fscklog; /* 1: which fsck service log is most recent
* 0 => no service log data yet
* 1 => the first one
* 2 => the 2nd one
*/
char s_fpack[11]; /* 11: file system volume name
* N.B. This must be 11 bytes to
* conform with the OS/2 BootSector
* requirements
*/
/* extendfs() parameter under s_state & FM_EXTENDFS */
s64 s_xsize; /* 8: extendfs s_size */
pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */
pxd_t s_xlogpxd; /* 8: extendfs logpxd */
/* - 128 byte boundary - */
/*
* DFS VFS support (preliminary)
*/
char s_attach; /* 1: VFS: flag: set when aggregate is attached
*/
u8 rsrvd4[7]; /* 7: reserved - set to 0 */
u64 totalUsable; /* 8: VFS: total of 1K blocks which are
* available to "normal" (non-root) users.
*/
u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for
* exclusive use of root. This value can be 0,
* and if it is then totalUsable will be equal
* to # of blocks in aggregate. I believe this
* means that minFree + totalUsable = # blocks.
* In that case, we don't need to store both
* totalUsable and minFree since we can compute
* one from the other. I would guess minFree
* would be the one we should store, and
* totalUsable would be the one we should
* compute. (Just a guess...)
*/
u64 realFree; /* 8: VFS: # of free 1K blocks can be used by
* "normal" users. It may be this is something
* we should compute when asked for instead of
* storing in the superblock. I don't know how
* often this information is needed.
*/
/*
* graffiti area
*/
};
#endif /*_H_JFS_SUPERBLOCK */

View File

@@ -0,0 +1,527 @@
/*
* Copyright (c) International Business Machines Corp., 2000
*
* 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 _H_JFS_TYPES
#define _H_JFS_TYPES
/*
* jfs_types.h:
*
* basic type/utility definitions
*
* note: this header file must be the 1st include file
* of JFS include list in all JFS .c file.
*/
#ifdef _JFS_UTILITY
/* this is defined in asm/byteorder.h for i386, but
* is NOT defined in asm/byteorder.h for ppc (non-kernel).
* Until that is changed, we'll define it here. */
#define __BYTEORDER_HAS_U64__
#include <sys/types.h>
//#include <asm/byteorder.h>
typedef unsigned short UniChar;
#else
#include <linux/types.h>
#include <linux/jfs_fs.h>
#include <linux/nls.h>
#ifndef _ULS_UNICHAR_DEFINED
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0))
typedef wchar_t UniChar;
#else
typedef unsigned short UniChar;
#endif
#define _ULS_UNICHAR_DEFINED
#endif
#endif
/* #include "endian24.h" */
/*
* primitive types
*/
#ifdef _JFS_UTILITY
typedef int8_t s8;
typedef uint8_t u8;
typedef int16_t s16;
typedef uint16_t u16;
typedef int32_t s32;
typedef uint32_t u32;
typedef int64_t s64;
typedef uint64_t u64;
#ifndef _UINT_TYPES
/* unicode includes also define these */
typedef u16 uint16;
typedef u32 uint32;
#define _UINT_TYPES
#endif
typedef s8 int8;
typedef u8 uint8;
typedef s16 int16;
typedef s32 int32;
typedef s64 int64;
typedef u64 uint64;
#endif /* _JFS_UTILITY */
/*
* Holdovers from OS/2. Try to get away from using these altogether.
*/
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
typedef void *PVOID;
#define MAXPATHLEN 255
/*
* Almost identical to Linux's timespec, but not quite
*/
struct timestruc_t {
u32 tv_sec;
u32 tv_nsec;
};
/*
* handy
*/
#undef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#undef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#undef ROUNDUP
#define ROUNDUP(x, y) ( ((x) + ((y) - 1)) & ~((y) - 1) )
#define LEFTMOSTONE 0x80000000
#define HIGHORDER 0x80000000u /* high order bit on */
#define ONES 0xffffffffu /* all bit on */
typedef int boolean_t;
#define TRUE 1
#define FALSE 0
/*
* logical xd (lxd)
*/
typedef struct {
unsigned len:24;
unsigned off1:8;
u32 off2;
} lxd_t;
/* lxd_t field construction */
#define LXDlength(lxd, length32) ( (lxd)->len = length32 )
#define LXDoffset(lxd, offset64)\
{\
(lxd)->off1 = ((s64)offset64) >> 32;\
(lxd)->off2 = (offset64) & 0xffffffff;\
}
/* lxd_t field extraction */
#define lengthLXD(lxd) ( (lxd)->len )
#define offsetLXD(lxd)\
( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
/* lxd list */
typedef struct {
s16 maxnlxd;
s16 nlxd;
lxd_t *lxd;
} lxdlist_t;
/*
* physical xd (pxd)
*/
typedef struct {
unsigned len:24;
unsigned addr1:8;
u32 addr2;
} pxd_t;
/* xd_t field construction */
#define PXDlength(pxd, length32) ((pxd)->len = __cpu_to_le24(length32))
#define PXDaddress(pxd, address64)\
{\
(pxd)->addr1 = ((s64)address64) >> 32;\
(pxd)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
}
/* xd_t field extraction */
#define lengthPXD(pxd) __le24_to_cpu((pxd)->len)
#define addressPXD(pxd)\
( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2))
/* pxd list */
typedef struct {
s16 maxnpxd;
s16 npxd;
pxd_t pxd[8];
} pxdlist_t;
/*
* data extent descriptor (dxd)
*/
typedef struct {
unsigned flag:8; /* 1: flags */
unsigned rsrvd:24; /* 3: */
u32 size; /* 4: size in byte */
unsigned len:24; /* 3: length in unit of fsblksize */
unsigned addr1:8; /* 1: address in unit of fsblksize */
u32 addr2; /* 4: address in unit of fsblksize */
} dxd_t; /* - 16 - */
/* dxd_t flags */
#define DXD_INDEX 0x80 /* B+-tree index */
#define DXD_INLINE 0x40 /* in-line data extent */
#define DXD_EXTENT 0x20 /* out-of-line single extent */
#define DXD_FILE 0x10 /* out-of-line file (inode) */
#define DXD_CORRUPT 0x08 /* Inconsistency detected */
/* dxd_t field construction
* Conveniently, the PXD macros work for DXD
*/
#define DXDlength PXDlength
#define DXDaddress PXDaddress
#define lengthDXD lengthPXD
#define addressDXD addressPXD
/*
* directory entry argument
*/
typedef struct component_name {
int namlen;
UniChar *name;
} component_t;
/*
* DASD limit information - stored in directory inode
*/
typedef struct dasd {
u8 thresh; /* Alert Threshold (in percent) */
u8 delta; /* Alert Threshold delta (in percent) */
u8 rsrvd1;
u8 limit_hi; /* DASD limit (in logical blocks) */
u32 limit_lo; /* DASD limit (in logical blocks) */
u8 rsrvd2[3];
u8 used_hi; /* DASD usage (in logical blocks) */
u32 used_lo; /* DASD usage (in logical blocks) */
} dasd_t;
#define DASDLIMIT(dasdp) \
(((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo))
#define setDASDLIMIT(dasdp, limit)\
{\
(dasdp)->limit_hi = ((u64)limit) >> 32;\
(dasdp)->limit_lo = __cpu_to_le32(limit);\
}
#define DASDUSED(dasdp) \
(((u64)((dasdp)->used_hi) << 32) + __le32_to_cpu((dasdp)->used_lo))
#define setDASDUSED(dasdp, used)\
{\
(dasdp)->used_hi = ((u64)used) >> 32;\
(dasdp)->used_lo = __cpu_to_le32(used);\
}
/*
* circular doubly-linked list (cdll)
*
* A circular doubly-linked list (cdll) is anchored by a pair of pointers,
* one to the head of the list and the other to the tail of the list.
* The elements are doubly linked so that an arbitrary element can be
* removed without a need to traverse the list.
* New elements can be added to the list before or after an existing element,
* at the head of the list, or at the tail of the list.
* A circle queue may be traversed in either direction.
*
* +----------+ +-------------------------------------+
* | | | |
* +->+-----+ | +->+-----+ +->+-----+ +->+-----+ |
* | | h +-+ | | h +--+ | n +----+ | n +--+
* | +-----+ | +-----+ | +-----+ | +-----+
* | | t +-+ +-----+ t | | | p +--+ | | p +--+
* | +-----+ | | | +-----+ | +-----+ | | +-----+ |
* +----------+ | +-----------------------+ | |
* | | | |
* | +-------------------------+
* | |
* +----------------------------+
*/
/*
* define header
*
* list header field definition in header element:
*
* type - type of list element struct embedding the link field
*/
#define CDLL_HEADER(type)\
struct {\
struct type *head;\
struct type *tail;\
}
struct cdll_header {
struct cdll_header *head;
struct cdll_header *tail;
};
/*
* define link
*
* list link field definition in list element:
*
* type - type of parent list element struct embedding the link field
*/
#define CDLL_ENTRY(type)\
struct {\
struct type *next;\
struct type *prev;\
}
struct cdll_entry {
struct cdll_entry *next;
struct cdll_entry *prev;
};
/*
* initialize header
*
* header - ptr to the header field in the header element
*/
#define CDLL_INIT(header) {\
(header)->head = (void *)(header);\
(header)->tail = (void *)(header);\
}
/*
* scan list
*
* header - ptr to the header field in the header element
* elm - ptr to the element to be inserted
* field - name of the link field in the list element
*
* struct header_container *container;
* struct header_type *header;
* struct element_type *elm;
*
* header = &container->header_field;
* for (elm = header->head; elm != (void *)header; elm = elm->field.next)
*/
/*
* insert <elm> at head of list anchored at <header>
*
* header - ptr to the header field in the header element
* elm - ptr to the list element to be inserted
* field - name of the link field in the list element
*/
#define CDLL_INSERT_HEAD(header, elm, field) {\
(elm)->field.next = (header)->head;\
(elm)->field.prev = (void *)(header);\
if ((header)->tail == (void *)(header))\
(header)->tail = (elm);\
else\
(header)->head->field.prev = (elm);\
(header)->head = (elm);\
}
/*
* insert <elm> at tail of list anchored at <header>
*
* header - ptr to the header field in the header element
* elm - ptr to the list element to be inserted
* field - name of the link field in the list element
*/
#define CDLL_INSERT_TAIL(header, elm, field) {\
(elm)->field.next = (void *)(header);\
(elm)->field.prev = (header)->tail;\
if ((header)->head == (void *)(header))\
(header)->head = (elm);\
else\
(header)->tail->field.next = (elm);\
(header)->tail = (elm);\
}
/*
* insert <elm> after <listelm> of list anchored at <header>
*
* header - ptr to the header field in the header element
* listelm - ptr to the list element at insertion point
* elm - ptr to the list element to be inserted
* field - name of the link field in the list element
*/
#define CDLL_INSERT_AFTER(header, listelm, elm, field) {\
(elm)->field.next = (listelm)->field.next;\
(elm)->field.prev = (listelm);\
if ((listelm)->field.next == (void *)(header))\
(header)->tail = (elm);\
else\
(listelm)->field.next->field.prev = (elm);\
(listelm)->field.next = (elm);\
}
/*
* insert <elm> before <listelm> of list anchored at <header>
*
* header - ptr to the header field in the header element
* listelm - ptr to list element at insertion point
* elm - ptr to the element to be inserted
* field - name of the link field in the list element
*/
#define CDLL_INSERT_BEFORE(header, listelm, elm, field) {\
(elm)->field.next = (listelm);\
(elm)->field.prev = (listelm)->field.prev;\
if ((listelm)->field.prev == (void *)(header))\
(header)->head = (elm);\
else\
(listelm)->field.prev->field.next = (elm);\
(listelm)->field.prev = (elm);\
}
/*
* remove <elm> from list anchored at <header>
*
* header - ptr to the header field in the header element
* elm - ptr to the list element to be removed
* field - name of the link field in the list element
*/
#define CDLL_REMOVE(header, elm, field) {\
if ((elm)->field.next == (void *)(header))\
(header)->tail = (elm)->field.prev;\
else\
(elm)->field.next->field.prev = (elm)->field.prev;\
if ((elm)->field.prev == (void *)(header))\
(header)->head = (elm)->field.next;\
else\
(elm)->field.prev->field.next = (elm)->field.next;\
}
#define CDLL_MOVE_TO_HEAD(header, elm, field) {\
if ((elm)->field.prev != (void *)(header))\
{\
if ((elm)->field.next == (void *)(header))\
(header)->tail = (elm)->field.prev;\
else\
(elm)->field.next->field.prev = (elm)->field.prev;\
(elm)->field.prev->field.next = (elm)->field.next;\
(elm)->field.next = (header)->head;\
(elm)->field.prev = (void *)(header);\
(header)->head->field.prev = (elm);\
(header)->head = (elm);\
}\
}
#define CDLL_MOVE_TO_TAIL(header, elm, field) {\
if ((elm)->field.next != (void *)(header))\
{\
(elm)->field.next->field.prev = (elm)->field.prev;\
if ((elm)->field.prev == (void *)(header))\
(header)->head = (elm)->field.next;\
else\
(elm)->field.prev->field.next = (elm)->field.next;\
(elm)->field.next = (void *)(header);\
(elm)->field.prev = (header)->tail;\
(header)->tail->field.next = (elm);\
(header)->tail = (elm);\
}\
}
/*
* orphan list element
*/
#define CDLL_SELF(elm, field)\
(elm)->field.next = (elm)->field.prev = (elm);
/*
* single head doubly-linked list
*
* A list is headed by a single head pointer.
* The elements are doubly linked so that an arbitrary element can be
* removed without a need to traverse the list.
* New elements can be added to the list at the head of the list, or
* after an existing element (NO insert at tail).
* A list may only be traversed in the forward direction.
* (note: the list is NULL terminated in next field.)
*
* +-----+ +->+-----+ +->+-----+ +->+-----+
* | NULL| | | h +--+ | n +----+ | NULL|
* +-----+ | +-----+ | +-----+ +-----+
* | | | p +--+ | p +--+
* | | +-----+ | +-----+ |
* +-----------------------+ |
* | |
* +-------------------------+
*/
#define LIST_HEADER(type)\
struct {\
struct type *head;\
}
#define LIST_ENTRY(type)\
struct {\
struct type *next;\
struct type **prev;\
}
#define LIST_INIT(header) { (header)->head = NULL; }
/*
* scan list
*
* header - ptr to the header (field in header element)
* elm - ptr to the element to be inserted
* field - name of the link field in list element
*
* struct header_container *container;
* struct header_type *header;
* struct element_type *elm;
*
* header = &container->header_field;
* for (elm = header->head; elm; elm = elm->field.next)
*/
#define LIST_INSERT_HEAD(header, elm, field) {\
if (((elm)->field.next = (header)->head) != NULL)\
(header)->head->field.prev = &(elm)->field.next;\
(header)->head = (elm);\
(elm)->field.prev = &(header)->head;\
}
#define LIST_INSERT_AFTER(listelm, elm, field) {\
if (((elm)->field.next = (listelm)->field.next) != NULL)\
(listelm)->field.next->field.prev = &(elm)->field.next;\
(listelm)->field.next = (elm);\
(elm)->field.prev = &(listelm)->field.next;\
}
#define LIST_REMOVE(elm, field) {\
if ((elm)->field.next != NULL)\
(elm)->field.next->field.prev = (elm)->field.prev;\
*(elm)->field.prev = (elm)->field.next;\
}
#define LIST_SELF(elm, field) {\
(elm)->field.next = NULL;\
(elm)->field.prev = &(elm)->field.next;\
}
#endif /* !_H_JFS_TYPES */

View File

@@ -0,0 +1,396 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 1999-2000, 2002, 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/>.
*/
/* It's a bit silly calling a swap partition a file system. Oh well... */
#include <config.h>
#include <parted/parted.h>
#include <parted/endian.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#include <unistd.h>
#include <uuid/uuid.h>
#define SWAP_SPECIFIC(fs) ((SwapSpecific*) (fs->type_specific))
#define BUFFER_SIZE 128
#define LINUXSWAP_BLOCK_SIZES ((int[2]){512, 0})
typedef struct {
char page_map[1];
} SwapOldHeader;
/* ripped from mkswap */
typedef struct {
char bootbits[1024]; /* Space for disklabel etc. */
uint32_t version;
uint32_t last_page;
uint32_t nr_badpages;
unsigned char sws_uuid[16];
unsigned char sws_volume[16];
uint32_t padding[117];
uint32_t badpages[1];
} SwapNewHeader;
typedef struct {
union {
SwapNewHeader new;
SwapOldHeader old;
}* header;
void* buffer;
int buffer_size;
PedSector page_sectors;
unsigned int page_count;
unsigned int version;
unsigned int max_bad_pages;
} SwapSpecific;
static PedFileSystemType _swap_v0_type;
static PedFileSystemType _swap_v1_type;
static PedFileSystemType _swap_swsusp_type;
static PedFileSystem* _swap_v0_open (PedGeometry* geom);
static PedFileSystem* _swap_v1_open (PedGeometry* geom);
static PedFileSystem* _swap_swsusp_open (PedGeometry* geom);
static int swap_close (PedFileSystem* fs);
static PedGeometry*
_generic_swap_probe (PedGeometry* geom, int kind)
{
PedFileSystem* fs;
SwapSpecific* fs_info;
PedGeometry* probed_geom;
PedSector length;
switch (kind) {
/* Check for old style swap partitions. */
case 0:
fs = _swap_v0_open(geom);
break;
/* Check for new style swap partitions. */
case 1:
fs = _swap_v1_open(geom);
break;
/* Check for swap partitions containing swsusp data. */
case -1:
fs = _swap_swsusp_open(geom);
break;
/* Not reached. */
default:
goto error;
}
if (!fs)
goto error;
fs_info = SWAP_SPECIFIC (fs);
if (fs_info->version)
length = fs_info->page_sectors * fs_info->page_count;
else
length = geom->length;
probed_geom = ped_geometry_new (geom->dev, geom->start, length);
if (!probed_geom)
goto error_close_fs;
swap_close (fs);
return probed_geom;
error_close_fs:
swap_close (fs);
error:
return NULL;
}
static int
swap_init (PedFileSystem* fs)
{
SwapSpecific* fs_info = SWAP_SPECIFIC (fs);
fs_info->page_sectors = getpagesize () / fs->geom->dev->sector_size;
fs_info->page_count = fs->geom->length / fs_info->page_sectors;
fs_info->version = 1;
fs_info->max_bad_pages = (getpagesize()
- sizeof (SwapNewHeader)) / 4;
return ped_geometry_read (fs->geom, fs_info->header,
0, fs_info->page_sectors);
}
static PedFileSystem*
swap_alloc (PedGeometry* geom)
{
PedFileSystem* fs;
SwapSpecific* fs_info;
fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
if (!fs)
goto error;
fs->type_specific = (SwapSpecific*) ped_malloc (sizeof (SwapSpecific));
if (!fs->type_specific)
goto error_free_fs;
fs_info = SWAP_SPECIFIC (fs);
fs_info->header = ped_malloc (PED_MAX(getpagesize(), geom->dev->sector_size));
if (!fs_info->header)
goto error_free_type_specific;
fs_info = SWAP_SPECIFIC (fs);
fs_info->buffer_size = getpagesize() * BUFFER_SIZE;
fs_info->buffer = ped_malloc (fs_info->buffer_size);
if (!fs_info->buffer)
goto error_free_header;
fs->geom = ped_geometry_duplicate (geom);
if (!fs->geom)
goto error_free_buffer;
fs->type = &_swap_v1_type;
return fs;
error_free_buffer:
free (fs_info->buffer);
error_free_header:
free (fs_info->header);
error_free_type_specific:
free (fs->type_specific);
error_free_fs:
free (fs);
error:
return NULL;
}
static void
swap_free (PedFileSystem* fs)
{
SwapSpecific* fs_info = SWAP_SPECIFIC (fs);
free (fs_info->buffer);
free (fs_info->header);
free (fs->type_specific);
ped_geometry_destroy (fs->geom);
free (fs);
}
static PedFileSystem*
_swap_v0_open (PedGeometry* geom)
{
PedFileSystem* fs;
SwapSpecific* fs_info;
const char* sig;
fs = swap_alloc (geom);
if (!fs)
goto error;
swap_init (fs);
fs_info = SWAP_SPECIFIC (fs);
if (!ped_geometry_read (fs->geom, fs_info->header, 0,
fs_info->page_sectors))
goto error_free_fs;
sig = ((char*) fs_info->header) + getpagesize() - 10;
if (strncmp (sig, "SWAP-SPACE", 10) == 0) {
fs_info->version = 0;
fs_info->page_count
= PED_MIN (fs->geom->length / fs_info->page_sectors,
8 * (getpagesize() - 10));
} else {
char _sig [11];
memcpy (_sig, sig, 10);
_sig [10] = 0;
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Unrecognised old style linux swap signature '%10s'."), _sig);
goto error_free_fs;
}
fs->checked = 1;
return fs;
error_free_fs:
swap_free (fs);
error:
return NULL;
}
static PedFileSystem*
_swap_v1_open (PedGeometry* geom)
{
PedFileSystem* fs;
SwapSpecific* fs_info;
const char* sig;
fs = swap_alloc (geom);
if (!fs)
goto error;
if (!swap_init(fs))
goto error_free_fs;
fs_info = SWAP_SPECIFIC (fs);
sig = ((char*) fs_info->header) + getpagesize() - 10;
if (strncmp (sig, "SWAPSPACE2", 10) == 0) {
fs_info->version = 1;
fs_info->page_count = fs_info->header->new.last_page;
} else {
char _sig [11];
memcpy (_sig, sig, 10);
_sig [10] = 0;
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Unrecognised new style linux swap signature '%10s'."), _sig);
goto error_free_fs;
}
fs->checked = 1;
return fs;
error_free_fs:
swap_free (fs);
error:
return NULL;
}
static PedFileSystem*
_swap_swsusp_open (PedGeometry* geom)
{
PedFileSystem* fs;
SwapSpecific* fs_info;
const char* sig;
fs = swap_alloc (geom);
if (!fs)
goto error;
fs->type = &_swap_swsusp_type;
swap_init (fs);
fs_info = SWAP_SPECIFIC (fs);
if (!ped_geometry_read (fs->geom, fs_info->header, 0,
fs_info->page_sectors))
goto error_free_fs;
sig = ((char*) fs_info->header) + getpagesize() - 10;
if (strncmp (sig, "S1SUSPEND", 9) == 0) {
fs_info->version = -1;
} else {
char _sig [10];
memcpy (_sig, sig, 9);
_sig [9] = 0;
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Unrecognised swsusp linux swap signature '%9s'."), _sig);
goto error_free_fs;
}
fs->checked = 1;
return fs;
error_free_fs:
swap_free (fs);
error:
return NULL;
}
static int
swap_close (PedFileSystem* fs)
{
swap_free (fs);
return 1;
}
static PedGeometry*
_swap_v0_probe (PedGeometry* geom) {
return _generic_swap_probe (geom, 0);
}
static PedGeometry*
_swap_v1_probe (PedGeometry* geom) {
return _generic_swap_probe (geom, 1);
}
static PedGeometry*
_swap_swsusp_probe (PedGeometry* geom) {
return _generic_swap_probe (geom, -1);
}
static PedFileSystemOps _swap_v0_ops = {
probe: _swap_v0_probe,
};
static PedFileSystemOps _swap_v1_ops = {
probe: _swap_v1_probe,
};
static PedFileSystemOps _swap_swsusp_ops = {
probe: _swap_swsusp_probe,
};
static PedFileSystemType _swap_v0_type = {
next: NULL,
ops: &_swap_v0_ops,
name: "linux-swap(v0)",
};
static PedFileSystemType _swap_v1_type = {
next: NULL,
ops: &_swap_v1_ops,
name: "linux-swap(v1)",
};
static PedFileSystemType _swap_swsusp_type = {
next: NULL,
ops: &_swap_swsusp_ops,
name: "swsusp",
};
void
ped_file_system_linux_swap_init ()
{
ped_file_system_type_register (&_swap_v0_type);
ped_file_system_type_register (&_swap_v1_type);
ped_file_system_type_register (&_swap_swsusp_type);
ped_file_system_alias_register (&_swap_v0_type, "linux-swap(old)", 1);
ped_file_system_alias_register (&_swap_v1_type, "linux-swap(new)", 1);
ped_file_system_alias_register (&_swap_v1_type, "linux-swap", 0);
}
void
ped_file_system_linux_swap_done ()
{
ped_file_system_alias_unregister (&_swap_v0_type, "linux-swap(old)");
ped_file_system_alias_unregister (&_swap_v1_type, "linux-swap(new)");
ped_file_system_alias_unregister (&_swap_v1_type, "linux-swap");
ped_file_system_type_unregister (&_swap_v0_type);
ped_file_system_type_unregister (&_swap_v1_type);
ped_file_system_type_unregister (&_swap_swsusp_type);
}

View File

@@ -0,0 +1,155 @@
/*
* nilfs2.c - New Implementation of Log filesystem
*
* Written by Jiro SEKIBA <jir@unicus.jp>
*
* Copyright (C) 2011-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/crc32.h>
#include <parted/endian.h>
/* Magic value for nilfs2 superblock. */
#define NILFS2_SUPER_MAGIC 0x3434
/* primariy superblock offset in 512bytes blocks. */
#define NILFS_SB_OFFSET 2
/* secondary superblock offset in 512byte blocks. */
#define NILFS_SB2_OFFSET(devsize) ((((devsize)>>3) - 1) << 3)
struct __attribute__ ((packed)) nilfs2_super_block {
uint32_t s_rev_level;
uint16_t s_minor_rev_level;
uint16_t s_magic;
uint16_t s_bytes;
uint16_t s_flags;
uint32_t s_crc_seed;
uint32_t s_sum;
uint32_t s_log_block_size;
uint64_t s_nsegments;
uint64_t s_dev_size;
uint64_t s_first_data_block;
uint32_t s_blocks_per_segment;
uint32_t s_r_segments_percentage;
uint64_t s_last_cno;
uint64_t s_last_pseg;
uint64_t s_last_seq;
uint64_t s_free_blocks_count;
uint64_t s_ctime;
uint64_t s_mtime;
uint64_t s_wtime;
uint16_t s_mnt_count;
uint16_t s_max_mnt_count;
uint16_t s_state;
uint16_t s_errors;
uint64_t s_lastcheck;
uint32_t s_checkinterval;
uint32_t s_creator_os;
uint16_t s_def_resuid;
uint16_t s_def_resgid;
uint32_t s_first_ino;
uint16_t s_inode_size;
uint16_t s_dat_entry_size;
uint16_t s_checkpoint_size;
uint16_t s_segment_usage_size;
uint8_t s_uuid[16];
char s_volume_name[80];
uint32_t s_c_interval;
uint32_t s_c_block_max;
uint32_t s_reserved[192];
};
static int
is_valid_nilfs_sb(struct nilfs2_super_block *sb)
{
static unsigned char sum[4];
const int sumoff = offsetof (struct nilfs2_super_block, s_sum);
size_t bytes;
uint32_t crc;
if (PED_LE16_TO_CPU(sb->s_magic) != NILFS2_SUPER_MAGIC)
return 0;
bytes = PED_LE16_TO_CPU(sb->s_bytes);
if (bytes > 1024 || bytes < sumoff - 4)
return 0;
crc = __efi_crc32(sb, sumoff, PED_LE32_TO_CPU(sb->s_crc_seed));
crc = __efi_crc32(sum, 4, crc);
crc = __efi_crc32((unsigned char *)sb + sumoff + 4,
bytes - sumoff - 4, crc);
return crc == PED_LE32_TO_CPU(sb->s_sum);
}
PedGeometry*
nilfs2_probe (PedGeometry* geom)
{
struct nilfs2_super_block *sb = NULL;
struct nilfs2_super_block *sb2 = NULL;
PedSector length = geom->length * (geom->dev->sector_size / 512);
PedSector sb2off = NILFS_SB2_OFFSET(length) / (geom->dev->sector_size / 512);
if (sb2off <= 2)
return NULL;
const int sectors = (4096 + geom->dev->sector_size - 1) /
geom->dev->sector_size;
uint8_t *buf = alloca (sectors * geom->dev->sector_size);
const int sectors2 = (1024 + geom->dev->sector_size -1 ) /
geom->dev->sector_size;
void *buff2 = alloca (sectors2 * geom->dev->sector_size);
if (ped_geometry_read(geom, buf, 0, sectors))
sb = (struct nilfs2_super_block*)(buf + 1024);
if (ped_geometry_read(geom, buff2, sb2off, sectors2))
sb2 = (struct nilfs2_super_block*)buff2;
if ((!sb || !is_valid_nilfs_sb(sb)) &&
(!sb2 || !is_valid_nilfs_sb(sb2)))
return NULL;
/* reserve 4k bytes for secondary superblock */
length = sb2off + ((4096 + geom->dev->sector_size - 1) /
geom->dev->sector_size);
return ped_geometry_new(geom->dev, geom->start, length);
}
static PedFileSystemOps nilfs2_ops = {
probe: nilfs2_probe,
};
static PedFileSystemType nilfs2_type = {
next: NULL,
ops: &nilfs2_ops,
name: "nilfs2",
};
void
ped_file_system_nilfs2_init ()
{
ped_file_system_type_register (&nilfs2_type);
}
void
ped_file_system_nilfs2_done ()
{
ped_file_system_type_unregister (&nilfs2_type);
}

View File

@@ -0,0 +1,73 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 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 <parted/parted.h>
#include <parted/endian.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#include <unistd.h>
#define NTFS_SIGNATURE "NTFS"
PedGeometry*
ntfs_probe (PedGeometry* geom)
{
uint8_t *buf = alloca(geom->dev->sector_size);
PedGeometry *newg = NULL;
if (!ped_geometry_read(geom, buf, 0, 1))
return 0;
if (strncmp (NTFS_SIGNATURE, ((char *)buf + 3), strlen (NTFS_SIGNATURE)) == 0) {
uint64_t length;
memcpy(&length, buf + 0x28, sizeof(uint64_t));
newg = ped_geometry_new (geom->dev, geom->start, length);
}
return newg;
}
static PedFileSystemOps ntfs_ops = {
probe: ntfs_probe,
};
static PedFileSystemType ntfs_type = {
next: NULL,
ops: &ntfs_ops,
name: "ntfs",
};
void
ped_file_system_ntfs_init ()
{
ped_file_system_type_register (&ntfs_type);
}
void
ped_file_system_ntfs_done ()
{
ped_file_system_type_unregister (&ntfs_type);
}

View File

@@ -0,0 +1,441 @@
/*
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 */

View File

@@ -0,0 +1,130 @@
/*
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 */

View File

@@ -0,0 +1,433 @@
/*
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 */

View File

@@ -0,0 +1,77 @@
/*
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 */

View File

@@ -0,0 +1,423 @@
/*
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 */

View File

@@ -0,0 +1,28 @@
/*
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 */

View File

@@ -0,0 +1,261 @@
/*
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 */

View File

@@ -0,0 +1,70 @@
/*
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 */

View File

@@ -0,0 +1,319 @@
/*
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 */

View File

@@ -0,0 +1,46 @@
/*
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 */

View File

@@ -0,0 +1,652 @@
/*
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 */

View File

@@ -0,0 +1,159 @@
/*
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 */

View File

@@ -0,0 +1,150 @@
/*
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 */

View File

@@ -0,0 +1,49 @@
/*
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 */

View File

@@ -0,0 +1,876 @@
/*
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 */

View File

@@ -0,0 +1,481 @@
/*
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;
}

View File

@@ -0,0 +1,74 @@
/*
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 */

View File

@@ -0,0 +1,368 @@
/*
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 */

View File

@@ -0,0 +1,75 @@
/*
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 */

View File

@@ -0,0 +1,320 @@
/* 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);
}

View File

@@ -0,0 +1,332 @@
/*
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 */

View File

@@ -0,0 +1,49 @@
/*
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 */

View File

@@ -0,0 +1,385 @@
/*
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 */

View File

@@ -0,0 +1,52 @@
/*
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 */

View File

@@ -0,0 +1,239 @@
/*
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 */

View File

@@ -0,0 +1,118 @@
/*
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 */

View File

@@ -0,0 +1,229 @@
/*
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 */

View File

@@ -0,0 +1,42 @@
/*
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 */

View File

@@ -0,0 +1,274 @@
/*
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 */

View File

@@ -0,0 +1,61 @@
/*
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

View File

@@ -0,0 +1,648 @@
/*
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 */

View File

@@ -0,0 +1,392 @@
/*
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 */

View File

@@ -0,0 +1,45 @@
/*
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 */

View File

@@ -0,0 +1,99 @@
/*
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;
}

View File

@@ -0,0 +1,35 @@
/*
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 */

View File

@@ -0,0 +1,676 @@
/*
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 */

View File

@@ -0,0 +1,36 @@
/*
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 */

View File

@@ -0,0 +1,948 @@
/*
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 */

View File

@@ -0,0 +1,37 @@
/*
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 */

View File

@@ -0,0 +1,94 @@
/*
reiserfs.c -- ReiserFS detection
Copyright (C) 2001-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 <uuid/uuid.h>
#include <fcntl.h>
#include <errno.h>
#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif
#include "reiserfs.h"
static PedSector reiserfs_super_offset[] = { 128, 16, -1 };
static PedFileSystemType* reiserfs_type;
static PedGeometry *reiserfs_probe(PedGeometry *geom)
{
int i;
PED_ASSERT(geom != NULL);
reiserfs_super_block_t *sb = alloca (geom->dev->sector_size);
for (i = 0; reiserfs_super_offset[i] != -1; i++) {
if (reiserfs_super_offset[i] >= geom->length)
continue;
if (!ped_geometry_read (geom, sb, reiserfs_super_offset[i], 1))
continue;
if (strncmp(REISERFS_SIGNATURE, sb->s_magic,
strlen(REISERFS_SIGNATURE)) == 0
|| strncmp(REISER2FS_SIGNATURE, sb->s_magic,
strlen(REISER2FS_SIGNATURE)) == 0
|| strncmp(REISER3FS_SIGNATURE, sb->s_magic,
strlen(REISER3FS_SIGNATURE)) == 0) {
PedSector block_size;
PedSector block_count;
block_size = PED_LE16_TO_CPU(sb->s_blocksize)
/ geom->dev->sector_size;
block_count = PED_LE32_TO_CPU(sb->s_block_count);
return ped_geometry_new(geom->dev, geom->start,
block_size * block_count);
}
}
return NULL;
}
static PedFileSystemOps reiserfs_simple_ops = {
probe: reiserfs_probe,
};
static PedFileSystemType reiserfs_simple_type = {
next: NULL,
ops: &reiserfs_simple_ops,
name: "reiserfs",
};
void ped_file_system_reiserfs_init()
{
reiserfs_type = &reiserfs_simple_type;
ped_file_system_type_register(reiserfs_type);
}
void ped_file_system_reiserfs_done()
{
ped_file_system_type_unregister(reiserfs_type);
}

View File

@@ -0,0 +1,109 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 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 REISERFS_H
#define REISERFS_H
#define REISERFS_API_VERSION 0
#define REISERFS_SIGNATURE "ReIsErFs"
#define REISER2FS_SIGNATURE "ReIsEr2Fs"
#define REISER3FS_SIGNATURE "ReIsEr3Fs"
#define DEFAULT_BLOCK_SIZE 4096
struct reiserfs_super_block {
uint32_t s_block_count;
uint32_t s_free_blocks;
uint32_t s_root_block;
uint32_t s_journal_block;
uint32_t s_journal_dev;
uint32_t s_orig_journal_size;
uint32_t s_journal_trans_max;
uint32_t s_journal_block_count;
uint32_t s_journal_max_batch;
uint32_t s_journal_max_commit_age;
uint32_t s_journal_max_trans_age;
uint16_t s_blocksize;
uint16_t s_oid_maxsize;
uint16_t s_oid_cursize;
uint16_t s_state;
char s_magic[10];
uint16_t s_fsck_state;
uint32_t s_hash_function_code;
uint16_t s_tree_height;
uint16_t s_bmap_nr;
uint16_t s_version;
char padding[438];
};
typedef struct reiserfs_super_block reiserfs_super_block_t;
enum reiserfs_exception_type {
EXCEPTION_INFORMATION = 1,
EXCEPTION_WARNING = 2,
EXCEPTION_ERROR = 3,
EXCEPTION_FATAL = 4,
EXCEPTION_BUG = 5,
EXCEPTION_NO_FEATURE = 6
};
typedef enum reiserfs_exception_type reiserfs_exception_type_t;
enum reiserfs_exception_option {
EXCEPTION_UNHANDLED = 1 << 0,
EXCEPTION_FIX = 1 << 1,
EXCEPTION_YES = 1 << 2,
EXCEPTION_NO = 1 << 3,
EXCEPTION_OK = 1 << 4,
EXCEPTION_RETRY = 1 << 5,
EXCEPTION_IGNORE = 1 << 6,
EXCEPTION_CANCEL = 1 << 7
};
typedef enum reiserfs_exception_option reiserfs_exception_option_t;
typedef void (reiserfs_gauge_handler_t)(const char *, unsigned int, void *, int, int, int);
typedef void * reiserfs_exception_t;
typedef void * reiserfs_gauge_t;
typedef void * reiserfs_fs_t;
#define FS_FORMAT_3_5 0
#define FS_FORMAT_3_6 2
#define SUPER_OFFSET_IN_BYTES 64*1024
#define DEFAULT_JOURNAL_SIZE 8192
#define JOURNAL_MIN_SIZE 512
#define JOURNAL_MIN_TRANS 256
#define JOURNAL_MAX_TRANS 1024
#define JOURNAL_DEF_RATIO 8
#define JOURNAL_MIN_RATIO 2
#define JOURNAL_MAX_BATCH 900
#define JOURNAL_MAX_COMMIT_AGE 30
#define JOURNAL_MAX_TRANS_AGE 30
#define TEA_HASH 1
#define YURA_HASH 2
#define R5_HASH 3
#endif

175
jni/parted/libparted/fs/udf/udf.c Executable file
View File

@@ -0,0 +1,175 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2018-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>
/* Read bytes using ped_geometry_read() function */
static int read_bytes (const PedGeometry* geom, void* buffer, PedSector offset, PedSector count)
{
char* sector_buffer;
PedSector sector_offset, sector_count, buffer_offset;
sector_offset = offset / geom->dev->sector_size;
sector_count = (offset + count + geom->dev->sector_size - 1) / geom->dev->sector_size - sector_offset;
buffer_offset = offset - sector_offset * geom->dev->sector_size;
sector_buffer = alloca (sector_count * geom->dev->sector_size);
if (!ped_geometry_read (geom, sector_buffer, sector_offset, sector_count))
return 0;
memcpy (buffer, sector_buffer + buffer_offset, count);
return 1;
}
/* Scan VSR and check for UDF VSD */
static int check_vrs (const PedGeometry* geom, unsigned int vsdsize)
{
PedSector block;
PedSector offset;
unsigned char ident[5];
/* Check only first 64 blocks, but theoretically standard does not define upper limit */
for (block = 0; block < 64; block++) {
/* VRS starts at fixed offset 32kB, it is independent of block size or vsd size */
offset = 32768 + block * vsdsize;
/* Read VSD identifier, it is at offset 1 */
if (!read_bytes (geom, ident, offset + 1, 5))
return 0;
/* Check for UDF identifier */
if (memcmp (ident, "NSR02", 5) == 0 ||
memcmp (ident, "NSR03", 5) == 0)
return 1;
/* Unknown VSD identifier means end of VRS */
if (memcmp (ident, "BEA01", 5) != 0 &&
memcmp (ident, "TEA01", 5) != 0 &&
memcmp (ident, "BOOT2", 5) != 0 &&
memcmp (ident, "CD001", 5) != 0 &&
memcmp (ident, "CDW02", 5) != 0)
break;
}
return 0;
}
/* Check for UDF AVDP */
static int check_anchor (const PedGeometry* geom, unsigned int blocksize, int rel_block)
{
PedSector block;
unsigned char tag[16];
/* Negative block means relative to the end of device */
if (rel_block < 0) {
block = geom->length * geom->dev->sector_size / blocksize;
if (block <= (PedSector)(-rel_block))
return 0;
block -= (PedSector)(-rel_block);
if (block < 257)
return 0;
} else {
block = rel_block;
}
if (!read_bytes (geom, tag, block * blocksize, 16))
return 0;
/* Check for AVDP type (0x0002) */
if (((unsigned short)tag[0] | ((unsigned short)tag[1] << 8)) != 0x0002)
return 0;
/* Check that location stored in AVDP matches */
if (((unsigned long)tag[12] | ((unsigned long)tag[13] << 8) | ((unsigned long)tag[14] << 16) | ((unsigned long)tag[15] << 24)) != block)
return 0;
return 1;
}
/* Detect presence of UDF AVDP */
static int detect_anchor(const PedGeometry* geom, unsigned int blocksize)
{
/* All possible AVDP locations in preferred order */
static int anchors[] = { 256, -257, -1, 512 };
size_t i;
for (i = 0; i < sizeof (anchors)/sizeof (*anchors); i++) {
if (check_anchor (geom, blocksize, anchors[i]))
return 1;
}
return 0;
}
/* Detect UDF filesystem, it must have VRS and AVDP */
static int detect_udf (const PedGeometry* geom)
{
unsigned int blocksize;
/* VSD size is min(2048, UDF block size), check for block sizes <= 2048 */
if (check_vrs (geom, 2048)) {
for (blocksize = 512; blocksize <= 2048; blocksize *= 2) {
if (detect_anchor (geom, blocksize))
return 1;
}
}
/* Check for block sizes larger then 2048, maximal theoretical block size is 32kB */
for (blocksize = 4096; blocksize <= 32768; blocksize *= 2) {
if (!check_vrs (geom, blocksize))
continue;
if (detect_anchor (geom, blocksize))
return 1;
}
return 0;
}
PedGeometry*
udf_probe (PedGeometry* geom)
{
if (!detect_udf (geom))
return NULL;
return ped_geometry_duplicate (geom);
}
static PedFileSystemOps udf_ops = {
probe: udf_probe,
};
static PedFileSystemType udf_type = {
next: NULL,
ops: &udf_ops,
name: "udf",
};
void
ped_file_system_udf_init ()
{
ped_file_system_type_register (&udf_type);
}
void
ped_file_system_udf_done ()
{
ped_file_system_type_unregister (&udf_type);
}

281
jni/parted/libparted/fs/ufs/ufs.c Executable file
View File

@@ -0,0 +1,281 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 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/>.
Contributor: Ben Collins <bcollins@debian.org>
*/
#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 <unistd.h>
#include <string.h>
/* taken from ufs_fs.h in Linux */
#define UFS_MAXNAMLEN 255
#define UFS_MAXMNTLEN 512
#define UFS_MAXCSBUFS 31
#define UFS_LINK_MAX 32000
#define UFS_MAGIC 0x00011954
#define UFS_MAGIC_LFN 0x00095014
#define UFS_MAGIC_FEA 0x00195612
#define UFS_MAGIC_4GB 0x05231994
struct __attribute__ ((packed)) ufs_csum {
uint32_t cs_ndir; /* number of directories */
uint32_t cs_nbfree; /* number of free blocks */
uint32_t cs_nifree; /* number of free inodes */
uint32_t cs_nffree; /* number of free frags */
};
struct __attribute__ ((packed)) ufs_super_block {
uint32_t fs_link; /* UNUSED */
uint32_t fs_rlink; /* UNUSED */
uint32_t fs_sblkno; /* addr of super-block in filesys */
uint32_t fs_cblkno; /* offset of cyl-block in filesys */
uint32_t fs_iblkno; /* offset of inode-blocks in filesys */
uint32_t fs_dblkno; /* offset of first data after cg */
uint32_t fs_cgoffset; /* cylinder group offset in cylinder */
uint32_t fs_cgmask; /* used to calc mod fs_ntrak */
uint32_t fs_time; /* last time written -- time_t */
uint32_t fs_size; /* number of blocks in fs */
uint32_t fs_dsize; /* number of data blocks in fs */
uint32_t fs_ncg; /* number of cylinder groups */
uint32_t fs_bsize; /* size of basic blocks in fs */
uint32_t fs_fsize; /* size of frag blocks in fs */
uint32_t fs_frag; /* number of frags in a block in fs */
/* these are configuration parameters */
uint32_t fs_minfree; /* minimum percentage of free blocks */
uint32_t fs_rotdelay; /* num of ms for optimal next block */
uint32_t fs_rps; /* disk revolutions per second */
/* these fields can be computed from the others */
uint32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
uint32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
uint32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
uint32_t fs_fshift; /* ``numfrags'' calc number of frags */
/* these are configuration parameters */
uint32_t fs_maxcontig; /* max number of contiguous blks */
uint32_t fs_maxbpg; /* max number of blks per cyl group */
/* these fields can be computed from the others */
uint32_t fs_fragshift; /* block to frag shift */
uint32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
uint32_t fs_sbsize; /* actual size of super block */
uint32_t fs_csmask; /* csum block offset */
uint32_t fs_csshift; /* csum block number */
uint32_t fs_nindir; /* value of NINDIR */
uint32_t fs_inopb; /* value of INOPB */
uint32_t fs_nspf; /* value of NSPF */
/* yet another configuration parameter */
uint32_t fs_optim; /* optimization preference, see below */
/* these fields are derived from the hardware */
union {
struct {
uint32_t fs_npsect; /* # sectors/track including spares */
} fs_sun;
struct {
int32_t fs_state; /* file system state timestamp */
} fs_sunx86;
} fs_u1;
uint32_t fs_interleave; /* hardware sector interleave */
uint32_t fs_trackskew; /* sector 0 skew, per track */
/* a unique id for this file system (currently unused and unmaintained) */
/* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
/* Neither of those fields is used in the Tahoe code right now but */
/* there could be problems if they are. */
uint32_t fs_id[2]; /* file system id */
/* sizes determined by number of cylinder groups and their sizes */
uint32_t fs_csaddr; /* blk addr of cyl grp summary area */
uint32_t fs_cssize; /* size of cyl grp summary area */
uint32_t fs_cgsize; /* cylinder group size */
/* these fields are derived from the hardware */
uint32_t fs_ntrak; /* tracks per cylinder */
uint32_t fs_nsect; /* sectors per track */
uint32_t fs_spc; /* sectors per cylinder */
/* this comes from the disk driver partitioning */
uint32_t fs_ncyl; /* cylinders in file system */
/* these fields can be computed from the others */
uint32_t fs_cpg; /* cylinders per group */
uint32_t fs_ipg; /* inodes per group */
uint32_t fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct ufs_csum fs_cstotal; /* cylinder summary information */
/* these fields are cleared at mount time */
int8_t fs_fmod; /* super block modified flag */
int8_t fs_clean; /* file system is clean flag */
int8_t fs_ronly; /* mounted read-only flag */
int8_t fs_flags; /* currently unused flag */
int8_t fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */
/* these fields retain the current block allocation info */
uint32_t fs_cgrotor; /* last cg searched */
uint32_t fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */
uint32_t fs_maxcluster;
uint32_t fs_cpc; /* cyl per cycle in postbl */
uint16_t fs_opostbl[16][8]; /* old rotation block list head */
union {
struct {
int32_t fs_sparecon[53];/* reserved for future constants */
int32_t fs_reclaim;
int32_t fs_sparecon2[1];
int32_t fs_state; /* file system state timestamp */
uint32_t fs_qbmask[2]; /* ~usb_bmask */
uint32_t fs_qfmask[2]; /* ~usb_fmask */
} fs_sun;
struct {
int32_t fs_sparecon[53];/* reserved for future constants */
int32_t fs_reclaim;
int32_t fs_sparecon2[1];
uint32_t fs_npsect; /* # sectors/track including spares */
uint32_t fs_qbmask[2]; /* ~usb_bmask */
uint32_t fs_qfmask[2]; /* ~usb_fmask */
} fs_sunx86;
struct {
int32_t fs_sparecon[50];/* reserved for future constants */
int32_t fs_contigsumsize;/* size of cluster summary array */
int32_t fs_maxsymlinklen;/* max length of an internal symlink */
int32_t fs_inodefmt; /* format of on-disk inodes */
uint32_t fs_maxfilesize[2]; /* max representable file size */
uint32_t fs_qbmask[2]; /* ~usb_bmask */
uint32_t fs_qfmask[2]; /* ~usb_fmask */
int32_t fs_state; /* file system state timestamp */
} fs_44;
} fs_u2;
int32_t fs_postblformat; /* format of positional layout tables */
int32_t fs_nrpos; /* number of rotational positions */
int32_t fs_postbloff; /* (__s16) rotation block list head */
int32_t fs_rotbloff; /* (uint8_t) blocks for each rotation */
int32_t fs_magic; /* magic number */
uint8_t fs_space[4]; /* list of blocks for each rotation */
};
static PedGeometry*
ufs_probe_sun (PedGeometry* geom)
{
const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
geom->dev->sector_size;
uint8_t* buf = alloca (sectors * geom->dev->sector_size);
struct ufs_super_block *sb;
if (geom->length < 5)
return 0;
if (!ped_geometry_read (geom, buf, 16 * 512 / geom->dev->sector_size, sectors))
return 0;
sb = (struct ufs_super_block *)buf;
if (PED_BE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
PedSector block_size = PED_BE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
PedSector block_count = PED_BE32_TO_CPU(sb->fs_size);
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
}
if (PED_LE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
PedSector block_size = PED_LE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
PedSector block_count = PED_LE32_TO_CPU(sb->fs_size);
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
}
return NULL;
}
static PedGeometry*
ufs_probe_hp (PedGeometry* geom)
{
struct ufs_super_block *sb;
PedSector block_size;
PedSector block_count;
if (geom->length < 5)
return 0;
const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
geom->dev->sector_size;
uint8_t* buf = alloca (sectors * geom->dev->sector_size);
if (!ped_geometry_read (geom, buf, 16 * 512 / geom->dev->sector_size, sectors))
return 0;
sb = (struct ufs_super_block *)buf;
/* Try sane bytesex */
switch (PED_BE32_TO_CPU(sb->fs_magic)) {
case UFS_MAGIC_LFN:
case UFS_MAGIC_FEA:
case UFS_MAGIC_4GB:
block_size = PED_BE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
block_count = PED_BE32_TO_CPU(sb->fs_size);
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
}
/* Try perverted bytesex */
switch (PED_LE32_TO_CPU(sb->fs_magic)) {
case UFS_MAGIC_LFN:
case UFS_MAGIC_FEA:
case UFS_MAGIC_4GB:
block_size = PED_LE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
block_count = PED_LE32_TO_CPU(sb->fs_size);
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
}
return NULL;
}
static PedFileSystemOps ufs_ops_sun = {
probe: ufs_probe_sun,
};
static PedFileSystemOps ufs_ops_hp = {
probe: ufs_probe_hp,
};
static PedFileSystemType ufs_type_sun = {
next: NULL,
ops: &ufs_ops_sun,
name: "sun-ufs",
};
static PedFileSystemType ufs_type_hp = {
next: NULL,
ops: &ufs_ops_hp,
name: "hp-ufs",
};
void
ped_file_system_ufs_init ()
{
PED_ASSERT (sizeof (struct ufs_super_block) == 1380);
ped_file_system_type_register (&ufs_type_sun);
ped_file_system_type_register (&ufs_type_hp);
}
void
ped_file_system_ufs_done ()
{
ped_file_system_type_unregister (&ufs_type_hp);
ped_file_system_type_unregister (&ufs_type_sun);
}

View File

@@ -0,0 +1,109 @@
/* include/platform_defs.h. Generated automatically by configure. */
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*
* @configure_input@
*/
#ifndef __XFS_PLATFORM_DEFS_H__
#define __XFS_PLATFORM_DEFS_H__
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <endian.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1)
# define constpp const char * const *
#else
# define constpp char * const *
#endif
typedef loff_t xfs_off_t;
typedef uint64_t xfs_ino_t;
typedef uint32_t xfs_dev_t;
typedef int64_t xfs_daddr_t;
typedef char* xfs_caddr_t;
/* long and pointer must be either 32 bit or 64 bit */
/* #undef HAVE_64BIT_LONG */
#define HAVE_32BIT_LONG 1
#define HAVE_32BIT_PTR 1
/* #undef HAVE_64BIT_PTR */
/* Check if __psint_t is set to something meaningful */
/* #undef HAVE___PSINT_T */
#ifndef HAVE___PSINT_T
# ifdef HAVE_32BIT_PTR
typedef int __psint_t;
# elif defined HAVE_64BIT_PTR
# ifdef HAVE_64BIT_LONG
typedef long __psint_t;
# else
/* This is a very strange architecture, which has 64 bit pointers but
* not 64 bit longs. So, I'd just punt here and assume long long is Ok */
typedef long long __psint_t;
# endif
# else
# error Unknown pointer size
# endif
#endif
/* Check if __psunsigned_t is set to something meaningful */
/* #undef HAVE___PSUNSIGNED_T */
#ifndef HAVE___PSUNSIGNED_T
# ifdef HAVE_32BIT_PTR
typedef unsigned int __psunsigned_t;
# elif defined HAVE_64BIT_PTR
# ifdef HAVE_64BIT_LONG
typedef long __psunsigned_t;
# else
/* This is a very strange architecture, which has 64 bit pointers but
* not 64 bit longs. So, I'd just punt here and assume long long is Ok */
typedef unsigned long long __psunsigned_t;
# endif
# else
# error Unknown pointer size
# endif
#endif
#ifdef DEBUG
# define ASSERT assert
#else
# define ASSERT(EX) ((void) 0)
#endif
#endif /* __XFS_PLATFORM_DEFS_H__ */

View File

@@ -0,0 +1,87 @@
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2001, 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>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#include <uuid/uuid.h>
#include "platform_defs.h"
#include "xfs_types.h"
#include "xfs_sb.h"
static PedGeometry*
xfs_probe (PedGeometry* geom)
{
PedSector block_size;
PedSector block_count;
struct xfs_sb *sb = alloca (geom->dev->sector_size);
if (geom->length < XFS_SB_DADDR + 1)
return NULL;
if (!ped_geometry_read (geom, sb, XFS_SB_DADDR, 1))
return NULL;
if (PED_LE32_TO_CPU (sb->sb_magicnum) == XFS_SB_MAGIC) {
block_size = PED_LE32_TO_CPU (sb->sb_blocksize) / geom->dev->sector_size;
block_count = PED_LE64_TO_CPU (sb->sb_dblocks);
return ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
}
if (PED_BE32_TO_CPU (sb->sb_magicnum) == XFS_SB_MAGIC) {
block_size = PED_BE32_TO_CPU (sb->sb_blocksize) / geom->dev->sector_size;
block_count = PED_BE64_TO_CPU (sb->sb_dblocks);
geom = ped_geometry_new (geom->dev, geom->start,
block_size * block_count);
return geom;
}
return NULL;
}
static PedFileSystemOps xfs_ops = {
probe: xfs_probe,
};
static PedFileSystemType xfs_type = {
next: NULL,
ops: &xfs_ops,
name: "xfs",
};
void
ped_file_system_xfs_init ()
{
ped_file_system_type_register (&xfs_type);
}
void
ped_file_system_xfs_done ()
{
ped_file_system_type_unregister (&xfs_type);
}

View File

@@ -0,0 +1,489 @@
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#ifndef __XFS_SB_H__
#define __XFS_SB_H__
/*
* Super block
* Fits into a 512-byte buffer at daddr_t 0 of each allocation group.
* Only the first of these is ever updated except during growfs.
*/
struct xfs_buf;
struct xfs_mount;
#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */
#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
#define XFS_SB_VERSION_NUMBITS 0x000f
#define XFS_SB_VERSION_ALLFBITS 0xfff0
#define XFS_SB_VERSION_SASHFBITS 0xf000
#define XFS_SB_VERSION_REALFBITS 0x0ff0
#define XFS_SB_VERSION_ATTRBIT 0x0010
#define XFS_SB_VERSION_NLINKBIT 0x0020
#define XFS_SB_VERSION_QUOTABIT 0x0040
#define XFS_SB_VERSION_ALIGNBIT 0x0080
#define XFS_SB_VERSION_DALIGNBIT 0x0100
#define XFS_SB_VERSION_SHAREDBIT 0x0200
#define XFS_SB_VERSION_EXTFLGBIT 0x1000
#define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_OKSASHFBITS \
(XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT)
#define XFS_SB_VERSION_OKREALFBITS \
(XFS_SB_VERSION_ATTRBIT | \
XFS_SB_VERSION_NLINKBIT | \
XFS_SB_VERSION_QUOTABIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_DALIGNBIT | \
XFS_SB_VERSION_SHAREDBIT)
#define XFS_SB_VERSION_OKSASHBITS \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_REALFBITS | \
XFS_SB_VERSION_OKSASHFBITS)
#define XFS_SB_VERSION_OKREALBITS \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_OKREALFBITS | \
XFS_SB_VERSION_OKSASHFBITS)
#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2) \
(((ia) || (dia) || (extflag) || (dirv2)) ? \
(XFS_SB_VERSION_4 | \
((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \
((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \
((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \
((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0)) : \
XFS_SB_VERSION_1)
typedef struct xfs_sb
{
uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
uint32_t sb_blocksize; /* logical block size, bytes */
xfs_drfsbno_t sb_dblocks; /* number of data blocks */
xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
xfs_drtbno_t sb_rextents; /* number of realtime extents */
uuid_t sb_uuid; /* file system unique id */
xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
xfs_ino_t sb_rootino; /* root inode number */
xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
xfs_agblock_t sb_agblocks; /* size of an allocation group */
xfs_agnumber_t sb_agcount; /* number of allocation groups */
xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
xfs_extlen_t sb_logblocks; /* number of log blocks */
uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
uint16_t sb_sectsize; /* volume sector size, bytes */
uint16_t sb_inodesize; /* inode size, bytes */
uint16_t sb_inopblock; /* inodes per block */
char sb_fname[12]; /* file system name */
uint8_t sb_blocklog; /* log2 of sb_blocksize */
uint8_t sb_sectlog; /* log2 of sb_sectsize */
uint8_t sb_inodelog; /* log2 of sb_inodesize */
uint8_t sb_inopblog; /* log2 of sb_inopblock */
uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
uint8_t sb_rextslog; /* log2 of sb_rextents */
uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
uint8_t sb_imax_pct; /* max % of fs for inode space */
/* statistics */
/*
* These fields must remain contiguous. If you really
* want to change their layout, make sure you fix the
* code in xfs_trans_apply_sb_deltas().
*/
uint64_t sb_icount; /* allocated inodes */
uint64_t sb_ifree; /* free inodes */
uint64_t sb_fdblocks; /* free data blocks */
uint64_t sb_frextents; /* free realtime extents */
/*
* End contiguous fields.
*/
xfs_ino_t sb_uquotino; /* user quota inode */
xfs_ino_t sb_gquotino; /* group quota inode */
uint16_t sb_qflags; /* quota flags */
uint8_t sb_flags; /* misc. flags */
uint8_t sb_shared_vn; /* shared version number */
xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
uint32_t sb_unit; /* stripe or raid unit */
uint32_t sb_width; /* stripe or raid width */
uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
uint8_t sb_dummy[7]; /* padding */
} xfs_sb_t;
/*
* Sequence number values for the fields.
*/
typedef enum {
XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
XFS_SBS_DUMMY,
XFS_SBS_FIELDCOUNT
} xfs_sb_field_t;
/*
* Mask values, defined based on the xfs_sb_field_t values.
* Only define the ones we're using.
*/
#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
#define XFS_SB_UUID XFS_SB_MVAL(UUID)
#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
#define XFS_SB_MOD_BITS \
(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH)
/*
* Misc. Flags - warning - these will be cleared by xfs_repair unless
* a feature bit is set when the flag is used.
*/
#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
/*
* define max. shared version we can interoperate with
*/
#define XFS_SB_MAX_SHARED_VN 0
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_NUM)
int xfs_sb_version_num(xfs_sb_t *sbp);
#define XFS_SB_VERSION_NUM(sbp) xfs_sb_version_num(sbp)
#else
#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_GOOD_VERSION)
int xfs_sb_good_version(xfs_sb_t *sbp);
#define XFS_SB_GOOD_VERSION(sbp) xfs_sb_good_version(sbp)
#else
#define XFS_SB_GOOD_VERSION_INT(sbp) \
((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
!((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS)
#ifdef __KERNEL__
#define XFS_SB_GOOD_VERSION(sbp) \
(XFS_SB_GOOD_VERSION_INT(sbp) && \
(sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN) ))
#else
/*
* extra 2 paren's here (( to unconfuse paren-matching editors
* like vi because XFS_SB_GOOD_VERSION_INT is a partial expression
* and the two XFS_SB_GOOD_VERSION's each 2 more close paren's to
* complete the expression.
*/
#define XFS_SB_GOOD_VERSION(sbp) \
(XFS_SB_GOOD_VERSION_INT(sbp) && \
(!((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \
(sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)) ))
#endif /* __KERNEL__ */
#endif
#define XFS_SB_GOOD_SASH_VERSION(sbp) \
((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
!((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS)))
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TONEW)
unsigned xfs_sb_version_tonew(unsigned v);
#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v)
#else
#define XFS_SB_VERSION_TONEW(v) \
((((v) == XFS_SB_VERSION_1) ? \
0 : \
(((v) == XFS_SB_VERSION_2) ? \
XFS_SB_VERSION_ATTRBIT : \
(XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \
XFS_SB_VERSION_4)
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TOOLD)
unsigned xfs_sb_version_toold(unsigned v);
#define XFS_SB_VERSION_TOOLD(v) xfs_sb_version_toold(v)
#else
#define XFS_SB_VERSION_TOOLD(v) \
(((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \
0 : \
(((v) & XFS_SB_VERSION_NLINKBIT) ? \
XFS_SB_VERSION_3 : \
(((v) & XFS_SB_VERSION_ATTRBIT) ? \
XFS_SB_VERSION_2 : \
XFS_SB_VERSION_1)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASATTR)
int xfs_sb_version_hasattr(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASATTR(sbp) xfs_sb_version_hasattr(sbp)
#else
#define XFS_SB_VERSION_HASATTR(sbp) \
(((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \
((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDATTR)
void xfs_sb_version_addattr(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDATTR(sbp) xfs_sb_version_addattr(sbp)
#else
#define XFS_SB_VERSION_ADDATTR(sbp) \
((sbp)->sb_versionnum = \
(((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \
XFS_SB_VERSION_2 : \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \
((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \
(XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT))))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASNLINK)
int xfs_sb_version_hasnlink(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASNLINK(sbp) xfs_sb_version_hasnlink(sbp)
#else
#define XFS_SB_VERSION_HASNLINK(sbp) \
(((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDNLINK)
void xfs_sb_version_addnlink(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDNLINK(sbp) xfs_sb_version_addnlink(sbp)
#else
#define XFS_SB_VERSION_ADDNLINK(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \
XFS_SB_VERSION_3 : \
((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASQUOTA)
int xfs_sb_version_hasquota(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASQUOTA(sbp) xfs_sb_version_hasquota(sbp)
#else
#define XFS_SB_VERSION_HASQUOTA(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDQUOTA)
void xfs_sb_version_addquota(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDQUOTA(sbp) xfs_sb_version_addquota(sbp)
#else
#define XFS_SB_VERSION_ADDQUOTA(sbp) \
((sbp)->sb_versionnum = \
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \
((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \
(XFS_SB_VERSION_TONEW((sbp)->sb_versionnum) | \
XFS_SB_VERSION_QUOTABIT)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASALIGN)
int xfs_sb_version_hasalign(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASALIGN(sbp) xfs_sb_version_hasalign(sbp)
#else
#define XFS_SB_VERSION_HASALIGN(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBALIGN)
void xfs_sb_version_subalign(xfs_sb_t *sbp);
#define XFS_SB_VERSION_SUBALIGN(sbp) xfs_sb_version_subalign(sbp)
#else
#define XFS_SB_VERSION_SUBALIGN(sbp) \
((sbp)->sb_versionnum = \
XFS_SB_VERSION_TOOLD((sbp)->sb_versionnum & ~XFS_SB_VERSION_ALIGNBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDALIGN)
int xfs_sb_version_hasdalign(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASDALIGN(sbp) xfs_sb_version_hasdalign(sbp)
#else
#define XFS_SB_VERSION_HASDALIGN(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDDALIGN)
int xfs_sb_version_adddalign(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDDALIGN(sbp) xfs_sb_version_adddalign(sbp)
#else
#define XFS_SB_VERSION_ADDDALIGN(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum | XFS_SB_VERSION_DALIGNBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASSHARED)
int xfs_sb_version_hasshared(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASSHARED(sbp) xfs_sb_version_hasshared(sbp)
#else
#define XFS_SB_VERSION_HASSHARED(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDSHARED)
int xfs_sb_version_addshared(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDSHARED(sbp) xfs_sb_version_addshared(sbp)
#else
#define XFS_SB_VERSION_ADDSHARED(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum | XFS_SB_VERSION_SHAREDBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBSHARED)
int xfs_sb_version_subshared(xfs_sb_t *sbp);
#define XFS_SB_VERSION_SUBSHARED(sbp) xfs_sb_version_subshared(sbp)
#else
#define XFS_SB_VERSION_SUBSHARED(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum & ~XFS_SB_VERSION_SHAREDBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDIRV2)
int xfs_sb_version_hasdirv2(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASDIRV2(sbp) xfs_sb_version_hasdirv2(sbp)
#else
#define XFS_SB_VERSION_HASDIRV2(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT)
int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp)
#else
#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDEXTFLGBIT)
int xfs_sb_version_addextflgbit(xfs_sb_t *sbp);
#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) xfs_sb_version_addextflgbit(sbp)
#else
#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum | XFS_SB_VERSION_EXTFLGBIT))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBEXTFLGBIT)
int xfs_sb_version_subextflgbit(xfs_sb_t *sbp);
#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) xfs_sb_version_subextflgbit(sbp)
#else
#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) \
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum & ~XFS_SB_VERSION_EXTFLGBIT))
#endif
/*
* end of superblock version macros
*/
#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in file system/ag */
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_BLOCK)
xfs_agblock_t xfs_sb_block(struct xfs_mount *mp);
#define XFS_SB_BLOCK(mp) xfs_sb_block(mp)
#else
#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_HDR_BLOCK)
xfs_agblock_t xfs_hdr_block(struct xfs_mount *mp, xfs_daddr_t d);
#define XFS_HDR_BLOCK(mp,d) xfs_hdr_block(mp,d)
#else
#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp,d)))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_FSB)
xfs_fsblock_t xfs_daddr_to_fsb(struct xfs_mount *mp, xfs_daddr_t d);
#define XFS_DADDR_TO_FSB(mp,d) xfs_daddr_to_fsb(mp,d)
#else
#define XFS_DADDR_TO_FSB(mp,d) \
XFS_AGB_TO_FSB(mp, XFS_DADDR_TO_AGNO(mp,d), XFS_DADDR_TO_AGBNO(mp,d))
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DADDR)
xfs_daddr_t xfs_fsb_to_daddr(struct xfs_mount *mp, xfs_fsblock_t fsbno);
#define XFS_FSB_TO_DADDR(mp,fsbno) xfs_fsb_to_daddr(mp,fsbno)
#else
#define XFS_FSB_TO_DADDR(mp,fsbno) \
XFS_AGB_TO_DADDR(mp, XFS_FSB_TO_AGNO(mp,fsbno), \
XFS_FSB_TO_AGBNO(mp,fsbno))
#endif
/*
* File system block to basic block conversions.
*/
#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
#define XFS_BB_TO_FSB(mp,bb) \
(((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
#define XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1))
/*
* File system block to byte conversions.
*/
#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << \
(mp)->m_sb.sb_blocklog)
#define XFS_B_TO_FSB(mp,b) \
((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBP)
xfs_sb_t *xfs_buf_to_sbp(struct xfs_buf *bp);
#define XFS_BUF_TO_SBP(bp) xfs_buf_to_sbp(bp)
#else
#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp))
#endif
#endif /* __XFS_SB_H__ */

View File

@@ -0,0 +1,302 @@
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#ifndef __XFS_TYPES_H__
#define __XFS_TYPES_H__
/*
* Some types are conditional based on the selected configuration.
* Set XFS_BIG_FILES=1 or 0 and XFS_BIG_FILESYSTEMS=1 or 0 depending
* on the desired configuration.
* XFS_BIG_FILES needs pgno_t to be 64 bits (64-bit kernels).
* XFS_BIG_FILESYSTEMS needs daddr_t to be 64 bits (N32 and 64-bit kernels).
*
* Expect these to be set from klocaldefs, or from the machine-type
* defs files for the normal case.
*/
#define XFS_BIG_FILES 1
#define XFS_BIG_FILESYSTEMS 1
typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
typedef uint32_t xfs_extlen_t; /* extent length in blocks */
typedef uint32_t xfs_agnumber_t; /* allocation group number */
typedef int32_t xfs_extnum_t; /* # of extents in a file */
typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
typedef int64_t xfs_fsize_t; /* bytes in a file */
typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
typedef int64_t xfs_lsn_t; /* log sequence number */
typedef int32_t xfs_tid_t; /* transaction identifier */
typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
typedef uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */
/*
* These types are 64 bits on disk but are either 32 or 64 bits in memory.
* Disk based types:
*/
typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
typedef uint64_t xfs_dfiloff_t; /* block number in a file */
typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
/*
* Memory based types are conditional.
*/
#if XFS_BIG_FILESYSTEMS
typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
#else
typedef uint32_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
typedef uint32_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
typedef uint32_t xfs_rtblock_t; /* extent (block) in realtime area */
typedef int32_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
#endif
#if XFS_BIG_FILES
typedef uint64_t xfs_fileoff_t; /* block number in a file */
typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
#else
typedef uint32_t xfs_fileoff_t; /* block number in a file */
typedef int32_t xfs_sfiloff_t; /* signed block number in a file */
typedef uint32_t xfs_filblks_t; /* number of blocks in a file */
#endif
typedef uint8_t xfs_arch_t; /* architecutre of an xfs fs */
/*
* Null values for the types.
*/
#define NULLDFSBNO ((xfs_dfsbno_t)-1)
#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
#define NULLDRTBNO ((xfs_drtbno_t)-1)
#define NULLDFILOFF ((xfs_dfiloff_t)-1)
#define NULLFSBLOCK ((xfs_fsblock_t)-1)
#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
#define NULLRTBLOCK ((xfs_rtblock_t)-1)
#define NULLFILEOFF ((xfs_fileoff_t)-1)
#define NULLAGBLOCK ((xfs_agblock_t)-1)
#define NULLAGNUMBER ((xfs_agnumber_t)-1)
#define NULLEXTNUM ((xfs_extnum_t)-1)
#define NULLCOMMITLSN ((xfs_lsn_t)-1)
/*
* Max values for extlen, extnum, aextnum.
*/
#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
/*
* MAXNAMELEN is the length (including the terminating null) of
* the longest permissible file (component) name.
*/
#define MAXNAMELEN 256
typedef enum {
XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
} xfs_lookup_t;
typedef enum {
XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
XFS_BTNUM_MAX
} xfs_btnum_t;
#ifdef CONFIG_PROC_FS
/*
* XFS global statistics
*/
struct xfsstats {
# define XFSSTAT_END_EXTENT_ALLOC 4
uint32_t xs_allocx;
uint32_t xs_allocb;
uint32_t xs_freex;
uint32_t xs_freeb;
# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4)
uint32_t xs_abt_lookup;
uint32_t xs_abt_compare;
uint32_t xs_abt_insrec;
uint32_t xs_abt_delrec;
# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7)
uint32_t xs_blk_mapr;
uint32_t xs_blk_mapw;
uint32_t xs_blk_unmap;
uint32_t xs_add_exlist;
uint32_t xs_del_exlist;
uint32_t xs_look_exlist;
uint32_t xs_cmp_exlist;
# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4)
uint32_t xs_bmbt_lookup;
uint32_t xs_bmbt_compare;
uint32_t xs_bmbt_insrec;
uint32_t xs_bmbt_delrec;
# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4)
uint32_t xs_dir_lookup;
uint32_t xs_dir_create;
uint32_t xs_dir_remove;
uint32_t xs_dir_getdents;
# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3)
uint32_t xs_trans_sync;
uint32_t xs_trans_async;
uint32_t xs_trans_empty;
# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7)
uint32_t xs_ig_attempts;
uint32_t xs_ig_found;
uint32_t xs_ig_frecycle;
uint32_t xs_ig_missed;
uint32_t xs_ig_dup;
uint32_t xs_ig_reclaims;
uint32_t xs_ig_attrchg;
# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5)
uint32_t xs_log_writes;
uint32_t xs_log_blocks;
uint32_t xs_log_noiclogs;
uint32_t xs_log_force;
uint32_t xs_log_force_sleep;
# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10)
uint32_t xs_try_logspace;
uint32_t xs_sleep_logspace;
uint32_t xs_push_ail;
uint32_t xs_push_ail_success;
uint32_t xs_push_ail_pushbuf;
uint32_t xs_push_ail_pinned;
uint32_t xs_push_ail_locked;
uint32_t xs_push_ail_flushing;
uint32_t xs_push_ail_restarts;
uint32_t xs_push_ail_flush;
# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2)
uint32_t xs_xstrat_quick;
uint32_t xs_xstrat_split;
# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2)
uint32_t xs_write_calls;
uint32_t xs_read_calls;
# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4)
uint32_t xs_attr_get;
uint32_t xs_attr_set;
uint32_t xs_attr_remove;
uint32_t xs_attr_list;
# define XFSSTAT_END_QUOTA_OPS (XFSSTAT_END_ATTRIBUTE_OPS+8)
uint32_t xs_qm_dqreclaims;
uint32_t xs_qm_dqreclaim_misses;
uint32_t xs_qm_dquot_dups;
uint32_t xs_qm_dqcachemisses;
uint32_t xs_qm_dqcachehits;
uint32_t xs_qm_dqwants;
uint32_t xs_qm_dqshake_reclaims;
uint32_t xs_qm_dqinact_reclaims;
# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_QUOTA_OPS+3)
uint32_t xs_iflush_count;
uint32_t xs_icluster_flushcnt;
uint32_t xs_icluster_flushinode;
# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8)
uint32_t vn_active; /* # vnodes not on free lists */
uint32_t vn_alloc; /* # times vn_alloc called */
uint32_t vn_get; /* # times vn_get called */
uint32_t vn_hold; /* # times vn_hold called */
uint32_t vn_rele; /* # times vn_rele called */
uint32_t vn_reclaim; /* # times vn_reclaim called */
uint32_t vn_remove; /* # times vn_remove called */
uint32_t vn_free; /* # times vn_free called */
struct xfsstats_xpc {
uint64_t xs_xstrat_bytes;
uint64_t xs_write_bytes;
uint64_t xs_read_bytes;
} xpc;
} xfsstats;
# define XFS_STATS_INC(count) ( xfsstats.##count ++ )
# define XFS_STATS_DEC(count) ( xfsstats.##count -- )
# define XFS_STATS_ADD(count, inc) ( xfsstats.##count += (inc) )
# define XFS_STATS64_INC(count) ( xfsstats.xpc.##count ++ )
# define XFS_STATS64_ADD(count, inc) ( xfsstats.xpc.##count += (inc) )
#else /* !CONFIG_PROC_FS */
# define XFS_STATS_INC(count)
# define XFS_STATS_DEC(count)
# define XFS_STATS_ADD(count, inc)
# define XFS_STATS64_INC(count)
# define XFS_STATS64_ADD(count, inc)
#endif /* !CONFIG_PROC_FS */
#ifdef __KERNEL__
/* juggle IRIX device numbers - still used in ondisk structures */
#define IRIX_DEV_BITSMAJOR 14
#define IRIX_DEV_BITSMINOR 18
#define IRIX_DEV_MAXMAJ 0x1ff
#define IRIX_DEV_MAXMIN 0x3ffff
#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \
& IRIX_DEV_MAXMAJ))
#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN))
#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)<<IRIX_DEV_BITSMINOR) \
| (minor&IRIX_DEV_MAXMIN)))
#define IRIX_DEV_TO_KDEVT(dev) MKDEV(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev))
#define IRIX_DEV_TO_DEVT(dev) ((IRIX_DEV_MAJOR(dev)<<8)|IRIX_DEV_MINOR(dev))
/* __psint_t is the same size as a pointer */
#if (BITS_PER_LONG == 32)
typedef int32_t __psint_t;
typedef uint32_t __psunsigned_t;
#elif (BITS_PER_LONG == 64)
typedef int64_t __psint_t;
typedef uint64_t __psunsigned_t;
#else
#error BITS_PER_LONG must be 32 or 64
#endif
/*
* struct for passing owner/requestor id
*/
typedef struct flid {
#ifdef CELL_CAPABLE
pid_t fl_pid;
sysid_t fl_sysid;
#endif
} flid_t;
#endif /* __KERNEL__ */
#endif /* !__XFS_TYPES_H */