| /* |
| libparted |
| Copyright (C) 1998, 1999, 2000, 2001, 2007 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 <config.h> |
| #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); |
| 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); |
| } |
| |