Skip to content

Commit

Permalink
Merge pull request dlbeer#13 from FreddieChopin/mkfs-improvements-2
Browse files Browse the repository at this point in the history
mkfs improvements - round 2
  • Loading branch information
dlbeer authored Sep 13, 2019
2 parents e55cfb3 + 6eabe7e commit e2a7466
Showing 1 changed file with 92 additions and 46 deletions.
138 changes: 92 additions & 46 deletions ufat_mkfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "ufat.h"
#include "ufat_internal.h"

#define BACKUP_SECTOR 6
#define FSINFO_SECTOR 1
#define MEDIA_DISK 0xf8

struct fs_layout {
Expand Down Expand Up @@ -94,10 +96,6 @@ static int calculate_layout(struct fs_layout *fl,
/* Calculate total logical sector count. */
nsect = nblk >> log2_bps;

/* Calculate the number of reserved blocks. */
fl->reserved_blocks = bytes_to_blocks(log2_block_size,
2 << fl->log2_sector_size) << 1;

/* Threshold values taken from "fatgen103.pdf" -
* https://staff.washington.edu/dittrich/misc/fatgen103.pdf - "FAT
* Volume Initialization" chapter.
Expand Down Expand Up @@ -130,6 +128,19 @@ static int calculate_layout(struct fs_layout *fl,

fl->log2_bpc = log2_bps + log2_spc;

/* Calculate the number of reserved blocks.
*
* "fatgen103.pdf" -
* https://staff.washington.edu/dittrich/misc/fatgen103.pdf - "Boot
* Sector and BPB" chapter.
*
* FAT12 and FAT16 should have 1 reserved sector. Typical number of
* reserved sectors for FAT32 is 32.
*/
const ufat_block_t reserved_sectors =
fl->type == UFAT_TYPE_FAT32 ? 32 : 1;
fl->reserved_blocks = reserved_sectors << log2_bps;

/* Estimate an upper bound on the cluster count and allocate blocks
* for the FAT.
*/
Expand Down Expand Up @@ -168,6 +179,26 @@ static int calculate_layout(struct fs_layout *fl,
return 0;
}

static int erase_blocks(struct ufat_device *dev, ufat_block_t start,
ufat_block_t count)
{
const unsigned int block_size = 1 << dev->log2_block_size;
uint8_t buf[block_size];

memset(buf, 0, sizeof(buf));
for (ufat_block_t i = 0; i < count; i++)
if (dev->write(dev, start + i, 1, buf) < 0)
return -UFAT_ERR_IO;

return 0;
}

static int erase_reserved_blocks(struct ufat_device *dev,
const struct fs_layout *fl)
{
return erase_blocks(dev, 0, fl->reserved_blocks);
}

static int write_bpb(struct ufat_device *dev, const struct fs_layout *fl)
{
static const uint8_t boot_header[11] = {
Expand All @@ -176,12 +207,10 @@ static int write_bpb(struct ufat_device *dev, const struct fs_layout *fl)
'u', 'f', 'a', 't', ' ', ' ', ' ', ' '
};
const char *type_name = "FAT ";
const unsigned int log2_spb =
dev->log2_block_size - fl->log2_sector_size;
const unsigned int log2_bps =
fl->log2_sector_size - dev->log2_block_size;
const unsigned int block_size = 1 << dev->log2_block_size;
const ufat_block_t backup = fl->reserved_blocks >> 1;
uint8_t buf[block_size];
ufat_block_t i;

switch (fl->type) {
case UFAT_TYPE_FAT12:
Expand All @@ -197,14 +226,7 @@ static int write_bpb(struct ufat_device *dev, const struct fs_layout *fl)
break;
}

/* All reserved blocks are zeroed except for the one containing the
* boot sector.
*/
memset(buf, 0, sizeof(buf));
for (i = 1; i < backup; i++)
if (dev->write(dev, i, 1, buf) < 0 ||
dev->write(dev, i + backup, 1, buf) < 0)
return -UFAT_ERR_IO;

/* Boot sector signature */
memcpy(buf, boot_header, sizeof(boot_header));
Expand All @@ -213,34 +235,63 @@ static int write_bpb(struct ufat_device *dev, const struct fs_layout *fl)

/* BIOS Parameter Block */
w16(buf + 0x00b, 1 << fl->log2_sector_size);
buf[0x00d] = 1 << (fl->log2_bpc - log2_spb);
w16(buf + 0x00e, fl->reserved_blocks << log2_spb);
buf[0x00d] = 1 << (fl->log2_bpc - log2_bps);
w16(buf + 0x00e, fl->reserved_blocks << log2_bps);
buf[0x010] = 2; /* 2 FATs */
w16(buf + 0x011, fl->root_blocks << (dev->log2_block_size - 5));
if (fl->type != UFAT_TYPE_FAT32 && fl->logical_blocks <= UINT16_MAX)
w16(buf + 0x013, fl->logical_blocks << log2_spb);
w16(buf + 0x013, fl->logical_blocks << log2_bps);
else
w32(buf + 0x020, fl->logical_blocks << log2_spb);
w32(buf + 0x020, fl->logical_blocks << log2_bps);
buf[0x015] = MEDIA_DISK;

if (fl->type != UFAT_TYPE_FAT32) {
w16(buf + 0x016, fl->fat_blocks << log2_spb);
w16(buf + 0x016, fl->fat_blocks << log2_bps);
buf[0x026] = 0x29; /* Extended boot signature */
memset(buf + 0x02b, ' ', 11); /* Volume label */
memcpy(buf + 0x036, type_name, 8);
} else {
w32(buf + 0x024, fl->fat_blocks << log2_spb);
w32(buf + 0x024, fl->fat_blocks << log2_bps);
w32(buf + 0x02c, 2); /* Root directory cluster */
w16(buf + 0x030, 1); /* FS informations sector */
w16(buf + 0x032, backup << log2_spb);
w16(buf + 0x032, BACKUP_SECTOR);
buf[0x042] = 0x29; /* Extended boot signature */
memset(buf + 0x047, ' ', 11); /* Volume label */
memcpy(buf + 0x052, type_name, 8);
}

/* Write boot sector and backup */
if (dev->write(dev, 0, 1, buf) < 0 ||
dev->write(dev, backup, 1, buf) < 0)
/* Write boot sector */
if (dev->write(dev, 0, 1, buf) < 0)
return -UFAT_ERR_IO;

/* Write backup of boot sector in case of FAT32 */
if (fl->type == UFAT_TYPE_FAT32 &&
dev->write(dev, BACKUP_SECTOR >> log2_bps, 1, buf) < 0)
return -UFAT_ERR_IO;

return 0;
}

static int write_fsinfo(struct ufat_device *dev, const struct fs_layout *fl)
{
const unsigned int log2_bps =
fl->log2_sector_size - dev->log2_block_size;
const unsigned int block_size = 1 << dev->log2_block_size;
uint8_t buf[block_size];

memset(buf, 0, sizeof(buf));
w32(buf + 0x000, 0x41615252); /* FSI_LeadSig */
w32(buf + 0x1e4, 0x61417272); /* FSI_StrucSig */
w32(buf + 0x1e8, fl->clusters - 3); /* FSI_Free_Count */
w32(buf + 0x1ec, 2); /* FSI_Nxt_Free */
w32(buf + 0x1fc, 0xaa550000); /* FSI_TrailSig */

/* Write FSInfo and its backup */
const ufat_block_t fsinfo_block = FSINFO_SECTOR >> log2_bps;
const ufat_block_t fsinfo_backup_block =
(FSINFO_SECTOR + BACKUP_SECTOR) >> log2_bps;
if (dev->write(dev, fsinfo_block, 1, buf) < 0 ||
dev->write(dev, fsinfo_backup_block, 1, buf) < 0)
return -UFAT_ERR_IO;

return 0;
Expand Down Expand Up @@ -374,34 +425,18 @@ static int init_root_blocks(struct ufat_device *dev, const struct fs_layout *fl)
{
const ufat_block_t root_start =
fl->fat_blocks * 2 + fl->reserved_blocks;
const unsigned int block_size = 1 << dev->log2_block_size;
uint8_t buf[block_size];
ufat_block_t i;

memset(buf, 0, block_size);
for (i = 0; i < fl->root_blocks; i++)
if (dev->write(dev, root_start + i, 1, buf) < 0)
return -UFAT_ERR_IO;

return 0;
return erase_blocks(dev, root_start, fl->root_blocks);
}

static int init_root_cluster(struct ufat_device *dev,
const struct fs_layout *fl)
{
const ufat_block_t cluster_start =
fl->fat_blocks * 2 + fl->reserved_blocks + fl->root_blocks;
const unsigned int block_size = 1 << dev->log2_block_size;
const unsigned int cluster_blocks = 1 << fl->log2_bpc;
uint8_t buf[block_size];
ufat_block_t i;

memset(buf, 0, block_size);
for (i = 0; i < cluster_blocks; i++)
if (dev->write(dev, cluster_start + i, 1, buf) < 0)
return -UFAT_ERR_IO;

return 0;
return erase_blocks(dev, cluster_start, cluster_blocks);
}

int ufat_mkfs(struct ufat_device *dev, ufat_block_t nblk)
Expand All @@ -413,7 +448,7 @@ int ufat_mkfs(struct ufat_device *dev, ufat_block_t nblk)
if (err < 0)
return err;

err = write_bpb(dev, &fl);
err = erase_reserved_blocks(dev, &fl);
if (err < 0)
return err;

Expand All @@ -435,7 +470,18 @@ int ufat_mkfs(struct ufat_device *dev, ufat_block_t nblk)
return err;

if (fl.type == UFAT_TYPE_FAT32)
return init_root_cluster(dev, &fl);
err = init_root_cluster(dev, &fl);
else
err = init_root_blocks(dev, &fl);

if (err < 0)
return err;

if (fl.type == UFAT_TYPE_FAT32) {
err = write_fsinfo(dev, &fl);
if (err < 0)
return err;
}

return init_root_blocks(dev, &fl);
return write_bpb(dev, &fl);
}

0 comments on commit e2a7466

Please sign in to comment.