pmt: initial 3.0.2 update
This commit is contained in:
88
jni/parted/libparted/fs/amiga/a-interface.c
Executable file
88
jni/parted/libparted/fs/amiga/a-interface.c
Executable 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);
|
||||
}
|
||||
292
jni/parted/libparted/fs/amiga/affs.c
Executable file
292
jni/parted/libparted/fs/amiga/affs.c
Executable 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",
|
||||
};
|
||||
19
jni/parted/libparted/fs/amiga/affs.h
Executable file
19
jni/parted/libparted/fs/amiga/affs.h
Executable 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/>.
|
||||
*/
|
||||
351
jni/parted/libparted/fs/amiga/amiga.c
Executable file
351
jni/parted/libparted/fs/amiga/amiga.c
Executable 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;
|
||||
}
|
||||
70
jni/parted/libparted/fs/amiga/amiga.h
Executable file
70
jni/parted/libparted/fs/amiga/amiga.h
Executable 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;
|
||||
128
jni/parted/libparted/fs/amiga/apfs.c
Executable file
128
jni/parted/libparted/fs/amiga/apfs.c
Executable 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",
|
||||
};
|
||||
18
jni/parted/libparted/fs/amiga/apfs.h
Executable file
18
jni/parted/libparted/fs/amiga/apfs.h
Executable 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/>.
|
||||
*/
|
||||
130
jni/parted/libparted/fs/amiga/asfs.c
Executable file
130
jni/parted/libparted/fs/amiga/asfs.c
Executable 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",
|
||||
};
|
||||
18
jni/parted/libparted/fs/amiga/asfs.h
Executable file
18
jni/parted/libparted/fs/amiga/asfs.h
Executable 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/>.
|
||||
*/
|
||||
77
jni/parted/libparted/fs/btrfs/btrfs.c
Executable file
77
jni/parted/libparted/fs/btrfs/btrfs.c
Executable 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);
|
||||
}
|
||||
79
jni/parted/libparted/fs/ext2/ext2.h
Executable file
79
jni/parted/libparted/fs/ext2/ext2.h
Executable 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
|
||||
329
jni/parted/libparted/fs/ext2/ext2_fs.h
Executable file
329
jni/parted/libparted/fs/ext2/ext2_fs.h
Executable 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
|
||||
163
jni/parted/libparted/fs/ext2/interface.c
Executable file
163
jni/parted/libparted/fs/ext2/interface.c
Executable 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);
|
||||
}
|
||||
60
jni/parted/libparted/fs/f2fs/f2fs.c
Executable file
60
jni/parted/libparted/fs/f2fs/f2fs.c
Executable 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);
|
||||
}
|
||||
57
jni/parted/libparted/fs/f2fs/f2fs.h
Executable file
57
jni/parted/libparted/fs/f2fs/f2fs.h
Executable 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
|
||||
271
jni/parted/libparted/fs/fat/bootsector.c
Executable file
271
jni/parted/libparted/fs/fat/bootsector.c
Executable 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;
|
||||
}
|
||||
126
jni/parted/libparted/fs/fat/bootsector.h
Executable file
126
jni/parted/libparted/fs/fat/bootsector.h
Executable 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 */
|
||||
46
jni/parted/libparted/fs/fat/count.h
Executable file
46
jni/parted/libparted/fs/fat/count.h
Executable 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
162
jni/parted/libparted/fs/fat/fat.c
Executable 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
163
jni/parted/libparted/fs/fat/fat.h
Executable 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
92
jni/parted/libparted/fs/hfs/DOC
Executable 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.
|
||||
|
||||
---
|
||||
115
jni/parted/libparted/fs/hfs/HISTORY
Executable file
115
jni/parted/libparted/fs/hfs/HISTORY
Executable 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
|
||||
27
jni/parted/libparted/fs/hfs/TODO
Executable file
27
jni/parted/libparted/fs/hfs/TODO
Executable 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(+)
|
||||
92
jni/parted/libparted/fs/hfs/hfs.c
Executable file
92
jni/parted/libparted/fs/hfs/hfs.c
Executable 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
648
jni/parted/libparted/fs/hfs/hfs.h
Executable 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 */
|
||||
238
jni/parted/libparted/fs/hfs/probe.c
Executable file
238
jni/parted/libparted/fs/hfs/probe.c
Executable 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;
|
||||
}
|
||||
44
jni/parted/libparted/fs/hfs/probe.h
Executable file
44
jni/parted/libparted/fs/hfs/probe.h
Executable 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 */
|
||||
80
jni/parted/libparted/fs/jfs/jfs.c
Executable file
80
jni/parted/libparted/fs/jfs/jfs.c
Executable 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);
|
||||
}
|
||||
144
jni/parted/libparted/fs/jfs/jfs_superblock.h
Executable file
144
jni/parted/libparted/fs/jfs/jfs_superblock.h
Executable 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 */
|
||||
527
jni/parted/libparted/fs/jfs/jfs_types.h
Executable file
527
jni/parted/libparted/fs/jfs/jfs_types.h
Executable 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 */
|
||||
396
jni/parted/libparted/fs/linux_swap/linux_swap.c
Executable file
396
jni/parted/libparted/fs/linux_swap/linux_swap.c
Executable 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);
|
||||
}
|
||||
155
jni/parted/libparted/fs/nilfs2/nilfs2.c
Executable file
155
jni/parted/libparted/fs/nilfs2/nilfs2.c
Executable 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);
|
||||
}
|
||||
73
jni/parted/libparted/fs/ntfs/ntfs.c
Executable file
73
jni/parted/libparted/fs/ntfs/ntfs.c
Executable 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);
|
||||
}
|
||||
441
jni/parted/libparted/fs/r/fat/bootsector.c
Executable file
441
jni/parted/libparted/fs/r/fat/bootsector.c
Executable 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 */
|
||||
130
jni/parted/libparted/fs/r/fat/bootsector.h
Executable file
130
jni/parted/libparted/fs/r/fat/bootsector.h
Executable 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 */
|
||||
433
jni/parted/libparted/fs/r/fat/calc.c
Executable file
433
jni/parted/libparted/fs/r/fat/calc.c
Executable 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 */
|
||||
77
jni/parted/libparted/fs/r/fat/calc.h
Executable file
77
jni/parted/libparted/fs/r/fat/calc.h
Executable 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 */
|
||||
423
jni/parted/libparted/fs/r/fat/clstdup.c
Executable file
423
jni/parted/libparted/fs/r/fat/clstdup.c
Executable 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 */
|
||||
28
jni/parted/libparted/fs/r/fat/clstdup.h
Executable file
28
jni/parted/libparted/fs/r/fat/clstdup.h
Executable 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 */
|
||||
261
jni/parted/libparted/fs/r/fat/context.c
Executable file
261
jni/parted/libparted/fs/r/fat/context.c
Executable 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 */
|
||||
70
jni/parted/libparted/fs/r/fat/context.h
Executable file
70
jni/parted/libparted/fs/r/fat/context.h
Executable 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 */
|
||||
319
jni/parted/libparted/fs/r/fat/count.c
Executable file
319
jni/parted/libparted/fs/r/fat/count.c
Executable 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 */
|
||||
46
jni/parted/libparted/fs/r/fat/count.h
Executable file
46
jni/parted/libparted/fs/r/fat/count.h
Executable 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 */
|
||||
652
jni/parted/libparted/fs/r/fat/fat.c
Executable file
652
jni/parted/libparted/fs/r/fat/fat.c
Executable 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 */
|
||||
159
jni/parted/libparted/fs/r/fat/fat.h
Executable file
159
jni/parted/libparted/fs/r/fat/fat.h
Executable 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 */
|
||||
150
jni/parted/libparted/fs/r/fat/fatio.c
Executable file
150
jni/parted/libparted/fs/r/fat/fatio.c
Executable 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 */
|
||||
49
jni/parted/libparted/fs/r/fat/fatio.h
Executable file
49
jni/parted/libparted/fs/r/fat/fatio.h
Executable 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 */
|
||||
876
jni/parted/libparted/fs/r/fat/resize.c
Executable file
876
jni/parted/libparted/fs/r/fat/resize.c
Executable 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 */
|
||||
481
jni/parted/libparted/fs/r/fat/table.c
Executable file
481
jni/parted/libparted/fs/r/fat/table.c
Executable 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;
|
||||
}
|
||||
74
jni/parted/libparted/fs/r/fat/table.h
Executable file
74
jni/parted/libparted/fs/r/fat/table.h
Executable 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 */
|
||||
368
jni/parted/libparted/fs/r/fat/traverse.c
Executable file
368
jni/parted/libparted/fs/r/fat/traverse.c
Executable 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 */
|
||||
75
jni/parted/libparted/fs/r/fat/traverse.h
Executable file
75
jni/parted/libparted/fs/r/fat/traverse.h
Executable 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 */
|
||||
320
jni/parted/libparted/fs/r/filesys.c
Executable file
320
jni/parted/libparted/fs/r/filesys.c
Executable 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);
|
||||
}
|
||||
332
jni/parted/libparted/fs/r/hfs/advfs.c
Executable file
332
jni/parted/libparted/fs/r/hfs/advfs.c
Executable 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 */
|
||||
49
jni/parted/libparted/fs/r/hfs/advfs.h
Executable file
49
jni/parted/libparted/fs/r/hfs/advfs.h
Executable 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 */
|
||||
385
jni/parted/libparted/fs/r/hfs/advfs_plus.c
Executable file
385
jni/parted/libparted/fs/r/hfs/advfs_plus.c
Executable 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 */
|
||||
52
jni/parted/libparted/fs/r/hfs/advfs_plus.h
Executable file
52
jni/parted/libparted/fs/r/hfs/advfs_plus.h
Executable 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 */
|
||||
239
jni/parted/libparted/fs/r/hfs/cache.c
Executable file
239
jni/parted/libparted/fs/r/hfs/cache.c
Executable 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 */
|
||||
118
jni/parted/libparted/fs/r/hfs/cache.h
Executable file
118
jni/parted/libparted/fs/r/hfs/cache.h
Executable 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 */
|
||||
0
jni/parted/libparted/fs/r/hfs/file-16771e92.o.tmp
Executable file
0
jni/parted/libparted/fs/r/hfs/file-16771e92.o.tmp
Executable file
229
jni/parted/libparted/fs/r/hfs/file.c
Executable file
229
jni/parted/libparted/fs/r/hfs/file.c
Executable 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 */
|
||||
42
jni/parted/libparted/fs/r/hfs/file.h
Executable file
42
jni/parted/libparted/fs/r/hfs/file.h
Executable 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 */
|
||||
274
jni/parted/libparted/fs/r/hfs/file_plus.c
Executable file
274
jni/parted/libparted/fs/r/hfs/file_plus.c
Executable 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 */
|
||||
61
jni/parted/libparted/fs/r/hfs/file_plus.h
Executable file
61
jni/parted/libparted/fs/r/hfs/file_plus.h
Executable 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 */
|
||||
1166
jni/parted/libparted/fs/r/hfs/hfs.c
Executable file
1166
jni/parted/libparted/fs/r/hfs/hfs.c
Executable file
File diff suppressed because it is too large
Load Diff
648
jni/parted/libparted/fs/r/hfs/hfs.h
Executable file
648
jni/parted/libparted/fs/r/hfs/hfs.h
Executable 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 */
|
||||
392
jni/parted/libparted/fs/r/hfs/journal.c
Executable file
392
jni/parted/libparted/fs/r/hfs/journal.c
Executable 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 */
|
||||
45
jni/parted/libparted/fs/r/hfs/journal.h
Executable file
45
jni/parted/libparted/fs/r/hfs/journal.h
Executable 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 */
|
||||
99
jni/parted/libparted/fs/r/hfs/probe.c
Executable file
99
jni/parted/libparted/fs/r/hfs/probe.c
Executable 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;
|
||||
}
|
||||
35
jni/parted/libparted/fs/r/hfs/probe.h
Executable file
35
jni/parted/libparted/fs/r/hfs/probe.h
Executable 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 */
|
||||
676
jni/parted/libparted/fs/r/hfs/reloc.c
Executable file
676
jni/parted/libparted/fs/r/hfs/reloc.c
Executable 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 */
|
||||
36
jni/parted/libparted/fs/r/hfs/reloc.h
Executable file
36
jni/parted/libparted/fs/r/hfs/reloc.h
Executable 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 */
|
||||
948
jni/parted/libparted/fs/r/hfs/reloc_plus.c
Executable file
948
jni/parted/libparted/fs/r/hfs/reloc_plus.c
Executable 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 */
|
||||
37
jni/parted/libparted/fs/r/hfs/reloc_plus.h
Executable file
37
jni/parted/libparted/fs/r/hfs/reloc_plus.h
Executable 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 */
|
||||
94
jni/parted/libparted/fs/reiserfs/reiserfs.c
Executable file
94
jni/parted/libparted/fs/reiserfs/reiserfs.c
Executable 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);
|
||||
}
|
||||
109
jni/parted/libparted/fs/reiserfs/reiserfs.h
Executable file
109
jni/parted/libparted/fs/reiserfs/reiserfs.h
Executable 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
175
jni/parted/libparted/fs/udf/udf.c
Executable 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
281
jni/parted/libparted/fs/ufs/ufs.c
Executable 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);
|
||||
}
|
||||
109
jni/parted/libparted/fs/xfs/platform_defs.h
Executable file
109
jni/parted/libparted/fs/xfs/platform_defs.h
Executable 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__ */
|
||||
87
jni/parted/libparted/fs/xfs/xfs.c
Executable file
87
jni/parted/libparted/fs/xfs/xfs.c
Executable 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);
|
||||
}
|
||||
489
jni/parted/libparted/fs/xfs/xfs_sb.h
Executable file
489
jni/parted/libparted/fs/xfs/xfs_sb.h
Executable 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__ */
|
||||
302
jni/parted/libparted/fs/xfs/xfs_types.h
Executable file
302
jni/parted/libparted/fs/xfs/xfs_types.h
Executable 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 */
|
||||
Reference in New Issue
Block a user