blob: 4752ca5d7c251f73636ac673c3f50cd862b21fe8 [file] [log] [blame]
===============================================================================
GNU Parted FAT file system documentation
===============================================================================
by Andrew Clausen <clausen@gnu.org>
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
with the no Invariant Sections, with the no Front-Cover Texts, and
with no Back-Cover Texts. A copy of the license is included in the
file, COPYING.DOC.
CONTENTS
--------
PART I - THE FAT FILE SYSTEM
1 Introduction
2 Overview
3 The Boot Sector
3.1 Data Layout
3.2 Descriptions of Fields
3.3 Calculating the ignored fields
3.4 DOS/Windows bootstrap process
4 The Info Sector
4.1 Data Layout
4.2 Descriptions of Fields
5 File Allocation Tables
6 Directory tree
6.1 Directory entries
PART II - GNU PARTED'S FAT IMPLEMENTATION
7 Resizing "issues"
8 Overview of GNU Parted's Strategy
===============================================================================
PART I - THE FAT FILE SYSTEM
===============================================================================
-------------------------------------------------------------------------------
1 INTRODUCTION
-------------------------------------------------------------------------------
This document describes the FAT filesystem, and GNU Parted's support for it.
Unfortunately, there are no particularly good sources of information on the FAT
filesystem. The information here was deduced from the source code of about 10
different programs, documentation from about 20 different sources and testing.
There are many cases where documentation for FAT from various sources
(including Microsoft) are misleading, or just plain wrong. For us,
documentation is correct if it matches the behaviour of Microsoft's
implementation.
-------------------------------------------------------------------------------
2 OVERVIEW
-------------------------------------------------------------------------------
FAT is a filesystem that is mainly used by Microsoft DOS, Windows 95,
Windows 98 and Windows 2000. FAT also stands for File Allocation Table - a
part of the FAT filesystem.
FAT comes in three flavors: FAT12, FAT16 and FAT32.
FAT12 is used on floppy disks, and REALLY old hard drives <32Mb. FAT16 is
typically used on small hard drives <500Mb, and is very inefficient for large
hard drives. FAT32 is used on hard drives >500Mb under Windows 95 OSR2 and
later and Windows 2000. These three flavors have important differences (not
JUST an increase in the maximum possible number of clusters). On FAT12 and
FAT16 cluster size directly relates to the filesystem size: the number of
clusters is always between 2041 and 4080 resp. 32761 and 65520.
The FAT filesystem has these parts (on disk, in this order):
* a bootsector. This contains all of the information about the filesystem
- whether it's FAT12, FAT16 or FAT32, how big it is, etc.
* an information sector (FAT32 only). This contains additional information
that couldn't fit in the boot sector.
* file allocation tables (FATs). There are usually two identical copies.
This is used to store the sequence of clusters that make of files. Essentially,
if you want to know the number of the cluster that comes after cluster X
in a file, you look up the number for X. If X is a magic number, it means
it's the end of the file.
* clusters. The data inside files are stored in clusters. Most directory
information is stored in clusters (except the root directory in FAT12 and
FAT16). Clusters may be 1, 2, 4, 8, etc. sectors. Clusters are numbered,
counting from 2.
* directory tree. The FAT filesystem has files and directories (no named
pipes, links, or anything fancy like that), that are stored in clusters. The
root directory on FAT12 and FAT16 is stored separately. In FAT32, the root
directory is stored inside a normal cluster, just like everything else.
-------------------------------------------------------------------------------
3 THE BOOT SECTOR
-------------------------------------------------------------------------------
The boot sector contains all of the information about the filesystem
- whether it's FAT12, FAT16 or FAT32, how big it is, etc. It also contains
the boot loader for the operating system, if there is an operating system
on the file system. It is always the first thing to appear in the filesystem
- i.e. it's found at sector 0.
A word of warning: while the values inside the boot sector will always be
consistent with the file system, many of these values are not read by
Microsoft's implementation - they are calculated independently.
3.1 The Data Layout
-------------------------------------------------------------------------------
Taken from libparted/fs_fat/bootsector.h:
struct __attribute__ ((packed)) _FatBootSector {
__u8 boot_jump[3]; /* 00: Boot strap short or near jump */
__u8 system_id[8]; /* 03: system name */
__u16 sector_size; /* 0b: bytes per logical sector */
__u8 cluster_size; /* 0d: sectors/cluster */
__u16 reserved; /* 0e: reserved sectors */
__u8 fats; /* 10: number of FATs */
__u16 dir_entries; /* 11: number of root directory entries */
__u16 sectors; /* 13: if 0, sector_count supersedes */
__u8 media; /* 15: media code */
__u16 fat_length; /* 16: sectors/FAT for FAT12/16 */
__u16 secs_track; /* 18: sectors per track */
__u16 heads; /* 1a: number of heads */
__u32 hidden; /* 1c: hidden sectors (partition start) */
__u32 sector_count; /* 20: no. of sectors (if sectors == 0) */
union __attribute__ ((packed)) {
/* FAT16 fields */
struct __attribute__ ((packed)) {
__u8 drive_num; /* 24: */
__u8 empty_1; /* 25: */
__u8 ext_signature; /* 26: always 0x29 */
__u32 serial_number; /* 27: */
__u8 volume_name [11]; /* 2b: */
__u8 fat_name [8]; /* 37: */
__u8 boot_code[448]; /* 3f: Boot code (or message) */
} fat16;
/* FAT32 fields */
struct __attribute__ ((packed)) {
__u32 fat_length; /* 24: size of FAT in sectors */
__u16 flags; /* 28: bit8: fat mirroring, low4: active fat */
__u16 version; /* 2a: minor * 256 + major */
__u32 root_dir_cluster; /* 2c: */
__u16 info_sector; /* 30: */
__u16 backup_sector; /* 32: */
__u8 empty_1 [12]; /* 34: */
__u16 drive_num; /* 40: */
__u8 ext_signature; /* 42: always 0x29 */
__u32 serial_number; /* 43: */
__u8 volume_name [11]; /* 47: */
__u8 fat_name [8]; /* 52: */
__u8 boot_code[420]; /* 5a: Boot code (or message) */
} fat32;
} u;
__u16 boot_sign; /* 1fe: always 0xAA55 */
};
3.2 Descriptions of Fields
-------------------------------------------------------------------------------
3.2.1 Fields common to FAT12, FAT16 and FAT32
-----------------------------------------------
__u8 boot_jump[3]; /* 00: Boot strap short or near jump */
This contains the Intel x86 instruction to "jump" to further down in the
boot sector. This is necessary, because on PC systems, the first sector of
the disk is loaded and executed. On hard disks of PC systems, the first
sector of the disk is in fact the Master Boot Record - which contains the
partition table. The master boot record loads the first sector of the boot
partition, so the end result is the same for floppy's and hard disks.
__u8 system_id[8]; /* 03: system name */
This contains the name of the program or operatings system that created the
file system. For FAT32, it seems you must have "MSWIN4.1" here.
If this is "MSDMF3.2" (afaik only the "MSDMF" is checked") the partition
can't be written under Windows 9x, Windows NT and Windows 2000. This is
how Microsoft realizes read-only installation or distribution floppy disks.
__u16 sector_size; /* 0b: bytes per logical sector */
This is bizarre. Sectors are always 512 bytes. However, a "logical" sector
is a hack that allows sectors to be bigger (a multiple of 512 bytes). This
is rarely used, and untested in GNU Parted at the moment. (Side note: is
it possible to use this to avoid requiring a cluster resize?)
__u8 cluster_size; /* 0d: sectors/cluster */
THIS IS IGNORED BY MICROSOFT'S IMPLEMENTATION OF FAT12 AND FAT16! (See section
3.3) This contains the size of all clusters, given in sectors. This value is
"read-only".
__u16 reserved; /* 0e: reserved sectors */
The number of sectors before the file allocation tables begin. i.e. The
number of the first sector of the first file allocation table.
__u8 fats; /* 10: number of FATs */
The number of file allocation tables (usually 2).
__u16 dir_entries; /* 11: number of root directory entries */
The size of the root directory (FAT12 and FAT16 only), in "directory entries"
(32 bytes). The root directory is immediately after the FATs (FAT12 and
FAT16 only). The first cluster (i.e. cluster number 2) starts immediately
after the root directory (or after the FATs for FAT32).
__u16 sectors; /* 13: if 0, sector_count supersedes */
THIS IS IGNORED BY MICROSOFT'S IMPLEMENTATION! The total size of the file
system. If the file system is bigger than 65536 sectors, this is set to 0,
and a 32 bit field is used instead. Microsoft's implementation gets this
values from hardware (for floppy disks), or the partition table (for hard
disks), rather than reading it off disk.
__u8 media; /* 15: media code */
For hard disks, this should always be 0xf8.
__u16 fat_length; /* 16: sectors/FAT for FAT12/16 */
THIS IS IGNORED BY MICROSOFT'S IMPLEMENTATION! (See section 3.3) The size in
sectors of each file allocation table (FAT12 and FAT16 only). A 32-bit field
is used for FAT32. This value is "read-only".
__u16 secs_track; /* 18: sectors per track */
__u16 heads; /* 1a: number of heads */
These should match the BIOS geometry. The GNU Parted README file explains
BIOS geometry.
__u32 hidden; /* 1c: hidden sectors (partition start) */
On a hard disk, this should be the number of sectors from the start of the
head (in terms of BIOS geometry) to the start of the partition. i.e. the
S in the CHS partition start.
__u32 sector_count; /* 20: no. of sectors (if sectors == 0) */
The size of the file system in sectors (if sectors is 0).
__u16 boot_sign; /* 1fe: always 0xAA55 */
Boot sector signature. Don't use this exclusively to detect FAT file systems!
It's also the signature for partition table sectors (and it appears in the
same place too!) Idiots.
3.2.2 Fields in FAT12 and FAT16
---------------------------------
__u8 drive_num; /* 24: */
Always 0x80.
__u8 ext_signature; /* 26: always 0x29 */
Always 0x29.
__u32 serial_number; /* 27: */
Serial number: Used to detect media change on floppy disk and removable drives.
__u8 volume_name [11]; /* 2b: */
The disk label.
__u8 fat_name [8]; /* 37: */
"FAT12\0\0\0" or "FAT16\0\0\0".
3.2.3 Fields in FAT32
-----------------------
__u32 fat_length; /* 24: size of FAT in sectors */
The size in sectors of each file allocation table.
__u16 flags; /* 28: bit8: fat mirroring, low4: active fat */
No idea what these are.
__u16 version; /* 2a: minor * 256 + major */
Seems to be 0 (?)
__u32 root_dir_cluster; /* 2c: */
The number of the first cluster in the root directory.
__u16 info_sector; /* 30: */
The number of the information sector.
__u16 backup_sector; /* 32: */
The number of the backup of the boot sector (i.e. this sector).
__u16 drive_num; /* 40: */
Always 0x80.
__u8 ext_signature; /* 42: always 0x29 */
Always 0x29.
__u32 serial_number; /* 43: */
Serial number (for Echelon, or something)
__u8 volume_name [11]; /* 47: */
The disk label.
__u8 fat_name [8]; /* 52: */
"FAT32\0\0\0".
3.3 Calculating the ignored fields
-------------------------------------------------------------------------------
The cluster_size and fat_length fields are ignored by Microsoft's
implementation of FAT12 and FAT16, but NOT FAT32. That is, they are written out
correctly, but NOT READ IN. (Note: if FAT32 file system is configured to
have less than 65520 clusters, then Windows assumes it's FAT16)
Since these values don't usually change unless you resize a filesystem, this
causes no problems. However, if you want to resize the filesystem, you have to
calculate these values to what Microsoft calculates them to, from the size of
the filesystem. It took me 2 months to figure this out (I want to KILL
somebody...)
Here's the algorithm I came up with that seemed to match all my test data:
(from libparted/fs_fat/calc.c)
FatCluster
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;
}
FatCluster
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;
}
static int
calc_sizes (PedGeometry* geom, PedSector align, int cluster_size,
PedSector root_dir_sectors, FatCluster* out_cluster_count,
PedSector* out_fat_size, FatType fat_type)
{
PedSector data_fat_size;
PedSector fat_sectors;
PedSector cluster_sectors;
FatCluster cluster_count;
int i;
data_fat_size = geom->length - fat_min_reserved_sector_count (fat_type)
- align;
if (fat_type == FAT_TYPE_FAT16)
data_fat_size -= root_dir_sectors;
fat_sectors = 0;
for (i = 0; i < 2; i++) {
if (fat_type == FAT_TYPE_FAT32)
cluster_sectors = data_fat_size - fat_sectors;
else
cluster_sectors = data_fat_size - 2 * fat_sectors;
cluster_count = cluster_sectors / (cluster_size / 512);
fat_sectors = div_round_up (cluster_count + 2,
entries_per_sector (fat_type));
}
cluster_sectors = data_fat_size - 2 * fat_sectors;
cluster_count = cluster_sectors / (cluster_size / 512);
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_sectors;
return 1;
}
FIXME: this is the "trial and error" algorithm. What happened to my simple,
test one?
If the implications of the above code aren't that clear, here are some of
them:
* for FAT16, the minimum number of clusters is 32760.
* the cluster size is completely determined by the size of the file system,
for FAT16. That means, if a file system is to be resized, it is quite
possible that the cluster size must be changed just to be compatible
with Microsoft's implementation (Linux, for example, doesn't calculate the
numbers independently, so it would work fine. So always test your code on
Microsoft as well as Linux)
3.4 DOS/Windows bootstrap process
-------------------------------------------------------------------------------
All of the information that follows is from me reverse-engineering different
versions of Microsoft's boot sectors. It's pretty weird code (as you can
imagine...), so there might be mistakes here.
There are many different versions of the boot sector:
* Windows 98/2000/ME FAT12/FAT16 (supports CHS and LBA)
* Windows 98/2000/ME FAT32 (supports CHS and LBA)
(1) The MBR, LILO, or whatever loads in the first sector of the FAT
partition into 0000:7c00, and executes it.
(2) The first sector of the FAT partition (the "boot sector") does:
(a) loads the Master Boot Record (sector 0 of the disk) using the
BIOS's CHS calls, and finds the boot partition. If the boot partition
has the LBA flag marked, it writes 0xe to [bp+2] (0000:7c02). The "read
sectors" function in the boot loader checks for 0xe here, and uses LBA if
it finds it, and CHS otherwise.
(b) If it is the FAT32 version of the boot sector, it loads sectors 1
through 3 of the partition (it finds this from the "hidden" field in the
FAT boot sector, that was loaded by the MBR/LILO) at address 0000:7e00, and
continues executing at 0000:8000. Note: the FAT16 version doesn't require
any more sectors to be read (they crammed it all in!), and it goes
directly to step 3.
(3) The code loads IO.SYS (starting at address 0000:0700), off the same
partition, and executes it, beginning execution at 0070:0200. (Note:
According to the x86 real mode segmentation scheme, 0070:0200 refers to the
same physical memory as 0000:0900)
-------------------------------------------------------------------------------
4 THE INFO SECTOR
-------------------------------------------------------------------------------
The info sector is used in FAT32 to store additional information about the
file system.
4.1 Data Layout
-------------------------------------------------------------------------------
struct __attribute__ ((packed)) _FatInfoSector {
__u32 signature_1; /* should be 0x41615252 */
__u8 unused [480];
__u32 signature_2; /* should be 0x61417272 */
__u32 free_clusters;
__u32 next_cluster; /* most recently allocated cluster */
__u8 unused2 [0xe];
__u16 signature_3; /* should be 0xaa55 */
};
4.2 Descriptions of Fields
-------------------------------------------------------------------------------
__u32 signature_1; /* should be 0x41615252 */
Always 0x41615252 ("AaRR")
__u32 signature_2; /* should be 0x61417272 */
Always 0x61417272 ("aArr")
__u32 free_clusters;
The number of free clusters. This could be calculated by going through the
FATs, but this is stored on shutdown to speed things up.
__u32 next_cluster; /* most recently allocated cluster */
This contains the number of the last cluster allocated. This speeds up
cluster allocation, because free clusters usually come in chunks, so you
can scan right for free clusters in the FAT.
__u16 signature_3; /* should be 0xaa55 */
Always 0xaa55.
-------------------------------------------------------------------------------
5 FILE ALLOCATION TABLES
-------------------------------------------------------------------------------
File allocation table (FAT) is a strange name, come to think of it. Perhaps it
should be called cluster allocation table, or something (?). Essentially,
it is used to represent file chains (i.e. linked lists) for files and
directories. There are usually two FATs (one is a backup, and should be
identical).
Anyway, a FAT is essentially an array. In FAT12, each entry is 12 bits,
FAT16 - 16 bits, FAT32 - 32 bits. Hence the names.
The first byte of each FAT must match the "media" field in the boot sector.
The rest of the first 2 entries are filled with 0xff.
All remaining entries - from 2 onwards - correspond to a cluster. i.e.
the second entry corresponds to cluster 2. Clusters are numbered from 2 onwards
(i.e. there is no cluster 1).
The number in each entry gives the number of the cluster that occurs next in
the file chain (linked list). However, there are a few magic numbers:
* unused (0). Indicates the cluster is unused.
* end of file (0xff0 for FAT12, 0xfff0 for FAT16, 0x0ffffff0 for FAT32).
Indicates this is the last cluster in the file or directory. Obviouslly for
FAT32, the number of clusters must be < 0x0ffffff0. So it should be called
FAT28, perhaps...
* bad cluster (0xff7 for FAT12, 0xfff7 for FAT16, 0x0ffffff7 for FAT32).
Indicates the disk is physically damaged where the cluster is stored.
-------------------------------------------------------------------------------
6 DIRECTORY TREE
-------------------------------------------------------------------------------
The directory tree is simple: there are files and directories. Files and
directories are stored in clusters (except the root directory on FAT12 and
FAT16). Directories are essentially special files that contain directory
entries.
In FAT12 and FAT16, the root directory is stored immediately after the FATs.
In FAT32, the first cluster of the root directory is given in the FAT. (To
get the second cluster - if there is one - you just look up the FAT)
6.1 Directory Entries
------------------------------------------------------------------------------
Directories are made up of directory entries, each of which represent a file,
a directory or part of a file name (the VFAT extension - YUCK!!!).
Each directory (except the root directory) contains a '.' (this directory) and
'..' (parent directory) entry.
6.1.1 Fields
--------------
From libparted/fs_fat/fat.h:
struct __attribute__ ((packed)) _FatDirEntry {
__u8 name[8];
__u8 extension[3];
__u8 attributes;
__u8 is_upper_case_name;
__u8 creation_time_low; /* milliseconds */
__u16 creation_time_high;
__u16 creation_date;
__u16 access_date;
__u16 first_cluster_high; /* for FAT32 */
__u16 time;
__u16 date;
__u16 first_cluster;
__u32 length;
};
6.1.2 Field Descriptions
--------------------------
__u8 name[8];
The first part of the file name. Eg, for a file called README.TXT, this is
README. Files with names longer than 8 characters use the VFAT extension (not
described here). When a file is deleted, the first character is set to 0xe5.
If the first character is 0x0, then the entire directory entry is unused.
__u8 extension[3];
The last part of the file name. Eg, for a file called README.TXT, this is TXT.
This explains all those .HTM files around the place...
__u8 attributes;
If this is 0x0f, then this directory entry is a VFAT entry, and stores part
of a file name. Otherwise, it's treated as various bit fields:
0x1 read-only
0x2 hidden
0x4 system
0x8 volume label
0x10 directory
0x20 archived
__u8 is_upper_case_name;
A Microsoft cludge: create a file with 8.3 name BUT containing small letters
(like ReadMe.Txt) which is treated as an LFN (long file name) and occupies
three directory entries. Now when you rename this file to all uppercase
README.TXT,- under Windows NT 4 the then superfluous LFN-VFAT entries are
removed, resulting in a smaller directory, but under Windows 9x the LFN-VFAT
entries are just upd- and this flag is set. Executing DEFRAG on such entries
MIGHT then remove the superfluous LFN-VFAT entries and shrink the directory.
__u8 creation_time_low; /* milliseconds */
__u16 creation_time_high;
__u16 creation_date;
Creation time and date. Not used wih MS-DOS <7.0!
__u16 access_date;
Last access date. Not used wih MS-DOS <7.0!
__u16 first_cluster_high; /* for FAT32 */
High 32 bits of the first cluster in the file or directory (FAT32 only)
__u16 time;
__u16 date;
?
__u16 first_cluster;
Low 16 bits of first cluster.
__u32 length;
Length of file in bytes.
===============================================================================
PART II - GNU PARTED'S FAT IMPLEMENTATION
===============================================================================
-------------------------------------------------------------------------------
7 RESIZING "ISSUES"
-------------------------------------------------------------------------------
To resize a FAT file system, a program must:
* copy all used clusters that lie outside of the new partition onto free
space on that partition. The directory tree and FATs must be updated to
reflect this.
* grow or shrink the file allocation table(s) to the size corresponding
to the size of the partition.
* convert between FAT16 and FAT32 if necessary. This involves:
- changing the form of the root directory (FAT16 has it's before the
clusters whereas FAT32 stores it in normal clusters).
- creating space for the backup boot sector and info sector.
- updating the directory tree to use 32 bit first cluster entries.
* align the start of the clusters (using the "reserved" field in the
boot sector), so that the clusters that are common to the old and new
partition can be preserved.
* re-number clusters. e.g. if you chop out some clusters from the beginning
(i.e. move the start forward), then the first cluster (i.e. number 2) will
be refer to a different cluster on the disk. The directory tree and FATs must
be updated to reflect this.
* create a new boot sector (and the info sector and backup boot sector for
FAT32)
-------------------------------------------------------------------------------
8 OVERVIEW OF GNU PARTED'S STRATEGY
-------------------------------------------------------------------------------
GNU Parted copies all clusters that are not accessible from the new file system
(either because it lies outside the file system, or file system meta-data must
reside there instead) to an accessible place.
Since all clusters must be renumbered (in most cases), the entire directory
tree must be updated. However converting the directory tree from one numbering
system to another would break the file system if it was interrupted halfway
through. Instead, GNU Parted duplicates the directory tree (except the root
directory for FAT16) along with clusters that need to be copied because they
lie outside the new file system. The directory tree is duplicated at the same
time as inaccessible clusters are. The relevant function,
needs_duplicating() in libparted/fs_fat/clstdup.c is:
static int
needs_duplicating (FatOpContext* ctx, FatCluster cluster)
{
FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
return (fs_info->fat_flag_map [cluster] == FAT_FLAG_FILE
&& !fat_op_context_map_static_cluster (ctx, cluster))
|| fs_info->fat_flag_map [cluster]
== FAT_FLAG_DIRECTORY;
}
A good overview of this implementation is in the fat_resize() function, in
libparted/fs_fat/resize.c (slightly edited):
int
fat_resize (PedFileSystem* fs, PedGeometry* geom)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatSpecific* new_fs_info;
FatOpContext* ctx;
PedFileSystem* new_fs;
ctx = create_resize_context (fs, geom);
if (!ctx)
return 0;
new_fs = ctx->new_fs;
new_fs_info = FAT_SPECIFIC (new_fs);
if (!fat_duplicate_clusters (ctx))
return 0;
if (fs_info->fat_type == FAT_TYPE_FAT16
&& new_fs_info->fat_type == FAT_TYPE_FAT32) {
if (!alloc_root_dir (ctx))
return 0;
}
if (!fat_construct_new_fat (ctx))
return 0;
if (!fat_construct_dir_tree (ctx))
return 0;
if (!fat_table_write_all (new_fs_info->fat, new_fs))
return 0;
if (!fat_boot_sector_generate (&new_fs_info->boot_sector,
new_fs))
return 0;
if (!fat_boot_sector_write (&new_fs_info->boot_sector, new_fs))
return 0;
if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
if (!fat_info_sector_generate (
&new_fs_info->info_sector, new_fs))
return 0;
if (!fat_info_sector_write (&new_fs_info->info_sector,
new_fs))
return 0;
}
if (!resize_context_assimilate (ctx))
return 0;
return 1;
}