This commit is contained in:
2024-12-14 10:43:33 +03:00
parent 7f8090bb1f
commit bbf76e4925
1292 changed files with 2823 additions and 500876 deletions

View File

@@ -1,441 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2002, 2004, 2007, 2009-2014, 2019-2023 Free
Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
/* Reads in the boot sector (superblock), and does a minimum of sanity
* checking. The goals are:
* - to detect fat file systems, even if they are damaged [i.e. not
* return an error / throw an exception]
* - to fail detection if there's not enough information for
* fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero)
*/
int
fat_boot_sector_read (FatBootSector** bsp, const PedGeometry *geom)
{
PED_ASSERT (bsp != NULL);
PED_ASSERT (geom != NULL);
if (!ped_geometry_read_alloc (geom, (void **)bsp, 0, 1))
return 0;
FatBootSector *bs = *bsp;
if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("File system has an invalid signature for a FAT "
"file system."));
return 0;
}
if (!bs->sector_size
|| PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("File system has an invalid sector size for a FAT "
"file system."));
return 0;
}
if (!bs->cluster_size) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("File system has an invalid cluster size for a FAT "
"file system."));
return 0;
}
if (!bs->reserved) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("File system has an invalid number of reserved "
"sectors for a FAT file system."));
return 0;
}
if (bs->fats < 1 || bs->fats > 4) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("File system has an invalid number of FATs."));
return 0;
}
return 1;
}
/*
Don't trust the FAT12, FAT16 or FAT32 label string.
*/
FatType _GL_ATTRIBUTE_PURE
fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
{
PedSector logical_sector_size;
PedSector first_cluster_sector;
FatCluster cluster_count;
if (!PED_LE16_TO_CPU (bs->dir_entries))
return FAT_TYPE_FAT32;
logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
first_cluster_sector
= PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
+ 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
+ PED_LE16_TO_CPU (bs->dir_entries)
/ (512 / sizeof (FatDirEntry));
cluster_count = (geom->length - first_cluster_sector)
/ bs->cluster_size / logical_sector_size;
if (cluster_count > MAX_FAT12_CLUSTERS)
return FAT_TYPE_FAT16;
else
return FAT_TYPE_FAT12;
}
/* Analyses the boot sector, and sticks appropriate numbers in
fs->type_specific.
Note: you need to subtract (2 * cluster_sectors) off cluster offset,
because the first cluster is number 2. (0 and 1 are not real clusters,
and referencing them is a bug)
*/
int
fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
int fat_entry_size;
PED_ASSERT (bs != NULL);
fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
fs_info->heads = PED_LE16_TO_CPU (bs->heads);
if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
|| fs_info->heads < 1 || fs_info->heads > 255) {
PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
int cyl_count = 0;
if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
cyl_count = fs->geom->dev->length / fs_info->heads
/ fs_info->sectors_per_track;
switch (ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE
+ PED_EXCEPTION_CANCEL,
_("The file system's CHS geometry is (%d, %d, %d), "
"which is invalid. The partition table's CHS "
"geometry is (%d, %d, %d). If you select Ignore, "
"the file system's CHS geometry will be left "
"unchanged. If you select Fix, the file system's "
"CHS geometry will be set to match the partition "
"table's CHS geometry."),
cyl_count, fs_info->heads, fs_info->sectors_per_track,
bios_geom->cylinders, bios_geom->heads,
bios_geom->sectors)) {
case PED_EXCEPTION_FIX:
fs_info->sectors_per_track = bios_geom->sectors;
fs_info->heads = bios_geom->heads;
bs->secs_track
= PED_CPU_TO_LE16 (fs_info->sectors_per_track);
bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
if (!fat_boot_sector_write (bs, fs))
return 0;
break;
case PED_EXCEPTION_CANCEL:
return 0;
case PED_EXCEPTION_IGNORE:
break;
default:
break;
}
}
if (bs->sectors)
fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
* fs_info->logical_sector_size;
else
fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
* fs_info->logical_sector_size;
fs_info->fat_table_count = bs->fats;
fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
* fs_info->logical_sector_size;
fs_info->cluster_sectors = bs->cluster_size
* fs_info->logical_sector_size;
fs_info->cluster_size = fs_info->cluster_sectors * 512;
if (fs_info->logical_sector_size == 0) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("FAT boot sector says logical sector size is 0. "
"This is weird. "));
return 0;
}
if (fs_info->fat_table_count == 0) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("FAT boot sector says there are no FAT tables. This "
"is weird. "));
return 0;
}
if (fs_info->cluster_sectors == 0) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("FAT boot sector says clusters are 0 sectors. This "
"is weird. "));
return 0;
}
fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
if (fs_info->fat_type == FAT_TYPE_FAT12) {
ped_exception_throw (
PED_EXCEPTION_NO_FEATURE,
PED_EXCEPTION_CANCEL,
_("File system is FAT12, which is unsupported."));
return 0;
}
if (fs_info->fat_type == FAT_TYPE_FAT16) {
fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
* fs_info->logical_sector_size;
fs_info->serial_number
= PED_LE32_TO_CPU (bs->u.fat16.serial_number);
fs_info->root_cluster = 0;
fs_info->root_dir_offset
= fs_info->fat_offset
+ fs_info->fat_sectors * fs_info->fat_table_count;
fs_info->root_dir_sector_count
= fs_info->root_dir_entry_count * sizeof (FatDirEntry)
/ (512 * fs_info->logical_sector_size);
fs_info->cluster_offset
= fs_info->root_dir_offset
+ fs_info->root_dir_sector_count;
}
if (fs_info->fat_type == FAT_TYPE_FAT32) {
fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
* fs_info->logical_sector_size;
fs_info->serial_number
= PED_LE32_TO_CPU (bs->u.fat32.serial_number);
fs_info->info_sector_offset
= PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.info_sector)
* fs_info->logical_sector_size;
fs_info->boot_sector_backup_offset
= PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.backup_sector)
* fs_info->logical_sector_size;
fs_info->root_cluster
= PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
fs_info->root_dir_offset = 0;
fs_info->root_dir_sector_count = 0;
fs_info->cluster_offset
= fs_info->fat_offset
+ fs_info->fat_sectors * fs_info->fat_table_count;
}
fs_info->cluster_count
= (fs_info->sector_count - fs_info->cluster_offset)
/ fs_info->cluster_sectors;
fat_entry_size = fat_table_entry_size (fs_info->fat_type);
if (fs_info->cluster_count + 2
> fs_info->fat_sectors * 512 / fat_entry_size)
fs_info->cluster_count
= fs_info->fat_sectors * 512 / fat_entry_size - 2;
fs_info->dir_entries_per_cluster
= fs_info->cluster_size / sizeof (FatDirEntry);
return 1;
}
#ifndef DISCOVER_ONLY
int
fat_boot_sector_set_boot_code (FatBootSector** bsp, const PedFileSystem* fs)
{
PED_ASSERT (bsp != NULL);
*bsp = ped_malloc (fs->geom->dev->sector_size);
FatBootSector *bs = *bsp;
PED_ASSERT (bs != NULL);
memset (bs, 0, 512);
memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3);
PED_ASSERT (sizeof(FAT_BOOT_CODE) < sizeof(bs->u.fat32.boot_code));
strcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE);
return 1;
}
int
fat_boot_sector_generate (FatBootSector** bsp, const PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (bsp != NULL);
FatBootSector *bs = *bsp;
PED_ASSERT (bs != NULL);
memcpy (bs->system_id, "MSWIN4.1", 8);
bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512);
bs->cluster_size = fs_info->cluster_sectors
/ fs_info->logical_sector_size;
bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset
/ fs_info->logical_sector_size);
bs->fats = fs_info->fat_table_count;
bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16)
? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count)
: 0;
if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff
|| fs_info->fat_type == FAT_TYPE_FAT32) {
bs->sectors = 0;
bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count
/ fs_info->logical_sector_size);
} else {
bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count
/ fs_info->logical_sector_size);
bs->sector_count = 0;
}
bs->media = 0xf8;
bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
bs->hidden = PED_CPU_TO_LE32 (fs->geom->start);
if (fs_info->fat_type == FAT_TYPE_FAT32) {
bs->fat_length = 0;
bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors
/ fs_info->logical_sector_size);
bs->u.fat32.flags = 0; /* FIXME: what the hell are these? */
bs->u.fat32.version = 0; /* must be 0, for Win98 bootstrap */
bs->u.fat32.root_dir_cluster
= PED_CPU_TO_LE32 (fs_info->root_cluster);
bs->u.fat32.info_sector
= PED_CPU_TO_LE16 (fs_info->info_sector_offset
/ fs_info->logical_sector_size);
bs->u.fat32.backup_sector
= PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset
/ fs_info->logical_sector_size);
bs->u.fat32.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
memset (bs->u.fat32.empty_1, 0, 12);
bs->u.fat32.ext_signature = 0x29;
bs->u.fat32.serial_number
= PED_CPU_TO_LE32 (fs_info->serial_number);
memcpy (bs->u.fat32.volume_name, "NO NAME ", 11);
memcpy (bs->u.fat32.fat_name, "FAT32 ", 8);
} else {
bs->fat_length
= PED_CPU_TO_LE16 (fs_info->fat_sectors
/ fs_info->logical_sector_size);
bs->u.fat16.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
bs->u.fat16.ext_signature = 0x29;
bs->u.fat16.serial_number
= PED_CPU_TO_LE32 (fs_info->serial_number);
memcpy (bs->u.fat16.volume_name, "NO NAME ", 11);
memcpy (bs->u.fat16.fat_name, "FAT16 ", 8);
}
bs->boot_sign = PED_CPU_TO_LE16 (0xaa55);
return 1;
}
int
fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (bs != NULL);
if (!ped_geometry_write (fs->geom, bs, 0, 1))
return 0;
if (fs_info->fat_type == FAT_TYPE_FAT32) {
if (!ped_geometry_write (fs->geom, bs,
fs_info->boot_sector_backup_offset, 1))
return 0;
}
return ped_geometry_sync (fs->geom);
}
int
fat_info_sector_read (FatInfoSector** isp, const PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
int status;
PED_ASSERT (isp != NULL);
if (!ped_geometry_read_alloc (fs->geom, (void **)isp, fs_info->info_sector_offset, 1))
return 0;
FatInfoSector *is = *isp;
if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) {
status = ped_exception_throw (PED_EXCEPTION_WARNING,
PED_EXCEPTION_IGNORE_CANCEL,
_("The information sector has the wrong "
"signature (%x). Select cancel for now, "
"and send in a bug report. If you're "
"desperate, it's probably safe to ignore."),
PED_LE32_TO_CPU (is->signature_2));
if (status == PED_EXCEPTION_CANCEL) return 0;
}
return 1;
}
int
fat_info_sector_generate (FatInfoSector** isp, const PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (isp != NULL);
*isp = ped_malloc (fs->geom->dev->sector_size);
FatInfoSector *is = *isp;
fat_table_count_stats (fs_info->fat);
memset (is, 0, 512);
is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1);
is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2);
is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count);
is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc);
is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3);
return 1;
}
int
fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (is != NULL);
if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
return 0;
return ped_geometry_sync (fs->geom);
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,130 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PED_FAT_BOOTSECTOR_H
#define PED_FAT_BOOTSECTOR_H
typedef struct _FatBootSector FatBootSector;
typedef struct _FatInfoSector FatInfoSector;
#include "fat.h"
#define FAT32_INFO_MAGIC1 0x41615252
#define FAT32_INFO_MAGIC2 0x61417272
#define FAT32_INFO_MAGIC3 0xaa55
/* stolen from mkdosfs, by Dave Hudson */
#define FAT_BOOT_MESSAGE \
"This partition does not have an operating system loader installed on it.\n\r"\
"Press a key to reboot..."
#define FAT_BOOT_JUMP "\xeb\x58\x90" /* jmp +5a */
#define FAT_BOOT_CODE "\x0e" /* push cs */ \
"\x1f" /* pop ds */ \
"\xbe\x74\x7e" /* mov si, offset message */ \
/* write_msg_loop: */ \
"\xac" /* lodsb */ \
"\x22\xc0" /* and al, al */ \
"\x74\x06" /* jz done (+8) */ \
"\xb4\x0e" /* mov ah, 0x0e */ \
"\xcd\x10" /* int 0x10 */ \
"\xeb\xf5" /* jmp write_msg_loop */ \
/* done: */ \
"\xb4\x00" /* mov ah, 0x00 */ \
"\xcd\x16" /* int 0x16 */ \
"\xb4\x00" /* mov ah, 0x00 */ \
"\xcd\x19" /* int 0x19 */ \
"\xeb\xfe" /* jmp +0 - in case int 0x19 */ \
/* doesn't work */ \
/* message: */ \
FAT_BOOT_MESSAGE
struct __attribute__ ((packed)) _FatBootSector {
uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */
uint8_t system_id[8]; /* 03: system name */
uint16_t sector_size; /* 0b: bytes per logical sector */
uint8_t cluster_size; /* 0d: sectors/cluster */
uint16_t reserved; /* 0e: reserved sectors */
uint8_t fats; /* 10: number of FATs */
uint16_t dir_entries; /* 11: number of root directory entries */
uint16_t sectors; /* 13: if 0, total_sect supersedes */
uint8_t media; /* 15: media code */
uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */
uint16_t secs_track; /* 18: sectors per track */
uint16_t heads; /* 1a: number of heads */
uint32_t hidden; /* 1c: hidden sectors (partition start) */
uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */
union __attribute__ ((packed)) {
/* FAT16 fields */
struct __attribute__ ((packed)) {
uint8_t drive_num; /* 24: */
uint8_t empty_1; /* 25: */
uint8_t ext_signature; /* 26: always 0x29 */
uint32_t serial_number; /* 27: */
uint8_t volume_name [11]; /* 2b: */
uint8_t fat_name [8]; /* 36: */
uint8_t boot_code[448]; /* 3f: Boot code (or message) */
} fat16;
/* FAT32 fields */
struct __attribute__ ((packed)) {
uint32_t fat_length; /* 24: size of FAT in sectors */
uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */
uint16_t version; /* 2a: minor * 256 + major */
uint32_t root_dir_cluster; /* 2c: */
uint16_t info_sector; /* 30: */
uint16_t backup_sector; /* 32: */
uint8_t empty_1 [12]; /* 34: */
uint16_t drive_num; /* 40: */
uint8_t ext_signature; /* 42: always 0x29 */
uint32_t serial_number; /* 43: */
uint8_t volume_name [11]; /* 47: */
uint8_t fat_name [8]; /* 52: */
uint8_t boot_code[420]; /* 5a: Boot code (or message) */
} fat32;
} u;
uint16_t boot_sign; /* 1fe: always 0xAA55 */
};
struct __attribute__ ((packed)) _FatInfoSector {
uint32_t signature_1; /* should be 0x41615252 */
uint8_t unused [480];
uint32_t signature_2; /* should be 0x61417272 */
uint32_t free_clusters;
uint32_t next_cluster; /* most recently allocated cluster */
uint8_t unused2 [0xe];
uint16_t signature_3; /* should be 0xaa55 */
};
int fat_boot_sector_read (FatBootSector** bs, const PedGeometry* geom);
FatType fat_boot_sector_probe_type (const FatBootSector* bs,
const PedGeometry* geom);
int fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs);
int fat_boot_sector_set_boot_code (FatBootSector** bs, const PedFileSystem* fs);
int fat_boot_sector_generate (FatBootSector** bs, const PedFileSystem* fs);
int fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs);
int fat_info_sector_read (FatInfoSector** is, const PedFileSystem* fs);
int fat_info_sector_generate (FatInfoSector** is, const PedFileSystem* fs);
int fat_info_sector_write (const FatInfoSector* is, PedFileSystem* fs);
#endif /* PED_FAT_BOOTSECTOR_H */

View File

@@ -1,433 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2002, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#ifndef DISCOVER_ONLY
/* returns the minimum size of clusters for a given file system type */
PedSector _GL_ATTRIBUTE_CONST
fat_min_cluster_size (FatType fat_type) {
switch (fat_type) {
case FAT_TYPE_FAT12: return 1;
case FAT_TYPE_FAT16: return 1024/512;
case FAT_TYPE_FAT32: return 4096/512;
}
return 0;
}
static PedSector _GL_ATTRIBUTE_CONST
_smallest_power2_over (PedSector ceiling)
{
PedSector result = 1;
while (result < ceiling)
result *= 2;
return result;
}
/* returns the minimum size of clusters for a given file system type */
PedSector _GL_ATTRIBUTE_CONST
fat_recommend_min_cluster_size (FatType fat_type, PedSector size) {
switch (fat_type) {
case FAT_TYPE_FAT12: return 1;
case FAT_TYPE_FAT16: return fat_min_cluster_size(fat_type);
case FAT_TYPE_FAT32:
return PED_MAX(_smallest_power2_over(size
/ MAX_FAT32_CLUSTERS),
fat_min_cluster_size (fat_type));
}
return 0;
}
/* returns the maxmimum size of clusters for a given file system type */
PedSector _GL_ATTRIBUTE_CONST
fat_max_cluster_size (FatType fat_type) {
switch (fat_type) {
case FAT_TYPE_FAT12: return 1; /* dunno... who cares? */
case FAT_TYPE_FAT16: return 65536/512;
case FAT_TYPE_FAT32: return 65536/512;
}
return 0;
}
/* returns the minimum number of clusters for a given file system type */
FatCluster _GL_ATTRIBUTE_CONST
fat_min_cluster_count (FatType fat_type) {
switch (fat_type) {
case FAT_TYPE_FAT12:
case FAT_TYPE_FAT16:
return fat_max_cluster_count (fat_type) / 2;
case FAT_TYPE_FAT32: return 0xfff0;
}
return 0;
}
/* returns the maximum number of clusters for a given file system type */
FatCluster _GL_ATTRIBUTE_CONST
fat_max_cluster_count (FatType fat_type) {
switch (fat_type) {
case FAT_TYPE_FAT12: return 0xff0;
case FAT_TYPE_FAT16: return 0xfff0;
case FAT_TYPE_FAT32: return 0x0ffffff0;
}
return 0;
}
/* what is this supposed to be? What drugs are M$ on? (Can I have some? :-) */
PedSector _GL_ATTRIBUTE_CONST
fat_min_reserved_sector_count (FatType fat_type)
{
return (fat_type == FAT_TYPE_FAT32) ? 32 : 1;
}
int
fat_check_resize_geometry (const PedFileSystem* fs,
const PedGeometry* geom,
PedSector new_cluster_sectors,
FatCluster new_cluster_count)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector free_space;
PedSector min_free_space;
PedSector total_space;
PedSector new_total_space;
PedSector dir_space;
PED_ASSERT (geom != NULL);
dir_space = fs_info->total_dir_clusters * fs_info->cluster_sectors;
free_space = fs_info->fat->free_cluster_count
* fs_info->cluster_sectors;
total_space = fs_info->fat->cluster_count * fs_info->cluster_sectors;
new_total_space = new_cluster_count * new_cluster_sectors;
min_free_space = total_space - new_total_space + dir_space;
PED_ASSERT (new_cluster_count
<= fat_max_cluster_count (FAT_TYPE_FAT32));
if (free_space < min_free_space) {
char* needed = ped_unit_format (geom->dev, min_free_space);
char* have = ped_unit_format (geom->dev, free_space);
ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("You need %s of free disk space to shrink this "
"partition to this size. Currently, only %s is "
"free."),
needed, have);
free (needed);
free (have);
return 0;
}
return 1;
}
/******************************************************************************/
/* DO NOT EDIT THIS ALGORITHM!
* As far as I can tell, this is the same algorithm used by Microsoft to
* calculate the size of the file allocaion tables, and the number of clusters.
* I have not verified this by dissassembling Microsoft code - I came to this
* conclusion by empirical analysis (i.e. trial and error - this was HORRIBLE).
*
* If you think this code makes no sense, then you are right. I will restrain
* the urge to inflict serious bodily harm on Microsoft people.
*/
static int
entries_per_sector (FatType fat_type)
{
switch (fat_type) {
case FAT_TYPE_FAT12:
return 512 * 3 / 2;
case FAT_TYPE_FAT16:
return 512 / 2;
case FAT_TYPE_FAT32:
return 512 / 4;
}
return 0;
}
static int
calc_sizes (PedSector size, PedSector align, FatType fat_type,
PedSector root_dir_sectors, PedSector cluster_sectors,
FatCluster* out_cluster_count, PedSector* out_fat_size)
{
PedSector data_fat_space; /* space available to clusters + FAT */
PedSector fat_space; /* space taken by each FAT */
PedSector cluster_space; /* space taken by clusters */
FatCluster cluster_count;
int i;
PED_ASSERT (out_cluster_count != NULL);
PED_ASSERT (out_fat_size != NULL);
data_fat_space = size - fat_min_reserved_sector_count (fat_type)
- align;
if (fat_type == FAT_TYPE_FAT16)
data_fat_space -= root_dir_sectors;
fat_space = 0;
for (i = 0; i < 2; i++) {
if (fat_type == FAT_TYPE_FAT32)
cluster_space = data_fat_space - fat_space;
else
cluster_space = data_fat_space - 2 * fat_space;
cluster_count = cluster_space / cluster_sectors;
fat_space = ped_div_round_up (cluster_count + 2,
entries_per_sector (fat_type));
}
cluster_space = data_fat_space - 2 * fat_space;
cluster_count = cluster_space / cluster_sectors;
/* looks like this should be part of the loop condition?
* Need to build the Big Table TM again to check
*/
if (fat_space < ped_div_round_up (cluster_count + 2,
entries_per_sector (fat_type))) {
fat_space = ped_div_round_up (cluster_count + 2,
entries_per_sector (fat_type));
}
if (cluster_count > fat_max_cluster_count (fat_type)
|| cluster_count < fat_min_cluster_count (fat_type))
return 0;
*out_cluster_count = cluster_count;
*out_fat_size = fat_space;
return 1;
}
/****************************************************************************/
int
fat_calc_sizes (PedSector size, PedSector align, FatType fat_type,
PedSector root_dir_sectors,
PedSector* out_cluster_sectors, FatCluster* out_cluster_count,
PedSector* out_fat_size)
{
PedSector cluster_sectors;
PED_ASSERT (out_cluster_sectors != NULL);
PED_ASSERT (out_cluster_count != NULL);
PED_ASSERT (out_fat_size != NULL);
for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
cluster_sectors <= fat_max_cluster_size (fat_type);
cluster_sectors *= 2) {
if (calc_sizes (size, align, fat_type, root_dir_sectors,
cluster_sectors,
out_cluster_count, out_fat_size)) {
*out_cluster_sectors = cluster_sectors;
return 1;
}
}
for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
cluster_sectors >= fat_min_cluster_size (fat_type);
cluster_sectors /= 2) {
if (calc_sizes (size, align, fat_type, root_dir_sectors,
cluster_sectors,
out_cluster_count, out_fat_size)) {
*out_cluster_sectors = cluster_sectors;
return 1;
}
}
/* only make the cluster size really small (<4k) if a bigger one is
* isn't possible. Windows never makes FS's like this, but it
* seems to work... (do more tests!)
*/
for (cluster_sectors = 4; cluster_sectors > 0; cluster_sectors /= 2) {
if (calc_sizes (size, align, fat_type, root_dir_sectors,
cluster_sectors,
out_cluster_count, out_fat_size)) {
*out_cluster_sectors = cluster_sectors;
return 1;
}
}
return 0;
}
/* Same as fat_calc_sizes, except it only attempts to match a particular
* cluster size. This is useful, because the FAT resizer can only shrink the
* cluster size.
*/
int
fat_calc_resize_sizes (
const PedGeometry* geom,
PedSector align,
FatType fat_type,
PedSector root_dir_sectors,
PedSector cluster_sectors,
PedSector* out_cluster_sectors,
FatCluster* out_cluster_count,
PedSector* out_fat_size)
{
PED_ASSERT (geom != NULL);
PED_ASSERT (out_cluster_sectors != NULL);
PED_ASSERT (out_cluster_count != NULL);
PED_ASSERT (out_fat_size != NULL);
/* libparted can only reduce the cluster size at this point */
for (*out_cluster_sectors = cluster_sectors;
*out_cluster_sectors >= fat_min_cluster_size (fat_type);
*out_cluster_sectors /= 2) {
if (calc_sizes (geom->length, align, fat_type, root_dir_sectors,
*out_cluster_sectors,
out_cluster_count, out_fat_size))
return 1;
}
return 0;
}
/* Calculates the number of sectors needed to be added to cluster_offset,
to make the cluster on the new file system match up with the ones
on the old file system.
However, some space is reserved by fat_calc_resize_sizes() and
friends, to allow room for this space. If too much of this space is left
over, everyone will complain, so we have to be greedy, and use it all up...
*/
PedSector _GL_ATTRIBUTE_PURE
fat_calc_align_sectors (const PedFileSystem* new_fs,
const PedFileSystem* old_fs)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
PedSector raw_old_meta_data_end;
PedSector new_meta_data_size;
PedSector min_new_meta_data_end;
PedSector new_data_size;
PedSector new_clusters_size;
PedSector align;
new_meta_data_size
= fat_min_reserved_sector_count (new_fs_info->fat_type)
+ new_fs_info->fat_sectors * 2;
if (new_fs_info->fat_type == FAT_TYPE_FAT16)
new_meta_data_size += new_fs_info->root_dir_sector_count;
raw_old_meta_data_end = old_fs->geom->start
+ old_fs_info->cluster_offset;
min_new_meta_data_end = new_fs->geom->start + new_meta_data_size;
if (raw_old_meta_data_end > min_new_meta_data_end)
align = (raw_old_meta_data_end - min_new_meta_data_end)
% new_fs_info->cluster_sectors;
else
align = (new_fs_info->cluster_sectors
- ( (min_new_meta_data_end - raw_old_meta_data_end)
% new_fs_info->cluster_sectors ))
% new_fs_info->cluster_sectors;
new_data_size = new_fs->geom->length - new_meta_data_size;
new_clusters_size = new_fs_info->cluster_count
* new_fs_info->cluster_sectors;
while (new_clusters_size + align + new_fs_info->cluster_sectors
<= new_data_size)
align += new_fs_info->cluster_sectors;
return align;
}
int _GL_ATTRIBUTE_PURE
fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
return sector >= fs_info->cluster_offset
&& sector < fs_info->cluster_offset
+ fs_info->cluster_sectors * fs_info->cluster_count;
}
FatFragment _GL_ATTRIBUTE_PURE
fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
return (cluster - 2) * fs_info->cluster_frags;
}
FatCluster _GL_ATTRIBUTE_PURE
fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
return frag / fs_info->cluster_frags + 2;
}
PedSector _GL_ATTRIBUTE_PURE
fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
return frag * fs_info->frag_sectors + fs_info->cluster_offset;
}
FatFragment _GL_ATTRIBUTE_PURE
fat_sector_to_frag (const PedFileSystem* fs, PedSector sector)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (sector >= fs_info->cluster_offset);
return (sector - fs_info->cluster_offset) / fs_info->frag_sectors;
}
PedSector _GL_ATTRIBUTE_PURE
fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
return (cluster - 2) * fs_info->cluster_sectors
+ fs_info->cluster_offset;
}
FatCluster _GL_ATTRIBUTE_PURE
fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (sector >= fs_info->cluster_offset);
return (sector - fs_info->cluster_offset) / fs_info->cluster_sectors
+ 2;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,77 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PED_FAT_CALC_H
#define PED_FAT_CALC_H
extern PedSector fat_min_cluster_size (FatType fat_type);
extern PedSector fat_max_cluster_size (FatType fat_type);
extern FatCluster fat_min_cluster_count (FatType fat_type);
extern FatCluster fat_max_cluster_count (FatType fat_type);
extern PedSector fat_min_reserved_sector_count (FatType fat_type);
extern int fat_check_resize_geometry (const PedFileSystem* fs,
const PedGeometry* geom,
PedSector new_cluster_sectors,
FatCluster new_cluster_count);
extern int fat_calc_sizes (PedSector size,
PedSector align,
FatType fat_type,
PedSector root_dir_sectors,
PedSector* out_cluster_sectors,
FatCluster* out_cluster_count,
PedSector* out_fat_size);
extern int fat_calc_resize_sizes (const PedGeometry* geom,
PedSector align,
FatType fat_type,
PedSector root_dir_sectors,
PedSector cluster_sectors,
PedSector* out_cluster_sectors,
FatCluster* out_cluster_count,
PedSector* out_fat_size);
extern PedSector
fat_calc_align_sectors (const PedFileSystem* new_fs,
const PedFileSystem* old_fs);
extern int
fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector);
extern FatFragment
fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster);
extern FatCluster
fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag);
extern PedSector
fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag);
extern FatFragment
fat_sector_to_frag (const PedFileSystem* fs, PedSector sector);
extern PedSector
fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster);
extern FatCluster
fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector);
#endif /* PED_FAT_CALC_H */

View File

@@ -1,423 +0,0 @@
/*
libparted
Copyright (C) 1998-2001, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <string.h>
#include "fat.h"
#ifndef DISCOVER_ONLY
static int
needs_duplicating (const FatOpContext* ctx, FatFragment frag)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatCluster cluster = fat_frag_to_cluster (ctx->old_fs, frag);
FatClusterFlag flag;
PED_ASSERT (cluster >= 2 && cluster < old_fs_info->cluster_count + 2);
flag = fat_get_fragment_flag (ctx->old_fs, frag);
switch (flag) {
case FAT_FLAG_FREE:
return 0;
case FAT_FLAG_DIRECTORY:
return 1;
case FAT_FLAG_FILE:
return fat_op_context_map_static_fragment (ctx, frag) == -1;
case FAT_FLAG_BAD:
return 0;
}
return 0;
}
static int
search_next_fragment (FatOpContext* ctx)
{
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
for (; ctx->buffer_offset < fs_info->frag_count; ctx->buffer_offset++) {
if (needs_duplicating (ctx, ctx->buffer_offset))
return 1;
}
return 0; /* all done! */
}
static int
read_marked_fragments (FatOpContext* ctx, FatFragment length)
{
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
int status;
FatFragment i;
ped_exception_fetch_all ();
status = fat_read_fragments (ctx->old_fs, fs_info->buffer,
ctx->buffer_offset, length);
ped_exception_leave_all ();
if (status)
return 1;
ped_exception_catch ();
/* something bad happened, so read fragments one by one. (The error may
have occurred on an unused fragment: who cares) */
for (i = 0; i < length; i++) {
if (ctx->buffer_map [i]) {
if (!fat_read_fragment (ctx->old_fs,
fs_info->buffer + i * fs_info->frag_size,
ctx->buffer_offset + i))
return 0;
}
}
return 1;
}
static int
fetch_fragments (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatFragment fetch_length = 0;
FatFragment frag;
for (frag = 0; frag < ctx->buffer_frags; frag++)
ctx->buffer_map [frag] = -1;
for (frag = 0;
frag < ctx->buffer_frags
&& ctx->buffer_offset + frag < old_fs_info->frag_count;
frag++) {
if (needs_duplicating (ctx, ctx->buffer_offset + frag)) {
ctx->buffer_map [frag] = 1;
fetch_length = frag + 1;
}
}
if (!read_marked_fragments (ctx, fetch_length))
return 0;
return 1;
}
/*****************************************************************************
* here starts the write code. All assumes that ctx->buffer_map [first] and
* ctx->buffer_map [last] are occupied by fragments that need to be duplicated.
*****************************************************************************/
/* finds the first fragment that is not going to get overwritten (that needs to
get read in) */
static FatFragment _GL_ATTRIBUTE_PURE
get_first_underlay (const FatOpContext* ctx, int first, int last)
{
int old;
FatFragment new;
PED_ASSERT (first <= last);
new = ctx->buffer_map [first];
for (old = first + 1; old <= last; old++) {
if (ctx->buffer_map [old] == -1)
continue;
new++;
if (ctx->buffer_map [old] != new)
return new;
}
return -1;
}
/* finds the last fragment that is not going to get overwritten (that needs to
get read in) */
static FatFragment _GL_ATTRIBUTE_PURE
get_last_underlay (const FatOpContext* ctx, int first, int last)
{
int old;
FatFragment new;
PED_ASSERT (first <= last);
new = ctx->buffer_map [last];
for (old = last - 1; old >= first; old--) {
if (ctx->buffer_map [old] == -1)
continue;
new--;
if (ctx->buffer_map [old] != new)
return new;
}
return -1;
}
/* "underlay" refers to the "static" fragments, that remain unchanged.
* when writing large chunks at a time, we don't want to clobber these,
* so we read them in, and write them back again. MUCH quicker that way.
*/
static int
quick_group_write_read_underlay (FatOpContext* ctx, int first, int last)
{
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatFragment first_underlay;
FatFragment last_underlay;
FatFragment underlay_length;
PED_ASSERT (first <= last);
first_underlay = get_first_underlay (ctx, first, last);
if (first_underlay == -1)
return 1;
last_underlay = get_last_underlay (ctx, first, last);
PED_ASSERT (first_underlay <= last_underlay);
underlay_length = last_underlay - first_underlay + 1;
if (!fat_read_fragments (ctx->new_fs,
new_fs_info->buffer
+ (first_underlay - ctx->buffer_map [first])
* new_fs_info->frag_size,
first_underlay,
underlay_length))
return 0;
return 1;
}
/* quick_group_write() makes no attempt to recover from errors - just
* does things fast. If there is an error, slow_group_write() is
* called.
* Note: we do syncing writes, to make sure there isn't any
* error writing out. It's rather difficult recovering from errors
* further on.
*/
static int
quick_group_write (FatOpContext* ctx, int first, int last)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
int active_length;
int i;
int offset;
PED_ASSERT (first <= last);
ped_exception_fetch_all ();
if (!quick_group_write_read_underlay (ctx, first, last))
goto error;
for (i = first; i <= last; i++) {
if (ctx->buffer_map [i] == -1)
continue;
offset = ctx->buffer_map [i] - ctx->buffer_map [first];
memcpy (new_fs_info->buffer + offset * new_fs_info->frag_size,
old_fs_info->buffer + i * new_fs_info->frag_size,
new_fs_info->frag_size);
}
active_length = ctx->buffer_map [last] - ctx->buffer_map [first] + 1;
if (!fat_write_sync_fragments (ctx->new_fs, new_fs_info->buffer,
ctx->buffer_map [first], active_length))
goto error;
ped_exception_leave_all ();
return 1;
error:
ped_exception_catch ();
ped_exception_leave_all ();
return 0;
}
/* Writes fragments out, one at a time, avoiding errors on redundant writes
* on damaged parts of the disk we already know about. If there's an error
* on one of the required fragments, it gets marked as bad, and a replacement
* is found.
*/
static int
slow_group_write (FatOpContext* ctx, int first, int last)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
int i;
PED_ASSERT (first <= last);
for (i = first; i <= last; i++) {
if (ctx->buffer_map [i] == -1)
continue;
while (!fat_write_sync_fragment (ctx->new_fs,
old_fs_info->buffer + i * old_fs_info->frag_size,
ctx->buffer_map [i])) {
fat_table_set_bad (new_fs_info->fat,
ctx->buffer_map [i]);
ctx->buffer_map [i] = fat_table_alloc_cluster
(new_fs_info->fat);
if (ctx->buffer_map [i] == 0)
return 0;
}
}
return 1;
}
static int
update_remap (FatOpContext* ctx, int first, int last)
{
int i;
PED_ASSERT (first <= last);
for (i = first; i <= last; i++) {
if (ctx->buffer_map [i] == -1)
continue;
ctx->remap [ctx->buffer_offset + i] = ctx->buffer_map [i];
}
return 1;
}
static int
group_write (FatOpContext* ctx, int first, int last)
{
PED_ASSERT (first <= last);
if (!quick_group_write (ctx, first, last)) {
if (!slow_group_write (ctx, first, last))
return 0;
}
if (!update_remap (ctx, first, last))
return 0;
return 1;
}
/* assumes fragment size and new_fs's cluster size are equal */
static int
write_fragments (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
int group_start;
int group_end = -1; /* shut gcc up! */
FatFragment mapped_length;
FatFragment i;
FatCluster new_cluster;
PED_ASSERT (ctx->buffer_offset < old_fs_info->frag_count);
group_start = -1;
for (i = 0; i < ctx->buffer_frags; i++) {
if (ctx->buffer_map [i] == -1)
continue;
ctx->frags_duped++;
new_cluster = fat_table_alloc_cluster (new_fs_info->fat);
if (!new_cluster)
return 0;
fat_table_set_eof (new_fs_info->fat, new_cluster);
ctx->buffer_map [i] = fat_cluster_to_frag (ctx->new_fs,
new_cluster);
if (group_start == -1)
group_start = group_end = i;
PED_ASSERT (ctx->buffer_map [i]
>= ctx->buffer_map [group_start]);
mapped_length = ctx->buffer_map [i]
- ctx->buffer_map [group_start] + 1;
if (mapped_length <= ctx->buffer_frags) {
group_end = i;
} else {
/* ran out of room in the buffer, so write this group,
* and start a new one...
*/
if (!group_write (ctx, group_start, group_end))
return 0;
group_start = group_end = i;
}
}
PED_ASSERT (group_start != -1);
if (!group_write (ctx, group_start, group_end))
return 0;
return 1;
}
/* default all fragments to unmoved
*/
static void
init_remap (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatFragment i;
for (i = 0; i < old_fs_info->frag_count; i++)
ctx->remap[i] = fat_op_context_map_static_fragment (ctx, i);
}
static FatFragment
count_frags_to_dup (FatOpContext* ctx)
{
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
FatFragment i;
FatFragment total;
total = 0;
for (i = 0; i < fs_info->frag_count; i++) {
if (needs_duplicating (ctx, i))
total++;
}
return total;
}
/* duplicates unreachable file clusters, and all directory clusters
*/
int
fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer)
{
FatFragment total_frags_to_dup;
init_remap (ctx);
total_frags_to_dup = count_frags_to_dup (ctx);
ped_timer_reset (timer);
ped_timer_set_state_name (timer, "moving data");
ctx->buffer_offset = 0;
ctx->frags_duped = 0;
while (search_next_fragment (ctx)) {
ped_timer_update (
timer, 1.0 * ctx->frags_duped / total_frags_to_dup);
if (!fetch_fragments (ctx))
return 0;
if (!write_fragments (ctx))
return 0;
ctx->buffer_offset += ctx->buffer_frags;
}
ped_timer_update (timer, 1.0);
return 1;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,28 +0,0 @@
/*
libparted
Copyright (C) 1999, 2007, 2009-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PED_FAT_CLSTDUP_H_INCLUDED
#define PED_FAT_CLSTDUP_H_INCLUDED
#include "context.h"
/* the big important one :-) */
extern int fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer);
#endif /* PED_FAT_CLSTDUP_H_INCLUDED */

View File

@@ -1,261 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <string.h>
#include "fat.h"
#ifndef DISCOVER_ONLY
/* Note: this deals with file system start and end sectors, even if the physical
* devices are different (eg for fat_copy()) Perhaps this is a hack, but it
* works ;-)
*/
static int
calc_deltas (FatOpContext* ctx)
{
PedFileSystem* old_fs = ctx->old_fs;
PedFileSystem* new_fs = ctx->new_fs;
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
PedSector old_cluster_ofs;
PedSector new_cluster_ofs;
PedSector sector_delta;
old_cluster_ofs = old_fs->geom->start + old_fs_info->cluster_offset;
new_cluster_ofs = new_fs->geom->start + new_fs_info->cluster_offset;
if (new_cluster_ofs > old_cluster_ofs) {
ctx->start_move_dir = FAT_DIR_FORWARD;
sector_delta = new_cluster_ofs - old_cluster_ofs;
} else {
ctx->start_move_dir = FAT_DIR_BACKWARD;
sector_delta = old_cluster_ofs - new_cluster_ofs;
}
if (sector_delta % new_fs_info->cluster_sectors) {
ped_exception_throw (
PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
_("Cluster start delta = %d, which is not a multiple "
"of the cluster size %d."),
(int) sector_delta,
(int) new_fs_info->cluster_sectors);
return 0;
}
ctx->start_move_delta = sector_delta / ctx->frag_sectors;
#ifdef PED_VERBOSE
printf ("Start move delta is: %d %s.\n",
(int) ctx->start_move_delta,
(ctx->start_move_dir == FAT_DIR_FORWARD)?
"forwards" : "backwards");
#endif
return 1;
}
FatOpContext*
fat_op_context_new (PedFileSystem* new_fs, PedFileSystem* old_fs)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
FatOpContext* ctx;
ctx = (FatOpContext*) ped_malloc (sizeof (FatOpContext));
if (!ctx)
goto error;
ctx->frag_sectors = PED_MIN (old_fs_info->cluster_sectors,
new_fs_info->cluster_sectors);
if (!fat_set_frag_sectors (new_fs, ctx->frag_sectors))
goto error;
if (!fat_set_frag_sectors (old_fs, ctx->frag_sectors))
goto error;
ctx->buffer_frags = old_fs_info->buffer_sectors / ctx->frag_sectors;
ctx->buffer_map = (FatFragment*) ped_malloc (sizeof (FatFragment)
* ctx->buffer_frags);
if (!ctx->buffer_map)
goto error_free_ctx;
ctx->remap = (FatFragment*) ped_malloc (sizeof (FatFragment)
* old_fs_info->frag_count);
if (!ctx->remap)
goto error_free_buffer_map;
ctx->new_fs = new_fs;
ctx->old_fs = old_fs;
if (!calc_deltas (ctx))
goto error_free_buffer_map;
return ctx;
error_free_buffer_map:
free (ctx->buffer_map);
error_free_ctx:
free (ctx);
error:
return NULL;
}
void
fat_op_context_destroy (FatOpContext* ctx)
{
free (ctx->buffer_map);
free (ctx->remap);
free (ctx);
}
FatFragment _GL_ATTRIBUTE_PURE
fat_op_context_map_static_fragment (const FatOpContext* ctx, FatFragment frag)
{
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatFragment result;
if (ctx->new_fs->geom->dev != ctx->old_fs->geom->dev)
return -1;
if (ctx->start_move_dir == FAT_DIR_FORWARD) {
if (frag < ctx->start_move_delta)
return -1;
result = frag - ctx->start_move_delta;
} else {
result = frag + ctx->start_move_delta;
}
if (result >= new_fs_info->frag_count)
return -1;
return result;
}
FatCluster
fat_op_context_map_static_cluster (const FatOpContext* ctx, FatCluster clst)
{
FatFragment mapped_frag;
mapped_frag = fat_op_context_map_static_fragment (ctx,
fat_cluster_to_frag (ctx->old_fs, clst));
if (mapped_frag != -1)
return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
else
return 0;
}
FatFragment _GL_ATTRIBUTE_PURE
fat_op_context_map_fragment (const FatOpContext* ctx, FatFragment frag)
{
return ctx->remap [frag];
}
FatCluster
fat_op_context_map_cluster (const FatOpContext* ctx, FatCluster clst)
{
FatFragment mapped_frag;
mapped_frag = fat_op_context_map_fragment (ctx,
fat_cluster_to_frag (ctx->old_fs, clst));
if (mapped_frag != -1)
return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
else
return 0;
}
/* This function sets the initial fat for the new resized file system.
This is in *NO WAY* a proper FAT table - all it does is:
a) mark bad clusters as bad.
b) mark used clusters (that is, clusters from the original FS that are
reachable from the resized one). Marks as EOF (i.e. used, end of
file chain).
c) mark original file system metadata as EOF (i.e. used), to prevent
it from being clobbered. This will leave the original file system
intact, until the partition table is modified, if the start of
the partition is moved.
The FATs are rebuilt *properly* after cluster relocation. This here is
only to mark clusters as used, so when cluster relocation occurs, clusters
aren't relocated on top of ones marked in a, b or c.
*/
int
fat_op_context_create_initial_fat (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatCluster clst;
FatCluster new_clst;
PedSector sect;
PedSector new_sect;
FatFragment frag;
FatFragment new_frag;
FatClusterFlag frag_flag;
new_fs_info->fat = fat_table_new (
new_fs_info->fat_type,
new_fs_info->fat_sectors * 512
/ fat_table_entry_size (new_fs_info->fat_type));
if (!new_fs_info->fat)
return 0;
if (!fat_table_set_cluster_count (new_fs_info->fat,
new_fs_info->cluster_count))
return 0;
/* mark bad and used clusters */
for (frag = 0; frag < old_fs_info->frag_count; frag++) {
frag_flag = fat_get_fragment_flag (ctx->old_fs, frag);
if (frag_flag == FAT_FLAG_FREE)
continue;
new_frag = fat_op_context_map_static_fragment (ctx, frag);
if (new_frag == -1)
continue;
new_clst = fat_frag_to_cluster (ctx->new_fs, new_frag);
PED_ASSERT (new_clst != 0);
if (frag_flag == FAT_FLAG_BAD) {
if (!fat_table_set_bad (new_fs_info->fat, new_clst))
return 0;
} else {
if (!fat_table_set_eof (new_fs_info->fat, new_clst))
return 0;
}
}
/* mark metadata regions that map to clusters on the new FS */
for (sect = 0; sect < old_fs_info->cluster_offset; sect++) {
new_sect = ped_geometry_map (ctx->new_fs->geom,
ctx->old_fs->geom, sect);
if (new_sect == -1
|| !fat_is_sector_in_clusters (ctx->new_fs, new_sect))
continue;
clst = fat_sector_to_cluster (ctx->new_fs, new_sect);
PED_ASSERT (clst != 0);
if (!fat_table_set_eof (new_fs_info->fat, clst))
return 0;
}
return 1;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,70 +0,0 @@
/*
libparted
Copyright (C) 1999-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PED_FAT_CONTEXT_H_INCLUDED
#define PED_FAT_CONTEXT_H_INCLUDED
#include "count.h"
enum _FatDirection {
FAT_DIR_FORWARD,
FAT_DIR_BACKWARD
};
typedef enum _FatDirection FatDirection;
struct _FatOpContext {
PedFileSystem* old_fs;
PedFileSystem* new_fs;
PedSector frag_sectors; /* should equal old_fs and
new_fs's frag_sectors */
FatDirection start_move_dir;
FatFragment start_move_delta;
FatFragment buffer_offset;
FatFragment buffer_frags;
FatFragment* buffer_map;
FatFragment frags_duped;
FatFragment* remap;
FatCluster new_root_dir [32];
};
typedef struct _FatOpContext FatOpContext;
extern FatOpContext* fat_op_context_new (PedFileSystem* new_fs,
PedFileSystem* old_fs);
extern void fat_op_context_destroy (FatOpContext* ctx);
extern FatFragment fat_op_context_map_static_fragment (const FatOpContext* ctx,
FatFragment frag);
extern FatCluster fat_op_context_map_static_cluster (const FatOpContext* ctx,
FatCluster clst);
extern FatFragment fat_op_context_map_fragment (const FatOpContext* ctx,
FatFragment frag);
extern FatCluster fat_op_context_map_cluster (const FatOpContext* ctx,
FatCluster clst);
extern int fat_op_context_create_initial_fat (FatOpContext* ctx);
#endif /* PED_FAT_CONTEXT_H_INCLUDED */

View File

@@ -1,319 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include "traverse.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef DISCOVER_ONLY
/*
prints out the sequence of clusters for a given file chain, beginning
at start_cluster.
*/
#ifdef PED_VERBOSE
static void
print_chain (PedFileSystem* fs, FatCluster start)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster clst;
int this_row;
this_row = 0;
for (clst = start; !fat_table_is_eof (fs_info->fat, clst);
clst = fat_table_get (fs_info->fat, clst)) {
printf (" %d", (int) clst);
if (++this_row == 7) {
putchar ('\n');
this_row = 0;
}
}
putchar ('\n');
}
#endif /* PED_VERBOSE */
static PedSector
remainder_round_up (PedSector a, PedSector b)
{
PedSector result;
result = a % b;
if (!result)
result = b;
return result;
}
/*
traverse the FAT for a file/directory, marking each entry's flag
to "flag".
*/
static int
flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
FatClusterFlag flag, PedSector size)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster clst;
FatCluster prev_clst;
int last_cluster_usage;
FatCluster chain_length = 0;
if (fat_table_is_eof (fs_info->fat, start)) {
if (ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("Bad directory entry for %s: first cluster is the "
"end of file marker."),
chain_name)
!= PED_EXCEPTION_IGNORE)
return 0;
}
for (prev_clst = clst = start; !fat_table_is_eof (fs_info->fat, clst);
prev_clst = clst, clst = fat_table_get (fs_info->fat, clst)) {
chain_length++;
if (!clst) {
ped_exception_throw (PED_EXCEPTION_FATAL,
PED_EXCEPTION_CANCEL,
_("Bad FAT: unterminated chain for %s. You "
"should run dosfsck or scandisk."),
chain_name);
return 0;
}
if (clst >= fs_info->fat->cluster_count + 2) {
ped_exception_throw (PED_EXCEPTION_FATAL,
PED_EXCEPTION_CANCEL,
_("Bad FAT: cluster %d outside file system "
"in chain for %s. You should run dosfsck "
"or scandisk."),
(int) clst, chain_name);
return 0;
}
if (fs_info->cluster_info [clst].flag != FAT_FLAG_FREE ) {
ped_exception_throw (PED_EXCEPTION_FATAL,
PED_EXCEPTION_CANCEL,
_("Bad FAT: cluster %d is cross-linked for "
"%s. You should run dosfsck or scandisk."),
(int) clst, chain_name);
return 0;
}
if (flag == FAT_FLAG_DIRECTORY)
fs_info->total_dir_clusters++;
fs_info->cluster_info [clst].flag = flag;
fs_info->cluster_info [clst].units_used = 0; /* 0 == 64 */
}
if (size
&& chain_length
!= ped_div_round_up (size, fs_info->cluster_sectors)) {
if (ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("%s is %dk, but it has %d clusters (%dk)."),
chain_name,
(int) size / 2,
(int) chain_length,
(int) chain_length * fs_info->cluster_sectors / 2)
!= PED_EXCEPTION_IGNORE)
return 0;
}
last_cluster_usage
= ped_div_round_up (64 * remainder_round_up (size,
fs_info->cluster_sectors),
fs_info->cluster_sectors);
fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;
return 1;
}
/*
recursively traverses a directory, flagging all clusters in the process.
It frees the traverse_info structure before returning.
*/
static int
flag_traverse_dir (FatTraverseInfo* trav_info) {
PedFileSystem* fs = trav_info->fs;
FatDirEntry* this_entry;
FatTraverseInfo* subdir_trav_info;
char file_name [4096];
char* file_name_start;
FatCluster first_cluster;
PedSector size;
PED_ASSERT (trav_info != NULL);
strcpy (file_name, trav_info->dir_name);
file_name_start = file_name + strlen (file_name);
while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
if (fat_dir_entry_is_null_term (this_entry))
break;
if (!fat_dir_entry_has_first_cluster (this_entry, fs))
continue;
if (this_entry->name [0] == '.')
continue; /* skip . and .. entries */
fat_dir_entry_get_name (this_entry, file_name_start);
first_cluster = fat_dir_entry_get_first_cluster(this_entry, fs);
size = ped_div_round_up (fat_dir_entry_get_length (this_entry),
512);
#ifdef PED_VERBOSE
printf ("%s: ", file_name);
print_chain (fs, first_cluster);
#endif
if (fat_dir_entry_is_directory (this_entry)) {
if (!flag_traverse_fat (fs, file_name, first_cluster,
FAT_FLAG_DIRECTORY, size))
return 0;
subdir_trav_info = fat_traverse_directory (trav_info,
this_entry);
if (!subdir_trav_info)
return 0;
if (!flag_traverse_dir (subdir_trav_info))
return 0;
} else if (fat_dir_entry_is_file (this_entry)) {
if (!flag_traverse_fat (fs, file_name, first_cluster,
FAT_FLAG_FILE, size))
return 0;
}
}
fat_traverse_complete (trav_info);
return 1;
}
static void
_mark_bad_clusters (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster cluster;
for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
if (fat_table_is_bad (fs_info->fat, cluster))
fs_info->cluster_info [cluster].flag = FAT_FLAG_BAD;
}
}
/*
fills in cluster_info. Each FAT entry (= cluster) is flagged as either
FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.
Also, the fraction of each cluster (x/64) is recorded
*/
int
fat_collect_cluster_info (PedFileSystem* fs) {
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatTraverseInfo* trav_info;
/* set all clusters to unused as a default */
memset (fs_info->cluster_info, 0, fs_info->fat->cluster_count + 2);
fs_info->total_dir_clusters = 0;
if (fs_info->fat_type == FAT_TYPE_FAT32) {
trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
"\\");
if (!flag_traverse_dir (trav_info))
return 0;
if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
FAT_FLAG_DIRECTORY, 0))
return 0;
} else {
trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
if (!flag_traverse_dir (trav_info))
return 0;
}
_mark_bad_clusters (fs);
return 1;
}
FatClusterFlag _GL_ATTRIBUTE_PURE
fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
return fs_info->cluster_info [cluster].flag;
}
PedSector _GL_ATTRIBUTE_PURE
fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
int fraction;
if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
return 0;
fraction = fs_info->cluster_info [cluster].units_used;
if (fraction == 0)
fraction = 64;
return fraction * fs_info->cluster_sectors / 64;
}
FatClusterFlag
fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster cluster = fat_frag_to_cluster (fs, frag);
FatFragment offset = frag % fs_info->cluster_frags;
FatFragment last_frag_used;
FatClusterFlag flag;
PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
flag = fat_get_cluster_flag (fs, cluster);
if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
return flag;
last_frag_used = (fat_get_cluster_usage (fs, cluster) - 1)
/ fs_info->frag_sectors;
if (offset > last_frag_used)
return FAT_FLAG_FREE;
else
return flag;
}
int
fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
{
switch (fat_get_fragment_flag (fs, frag)) {
case FAT_FLAG_FREE:
case FAT_FLAG_BAD:
return 0;
case FAT_FLAG_FILE:
case FAT_FLAG_DIRECTORY:
return 1;
}
return 0;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,46 +0,0 @@
/*
libparted
Copyright (C) 1999-2000, 2007-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COUNT_H_INCLUDED
#define COUNT_H_INCLUDED
typedef enum _FatClusterFlag FatClusterFlag;
typedef struct _FatClusterInfo FatClusterInfo;
enum _FatClusterFlag {
FAT_FLAG_FREE=0,
FAT_FLAG_FILE=1,
FAT_FLAG_DIRECTORY=2,
FAT_FLAG_BAD=3
};
struct __attribute__ ((packed)) _FatClusterInfo {
unsigned int units_used:6; /* 1 unit = cluster_size / 64 */
FatClusterFlag flag:2;
};
extern int fat_collect_cluster_info (PedFileSystem *fs);
extern FatClusterFlag fat_get_cluster_flag (PedFileSystem* fs,
FatCluster cluster);
extern PedSector fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster);
extern FatClusterFlag fat_get_fragment_flag (PedFileSystem* fs,
FatFragment frag);
extern int fat_is_fragment_active (PedFileSystem* fs, FatFragment frag);
#endif /* COUNT_H_INCLUDED */

View File

@@ -1,652 +0,0 @@
/*
libparted
Copyright (C) 1998-2001, 2007-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <string.h>
#include "fat.h"
#include "calc.h"
#include "../../../labels/misc.h"
PedFileSystem*
fat_alloc (const PedGeometry* geom)
{
PedFileSystem* fs;
fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
if (!fs)
goto error;
fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
if (!fs->type_specific)
goto error_free_fs;
FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
fs_info->boot_sector = NULL;
fs_info->info_sector = NULL;
fs->geom = ped_geometry_duplicate (geom);
if (!fs->geom)
goto error_free_type_specific;
fs->checked = 0;
return fs;
error_free_type_specific:
free (fs->type_specific);
error_free_fs:
free (fs);
error:
return NULL;
}
/* Requires the boot sector to be analysed */
int
fat_alloc_buffers (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
fs_info->buffer_sectors = BUFFER_SIZE;
fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
if (!fs_info->buffer)
goto error;
fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
if (!fs_info->cluster_info)
goto error_free_buffer;
return 1;
error_free_buffer:
free (fs_info->buffer);
error:
return 0;
};
void
fat_free_buffers (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
free (fs_info->cluster_info);
free (fs_info->buffer);
}
void
fat_free (PedFileSystem* fs)
{
FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
free (fs_info->boot_sector);
ped_geometry_destroy (fs->geom);
free (fs->type_specific);
free (fs);
}
int
fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
&& frag_sectors <= fs_info->cluster_sectors);
fs_info->frag_size = frag_sectors * 512;
fs_info->frag_sectors = frag_sectors;
fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
return 1;
}
#ifndef DISCOVER_ONLY
int
fat_clobber (PedGeometry* geom)
{
FatBootSector *boot_sector;
int ok;
if (!fat_boot_sector_read (&boot_sector, geom))
return 1;
boot_sector->system_id[0] = 0;
boot_sector->boot_sign = 0;
if (boot_sector->u.fat16.fat_name[0] == 'F')
boot_sector->u.fat16.fat_name[0] = 0;
if (boot_sector->u.fat32.fat_name[0] == 'F')
boot_sector->u.fat32.fat_name[0] = 0;
ok = ped_geometry_write (geom, boot_sector, 0, 1);
free (boot_sector);
return ok;
}
static int
_init_fats (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster table_size;
table_size = fs_info->fat_sectors * 512
/ fat_table_entry_size (fs_info->fat_type);
fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
if (!fs_info->fat)
goto error;
if (!fat_table_read (fs_info->fat, fs, 0))
goto error_free_fat;
return 1;
error_free_fat:
fat_table_destroy (fs_info->fat);
error:
return 0;
}
PedFileSystem*
fat_open (PedGeometry* geom)
{
PedFileSystem* fs;
FatSpecific* fs_info;
fs = fat_alloc (geom);
if (!fs)
goto error;
fs_info = (FatSpecific*) fs->type_specific;
if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
goto error_free_fs;
if (!fat_boot_sector_analyse (fs_info->boot_sector, fs))
goto error_free_fs;
fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
? &fat16_type
: &fat32_type;
if (fs_info->fat_type == FAT_TYPE_FAT32) {
if (!fat_info_sector_read (&fs_info->info_sector, fs))
goto error_free_fs;
}
if (!_init_fats (fs))
goto error_free_fs;
if (!fat_alloc_buffers (fs))
goto error_free_fat_table;
if (!fat_collect_cluster_info (fs))
goto error_free_buffers;
return fs;
error_free_buffers:
fat_free_buffers (fs);
error_free_fat_table:
fat_table_destroy (fs_info->fat);
error_free_fs:
fat_free (fs);
error:
return NULL;
}
static int
fat_root_dir_clear (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
return ped_geometry_write (fs->geom, fs_info->buffer,
fs_info->root_dir_offset,
fs_info->root_dir_sector_count);
}
PedFileSystem*
fat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
{
PedFileSystem* fs;
FatSpecific* fs_info;
FatCluster table_size;
fs = fat_alloc (geom);
if (!fs)
goto error;
fs_info = (FatSpecific*) fs->type_specific;
fs_info->logical_sector_size = 1;
fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
fs_info->heads = geom->dev->bios_geom.heads;
fs_info->sector_count = fs->geom->length;
fs_info->fat_table_count = 2;
/* some initial values, to be changed later */
fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
/ (512 / sizeof (FatDirEntry));
fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
fs_info->fat_type = fat_type;
if (!fat_calc_sizes (fs->geom->length, 0,
fs_info->fat_type,
fs_info->root_dir_sector_count,
&fs_info->cluster_sectors,
&fs_info->cluster_count,
&fs_info->fat_sectors)) {
ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("Partition too big/small for a %s file system."),
(fat_type == FAT_TYPE_FAT16)
? fat16_type.name
: fat32_type.name);
goto error_free_fs;
}
fs_info->cluster_size = fs_info->cluster_sectors * 512;
fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
fs_info->dir_entries_per_cluster
= fs_info->cluster_size / sizeof (FatDirEntry);
if (fs_info->fat_type == FAT_TYPE_FAT16) {
/* FAT16 */
fs->type = &fat16_type;
if (fs_info->cluster_count
> fat_max_cluster_count (fs_info->fat_type)) {
fs_info->cluster_count
= fat_max_cluster_count (fs_info->fat_type);
}
fs_info->root_dir_sector_count
= FAT_ROOT_DIR_ENTRY_COUNT
/ (512 / sizeof (FatDirEntry));
fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
fs_info->root_dir_offset
= fs_info->fat_offset
+ fs_info->fat_sectors * fs_info->fat_table_count;
fs_info->cluster_offset
= fs_info->root_dir_offset
+ fs_info->root_dir_sector_count;
} else {
/* FAT32 */
fs->type = &fat32_type;
fs_info->info_sector_offset = 1;
fs_info->boot_sector_backup_offset = 6;
fs_info->root_dir_sector_count = 0;
fs_info->root_dir_entry_count = 0;
fs_info->root_dir_offset = 0;
fs_info->cluster_offset
= fs_info->fat_offset
+ fs_info->fat_sectors * fs_info->fat_table_count;
}
table_size = fs_info->fat_sectors * 512
/ fat_table_entry_size (fs_info->fat_type);
fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
if (!fs_info->fat)
goto error_free_fs;
fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
if (!fat_alloc_buffers (fs))
goto error_free_fat_table;
if (fs_info->fat_type == FAT_TYPE_FAT32) {
fs_info->root_cluster
= fat_table_alloc_cluster (fs_info->fat);
fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
memset (fs_info->buffer, 0, fs_info->cluster_size);
if (!fat_write_cluster (fs, fs_info->buffer,
fs_info->root_cluster))
goto error_free_buffers;
}
fs_info->serial_number = generate_random_uint32 ();
if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector, fs))
goto error_free_buffers;
if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
goto error_free_buffers;
if (!fat_boot_sector_write (fs_info->boot_sector, fs))
goto error_free_buffers;
if (fs_info->fat_type == FAT_TYPE_FAT32) {
if (!fat_info_sector_generate (&fs_info->info_sector, fs))
goto error_free_buffers;
if (!fat_info_sector_write (fs_info->info_sector, fs))
goto error_free_buffers;
}
if (!fat_table_write_all (fs_info->fat, fs))
goto error_free_buffers;
if (fs_info->fat_type == FAT_TYPE_FAT16) {
if (!fat_root_dir_clear (fs))
goto error_free_buffers;
}
return fs;
error_free_buffers:
fat_free_buffers (fs);
error_free_fat_table:
fat_table_destroy (fs_info->fat);
error_free_fs:
fat_free (fs);
error:
return NULL;
}
PedFileSystem*
fat_create_fat16 (PedGeometry* geom, PedTimer* timer)
{
return fat_create (geom, FAT_TYPE_FAT16, timer);
}
PedFileSystem*
fat_create_fat32 (PedGeometry* geom, PedTimer* timer)
{
return fat_create (geom, FAT_TYPE_FAT32, timer);
}
int
fat_close (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
fat_free_buffers (fs);
fat_table_destroy (fs_info->fat);
fat_free (fs);
return 1;
}
/* Hack: just resize the file system outside of its boundaries! */
PedFileSystem*
fat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
{
PedFileSystem* new_fs;
new_fs = ped_file_system_open (fs->geom);
if (!new_fs)
goto error;
if (!ped_file_system_resize (new_fs, geom, timer))
goto error_close_new_fs;
return new_fs;
error_close_new_fs:
ped_file_system_close (new_fs);
error:
return 0;
}
static int
_compare_fats (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatTable* table_copy;
FatCluster table_size;
int i;
table_size = fs_info->fat_sectors * 512
/ fat_table_entry_size (fs_info->fat_type);
table_copy = fat_table_new (fs_info->fat_type, table_size);
if (!table_copy)
goto error;
for (i = 1; i < fs_info->fat_table_count; i++) {
if (!fat_table_read (table_copy, fs, i))
goto error_free_table_copy;
if (!fat_table_compare (fs_info->fat, table_copy)) {
if (ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("The FATs don't match. If you don't know "
"what this means, then select cancel, run "
"scandisk on the file system, and then come "
"back."))
!= PED_EXCEPTION_IGNORE)
goto error_free_table_copy;
}
}
fat_table_destroy (table_copy);
return 1;
error_free_table_copy:
fat_table_destroy (table_copy);
error:
return 0;
}
int
fat_check (PedFileSystem* fs, PedTimer* timer)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector cluster_sectors;
FatCluster cluster_count;
PedSector fat_sectors;
PedSector align_sectors;
FatCluster info_free_clusters;
align_sectors = fs_info->fat_offset
- fat_min_reserved_sector_count (fs_info->fat_type);
if (!fat_calc_sizes (fs->geom->length,
align_sectors,
fs_info->fat_type,
fs_info->root_dir_sector_count,
&cluster_sectors,
&cluster_count,
&fat_sectors)) {
if (ped_exception_throw (PED_EXCEPTION_BUG,
PED_EXCEPTION_IGNORE_CANCEL,
_("There are no possible configurations for this FAT "
"type."))
!= PED_EXCEPTION_IGNORE)
goto error;
}
if (fs_info->fat_type == FAT_TYPE_FAT16) {
if (cluster_sectors != fs_info->cluster_sectors
|| cluster_count != fs_info->cluster_count
|| fat_sectors != fs_info->fat_sectors) {
if (ped_exception_throw (PED_EXCEPTION_WARNING,
PED_EXCEPTION_IGNORE_CANCEL,
_("File system doesn't have expected sizes for "
"Windows to like it. "
"Cluster size is %dk (%dk expected); "
"number of clusters is %d (%d expected); "
"size of FATs is %d sectors (%d expected)."),
(int) fs_info->cluster_sectors / 2,
(int) cluster_sectors / 2,
(int) fs_info->cluster_count,
(int) cluster_count,
(int) fs_info->fat_sectors,
(int) fat_sectors)
!= PED_EXCEPTION_IGNORE)
goto error;
}
}
if (fs_info->fat_type == FAT_TYPE_FAT32) {
info_free_clusters
= PED_LE32_TO_CPU (fs_info->info_sector->free_clusters);
if (info_free_clusters != (FatCluster) -1
&& info_free_clusters != fs_info->fat->free_cluster_count) {
if (ped_exception_throw (PED_EXCEPTION_WARNING,
PED_EXCEPTION_IGNORE_CANCEL,
_("File system is reporting the free space as "
"%d clusters, not %d clusters."),
info_free_clusters,
fs_info->fat->free_cluster_count)
!= PED_EXCEPTION_IGNORE)
goto error;
}
}
if (!_compare_fats (fs))
goto error;
fs->checked = 1;
return 1; /* existence of fs implies consistency ;-) */
error:
return 0;
}
/* Calculates how much space there will be in clusters in:
* old_fs intersect the-new-fs
*/
static PedSector
_calc_resize_data_size (
const PedFileSystem* old_fs,
PedSector new_cluster_sectors,
FatCluster new_cluster_count,
PedSector new_fat_size)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
PedSector fat_size_delta;
fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
}
static int
_test_resize_size (const PedFileSystem* fs,
PedSector length, PedSector min_data_size)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedGeometry geom;
PedSector _cluster_sectors;
FatCluster _cluster_count;
PedSector _fat_size;
ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
if (fat_calc_resize_sizes (
&geom,
fs_info->cluster_sectors,
FAT_TYPE_FAT16,
fs_info->root_dir_sector_count,
fs_info->cluster_sectors,
&_cluster_sectors,
&_cluster_count,
&_fat_size)
&& _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
_fat_size)
>= min_data_size)
return 1;
if (fat_calc_resize_sizes (
&geom,
fs_info->cluster_sectors,
FAT_TYPE_FAT32,
0,
fs_info->cluster_sectors,
&_cluster_sectors,
&_cluster_count,
&_fat_size)
&& _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
_fat_size)
>= min_data_size)
return 1;
return 0;
}
/* does a binary search (!) for the mininum size. Too hard to compute directly
* (see calc_sizes() for why!)
*/
static PedSector
_get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
{
PedSector min_length = 0;
PedSector max_length = fs->geom->length;
PedSector length;
while (min_length < max_length - 1) {
length = (min_length + max_length) / 2;
if (_test_resize_size (fs, length, min_data_size))
max_length = length;
else
min_length = length;
}
/* adds a bit of leeway (64 sectors), for resolving extra issues, like root
* directory allocation, that aren't covered here.
*/
return max_length + 64;
}
PedConstraint*
fat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedGeometry full_dev;
PedSector min_cluster_count;
FatCluster used_clusters;
PedSector min_data_size;
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
return NULL;
used_clusters = fs_info->fat->cluster_count
- fs_info->fat->free_cluster_count;
min_cluster_count = used_clusters + fs_info->total_dir_clusters;
min_data_size = min_cluster_count * fs_info->cluster_sectors;
return ped_constraint_new (ped_alignment_any, ped_alignment_any,
&full_dev, &full_dev,
_get_min_resize_size (fs, min_data_size),
dev->length);
}
PedConstraint*
fat_get_resize_constraint (const PedFileSystem* fs)
{
return fat_get_copy_constraint (fs, fs->geom->dev);
}
PedConstraint*
fat_get_create_constraint_fat16 (const PedDevice* dev)
{
PedGeometry full_dev;
PedSector min_size;
PedSector max_size;
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
return NULL;
min_size = 65794;
max_size = 2097153;
return ped_constraint_new (
ped_alignment_any, ped_alignment_any,
&full_dev, &full_dev,
min_size, max_size);
}
PedConstraint*
fat_get_create_constraint_fat32 (const PedDevice* dev)
{
PedGeometry full_dev;
PedSector min_size;
if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
return NULL;
min_size = 525224;
return ped_constraint_new (
ped_alignment_any, ped_alignment_any,
&full_dev, &full_dev,
min_size, dev->length);
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,159 +0,0 @@
/*
libparted
Copyright (C) 1998-2001, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FAT_H_INCLUDED
#define FAT_H_INCLUDED
#include <parted/parted.h>
#include <parted/endian.h>
#include <parted/debug.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFER_SIZE 1024 /* buffer size in sectors (512 bytes) */
typedef uint32_t FatCluster;
typedef int32_t FatFragment;
enum _FatType {
FAT_TYPE_FAT12,
FAT_TYPE_FAT16,
FAT_TYPE_FAT32
};
typedef enum _FatType FatType;
typedef struct _FatSpecific FatSpecific;
typedef struct _FatDirEntry FatDirEntry;
/* FIXME: YUCKY */
#include "table.h"
#include "bootsector.h"
#include "context.h"
#include "fatio.h"
#include "traverse.h"
#include "calc.h"
#include "count.h"
#include "clstdup.h"
struct __attribute__ ((packed)) _FatDirEntry {
char name[8];
uint8_t extension[3];
uint8_t attributes;
uint8_t is_upper_case_name;
uint8_t creation_time_low; /* milliseconds */
uint16_t creation_time_high;
uint16_t creation_date;
uint16_t access_date;
uint16_t first_cluster_high; /* for FAT32 */
uint16_t time;
uint16_t date;
uint16_t first_cluster;
uint32_t length;
};
struct _FatSpecific {
FatBootSector *boot_sector; /* structure of boot sector */
FatInfoSector *info_sector; /* fat32-only information sector */
int logical_sector_size; /* illogical sector size :-) */
PedSector sector_count;
int sectors_per_track; /* BIOS CHS stuff (S) */
int heads; /* BIOS CHS stuff (H) */
int cluster_size;
PedSector cluster_sectors;
FatCluster cluster_count;
int dir_entries_per_cluster;
FatType fat_type;
int fat_table_count;
PedSector fat_sectors;
uint32_t serial_number;
PedSector info_sector_offset; /* FAT32 only */
PedSector fat_offset;
PedSector root_dir_offset; /* non-FAT32 */
PedSector cluster_offset;
PedSector boot_sector_backup_offset;
FatCluster root_cluster; /* FAT32 only */
int root_dir_entry_count; /* non-FAT32 */
PedSector root_dir_sector_count; /* non-FAT32 */
FatCluster total_dir_clusters;
FatTable* fat;
FatClusterInfo* cluster_info;
PedSector buffer_sectors;
char* buffer;
int frag_size;
PedSector frag_sectors;
FatFragment frag_count;
FatFragment buffer_frags;
FatFragment cluster_frags;
};
#define FAT_SPECIFIC(fs) ((FatSpecific*) fs->type_specific)
#define FAT_ROOT 0
#define DELETED_FLAG 0xe5
#define READONLY_ATTR 0x01
#define HIDDEN_ATTR 0x02
#define SYSTEM_ATTR 0x04
#define VOLUME_LABEL_ATTR 0x08
#define VFAT_ATTR 0x0f
#define DIRECTORY_ATTR 0x10
#define ARCH_ATTR 0x20
#define MAX_FAT12_CLUSTERS 4086
#define MAX_FAT16_CLUSTERS 65526
#define MAX_FAT32_CLUSTERS 2000000
#define FAT_ROOT_DIR_ENTRY_COUNT 512
extern PedFileSystemType fat16_type;
extern PedFileSystemType fat32_type;
extern void fat_print (const PedFileSystem* fs);
extern PedFileSystem* fat_alloc (const PedGeometry* geom);
extern void fat_free (PedFileSystem* fs);
extern int fat_alloc_buffers (PedFileSystem* fs);
extern void fat_free_buffers (PedFileSystem* fs);
extern int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer);
extern int fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors);
#endif /* FAT_H_INCLUDED */

View File

@@ -1,150 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include "fatio.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#ifndef DISCOVER_ONLY
int
fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
FatFragment count)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector sector = fat_frag_to_sector (fs, frag);
PedSector sector_count = count * fs_info->frag_sectors;
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
return ped_geometry_read (fs->geom, buf, sector, sector_count);
}
int
fat_read_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
{
return fat_read_fragments (fs, buf, frag, 1);
}
int
fat_write_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
FatFragment count)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector sector = fat_frag_to_sector (fs, frag);
PedSector sector_count = count * fs_info->frag_sectors;
PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
return ped_geometry_write (fs->geom, buf, sector, sector_count);
}
int
fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
{
return fat_write_fragments (fs, buf, frag, 1);
}
int
fat_write_sync_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
FatFragment count)
{
if (!fat_write_fragments (fs, buf, frag, count))
return 0;
if (!ped_geometry_sync (fs->geom))
return 0;
return 1;
}
int
fat_write_sync_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
{
return fat_write_sync_fragments (fs, buf, frag, 1);
}
int
fat_read_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
FatCluster count)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector sector = fat_cluster_to_sector (fs, cluster);
PedSector sector_count = count * fs_info->cluster_sectors;
PED_ASSERT (cluster >= 2
&& cluster + count - 1 < fs_info->cluster_count + 2);
return ped_geometry_read (fs->geom, buf, sector, sector_count);
}
int
fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
{
return fat_read_clusters (fs, buf, cluster, 1);
}
int
fat_write_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
FatCluster count)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector sector = fat_cluster_to_sector (fs, cluster);
PedSector sector_count = count * fs_info->cluster_sectors;
PED_ASSERT (cluster >= 2
&& cluster + count - 1 < fs_info->cluster_count + 2);
return ped_geometry_write (fs->geom, buf, sector, sector_count);
}
int
fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
{
return fat_write_clusters (fs, buf, cluster, 1);
}
int
fat_write_sync_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
FatCluster count)
{
if (!fat_write_clusters (fs, buf, cluster, count))
return 0;
if (!ped_geometry_sync (fs->geom))
return 0;
return 1;
}
int
fat_write_sync_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
{
if (!fat_write_cluster (fs, buf, cluster))
return 0;
if (!ped_geometry_sync (fs->geom))
return 0;
return 1;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,49 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FATIO_H_INCLUDED
#define FATIO_H_INCLUDED
#include "fat.h"
extern int fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
FatFragment count);
extern int fat_write_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
FatFragment count);
extern int fat_write_sync_fragments (PedFileSystem* fs, char* buf,
FatFragment frag, FatFragment count);
extern int fat_read_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
extern int fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
extern int fat_write_sync_fragment (PedFileSystem* fs, char* buf,
FatFragment frag);
extern int fat_read_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
FatCluster count);
extern int fat_write_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
FatCluster count);
extern int fat_write_sync_clusters (PedFileSystem* fs, char* buf,
FatCluster cluster, FatCluster count);
extern int fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
extern int fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
extern int fat_write_sync_cluster (PedFileSystem* fs, char *buf,
FatCluster cluster);
#endif /* FATIO_H_INCLUDED */

View File

@@ -1,876 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include "traverse.h"
#include "count.h"
#include "fatio.h"
#include "calc.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#ifndef DISCOVER_ONLY
/* Recursively builds (i.e. makes consistent) the duplicated directory tree
* (leaving the original directory tree in tact)
*/
static int
fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info)
{
FatTraverseInfo* sub_dir_info;
FatDirEntry* dir_entry;
FatCluster old_first_cluster;
while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) {
if (fat_dir_entry_is_null_term (dir_entry))
break;
if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs))
continue;
fat_traverse_mark_dirty (trav_info);
old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry,
ctx->old_fs);
fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs,
fat_op_context_map_cluster (ctx, old_first_cluster));
if (fat_dir_entry_is_directory (dir_entry)
&& dir_entry->name [0] != '.') {
sub_dir_info
= fat_traverse_directory (trav_info, dir_entry);
if (!sub_dir_info)
return 0;
if (!fat_construct_directory (ctx, sub_dir_info))
return 0;
}
}
/* remove "stale" entries at the end */
while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) {
memset (dir_entry, 0, sizeof (FatDirEntry));
fat_traverse_mark_dirty (trav_info);
}
fat_traverse_complete (trav_info);
return 1;
}
static int
duplicate_legacy_root_dir (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
PED_ASSERT (old_fs_info->root_dir_sector_count
== new_fs_info->root_dir_sector_count);
if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
old_fs_info->root_dir_offset,
old_fs_info->root_dir_sector_count))
return 0;
if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
new_fs_info->root_dir_offset,
new_fs_info->root_dir_sector_count))
return 0;
return 1;
}
/*
Constructs the new directory tree for legacy (FAT16) file systems.
*/
static int
fat_construct_legacy_root (FatOpContext* ctx)
{
FatTraverseInfo* trav_info;
if (!duplicate_legacy_root_dir (ctx))
return 0;
trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\");
return fat_construct_directory (ctx, trav_info);
}
/*
Constructs the new directory tree for new (FAT32) file systems.
*/
static int
fat_construct_root (FatOpContext* ctx)
{
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatTraverseInfo* trav_info;
trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster,
"\\");
fat_construct_directory (ctx, trav_info);
return 1;
}
/* Converts the root directory between FAT16 and FAT32. NOTE: this code
* can also do no conversion. I'm leaving fat_construct_directory(), because
* it's really pretty :-) It also leaves a higher chance of deleted file
* recovery, because it doesn't remove redundant entries. (We do this here,
* because brain-damaged FAT16 has an arbitary limit on root directory entries,
* so we save room)
*/
static int
fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav,
FatTraverseInfo* new_trav)
{
FatTraverseInfo* sub_old_dir_trav;
FatTraverseInfo* sub_new_dir_trav;
FatDirEntry* new_dir_entry;
FatDirEntry* old_dir_entry;
FatCluster old_first_cluster;
while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) {
if (fat_dir_entry_is_null_term (old_dir_entry))
break;
if (!fat_dir_entry_is_active (old_dir_entry))
continue;
new_dir_entry = fat_traverse_next_dir_entry (new_trav);
if (!new_dir_entry) {
return ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("There's not enough room in the root "
"directory for all of the files. Either "
"cancel, or ignore to lose the files."))
== PED_EXCEPTION_IGNORE;
}
*new_dir_entry = *old_dir_entry;
fat_traverse_mark_dirty (new_trav);
if (!fat_dir_entry_has_first_cluster (old_dir_entry,
ctx->old_fs))
continue;
old_first_cluster = fat_dir_entry_get_first_cluster (
old_dir_entry, ctx->old_fs);
fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs,
fat_op_context_map_cluster (ctx, old_first_cluster));
if (fat_dir_entry_is_directory (old_dir_entry)
&& old_dir_entry->name [0] != '.') {
sub_old_dir_trav
= fat_traverse_directory (old_trav, old_dir_entry);
if (!sub_old_dir_trav) return 0;
sub_new_dir_trav
= fat_traverse_directory (new_trav, new_dir_entry);
if (!sub_new_dir_trav) {
fat_traverse_complete (sub_old_dir_trav);
return 0;
}
if (!fat_convert_directory (ctx, sub_old_dir_trav,
sub_new_dir_trav))
return 0;
}
}
/* remove "stale" entries at the end, just in case there is some
* overlap
*/
while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) {
memset (new_dir_entry, 0, sizeof (FatDirEntry));
fat_traverse_mark_dirty (new_trav);
}
fat_traverse_complete (old_trav);
fat_traverse_complete (new_trav);
return 1;
}
static void
clear_cluster (PedFileSystem* fs, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
memset (fs_info->buffer, 0, fs_info->cluster_size);
fat_write_cluster (fs, fs_info->buffer, cluster);
}
/* This MUST be called BEFORE the fat_construct_new_fat(), because cluster
* allocation depend on the old FAT. The reason is, old clusters may
* still be needed during the resize, (particularly clusters in the directory
* tree) even if they will be discarded later.
*/
static int
alloc_root_dir (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatCluster i;
FatCluster cluster;
FatCluster cluster_count;
PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT32);
cluster_count = ped_div_round_up (
PED_MAX (16, old_fs_info->root_dir_sector_count),
new_fs_info->cluster_sectors);
for (i = 0; i < cluster_count; i++) {
cluster = fat_table_alloc_check_cluster (new_fs_info->fat,
ctx->new_fs);
if (!cluster)
return 0;
ctx->new_root_dir [i] = cluster;
clear_cluster (ctx->new_fs, cluster);
}
ctx->new_root_dir [i] = 0;
new_fs_info->root_cluster = ctx->new_root_dir [0];
return 1;
}
/* when converting FAT32 -> FAT16
* fat_duplicate clusters() duplicated the root directory unnecessarily.
* Let's free it.
*
* This must be called AFTER fat_construct_new_fat(). (otherwise, our
* changes just get overwritten)
*/
static int
free_root_dir (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatCluster old_cluster;
FatFragment i;
PED_ASSERT (old_fs_info->fat_type == FAT_TYPE_FAT32);
PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT16);
for (old_cluster = old_fs_info->root_cluster;
!fat_table_is_eof (old_fs_info->fat, old_cluster);
old_cluster = fat_table_get (old_fs_info->fat, old_cluster)) {
FatFragment old_frag;
old_frag = fat_cluster_to_frag (ctx->old_fs, old_cluster);
for (i = 0; i < new_fs_info->cluster_frags; i++) {
FatFragment new_frag;
FatCluster new_clst;
new_frag = fat_op_context_map_fragment (ctx,
old_frag + i);
new_clst = fat_frag_to_cluster (ctx->old_fs, new_frag);
if (!fat_table_set_avail (new_fs_info->fat, new_clst))
return 0;
}
}
return 1;
}
static int
fat_clear_root_dir (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
int i;
PED_ASSERT (fs_info->fat_type == FAT_TYPE_FAT16);
PED_ASSERT (fs_info->root_dir_sector_count);
memset (fs_info->buffer, 0, 512);
for (i = 0; i < fs_info->root_dir_sector_count; i++) {
if (!ped_geometry_write (fs->geom, fs_info->buffer,
fs_info->root_dir_offset + i, 1)) {
if (ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("Error writing to the root directory."))
== PED_EXCEPTION_CANCEL)
return 0;
}
}
return 1;
}
static int
fat_construct_converted_tree (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatTraverseInfo* old_trav_info;
FatTraverseInfo* new_trav_info;
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
new_trav_info = fat_traverse_begin (ctx->new_fs,
new_fs_info->root_cluster, "\\");
if (!new_trav_info) return 0;
old_trav_info = fat_traverse_begin (ctx->old_fs, FAT_ROOT,
"\\");
} else {
fat_clear_root_dir (ctx->new_fs);
new_trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT,
"\\");
if (!new_trav_info) return 0;
old_trav_info = fat_traverse_begin (ctx->old_fs,
old_fs_info->root_cluster, "\\");
}
if (!old_trav_info) {
fat_traverse_complete (new_trav_info);
return 0;
}
if (!fat_convert_directory (ctx, old_trav_info, new_trav_info))
return 0;
return 1;
}
/*
Constructs the new directory tree to match the new file locations.
*/
static int
fat_construct_dir_tree (FatOpContext* ctx)
{
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
if (new_fs_info->fat_type == old_fs_info->fat_type) {
switch (old_fs_info->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0);
break;
case FAT_TYPE_FAT16:
return fat_construct_legacy_root (ctx);
case FAT_TYPE_FAT32:
return fat_construct_root (ctx);
}
} else {
return fat_construct_converted_tree (ctx);
}
return 0;
}
static FatFragment
_get_next_old_frag (FatOpContext* ctx, FatFragment frag)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatCluster cluster;
FatCluster next_cluster;
if ((frag + 1) % old_fs_info->cluster_frags != 0) {
if (fat_is_fragment_active (ctx->old_fs, frag + 1))
return frag + 1;
else
return -1;
} else {
cluster = fat_frag_to_cluster (ctx->old_fs, frag);
next_cluster = fat_table_get (old_fs_info->fat, cluster);
if (fat_table_is_eof (old_fs_info->fat, next_cluster))
return -1;
else
return fat_cluster_to_frag (ctx->old_fs, next_cluster);
}
}
/*
Constructs the new fat for the resized file system.
*/
static int
fat_construct_new_fat (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
FatFragment old_frag;
FatCluster new_cluster;
FatFragment new_frag;
FatFragment old_next_frag;
FatFragment new_next_frag;
FatCluster new_next_cluster;
FatClusterFlag flag;
int i;
fat_table_clear (new_fs_info->fat);
if (!fat_table_set_cluster_count (new_fs_info->fat,
new_fs_info->cluster_count))
return 0;
for (old_frag = 0; old_frag < old_fs_info->frag_count; old_frag++) {
flag = fat_get_fragment_flag (ctx->old_fs, old_frag);
if (flag == FAT_FLAG_FREE)
continue;
if (flag == FAT_FLAG_BAD) {
new_frag = fat_op_context_map_static_fragment (
ctx, old_frag);
if (new_frag == -1)
continue;
new_cluster = fat_frag_to_cluster (ctx->new_fs,
new_frag);
fat_table_set_bad (new_fs_info->fat, new_cluster);
continue;
}
new_frag = fat_op_context_map_fragment (ctx, old_frag);
new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag);
old_next_frag = _get_next_old_frag (ctx, old_frag);
if (old_next_frag == -1) {
fat_table_set_eof (new_fs_info->fat, new_cluster);
continue;
}
new_next_frag = fat_op_context_map_fragment (ctx,
old_next_frag);
PED_ASSERT (new_next_frag != -1);
new_next_cluster = fat_frag_to_cluster (ctx->new_fs,
new_next_frag);
PED_ASSERT (new_next_cluster != new_cluster);
fat_table_set (new_fs_info->fat, new_cluster, new_next_cluster);
}
if (old_fs_info->fat_type == FAT_TYPE_FAT32
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
new_fs_info->root_cluster
= fat_op_context_map_cluster (ctx,
old_fs_info->root_cluster);
}
if (old_fs_info->fat_type == FAT_TYPE_FAT16
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
for (i=0; ctx->new_root_dir[i+1]; i++) {
fat_table_set (new_fs_info->fat,
ctx->new_root_dir[i],
ctx->new_root_dir[i+1]);
}
fat_table_set_eof (new_fs_info->fat, ctx->new_root_dir[i]);
}
return 1;
}
static int
ask_type (PedFileSystem* fs, int fat16_ok, int fat32_ok, FatType* out_fat_type)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedExceptionOption status;
const char* fat16_msg;
const char* fat32_msg;
if (fs_info->fat_type == FAT_TYPE_FAT16)
fat16_msg = _("If you leave your file system as FAT16, "
"then you will have no problems.");
else
fat16_msg = _("If you convert to FAT16, and MS Windows "
"is installed on this partition, then "
"you must re-install the MS Windows boot "
"loader. If you want to do this, you "
"should consult the Parted manual (or "
"your distribution's manual).");
if (fs_info->fat_type == FAT_TYPE_FAT32)
fat32_msg = _("If you leave your file system as FAT32, "
"then you will not introduce any new "
"problems.");
else
fat32_msg = _("If you convert to FAT32, and MS Windows "
"is installed on this partition, then "
"you must re-install the MS Windows boot "
"loader. If you want to do this, you "
"should consult the Parted manual (or "
"your distribution's manual). Also, "
"converting to FAT32 will make the file "
"system unreadable by MS DOS, MS Windows "
"95a, and MS Windows NT.");
if (fat16_ok && fat32_ok) {
status = ped_exception_throw (
PED_EXCEPTION_INFORMATION,
PED_EXCEPTION_YES_NO_CANCEL,
_("%s %s %s"),
_("Would you like to use FAT32?"),
fat16_msg,
fat32_msg);
switch (status) {
case PED_EXCEPTION_YES:
*out_fat_type = FAT_TYPE_FAT32;
return 1;
case PED_EXCEPTION_NO:
*out_fat_type = FAT_TYPE_FAT16;
return 1;
case PED_EXCEPTION_UNHANDLED:
*out_fat_type = fs_info->fat_type;
return 1;
case PED_EXCEPTION_CANCEL:
return 0;
default:
PED_ASSERT (0);
break;
}
}
if (fat16_ok) {
if (fs_info->fat_type != FAT_TYPE_FAT16) {
status = ped_exception_throw (
PED_EXCEPTION_WARNING,
PED_EXCEPTION_OK_CANCEL,
_("%s %s"),
_("The file system can only be resized to this "
"size by converting to FAT16."),
fat16_msg);
if (status == PED_EXCEPTION_CANCEL)
return 0;
}
*out_fat_type = FAT_TYPE_FAT16;
return 1;
}
if (fat32_ok) {
if (fs_info->fat_type != FAT_TYPE_FAT32) {
status = ped_exception_throw (
PED_EXCEPTION_WARNING,
PED_EXCEPTION_OK_CANCEL,
_("%s %s"),
_("The file system can only be resized to this "
"size by converting to FAT32."),
fat32_msg);
if (status == PED_EXCEPTION_CANCEL)
return 0;
}
*out_fat_type = FAT_TYPE_FAT32;
return 1;
}
ped_exception_throw (
PED_EXCEPTION_NO_FEATURE,
PED_EXCEPTION_CANCEL,
_("GNU Parted cannot resize this partition to this size. "
"We're working on it!"));
return 0;
}
/* For resize operations: determine if the file system must be FAT16 or FAT32,
* or either. If the new file system must be FAT32, then query for
* confirmation. If either file system can be used, query for which one.
*/
static int
get_fat_type (PedFileSystem* fs, const PedGeometry* new_geom,
FatType* out_fat_type)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PedSector fat16_cluster_sectors;
PedSector fat32_cluster_sectors;
FatCluster dummy_cluster_count;
PedSector dummy_fat_sectors;
int fat16_ok;
int fat32_ok;
fat16_ok = fat_calc_resize_sizes (
new_geom,
fs_info->cluster_sectors,
FAT_TYPE_FAT16,
fs_info->root_dir_sector_count,
fs_info->cluster_sectors,
&fat16_cluster_sectors,
&dummy_cluster_count,
&dummy_fat_sectors);
fat32_ok = fat_calc_resize_sizes (
new_geom,
fs_info->cluster_sectors,
FAT_TYPE_FAT32,
fs_info->root_dir_sector_count,
fs_info->cluster_sectors,
&fat32_cluster_sectors,
&dummy_cluster_count,
&dummy_fat_sectors);
return ask_type (fs, fat16_ok, fat32_ok, out_fat_type);
}
/* Creates the PedFileSystem struct for the new resized file system, and
sticks it in a FatOpContext. At the end of the process, the original
(ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs).
*/
static FatOpContext*
create_resize_context (PedFileSystem* fs, const PedGeometry* new_geom)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatSpecific* new_fs_info;
PedFileSystem* new_fs;
PedSector new_cluster_sectors;
FatCluster new_cluster_count;
PedSector new_fat_sectors;
FatType new_fat_type;
PedSector root_dir_sector_count;
FatOpContext* context;
/* hypothetical number of root dir sectors, if we end up using
* FAT16
*/
if (fs_info->root_dir_sector_count)
root_dir_sector_count = fs_info->root_dir_sector_count;
else
root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
* sizeof (FatDirEntry) / 512;
if (!get_fat_type (fs, new_geom, &new_fat_type))
return 0;
fat_calc_resize_sizes (new_geom, fs_info->cluster_sectors, new_fat_type,
root_dir_sector_count, fs_info->cluster_sectors,
&new_cluster_sectors, &new_cluster_count, &new_fat_sectors);
if (!fat_check_resize_geometry (fs, new_geom, new_cluster_sectors,
new_cluster_count))
goto error;
new_fs = fat_alloc (new_geom);
if (!new_fs)
goto error;
new_fs_info = FAT_SPECIFIC (new_fs);
if (!new_fs_info)
goto error_free_new_fs;
/* preserve boot code, etc. */
new_fs_info->boot_sector = ped_malloc (new_geom->dev->sector_size);
memcpy (new_fs_info->boot_sector, fs_info->boot_sector,
new_geom->dev->sector_size);
new_fs_info->info_sector = NULL;
if (fs_info->fat_type == FAT_TYPE_FAT32)
{
PED_ASSERT (fs_info->info_sector != NULL);
new_fs_info->info_sector =
ped_malloc (new_geom->dev->sector_size);
memcpy (new_fs_info->info_sector, fs_info->info_sector,
new_geom->dev->sector_size);
}
new_fs_info->logical_sector_size = fs_info->logical_sector_size;
new_fs_info->sector_count = new_geom->length;
new_fs_info->sectors_per_track = fs_info->sectors_per_track;
new_fs_info->heads = fs_info->heads;
new_fs_info->cluster_size = new_cluster_sectors * 512;
new_fs_info->cluster_sectors = new_cluster_sectors;
new_fs_info->cluster_count = new_cluster_count;
new_fs_info->dir_entries_per_cluster = fs_info->dir_entries_per_cluster;
new_fs_info->fat_type = new_fat_type;
new_fs_info->fat_table_count = 2;
new_fs_info->fat_sectors = new_fat_sectors;
/* what about copying? */
new_fs_info->serial_number = fs_info->serial_number;
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
new_fs_info->info_sector_offset = 1;
new_fs_info->boot_sector_backup_offset = 6;
new_fs_info->root_dir_offset = 0;
new_fs_info->root_dir_entry_count = 0;
new_fs_info->root_dir_sector_count = 0;
/* we add calc_align_sectors to push the cluster_offset
forward, to keep the clusters aligned between the new
and old file systems
*/
new_fs_info->fat_offset
= fat_min_reserved_sector_count (FAT_TYPE_FAT32)
+ fat_calc_align_sectors (new_fs, fs);
new_fs_info->cluster_offset
= new_fs_info->fat_offset
+ 2 * new_fs_info->fat_sectors;
} else {
new_fs_info->root_dir_sector_count = root_dir_sector_count;
new_fs_info->root_dir_entry_count
= root_dir_sector_count * 512 / sizeof (FatDirEntry);
new_fs_info->fat_offset
= fat_min_reserved_sector_count (FAT_TYPE_FAT16)
+ fat_calc_align_sectors (new_fs, fs);
new_fs_info->root_dir_offset = new_fs_info->fat_offset
+ 2 * new_fs_info->fat_sectors;
new_fs_info->cluster_offset = new_fs_info->root_dir_offset
+ new_fs_info->root_dir_sector_count;
}
new_fs_info->total_dir_clusters = fs_info->total_dir_clusters;
context = fat_op_context_new (new_fs, fs);
if (!context)
goto error_free_new_fs_info;
if (!fat_op_context_create_initial_fat (context))
goto error_free_context;
if (!fat_alloc_buffers (new_fs))
goto error_free_fat;
return context;
error_free_fat:
fat_table_destroy (new_fs_info->fat);
error_free_context:
free (context);
error_free_new_fs_info:
free (new_fs_info);
error_free_new_fs:
free (new_fs);
error:
return NULL;
}
static int
resize_context_assimilate (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
fat_free_buffers (ctx->old_fs);
fat_table_destroy (old_fs_info->fat);
free (old_fs_info);
ped_geometry_destroy (ctx->old_fs->geom);
ctx->old_fs->type_specific = ctx->new_fs->type_specific;
ctx->old_fs->geom = ctx->new_fs->geom;
ctx->old_fs->type = (new_fs_info->fat_type == FAT_TYPE_FAT16)
? &fat16_type
: &fat32_type;
free (ctx->new_fs);
fat_op_context_destroy (ctx);
return 1;
}
static int
resize_context_abort (FatOpContext* ctx)
{
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
fat_free_buffers (ctx->new_fs);
fat_table_destroy (new_fs_info->fat);
free (new_fs_info);
ped_geometry_destroy (ctx->new_fs->geom);
free (ctx->new_fs);
fat_op_context_destroy (ctx);
return 1;
}
/* copies the "hidden" sectors, between the boot sector and the FAT. Required,
* for the Windows 98 FAT32 boot loader
*/
int
_copy_hidden_sectors (FatOpContext* ctx)
{
FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
PedSector first = 1;
PedSector last;
PedSector count;
/* nothing to copy for FAT16 */
if (old_fs_info->fat_type == FAT_TYPE_FAT16
|| new_fs_info->fat_type == FAT_TYPE_FAT16)
return 1;
last = PED_MIN (old_fs_info->fat_offset, new_fs_info->fat_offset) - 1;
count = last - first + 1;
PED_ASSERT (count < BUFFER_SIZE);
if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
first, count))
return 0;
if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
first, count))
return 0;
return 1;
}
int
fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatSpecific* new_fs_info;
FatOpContext* ctx;
PedFileSystem* new_fs;
ctx = create_resize_context (fs, geom);
if (!ctx)
goto error;
new_fs = ctx->new_fs;
new_fs_info = FAT_SPECIFIC (new_fs);
if (!fat_duplicate_clusters (ctx, timer))
goto error_abort_ctx;
if (fs_info->fat_type == FAT_TYPE_FAT16
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
if (!alloc_root_dir (ctx))
goto error_abort_ctx;
}
if (!fat_construct_new_fat (ctx))
goto error_abort_ctx;
if (fs_info->fat_type == FAT_TYPE_FAT32
&& new_fs_info->fat_type == FAT_TYPE_FAT16) {
if (!free_root_dir (ctx))
goto error_abort_ctx;
}
if (!fat_construct_dir_tree (ctx))
goto error_abort_ctx;
if (!fat_table_write_all (new_fs_info->fat, new_fs))
goto error_abort_ctx;
_copy_hidden_sectors (ctx);
fat_boot_sector_generate (&new_fs_info->boot_sector, new_fs);
fat_boot_sector_write (new_fs_info->boot_sector, new_fs);
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
fat_info_sector_generate (&new_fs_info->info_sector, new_fs);
fat_info_sector_write (new_fs_info->info_sector, new_fs);
}
if (!resize_context_assimilate (ctx))
goto error;
return 1;
error_abort_ctx:
resize_context_abort (ctx);
error:
return 0;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,481 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <parted/endian.h>
#include "fat.h"
#ifndef DISCOVER_ONLY
FatTable*
fat_table_new (FatType fat_type, FatCluster size)
{
FatTable* ft;
int entry_size = fat_table_entry_size (fat_type);
ft = (FatTable*) ped_malloc (sizeof (FatTable));
if (!ft) return NULL;
ft->cluster_count = ft->free_cluster_count = size - 2;
/* ensure there's some free room on the end, to finish off the sector */
ft->size = ped_div_round_up (size * entry_size, 512) * 512 / entry_size;
ft->fat_type = fat_type;
ft->raw_size = ft->size * entry_size;
ft->table = ped_malloc (ft->raw_size);
if (!ft->table) {
free (ft);
return NULL;
}
fat_table_clear (ft);
return ft;
}
void
fat_table_destroy (FatTable* ft)
{
free (ft->table);
free (ft);
}
FatTable*
fat_table_duplicate (const FatTable* ft)
{
FatTable* dup_ft;
dup_ft = fat_table_new (ft->fat_type, ft->size);
if (!dup_ft) return NULL;
dup_ft->cluster_count = ft->cluster_count;
dup_ft->free_cluster_count = ft->free_cluster_count;
dup_ft->bad_cluster_count = ft->bad_cluster_count;
dup_ft->last_alloc = ft->last_alloc;
memcpy (dup_ft->table, ft->table, ft->raw_size);
return dup_ft;
}
void
fat_table_clear (FatTable* ft)
{
memset (ft->table, 0, ft->raw_size);
fat_table_set (ft, 0, 0x0ffffff8);
fat_table_set (ft, 1, 0x0fffffff);
ft->free_cluster_count = ft->cluster_count;
ft->bad_cluster_count = 0;
ft->last_alloc = 1;
}
int
fat_table_set_cluster_count (FatTable* ft, FatCluster new_cluster_count)
{
PED_ASSERT (new_cluster_count + 2 <= ft->size);
ft->cluster_count = new_cluster_count;
return fat_table_count_stats (ft);
}
int
fat_table_count_stats (FatTable* ft)
{
FatCluster i;
PED_ASSERT (ft->cluster_count + 2 <= ft->size);
ft->free_cluster_count = 0;
ft->bad_cluster_count = 0;
for (i=2; i < ft->cluster_count + 2; i++) {
if (fat_table_is_available (ft, i))
ft->free_cluster_count++;
if (fat_table_is_bad (ft, i))
ft->bad_cluster_count++;
}
return 1;
}
int
fat_table_read (FatTable* ft, const PedFileSystem* fs, int table_num)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
memset (ft->table, 0, ft->raw_size);
if (!ped_geometry_read (fs->geom, (void *) ft->table,
fs_info->fat_offset
+ table_num * fs_info->fat_sectors,
fs_info->fat_sectors))
return 0;
if ( *((unsigned char*) ft->table) != fs_info->boot_sector->media) {
if (ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_IGNORE_CANCEL,
_("FAT %d media %x doesn't match the boot sector's "
"media %x. You should probably run scandisk."),
(int) table_num + 1,
(int) *((unsigned char*) ft->table),
(int) fs_info->boot_sector->media)
!= PED_EXCEPTION_IGNORE)
return 0;
}
ft->cluster_count = fs_info->cluster_count;
fat_table_count_stats (ft);
return 1;
}
int
fat_table_write (const FatTable* ft, PedFileSystem* fs, int table_num)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
if (!ped_geometry_write (fs->geom, (void *) ft->table,
fs_info->fat_offset
+ table_num * fs_info->fat_sectors,
fs_info->fat_sectors))
return 0;
if (!ped_geometry_sync (fs->geom))
return 0;
return 1;
}
int
fat_table_write_all (const FatTable* ft, PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
int i;
for (i = 0; i < fs_info->fat_table_count; i++) {
if (!fat_table_write (ft, fs, i))
return 0;
}
return 1;
}
int
fat_table_compare (const FatTable* a, const FatTable* b)
{
FatCluster i;
if (a->cluster_count != b->cluster_count)
return 0;
for (i = 0; i < a->cluster_count + 2; i++) {
if (fat_table_get (a, i) != fat_table_get (b, i))
return 0;
}
return 1;
}
static int
_test_code_available (const FatTable* ft, FatCluster code)
{
return code == 0;
}
static int
_test_code_bad (const FatTable* ft, FatCluster code)
{
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
if (code == 0xff7) return 1;
break;
case FAT_TYPE_FAT16:
if (code == 0xfff7) return 1;
break;
case FAT_TYPE_FAT32:
if (code == 0x0ffffff7) return 1;
break;
}
return 0;
}
static int
_test_code_eof (const FatTable* ft, FatCluster code)
{
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
if (code >= 0xff7) return 1;
break;
case FAT_TYPE_FAT16:
if (code >= 0xfff7) return 1;
break;
case FAT_TYPE_FAT32:
if (code >= 0x0ffffff7) return 1;
break;
}
return 0;
}
void
_update_stats (FatTable* ft, FatCluster cluster, FatCluster value)
{
if (_test_code_available (ft, value)
&& !fat_table_is_available (ft, cluster)) {
ft->free_cluster_count++;
if (fat_table_is_bad (ft, cluster))
ft->bad_cluster_count--;
}
if (!_test_code_available (ft, value)
&& fat_table_is_available (ft, cluster)) {
ft->free_cluster_count--;
if (_test_code_bad (ft, cluster))
ft->bad_cluster_count--;
}
}
int
fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value)
{
if (cluster >= ft->cluster_count + 2) {
ped_exception_throw (PED_EXCEPTION_BUG,
PED_EXCEPTION_CANCEL,
_("fat_table_set: cluster %ld outside "
"file system"),
(long) cluster);
return 0;
}
_update_stats (ft, cluster, value);
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0);
break;
case FAT_TYPE_FAT16:
((unsigned short *) ft->table) [cluster]
= PED_CPU_TO_LE16 (value);
break;
case FAT_TYPE_FAT32:
((unsigned int *) ft->table) [cluster]
= PED_CPU_TO_LE32 (value);
break;
}
return 1;
}
FatCluster
fat_table_get (const FatTable* ft, FatCluster cluster)
{
if (cluster >= ft->cluster_count + 2) {
ped_exception_throw (PED_EXCEPTION_BUG,
PED_EXCEPTION_CANCEL,
_("fat_table_get: cluster %ld outside "
"file system"),
(long) cluster);
exit (EXIT_FAILURE); /* FIXME */
}
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0);
break;
case FAT_TYPE_FAT16:
return PED_LE16_TO_CPU
(((unsigned short *) ft->table) [cluster]);
case FAT_TYPE_FAT32:
return PED_LE32_TO_CPU
(((unsigned int *) ft->table) [cluster]);
}
return 0;
}
FatCluster
fat_table_alloc_cluster (FatTable* ft)
{
FatCluster i;
FatCluster cluster;
/* hack: assumes the first two FAT entries are marked as used (which they
* always should be)
*/
for (i=1; i < ft->cluster_count + 1; i++) {
cluster = (i + ft->last_alloc) % ft->cluster_count;
if (fat_table_is_available (ft, cluster)) {
ft->last_alloc = cluster;
return cluster;
}
}
ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("fat_table_alloc_cluster: no free clusters"));
return 0;
}
FatCluster
fat_table_alloc_check_cluster (FatTable* ft, PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster result;
while (1) {
result = fat_table_alloc_cluster (ft);
if (!result)
return 0;
if (fat_read_cluster (fs, fs_info->buffer, result))
return result;
fat_table_set_bad (ft, result);
}
}
/*
returns true if <cluster> is marked as bad
*/
int
fat_table_is_bad (const FatTable* ft, FatCluster cluster)
{
return _test_code_bad (ft, fat_table_get (ft, cluster));
}
/*
returns true if <cluster> represents an EOF marker
*/
int _GL_ATTRIBUTE_PURE
fat_table_is_eof (const FatTable* ft, FatCluster cluster)
{
return _test_code_eof (ft, cluster);
}
/*
returns true if <cluster> is available.
*/
int
fat_table_is_available (const FatTable* ft, FatCluster cluster)
{
return _test_code_available (ft, fat_table_get (ft, cluster));
}
/*
returns true if <cluster> is empty. Note that this includes bad clusters.
*/
int
fat_table_is_empty (const FatTable* ft, FatCluster cluster)
{
return fat_table_is_available (ft, cluster)
|| fat_table_is_bad (ft, cluster);
}
/*
returns true if <cluster> is being used for something constructive.
*/
int
fat_table_is_active (const FatTable* ft, FatCluster cluster)
{
return !fat_table_is_bad (ft, cluster)
&& !fat_table_is_available (ft, cluster);
}
/*
marks <cluster> as the last cluster in the chain
*/
int
fat_table_set_eof (FatTable* ft, FatCluster cluster)
{
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0);
break;
case FAT_TYPE_FAT16:
return fat_table_set (ft, cluster, 0xfff8);
case FAT_TYPE_FAT32:
return fat_table_set (ft, cluster, 0x0fffffff);
}
return 0;
}
/*
Marks a clusters as unusable, due to physical disk damage.
*/
int
fat_table_set_bad (FatTable* ft, FatCluster cluster)
{
if (!fat_table_is_bad (ft, cluster))
ft->bad_cluster_count++;
switch (ft->fat_type) {
case FAT_TYPE_FAT12:
return fat_table_set (ft, cluster, 0xff7);
case FAT_TYPE_FAT16:
return fat_table_set (ft, cluster, 0xfff7);
case FAT_TYPE_FAT32:
return fat_table_set (ft, cluster, 0x0ffffff7);
}
return 0;
}
/*
marks <cluster> as unused/free/available
*/
int
fat_table_set_avail (FatTable* ft, FatCluster cluster)
{
return fat_table_set (ft, cluster, 0);
}
#endif /* !DISCOVER_ONLY */
int _GL_ATTRIBUTE_CONST
fat_table_entry_size (FatType fat_type)
{
switch (fat_type) {
case FAT_TYPE_FAT12:
return 2; /* FIXME: how? */
case FAT_TYPE_FAT16:
return 2;
case FAT_TYPE_FAT32:
return 4;
}
return 0;
}

View File

@@ -1,74 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007, 2009-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PED_FAT_TABLE_H_INCLUDED
#define PED_FAT_TABLE_H_INCLUDED
typedef struct _FatTable FatTable;
#include "fat.h"
struct _FatTable {
void* table;
FatCluster size;
int raw_size;
FatType fat_type;
FatCluster cluster_count;
FatCluster free_cluster_count;
FatCluster bad_cluster_count;
FatCluster last_alloc;
};
extern FatTable* fat_table_new (FatType fat_type, FatCluster size);
extern FatTable* fat_table_duplicate (const FatTable* ft);
extern void fat_table_destroy (FatTable* ft);
extern void fat_table_clear (FatTable* ft);
extern int fat_table_set_cluster_count (FatTable* ft,
FatCluster new_cluster_count);
extern int fat_table_read (FatTable* ft, const PedFileSystem* fs,
int table_num);
extern int fat_table_write (const FatTable* ft, PedFileSystem* fs,
int table_num);
extern int fat_table_write_all (const FatTable* ft, PedFileSystem* fs);
extern int fat_table_compare (const FatTable* a, const FatTable* b);
extern int fat_table_count_stats (FatTable* ft);
extern FatCluster fat_table_get (const FatTable* ft, FatCluster cluster);
extern int fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value);
extern FatCluster fat_table_alloc_cluster (FatTable* ft);
extern FatCluster fat_table_alloc_check_cluster (FatTable* ft,
PedFileSystem* fs);
extern int fat_table_is_bad (const FatTable* ft, FatCluster cluster);
extern int fat_table_is_eof (const FatTable* ft, FatCluster cluster);
extern int fat_table_is_empty (const FatTable* ft, FatCluster cluster);
extern int fat_table_is_available (const FatTable* ft, FatCluster cluster);
extern int fat_table_is_active (const FatTable* ft, FatCluster cluster);
extern int fat_table_set_eof (FatTable* ft, FatCluster cluster);
extern int fat_table_set_avail (FatTable* ft, FatCluster cluster);
extern int fat_table_set_bad (FatTable* ft, FatCluster cluster);
extern int fat_table_entry_size (FatType fat_type);
#endif /* PED_FAT_TABLE_H_INCLUDED */

View File

@@ -1,368 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2005, 2007-2014, 2019-2023 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include "traverse.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef DISCOVER_ONLY
#define NO_CLUSTER -1
static char tmp_buffer [4096];
int _GL_ATTRIBUTE_PURE
fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info)
{
return trav_info->buffer_size / sizeof (FatDirEntry);
}
/* returns 1 if there are no more directory entries in the directory being
* traversed, 0 otherwise.
*/
static int
is_last_buffer (FatTraverseInfo* trav_info) {
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
if (trav_info->is_legacy_root_dir)
return 1;
else
return fat_table_is_eof (fs_info->fat, trav_info->next_buffer);
}
static int
write_root_dir (FatTraverseInfo* trav_info)
{
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
if (!ped_geometry_write (trav_info->fs->geom, trav_info->dir_entries,
fs_info->root_dir_offset,
fs_info->root_dir_sector_count))
return 0;
if (!ped_geometry_sync (trav_info->fs->geom))
return 0;
trav_info->dirty = 0;
return 1;
}
static int
write_dir_cluster (FatTraverseInfo* trav_info)
{
if (!fat_write_sync_cluster (trav_info->fs,
(void*) trav_info->dir_entries,
trav_info->this_buffer))
return 0;
trav_info->dirty = 0;
return 1;
}
static int
write_dir_buffer (FatTraverseInfo* trav_info)
{
if (trav_info->is_legacy_root_dir)
return write_root_dir (trav_info);
else
return write_dir_cluster (trav_info);
}
static int
read_next_dir_buffer (FatTraverseInfo* trav_info)
{
FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
PED_ASSERT (!trav_info->is_legacy_root_dir);
trav_info->this_buffer = trav_info->next_buffer;
if (trav_info->this_buffer < 2
|| trav_info->this_buffer >= fs_info->cluster_count + 2) {
ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
"Cluster %ld in directory %s is outside file system!",
(long) trav_info->this_buffer,
trav_info->dir_name);
return 0;
}
trav_info->next_buffer
= fat_table_get (fs_info->fat, trav_info->this_buffer);
return fat_read_cluster (trav_info->fs, (void *) trav_info->dir_entries,
trav_info->this_buffer);
}
/* FIXME: put into fat_dir_entry_* operations */
void
fat_traverse_mark_dirty (FatTraverseInfo* trav_info)
{
trav_info->dirty = 1;
}
FatTraverseInfo*
fat_traverse_begin (PedFileSystem* fs, FatCluster start_cluster,
const char* dir_name)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatTraverseInfo* trav_info;
trav_info = (FatTraverseInfo*) ped_malloc (sizeof (FatTraverseInfo));
if (!trav_info)
goto error;
trav_info->dir_name = strdup (dir_name);
if (!trav_info->dir_name)
goto error_free_trav_info;
trav_info->fs = fs;
trav_info->is_legacy_root_dir
= (fs_info->fat_type == FAT_TYPE_FAT16) && (start_cluster == 0);
trav_info->dirty = 0;
trav_info->eof = 0;
trav_info->current_entry = -1;
if (trav_info->is_legacy_root_dir) {
trav_info->buffer_size = 512 * fs_info->root_dir_sector_count;
} else {
trav_info->next_buffer = start_cluster;
trav_info->buffer_size = fs_info->cluster_size;
}
trav_info->dir_entries
= (FatDirEntry*) ped_malloc (trav_info->buffer_size);
if (!trav_info->dir_entries)
goto error_free_dir_name;
if (trav_info->is_legacy_root_dir) {
if (!ped_geometry_read (fs->geom, trav_info->dir_entries,
fs_info->root_dir_offset,
fs_info->root_dir_sector_count))
goto error_free_dir_entries;
} else {
if (!read_next_dir_buffer (trav_info))
goto error_free_dir_entries;
}
return trav_info;
error_free_dir_entries:
free (trav_info->dir_entries);
error_free_dir_name:
free (trav_info->dir_name);
error_free_trav_info:
free (trav_info);
error:
return NULL;
}
int
fat_traverse_complete (FatTraverseInfo* trav_info)
{
if (trav_info->dirty) {
if (!write_dir_buffer (trav_info))
return 0;
}
free (trav_info->dir_entries);
free (trav_info->dir_name);
free (trav_info);
return 1;
}
FatTraverseInfo*
fat_traverse_directory (FatTraverseInfo *trav_info, FatDirEntry* parent)
{
strcpy (tmp_buffer, trav_info->dir_name);
fat_dir_entry_get_name (parent,
tmp_buffer + strlen (trav_info->dir_name));
strcat (tmp_buffer, "\\");
return fat_traverse_begin (trav_info->fs,
fat_dir_entry_get_first_cluster (parent, trav_info->fs),
tmp_buffer);
}
FatDirEntry*
fat_traverse_next_dir_entry (FatTraverseInfo *trav_info)
{
if (trav_info->eof)
return NULL;
trav_info->current_entry++;
if (trav_info->current_entry
>= fat_traverse_entries_per_buffer (trav_info)) {
if (trav_info->dirty) {
if (!write_dir_buffer (trav_info))
return NULL;
}
trav_info->current_entry = 0;
if (is_last_buffer (trav_info)) {
trav_info->eof = 1;
return NULL;
}
if (!read_next_dir_buffer (trav_info))
return NULL;
}
return trav_info->dir_entries + trav_info->current_entry;
}
FatCluster _GL_ATTRIBUTE_PURE
fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry, PedFileSystem *fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
switch (fs_info->fat_type) {
case FAT_TYPE_FAT12:
case FAT_TYPE_FAT16:
return PED_LE16_TO_CPU (dir_entry->first_cluster);
case FAT_TYPE_FAT32:
return PED_LE16_TO_CPU (dir_entry->first_cluster_high)
* 65536L
+ PED_LE16_TO_CPU (dir_entry->first_cluster);
}
return 0;
}
void
fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs,
FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
switch (fs_info->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0);
break;
case FAT_TYPE_FAT16:
dir_entry->first_cluster = PED_CPU_TO_LE16 (cluster);
break;
case FAT_TYPE_FAT32:
dir_entry->first_cluster
= PED_CPU_TO_LE16 (cluster & 0xffff);
dir_entry->first_cluster_high
= PED_CPU_TO_LE16 (cluster / 0x10000);
break;
}
}
uint32_t _GL_ATTRIBUTE_PURE
fat_dir_entry_get_length (FatDirEntry* dir_entry)
{
return PED_LE32_TO_CPU (dir_entry->length);
}
int
fat_dir_entry_is_null_term (const FatDirEntry* dir_entry)
{
FatDirEntry null_entry;
memset (&null_entry, 0, sizeof (null_entry));
return memcmp (&null_entry, dir_entry, sizeof (null_entry)) == 0;
}
int _GL_ATTRIBUTE_PURE
fat_dir_entry_is_active (FatDirEntry* dir_entry)
{
if ((unsigned char) dir_entry->name[0] == DELETED_FLAG) return 0;
if ((unsigned char) dir_entry->name[0] == 0) return 0;
if ((unsigned char) dir_entry->name[0] == 0xF6) return 0;
return 1;
}
int _GL_ATTRIBUTE_PURE
fat_dir_entry_is_file (FatDirEntry* dir_entry) {
if (dir_entry->attributes == VFAT_ATTR) return 0;
if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
if (!fat_dir_entry_is_active (dir_entry)) return 0;
if ((dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR) return 0;
return 1;
}
int _GL_ATTRIBUTE_PURE
fat_dir_entry_is_system_file (FatDirEntry* dir_entry)
{
if (!fat_dir_entry_is_file (dir_entry)) return 0;
return (dir_entry->attributes & SYSTEM_ATTR)
|| (dir_entry->attributes & HIDDEN_ATTR);
}
int _GL_ATTRIBUTE_PURE
fat_dir_entry_is_directory (FatDirEntry* dir_entry)
{
if (dir_entry->attributes == VFAT_ATTR) return 0;
if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
if (!fat_dir_entry_is_active (dir_entry)) return 0;
return (dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR;
}
int
fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster first_cluster;
if (!fat_dir_entry_is_file (dir_entry)
&& !fat_dir_entry_is_directory (dir_entry))
return 0;
first_cluster = fat_dir_entry_get_first_cluster (dir_entry, fs);
if (first_cluster == 0
|| fat_table_is_eof (fs_info->fat, first_cluster))
return 0;
return 1;
}
/*
decrypts silly DOS names to FILENAME.EXT
*/
void
fat_dir_entry_get_name (const FatDirEntry *dir_entry, char *result) {
size_t i;
const char *src;
const char *ext;
src = dir_entry->name;
for (i=0; i < sizeof dir_entry->name; i++) {
if (src[i] == ' ' || src[i] == 0) break;
*result++ = src[i];
}
ext = (const char *) dir_entry->extension;
if (ext[0] != ' ' && ext[0] != 0) {
*result++ = '.';
for (i=0; i < sizeof dir_entry->extension; i++) {
if (ext[i] == ' ' || ext[i] == 0) break;
*result++ = ext[i];
}
}
*result = 0;
}
#endif /* !DISCOVER_ONLY */

View File

@@ -1,75 +0,0 @@
/*
libparted
Copyright (C) 1998-2000, 2007-2014, 2019-2023 Free Software Foundation,
Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRAVERSE_H_INCLUDED
#define TRAVERSE_H_INCLUDED
#include "fatio.h"
typedef struct _FatTraverseInfo FatTraverseInfo;
struct _FatTraverseInfo {
PedFileSystem* fs;
char* dir_name;
int is_legacy_root_dir;
int dirty;
int eof;
FatDirEntry* dir_entries;
int current_entry;
FatCluster this_buffer, next_buffer;
int buffer_size;
};
extern int fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info);
/* starts traversal at an arbitary cluster. if start_cluster==0, then uses
root directory */
extern FatTraverseInfo* fat_traverse_begin (PedFileSystem* fs,
FatCluster start_cluster,
const char* dir_name);
extern int fat_traverse_complete (FatTraverseInfo* trav_info);
extern FatTraverseInfo* fat_traverse_directory (FatTraverseInfo* trav_info,
FatDirEntry* parent);
extern void fat_traverse_mark_dirty (FatTraverseInfo* trav_info);
extern FatDirEntry* fat_traverse_next_dir_entry (FatTraverseInfo* trav_info);
extern FatCluster fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry,
PedFileSystem* fs);
extern void fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry,
PedFileSystem* fs, FatCluster cluster);
extern uint32_t fat_dir_entry_get_length (FatDirEntry* dir_entry);
extern int fat_dir_entry_is_null_term (const FatDirEntry* dir_entry);
extern int fat_dir_entry_is_file (FatDirEntry* dir_entry);
extern int fat_dir_entry_is_system_file (FatDirEntry* dir_entry);
extern int fat_dir_entry_is_directory (FatDirEntry* dir_entry);
extern void fat_dir_entry_get_name (const FatDirEntry* dir_entry, char* result);
extern int fat_dir_entry_is_active (FatDirEntry* dir_entry);
extern int fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry,
PedFileSystem* fs);
#endif /* TRAVERSE_H_INCLUDED */