1N/A/*
1N/A libparted
1N/A Copyright (C) 1998-2001, 2007-2010 Free Software Foundation, Inc.
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A#include <config.h>
1N/A#include <string.h>
1N/A#include <uuid/uuid.h>
1N/A
1N/A#include "fat.h"
1N/A#include "calc.h"
1N/A
1N/APedFileSystem*
1N/Afat_alloc (const PedGeometry* geom)
1N/A{
1N/A PedFileSystem* fs;
1N/A
1N/A fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
1N/A if (!fs)
1N/A goto error;
1N/A
1N/A fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
1N/A if (!fs->type_specific)
1N/A goto error_free_fs;
1N/A
1N/A fs->geom = ped_geometry_duplicate (geom);
1N/A if (!fs->geom)
1N/A goto error_free_type_specific;
1N/A
1N/A fs->checked = 0;
1N/A return fs;
1N/A
1N/Aerror_free_type_specific:
1N/A free (fs->type_specific);
1N/Aerror_free_fs:
1N/A free (fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/A/* Requires the boot sector to be analysed */
1N/Aint
1N/Afat_alloc_buffers (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A
1N/A fs_info->buffer_sectors = BUFFER_SIZE;
1N/A fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
1N/A if (!fs_info->buffer)
1N/A goto error;
1N/A
1N/A fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
1N/A if (!fs_info->cluster_info)
1N/A goto error_free_buffer;
1N/A
1N/A return 1;
1N/A
1N/Aerror_free_buffer:
1N/A free (fs_info->buffer);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Avoid
1N/Afat_free_buffers (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A
1N/A free (fs_info->cluster_info);
1N/A free (fs_info->buffer);
1N/A}
1N/A
1N/Avoid
1N/Afat_free (PedFileSystem* fs)
1N/A{
1N/A ped_geometry_destroy (fs->geom);
1N/A free (fs->type_specific);
1N/A free (fs);
1N/A}
1N/A
1N/Aint
1N/Afat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A
1N/A PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
1N/A && frag_sectors <= fs_info->cluster_sectors,
1N/A return 0);
1N/A
1N/A fs_info->frag_size = frag_sectors * 512;
1N/A fs_info->frag_sectors = frag_sectors;
1N/A fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
1N/A fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
1N/A fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
1N/A
1N/A return 1;
1N/A}
1N/A
1N/APedGeometry*
1N/Afat_probe (PedGeometry* geom, FatType* fat_type)
1N/A{
1N/A PedFileSystem* fs;
1N/A FatSpecific* fs_info;
1N/A PedGeometry* result;
1N/A
1N/A fs = fat_alloc (geom);
1N/A if (!fs)
1N/A goto error;
1N/A fs_info = (FatSpecific*) fs->type_specific;
1N/A
1N/A if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
1N/A goto error_free_fs;
1N/A if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
1N/A goto error_free_fs;
1N/A
1N/A *fat_type = fs_info->fat_type;
1N/A result = ped_geometry_new (geom->dev, geom->start,
1N/A fs_info->sector_count);
1N/A
1N/A fat_free (fs);
1N/A return result;
1N/A
1N/Aerror_free_fs:
1N/A fat_free (fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/APedGeometry*
1N/Afat_probe_fat16 (PedGeometry* geom)
1N/A{
1N/A FatType fat_type;
1N/A PedGeometry* probed_geom = fat_probe (geom, &fat_type);
1N/A
1N/A if (probed_geom) {
1N/A if (fat_type == FAT_TYPE_FAT16)
1N/A return probed_geom;
1N/A ped_geometry_destroy (probed_geom);
1N/A }
1N/A return NULL;
1N/A}
1N/A
1N/APedGeometry*
1N/Afat_probe_fat32 (PedGeometry* geom)
1N/A{
1N/A FatType fat_type;
1N/A PedGeometry* probed_geom = fat_probe (geom, &fat_type);
1N/A
1N/A if (probed_geom) {
1N/A if (fat_type == FAT_TYPE_FAT32)
1N/A return probed_geom;
1N/A ped_geometry_destroy (probed_geom);
1N/A }
1N/A return NULL;
1N/A}
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/Aint
1N/Afat_clobber (PedGeometry* geom)
1N/A{
1N/A FatBootSector boot_sector;
1N/A
1N/A if (!fat_boot_sector_read (&boot_sector, geom))
1N/A return 1;
1N/A
1N/A boot_sector.system_id[0] = 0;
1N/A boot_sector.boot_sign = 0;
1N/A if (boot_sector.u.fat16.fat_name[0] == 'F')
1N/A boot_sector.u.fat16.fat_name[0] = 0;
1N/A if (boot_sector.u.fat32.fat_name[0] == 'F')
1N/A boot_sector.u.fat32.fat_name[0] = 0;
1N/A
1N/A return ped_geometry_write (geom, &boot_sector, 0, 1);
1N/A}
1N/A
1N/Astatic int
1N/A_init_fats (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A FatCluster table_size;
1N/A
1N/A table_size = fs_info->fat_sectors * 512
1N/A / fat_table_entry_size (fs_info->fat_type);
1N/A fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
1N/A if (!fs_info->fat)
1N/A goto error;
1N/A
1N/A if (!fat_table_read (fs_info->fat, fs, 0))
1N/A goto error_free_fat;
1N/A
1N/A return 1;
1N/A
1N/Aerror_free_fat:
1N/A fat_table_destroy (fs_info->fat);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/APedFileSystem*
1N/Afat_open (PedGeometry* geom)
1N/A{
1N/A PedFileSystem* fs;
1N/A FatSpecific* fs_info;
1N/A
1N/A fs = fat_alloc (geom);
1N/A if (!fs)
1N/A goto error;
1N/A fs_info = (FatSpecific*) fs->type_specific;
1N/A
1N/A if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
1N/A goto error_free_fs;
1N/A if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
1N/A goto error_free_fs;
1N/A fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
1N/A ? &fat16_type
1N/A : &fat32_type;
1N/A if (fs_info->fat_type == FAT_TYPE_FAT32) {
1N/A if (!fat_info_sector_read (&fs_info->info_sector, fs))
1N/A goto error_free_fs;
1N/A }
1N/A
1N/A if (!_init_fats (fs))
1N/A goto error_free_fs;
1N/A if (!fat_alloc_buffers (fs))
1N/A goto error_free_fat_table;
1N/A if (!fat_collect_cluster_info (fs))
1N/A goto error_free_buffers;
1N/A
1N/A return fs;
1N/A
1N/Aerror_free_buffers:
1N/A fat_free_buffers (fs);
1N/Aerror_free_fat_table:
1N/A fat_table_destroy (fs_info->fat);
1N/Aerror_free_fs:
1N/A fat_free (fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic int
1N/Afat_root_dir_clear (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
1N/A return ped_geometry_write (fs->geom, fs_info->buffer,
1N/A fs_info->root_dir_offset,
1N/A fs_info->root_dir_sector_count);
1N/A}
1N/A
1N/A/* hack: use the ext2 uuid library to generate a reasonably random (hopefully
1N/A * with /dev/random) number. Unfortunately, we can only use 4 bytes of it
1N/A */
1N/Astatic uint32_t
1N/A_gen_new_serial_number (void)
1N/A{
1N/A union {
1N/A uuid_t uuid;
1N/A uint32_t i;
1N/A } uu32;
1N/A
1N/A uuid_generate (uu32.uuid);
1N/A return uu32.i;
1N/A}
1N/A
1N/APedFileSystem*
1N/Afat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
1N/A{
1N/A PedFileSystem* fs;
1N/A FatSpecific* fs_info;
1N/A FatCluster table_size;
1N/A
1N/A fs = fat_alloc (geom);
1N/A if (!fs)
1N/A goto error;
1N/A fs_info = (FatSpecific*) fs->type_specific;
1N/A
1N/A fs_info->logical_sector_size = 1;
1N/A fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
1N/A fs_info->heads = geom->dev->bios_geom.heads;
1N/A fs_info->sector_count = fs->geom->length;
1N/A fs_info->fat_table_count = 2;
1N/A/* some initial values, to be changed later */
1N/A fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
1N/A / (512 / sizeof (FatDirEntry));
1N/A fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
1N/A
1N/A fs_info->fat_type = fat_type;
1N/A if (!fat_calc_sizes (fs->geom->length, 0,
1N/A fs_info->fat_type,
1N/A fs_info->root_dir_sector_count,
1N/A &fs_info->cluster_sectors,
1N/A &fs_info->cluster_count,
1N/A &fs_info->fat_sectors)) {
1N/A ped_exception_throw (PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Partition too big/small for a %s file system."),
1N/A (fat_type == FAT_TYPE_FAT16)
1N/A ? fat16_type.name
1N/A : fat32_type.name);
1N/A goto error_free_fs;
1N/A }
1N/A
1N/A fs_info->cluster_size = fs_info->cluster_sectors * 512;
1N/A
1N/A fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
1N/A fs_info->dir_entries_per_cluster
1N/A = fs_info->cluster_size / sizeof (FatDirEntry);
1N/A
1N/A if (fs_info->fat_type == FAT_TYPE_FAT16) {
1N/A /* FAT16 */
1N/A fs->type = &fat16_type;
1N/A
1N/A if (fs_info->cluster_count
1N/A > fat_max_cluster_count (fs_info->fat_type)) {
1N/A fs_info->cluster_count
1N/A = fat_max_cluster_count (fs_info->fat_type);
1N/A }
1N/A
1N/A fs_info->root_dir_sector_count
1N/A = FAT_ROOT_DIR_ENTRY_COUNT
1N/A / (512 / sizeof (FatDirEntry));
1N/A fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
1N/A fs_info->root_dir_offset
1N/A = fs_info->fat_offset
1N/A + fs_info->fat_sectors * fs_info->fat_table_count;
1N/A fs_info->cluster_offset
1N/A = fs_info->root_dir_offset
1N/A + fs_info->root_dir_sector_count;
1N/A } else {
1N/A /* FAT32 */
1N/A fs->type = &fat32_type;
1N/A
1N/A fs_info->info_sector_offset = 1;
1N/A fs_info->boot_sector_backup_offset = 6;
1N/A
1N/A fs_info->root_dir_sector_count = 0;
1N/A fs_info->root_dir_entry_count = 0;
1N/A fs_info->root_dir_offset = 0;
1N/A
1N/A fs_info->cluster_offset
1N/A = fs_info->fat_offset
1N/A + fs_info->fat_sectors * fs_info->fat_table_count;
1N/A }
1N/A
1N/A table_size = fs_info->fat_sectors * 512
1N/A / fat_table_entry_size (fs_info->fat_type);
1N/A fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
1N/A if (!fs_info->fat)
1N/A goto error_free_fs;
1N/A fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
1N/A if (!fat_alloc_buffers (fs))
1N/A goto error_free_fat_table;
1N/A
1N/A if (fs_info->fat_type == FAT_TYPE_FAT32) {
1N/A fs_info->root_cluster
1N/A = fat_table_alloc_cluster (fs_info->fat);
1N/A fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
1N/A memset (fs_info->buffer, 0, fs_info->cluster_size);
1N/A if (!fat_write_cluster (fs, fs_info->buffer,
1N/A fs_info->root_cluster))
1N/A return 0;
1N/A }
1N/A
1N/A fs_info->serial_number = _gen_new_serial_number ();
1N/A
1N/A if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector))
1N/A goto error_free_buffers;
1N/A if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
1N/A goto error_free_buffers;
1N/A if (!fat_boot_sector_write (&fs_info->boot_sector, fs))
1N/A goto error_free_buffers;
1N/A if (fs_info->fat_type == FAT_TYPE_FAT32) {
1N/A if (!fat_info_sector_generate (&fs_info->info_sector, fs))
1N/A goto error_free_buffers;
1N/A if (!fat_info_sector_write (&fs_info->info_sector, fs))
1N/A goto error_free_buffers;
1N/A }
1N/A
1N/A if (!fat_table_write_all (fs_info->fat, fs))
1N/A goto error_free_buffers;
1N/A
1N/A if (fs_info->fat_type == FAT_TYPE_FAT16) {
1N/A if (!fat_root_dir_clear (fs))
1N/A goto error_free_buffers;
1N/A }
1N/A
1N/A return fs;
1N/A
1N/Aerror_free_buffers:
1N/A fat_free_buffers (fs);
1N/Aerror_free_fat_table:
1N/A fat_table_destroy (fs_info->fat);
1N/Aerror_free_fs:
1N/A fat_free (fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/APedFileSystem*
1N/Afat_create_fat16 (PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A return fat_create (geom, FAT_TYPE_FAT16, timer);
1N/A}
1N/A
1N/APedFileSystem*
1N/Afat_create_fat32 (PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A return fat_create (geom, FAT_TYPE_FAT32, timer);
1N/A}
1N/A
1N/Aint
1N/Afat_close (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A
1N/A fat_free_buffers (fs);
1N/A fat_table_destroy (fs_info->fat);
1N/A fat_free (fs);
1N/A return 1;
1N/A}
1N/A
1N/A/* Hack: just resize the file system outside of its boundaries! */
1N/APedFileSystem*
1N/Afat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A PedFileSystem* new_fs;
1N/A
1N/A new_fs = ped_file_system_open (fs->geom);
1N/A if (!new_fs)
1N/A goto error;
1N/A if (!ped_file_system_resize (new_fs, geom, timer))
1N/A goto error_close_new_fs;
1N/A return new_fs;
1N/A
1N/Aerror_close_new_fs:
1N/A ped_file_system_close (new_fs);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_compare_fats (PedFileSystem* fs)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A FatTable* table_copy;
1N/A FatCluster table_size;
1N/A int i;
1N/A
1N/A table_size = fs_info->fat_sectors * 512
1N/A / fat_table_entry_size (fs_info->fat_type);
1N/A
1N/A table_copy = fat_table_new (fs_info->fat_type, table_size);
1N/A if (!table_copy)
1N/A goto error;
1N/A
1N/A for (i = 1; i < fs_info->fat_table_count; i++) {
1N/A if (!fat_table_read (table_copy, fs, i))
1N/A goto error_free_table_copy;
1N/A if (!fat_table_compare (fs_info->fat, table_copy)) {
1N/A if (ped_exception_throw (PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("The FATs don't match. If you don't know "
1N/A "what this means, then select cancel, run "
1N/A "scandisk on the file system, and then come "
1N/A "back."))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error_free_table_copy;
1N/A }
1N/A }
1N/A
1N/A fat_table_destroy (table_copy);
1N/A return 1;
1N/A
1N/Aerror_free_table_copy:
1N/A fat_table_destroy (table_copy);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Aint
1N/Afat_check (PedFileSystem* fs, PedTimer* timer)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A PedSector cluster_sectors;
1N/A FatCluster cluster_count;
1N/A PedSector fat_sectors;
1N/A PedSector align_sectors;
1N/A FatCluster info_free_clusters;
1N/A
1N/A align_sectors = fs_info->fat_offset
1N/A - fat_min_reserved_sector_count (fs_info->fat_type);
1N/A
1N/A if (!fat_calc_sizes (fs->geom->length,
1N/A align_sectors,
1N/A fs_info->fat_type,
1N/A fs_info->root_dir_sector_count,
1N/A &cluster_sectors,
1N/A &cluster_count,
1N/A &fat_sectors)) {
1N/A if (ped_exception_throw (PED_EXCEPTION_BUG,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("There are no possible configurations for this FAT "
1N/A "type."))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error;
1N/A }
1N/A
1N/A if (fs_info->fat_type == FAT_TYPE_FAT16) {
1N/A if (cluster_sectors != fs_info->cluster_sectors
1N/A || cluster_count != fs_info->cluster_count
1N/A || fat_sectors != fs_info->fat_sectors) {
1N/A if (ped_exception_throw (PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("File system doesn't have expected sizes for "
1N/A "Windows to like it. "
1N/A "Cluster size is %dk (%dk expected); "
1N/A "number of clusters is %d (%d expected); "
1N/A "size of FATs is %d sectors (%d expected)."),
1N/A (int) fs_info->cluster_sectors / 2,
1N/A (int) cluster_sectors / 2,
1N/A (int) fs_info->cluster_count,
1N/A (int) cluster_count,
1N/A (int) fs_info->fat_sectors,
1N/A (int) fat_sectors)
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error;
1N/A }
1N/A }
1N/A
1N/A if (fs_info->fat_type == FAT_TYPE_FAT32) {
1N/A info_free_clusters
1N/A = PED_LE32_TO_CPU (fs_info->info_sector.free_clusters);
1N/A if (info_free_clusters != (FatCluster) -1
1N/A && info_free_clusters != fs_info->fat->free_cluster_count) {
1N/A if (ped_exception_throw (PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("File system is reporting the free space as "
1N/A "%d clusters, not %d clusters."),
1N/A info_free_clusters,
1N/A fs_info->fat->free_cluster_count)
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error;
1N/A }
1N/A }
1N/A
1N/A if (!_compare_fats (fs))
1N/A goto error;
1N/A
1N/A fs->checked = 1;
1N/A return 1; /* existence of fs implies consistency ;-) */
1N/A
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/A/* Calculates how much space there will be in clusters in:
1N/A * old_fs intersect the-new-fs
1N/A */
1N/Astatic PedSector
1N/A_calc_resize_data_size (
1N/A const PedFileSystem* old_fs,
1N/A PedSector new_cluster_sectors,
1N/A FatCluster new_cluster_count,
1N/A PedSector new_fat_size)
1N/A{
1N/A FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
1N/A PedSector fat_size_delta;
1N/A
1N/A fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
1N/A return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
1N/A}
1N/A
1N/Astatic int
1N/A_test_resize_size (const PedFileSystem* fs,
1N/A PedSector length, PedSector min_data_size)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A PedGeometry geom;
1N/A PedSector _cluster_sectors;
1N/A FatCluster _cluster_count;
1N/A PedSector _fat_size;
1N/A
1N/A ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
1N/A
1N/A if (fat_calc_resize_sizes (
1N/A &geom,
1N/A fs_info->cluster_sectors,
1N/A FAT_TYPE_FAT16,
1N/A fs_info->root_dir_sector_count,
1N/A fs_info->cluster_sectors,
1N/A &_cluster_sectors,
1N/A &_cluster_count,
1N/A &_fat_size)
1N/A && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
1N/A _fat_size)
1N/A >= min_data_size)
1N/A return 1;
1N/A
1N/A if (fat_calc_resize_sizes (
1N/A &geom,
1N/A fs_info->cluster_sectors,
1N/A FAT_TYPE_FAT32,
1N/A 0,
1N/A fs_info->cluster_sectors,
1N/A &_cluster_sectors,
1N/A &_cluster_count,
1N/A &_fat_size)
1N/A && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
1N/A _fat_size)
1N/A >= min_data_size)
1N/A return 1;
1N/A
1N/A return 0;
1N/A}
1N/A
1N/A/* does a binary search (!) for the mininum size. Too hard to compute directly
1N/A * (see calc_sizes() for why!)
1N/A */
1N/Astatic PedSector
1N/A_get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
1N/A{
1N/A PedSector min_length = 0;
1N/A PedSector max_length = fs->geom->length;
1N/A PedSector length;
1N/A
1N/A while (min_length < max_length - 1) {
1N/A length = (min_length + max_length) / 2;
1N/A if (_test_resize_size (fs, length, min_data_size))
1N/A max_length = length;
1N/A else
1N/A min_length = length;
1N/A }
1N/A
1N/A/* adds a bit of leeway (64 sectors), for resolving extra issues, like root
1N/A * directory allocation, that aren't covered here.
1N/A */
1N/A return max_length + 64;
1N/A}
1N/A
1N/APedConstraint*
1N/Afat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
1N/A{
1N/A FatSpecific* fs_info = FAT_SPECIFIC (fs);
1N/A PedGeometry full_dev;
1N/A PedSector min_cluster_count;
1N/A FatCluster used_clusters;
1N/A PedSector min_data_size;
1N/A
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A
1N/A used_clusters = fs_info->fat->cluster_count
1N/A - fs_info->fat->free_cluster_count;
1N/A min_cluster_count = used_clusters + fs_info->total_dir_clusters;
1N/A min_data_size = min_cluster_count * fs_info->cluster_sectors;
1N/A
1N/A return ped_constraint_new (ped_alignment_any, ped_alignment_any,
1N/A &full_dev, &full_dev,
1N/A _get_min_resize_size (fs, min_data_size),
1N/A dev->length);
1N/A}
1N/A
1N/APedConstraint*
1N/Afat_get_resize_constraint (const PedFileSystem* fs)
1N/A{
1N/A return fat_get_copy_constraint (fs, fs->geom->dev);
1N/A}
1N/A
1N/A/* FIXME: fat_calc_sizes() needs to say "too big" or "too small", or
1N/A * something. This is a really difficult (maths) problem to do
1N/A * nicely...
1N/A * So, this algorithm works if dev->length / 2 is a valid fat_type
1N/A * size. (Which is how I got the magic numbers below)
1N/A */
1N/A#if 0
1N/A/* returns: -1 too small, 0 ok, 1 too big */
1N/Astatic int
1N/A_test_create_size (PedSector length, FatType fat_type,
1N/A PedSector cluster_sectors, PedSector cluster_count)
1N/A{
1N/A PedSector rootdir_sectors;
1N/A PedSector _cluster_sectors;
1N/A FatCluster _cluster_count;
1N/A PedSector _fat_size;
1N/A
1N/A rootdir_sectors = (fat_type == FAT_TYPE_FAT16) ? 16 : 0;
1N/A
1N/A if (!fat_calc_sizes (length, 0, fat_type, rootdir_sectors,
1N/A &_cluster_sectors, &_cluster_count, &_fat_size))
1N/A return -1; // XXX: doesn't work... can't see a better way!
1N/A
1N/A if (_cluster_sectors < cluster_sectors)
1N/A return -1;
1N/A if (_cluster_sectors > cluster_sectors)
1N/A return 1;
1N/A
1N/A if (_cluster_count < cluster_count)
1N/A return -1;
1N/A if (_cluster_count > cluster_count)
1N/A return 1;
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic PedSector
1N/A_get_create_size (PedSector upper_bound, FatType fat_type,
1N/A PedSector cluster_sectors, FatCluster cluster_count)
1N/A{
1N/A PedSector min_length = 0;
1N/A PedSector max_length = upper_bound;
1N/A PedSector length;
1N/A
1N/A while (1) {
1N/A length = (min_length + max_length) / 2;
1N/A switch (_test_create_size (length, fat_type, cluster_sectors,
1N/A cluster_count)) {
1N/A case -1: min_length = length; break;
1N/A case 0: return length;
1N/A case 1: max_length = length; break;
1N/A }
1N/A /* hack... won't always be able to get max cluster count
1N/A * with max cluster size, etc. */
1N/A if (max_length - min_length == 1)
1N/A return min_length;
1N/A }
1N/A
1N/A return 0; /* shut gcc up */
1N/A}
1N/A#endif
1N/A
1N/APedConstraint*
1N/Afat_get_create_constraint_fat16 (const PedDevice* dev)
1N/A{
1N/A PedGeometry full_dev;
1N/A PedSector min_size;
1N/A PedSector max_size;
1N/A
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A
1N/A#if 0
1N/A min_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
1N/A fat_min_cluster_size (FAT_TYPE_FAT16),
1N/A fat_min_cluster_count (FAT_TYPE_FAT16));
1N/A max_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
1N/A fat_max_cluster_size (FAT_TYPE_FAT16),
1N/A fat_max_cluster_count (FAT_TYPE_FAT16));
1N/A if (!min_size)
1N/A return NULL;
1N/A#else
1N/A min_size = 65794;
1N/A max_size = 2097153;
1N/A#endif
1N/A
1N/A return ped_constraint_new (
1N/A ped_alignment_any, ped_alignment_any,
1N/A &full_dev, &full_dev,
1N/A min_size, max_size);
1N/A}
1N/A
1N/APedConstraint*
1N/Afat_get_create_constraint_fat32 (const PedDevice* dev)
1N/A{
1N/A PedGeometry full_dev;
1N/A PedSector min_size;
1N/A
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A
1N/A#if 0
1N/A min_size = _get_create_size (dev->length, FAT_TYPE_FAT32,
1N/A fat_min_cluster_size (FAT_TYPE_FAT32),
1N/A fat_min_cluster_count (FAT_TYPE_FAT32));
1N/A if (!min_size)
1N/A return NULL;
1N/A#else
1N/A min_size = 525224;
1N/A#endif
1N/A
1N/A return ped_constraint_new (
1N/A ped_alignment_any, ped_alignment_any,
1N/A &full_dev, &full_dev,
1N/A min_size, dev->length);
1N/A}
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/Astatic PedFileSystemOps fat16_ops = {
1N/A .probe = fat_probe_fat16,
1N/A#ifndef DISCOVER_ONLY
1N/A .clobber = fat_clobber,
1N/A .open = fat_open,
1N/A .create = fat_create_fat16,
1N/A .close = fat_close,
1N/A .check = fat_check,
1N/A .resize = fat_resize,
1N/A .copy = fat_copy,
1N/A .get_create_constraint = fat_get_create_constraint_fat16,
1N/A .get_resize_constraint = fat_get_resize_constraint,
1N/A .get_copy_constraint = fat_get_copy_constraint,
1N/A#else /* !DISCOVER_ONLY */
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .resize = NULL,
1N/A .copy = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_resize_constraint = NULL,
1N/A .get_copy_constraint = NULL,
1N/A#endif /* !DISCOVER_ONLY */
1N/A};
1N/A
1N/Astatic PedFileSystemOps fat32_ops = {
1N/A .probe = fat_probe_fat32,
1N/A#ifndef DISCOVER_ONLY
1N/A .clobber = fat_clobber,
1N/A .open = fat_open,
1N/A .create = fat_create_fat32,
1N/A .close = fat_close,
1N/A .check = fat_check,
1N/A .resize = fat_resize,
1N/A .copy = fat_copy,
1N/A .get_create_constraint = fat_get_create_constraint_fat32,
1N/A .get_resize_constraint = fat_get_resize_constraint,
1N/A .get_copy_constraint = fat_get_copy_constraint,
1N/A#else /* !DISCOVER_ONLY */
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .resize = NULL,
1N/A .copy = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_resize_constraint = NULL,
1N/A .get_copy_constraint = NULL,
1N/A#endif /* !DISCOVER_ONLY */
1N/A};
1N/A
1N/A#define FAT_BLOCK_SIZES ((int[2]){512, 0})
1N/A
1N/APedFileSystemType fat16_type = {
1N/A .next = NULL,
1N/A .ops = &fat16_ops,
1N/A .name = "fat16",
1N/A .block_sizes = FAT_BLOCK_SIZES
1N/A};
1N/A
1N/APedFileSystemType fat32_type = {
1N/A .next = NULL,
1N/A .ops = &fat32_ops,
1N/A .name = "fat32",
1N/A .block_sizes = FAT_BLOCK_SIZES
1N/A};
1N/A
1N/Avoid
1N/Aped_file_system_fat_init ()
1N/A{
1N/A if (sizeof (FatBootSector) != 512) {
1N/A ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
1N/A _("GNU Parted was miscompiled: the FAT boot sector "
1N/A "should be 512 bytes. FAT support will be disabled."));
1N/A } else {
1N/A ped_file_system_type_register (&fat16_type);
1N/A ped_file_system_type_register (&fat32_type);
1N/A }
1N/A}
1N/A
1N/Avoid
1N/Aped_file_system_fat_done ()
1N/A{
1N/A ped_file_system_type_unregister (&fat16_type);
1N/A ped_file_system_type_unregister (&fat32_type);
1N/A}