pmt: initial 3.0.2 update
This commit is contained in:
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 */
|
||||
Reference in New Issue
Block a user