summaryrefslogtreecommitdiff
path: root/libparted/fs/fat/fat.c
diff options
context:
space:
mode:
authorAnant Narayanan <anant@kix.in>2006-09-14 15:18:45 +0000
committerAnant Narayanan <anant@kix.in>2006-09-14 15:18:45 +0000
commit232dbda915dfcfec99e5983b7f53d57d4498a6aa (patch)
tree4d54060e75f7f2df07de6e83004551b610ac9865 /libparted/fs/fat/fat.c
downloadparted-232dbda915dfcfec99e5983b7f53d57d4498a6aa.tar.gz
Fix ChangeLog
git-svn-id: svn://svn.debian.org/svn/parted/upstream/trunk@820 2d424fd7-7fe2-0310-af74-8bc65edeb173
Diffstat (limited to 'libparted/fs/fat/fat.c')
-rw-r--r--libparted/fs/fat/fat.c888
1 files changed, 888 insertions, 0 deletions
diff --git a/libparted/fs/fat/fat.c b/libparted/fs/fat/fat.c
new file mode 100644
index 0000000..ee06f1a
--- /dev/null
+++ b/libparted/fs/fat/fat.c
@@ -0,0 +1,888 @@
+/*
+ libparted
+ Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include <string.h>
+#include <uuid/uuid.h>
+
+#include "fat.h"
+#include "calc.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;
+
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom)
+ goto error_free_type_specific;
+
+ fs->checked = 0;
+ return fs;
+
+error_free_type_specific:
+ ped_free (fs->type_specific);
+error_free_fs:
+ ped_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:
+ ped_free (fs_info->buffer);
+error:
+ return 0;
+};
+
+void
+fat_free_buffers (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ ped_free (fs_info->cluster_info);
+ ped_free (fs_info->buffer);
+}
+
+void
+fat_free (PedFileSystem* fs)
+{
+ ped_geometry_destroy (fs->geom);
+ ped_free (fs->type_specific);
+ ped_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,
+ return 0);
+
+ 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;
+}
+
+PedGeometry*
+fat_probe (PedGeometry* geom, FatType* fat_type)
+{
+ PedFileSystem* fs;
+ FatSpecific* fs_info;
+ PedGeometry* result;
+
+ fs = fat_alloc (geom);
+ if (!fs)
+ goto error;
+ fs_info = (FatSpecific*) fs->type_specific;
+
+ if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
+ goto error_free_fs;
+ if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
+ goto error_free_fs;
+
+ *fat_type = fs_info->fat_type;
+ result = ped_geometry_new (geom->dev, geom->start,
+ fs_info->sector_count);
+
+ fat_free (fs);
+ return result;
+
+error_free_fs:
+ fat_free (fs);
+error:
+ return NULL;
+}
+
+PedGeometry*
+fat_probe_fat16 (PedGeometry* geom)
+{
+ FatType fat_type;
+ PedGeometry* probed_geom = fat_probe (geom, &fat_type);
+
+ if (probed_geom) {
+ if (fat_type == FAT_TYPE_FAT16)
+ return probed_geom;
+ ped_geometry_destroy (probed_geom);
+ }
+ return NULL;
+}
+
+PedGeometry*
+fat_probe_fat32 (PedGeometry* geom)
+{
+ FatType fat_type;
+ PedGeometry* probed_geom = fat_probe (geom, &fat_type);
+
+ if (probed_geom) {
+ if (fat_type == FAT_TYPE_FAT32)
+ return probed_geom;
+ ped_geometry_destroy (probed_geom);
+ }
+ return NULL;
+}
+
+#ifndef DISCOVER_ONLY
+int
+fat_clobber (PedGeometry* geom)
+{
+ FatBootSector boot_sector;
+
+ 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;
+
+ return ped_geometry_write (geom, &boot_sector, 0, 1);
+}
+
+static int
+_init_fats (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int i;
+ 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);
+}
+
+/* hack: use the ext2 uuid library to generate a reasonably random (hopefully
+ * with /dev/random) number. Unfortunately, we can only use 4 bytes of it
+ */
+static uint32_t
+_gen_new_serial_number ()
+{
+ uuid_t uuid;
+
+ uuid_generate (uuid);
+ return * (uint32_t*) &uuid [0];
+}
+
+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))
+ return 0;
+ }
+
+ fs_info->serial_number = _gen_new_serial_number ();
+
+ if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector))
+ 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);
+}
+
+/* FIXME: fat_calc_sizes() needs to say "too big" or "too small", or
+ * something. This is a really difficult (maths) problem to do
+ * nicely...
+ * So, this algorithm works if dev->length / 2 is a valid fat_type
+ * size. (Which is how I got the magic numbers below)
+ */
+#if 0
+/* returns: -1 too small, 0 ok, 1 too big */
+static int
+_test_create_size (PedSector length, FatType fat_type,
+ PedSector cluster_sectors, PedSector cluster_count)
+{
+ PedSector rootdir_sectors;
+ PedSector _cluster_sectors;
+ FatCluster _cluster_count;
+ PedSector _fat_size;
+
+ rootdir_sectors = (fat_type == FAT_TYPE_FAT16) ? 16 : 0;
+
+ if (!fat_calc_sizes (length, 0, fat_type, rootdir_sectors,
+ &_cluster_sectors, &_cluster_count, &_fat_size))
+ return -1; // XXX: doesn't work... can't see a better way!
+
+ if (_cluster_sectors < cluster_sectors)
+ return -1;
+ if (_cluster_sectors > cluster_sectors)
+ return 1;
+
+ if (_cluster_count < cluster_count)
+ return -1;
+ if (_cluster_count > cluster_count)
+ return 1;
+
+ return 0;
+}
+
+static PedSector
+_get_create_size (PedSector upper_bound, FatType fat_type,
+ PedSector cluster_sectors, FatCluster cluster_count)
+{
+ PedSector min_length = 0;
+ PedSector max_length = upper_bound;
+ PedSector length;
+
+ while (1) {
+ length = (min_length + max_length) / 2;
+ switch (_test_create_size (length, fat_type, cluster_sectors,
+ cluster_count)) {
+ case -1: min_length = length; break;
+ case 0: return length;
+ case 1: max_length = length; break;
+ }
+ /* hack... won't always be able to get max cluster count
+ * with max cluster size, etc. */
+ if (max_length - min_length == 1)
+ return min_length;
+ }
+
+ return 0; /* shut gcc up */
+}
+#endif
+
+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;
+
+#if 0
+ min_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
+ fat_min_cluster_size (FAT_TYPE_FAT16),
+ fat_min_cluster_count (FAT_TYPE_FAT16));
+ max_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
+ fat_max_cluster_size (FAT_TYPE_FAT16),
+ fat_max_cluster_count (FAT_TYPE_FAT16));
+ if (!min_size)
+ return NULL;
+#else
+ min_size = 65794;
+ max_size = 2097153;
+#endif
+
+ 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;
+
+#if 0
+ min_size = _get_create_size (dev->length, FAT_TYPE_FAT32,
+ fat_min_cluster_size (FAT_TYPE_FAT32),
+ fat_min_cluster_count (FAT_TYPE_FAT32));
+ if (!min_size)
+ return NULL;
+#else
+ min_size = 525224;
+#endif
+
+ return ped_constraint_new (
+ ped_alignment_any, ped_alignment_any,
+ &full_dev, &full_dev,
+ min_size, dev->length);
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedFileSystemOps fat16_ops = {
+ probe: fat_probe_fat16,
+#ifndef DISCOVER_ONLY
+ clobber: fat_clobber,
+ open: fat_open,
+ create: fat_create_fat16,
+ close: fat_close,
+ check: fat_check,
+ resize: fat_resize,
+ copy: fat_copy,
+ get_create_constraint: fat_get_create_constraint_fat16,
+ get_resize_constraint: fat_get_resize_constraint,
+ get_copy_constraint: fat_get_copy_constraint,
+#else /* !DISCOVER_ONLY */
+ clobber: NULL,
+ open: NULL,
+ create: NULL,
+ close: NULL,
+ check: NULL,
+ resize: NULL,
+ copy: NULL,
+ get_create_constraint: NULL,
+ get_resize_constraint: NULL,
+ get_copy_constraint: NULL,
+#endif /* !DISCOVER_ONLY */
+};
+
+static PedFileSystemOps fat32_ops = {
+ probe: fat_probe_fat32,
+#ifndef DISCOVER_ONLY
+ clobber: fat_clobber,
+ open: fat_open,
+ create: fat_create_fat32,
+ close: fat_close,
+ check: fat_check,
+ resize: fat_resize,
+ copy: fat_copy,
+ get_create_constraint: fat_get_create_constraint_fat32,
+ get_resize_constraint: fat_get_resize_constraint,
+ get_copy_constraint: fat_get_copy_constraint,
+#else /* !DISCOVER_ONLY */
+ clobber: NULL,
+ open: NULL,
+ create: NULL,
+ close: NULL,
+ check: NULL,
+ resize: NULL,
+ copy: NULL,
+ get_create_constraint: NULL,
+ get_resize_constraint: NULL,
+ get_copy_constraint: NULL,
+#endif /* !DISCOVER_ONLY */
+};
+
+#define FAT_BLOCK_SIZES ((int[2]){512, 0})
+
+PedFileSystemType fat16_type = {
+ next: NULL,
+ ops: &fat16_ops,
+ name: "fat16",
+ block_sizes: FAT_BLOCK_SIZES
+};
+
+PedFileSystemType fat32_type = {
+ next: NULL,
+ ops: &fat32_ops,
+ name: "fat32",
+ block_sizes: FAT_BLOCK_SIZES
+};
+
+void
+ped_file_system_fat_init ()
+{
+ if (sizeof (FatBootSector) != 512) {
+ ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
+ _("GNU Parted was miscompiled: the FAT boot sector "
+ "should be 512 bytes. FAT support will be disabled."));
+ } else {
+ ped_file_system_type_register (&fat16_type);
+ ped_file_system_type_register (&fat32_type);
+ }
+}
+
+void
+ped_file_system_fat_done ()
+{
+ ped_file_system_type_unregister (&fat16_type);
+ ped_file_system_type_unregister (&fat32_type);
+}
+