📄 mkdosfs.c
字号:
* not really present cluster. */
clust16 = (fatdata - nr_fats*fatlength16)/bs.cluster_size;
maxclust16 = (fatlength16 * sector_size) / 2;
if (maxclust16 > MAX_CLUST_16)
maxclust16 = MAX_CLUST_16;
if (verbose >= 2)
printf( "FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
clust16, fatlength16, maxclust16, MAX_CLUST_16 );
if (clust16 > maxclust16-2) {
if (verbose >= 2)
printf( "FAT16: too much clusters\n" );
clust16 = 0;
}
/* The < 4078 avoids that the filesystem will be misdetected as having a
* 12 bit FAT. */
if (clust16 < FAT12_THRESHOLD && !(size_fat_by_user && size_fat == 16)) {
if (verbose >= 2)
printf( clust16 < FAT12_THRESHOLD ?
"FAT16: would be misdetected as FAT12\n" :
"FAT16: too much clusters\n" );
clust16 = 0;
}
clust32 = ((ll_t) fatdata *sector_size + nr_fats*8) /
((int) bs.cluster_size * sector_size + nr_fats*4);
fatlength32 = cdiv ((clust32+2) * 4, sector_size);
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
clust32 = (fatdata - nr_fats*fatlength32)/bs.cluster_size;
maxclust32 = (fatlength32 * sector_size) / 4;
if (maxclust32 > MAX_CLUST_32)
maxclust32 = MAX_CLUST_32;
if (verbose >= 2)
printf( "FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
clust32, fatlength32, maxclust32, MAX_CLUST_32 );
if (clust32 > maxclust32) {
clust32 = 0;
if (verbose >= 2)
printf( "FAT32: too much clusters\n" );
}
if ((clust12 && (size_fat == 0 || size_fat == 12)) ||
(clust16 && (size_fat == 0 || size_fat == 16)) ||
(clust32 && size_fat == 32))
break;
bs.cluster_size <<= 1;
} while (bs.cluster_size && bs.cluster_size <= maxclustsize);
/* Use the optimal FAT size if not specified;
* FAT32 is (not yet) choosen automatically */
if (!size_fat) {
size_fat = (clust16 > clust12) ? 16 : 12;
if (verbose >= 2)
printf( "Choosing %d bits for FAT\n", size_fat );
}
switch (size_fat) {
case 12:
cluster_count = clust12;
fat_length = fatlength12;
bs.fat_length = CT_LE_W(fatlength12);
memcpy(vi->fs_type, MSDOS_FAT12_SIGN, 8);
break;
case 16:
if (clust16 < FAT12_THRESHOLD) {
if (size_fat_by_user) {
fprintf( stderr, "WARNING: Not enough clusters for a "
"16 bit FAT! The filesystem will be\n"
"misinterpreted as having a 12 bit FAT without "
"mount option \"fat=16\".\n" );
}
else {
fprintf( stderr, "This filesystem has an unfortunate size. "
"A 12 bit FAT cannot provide\n"
"enough clusters, but a 16 bit FAT takes up a little "
"bit more space so that\n"
"the total number of clusters becomes less than the "
"threshold value for\n"
"distinction between 12 and 16 bit FATs.\n" );
die( "Make the file system a bit smaller manually." );
}
}
cluster_count = clust16;
fat_length = fatlength16;
bs.fat_length = CT_LE_W(fatlength16);
memcpy(vi->fs_type, MSDOS_FAT16_SIGN, 8);
break;
case 32:
cluster_count = clust32;
fat_length = fatlength32;
bs.fat_length = CT_LE_W(0);
bs.fat32.fat32_length = CT_LE_L(fatlength32);
memcpy(vi->fs_type, MSDOS_FAT32_SIGN, 8);
break;
default:
die("FAT not 12, 16 or 32 bits");
}
}
else {
unsigned clusters, maxclust;
/* GEMDOS always uses a 12 bit FAT on floppies, and always a 16 bit FAT on
* hard disks. So use 12 bit if the size of the file system suggests that
* this fs is for a floppy disk, if the user hasn't explicitly requested a
* size.
*/
if (!size_fat)
size_fat = (num_sectors == 1440 || num_sectors == 2400 ||
num_sectors == 2880 || num_sectors == 5760) ? 12 : 16;
if (verbose >= 2)
printf( "Choosing %d bits for FAT\n", size_fat );
/* Atari format: cluster size should be 2, except explicitly requested by
* the user, since GEMDOS doesn't like other cluster sizes very much.
* Instead, tune the sector size for the FS to fit.
*/
bs.cluster_size = sectors_per_cluster ? sectors_per_cluster : 2;
if (!sector_size_set) {
while( num_sectors > GEMDOS_MAX_SECTORS ) {
num_sectors >>= 1;
sector_size <<= 1;
}
}
if (verbose >= 2)
printf( "Sector size must be %d to have less than %d log. sectors\n",
sector_size, GEMDOS_MAX_SECTORS );
/* Check if there are enough FAT indices for how much clusters we have */
do {
fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) -
reserved_sectors;
/* The factor 2 below avoids cut-off errors for nr_fats == 1 and
* size_fat == 12
* The "2*nr_fats*size_fat/8" is for the reserved first two FAT entries
*/
clusters = (2*((ll_t)fatdata*sector_size - 2*nr_fats*size_fat/8)) /
(2*((int)bs.cluster_size*sector_size + nr_fats*size_fat/8));
fat_length = cdiv( (clusters+2)*size_fat/8, sector_size );
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
clusters = (fatdata - nr_fats*fat_length)/bs.cluster_size;
maxclust = (fat_length*sector_size*8)/size_fat;
if (verbose >= 2)
printf( "ss=%d: #clu=%d, fat_len=%d, maxclu=%d\n",
sector_size, clusters, fat_length, maxclust );
/* last 10 cluster numbers are special (except FAT32: 4 high bits rsvd);
* first two numbers are reserved */
if (maxclust <= (size_fat == 32 ? MAX_CLUST_32 : (1<<size_fat)-0x10) &&
clusters <= maxclust-2)
break;
if (verbose >= 2)
printf( clusters > maxclust-2 ?
"Too many clusters\n" : "FAT too big\n" );
/* need to increment sector_size once more to */
if (sector_size_set)
die( "With this sector size, the maximum number of FAT entries "
"would be exceeded." );
num_sectors >>= 1;
sector_size <<= 1;
} while( sector_size <= GEMDOS_MAX_SECTOR_SIZE );
if (sector_size > GEMDOS_MAX_SECTOR_SIZE)
die( "Would need a sector size > 16k, which GEMDOS can't work with");
cluster_count = clusters;
if (size_fat != 32)
bs.fat_length = CT_LE_W(fat_length);
else {
bs.fat_length = 0;
bs.fat32.fat32_length = CT_LE_L(fat_length);
}
}
bs.sector_size[0] = (char) (sector_size & 0x00ff);
bs.sector_size[1] = (char) ((sector_size & 0xff00) >> 8);
if (size_fat == 32)
{
/* set up additional FAT32 fields */
bs.fat32.flags = CT_LE_W(0);
bs.fat32.version[0] = 0;
bs.fat32.version[1] = 0;
bs.fat32.root_cluster = CT_LE_L(2);
bs.fat32.info_sector = CT_LE_W(1);
if (!backup_boot)
backup_boot = (reserved_sectors >= 7) ? 6 :
(reserved_sectors >= 2) ? reserved_sectors-1 : 0;
else
{
if (backup_boot == 1)
die("Backup boot sector must be after sector 1");
else if (backup_boot >= reserved_sectors)
die("Backup boot sector must be a reserved sector");
}
if (verbose >= 2)
printf( "Using sector %d as backup boot sector (0 = none)\n",
backup_boot );
bs.fat32.backup_boot = CT_LE_W(backup_boot);
memset( &bs.fat32.reserved2, 0, sizeof(bs.fat32.reserved2) );
}
if (atari_format) {
/* Just some consistency checks */
if (num_sectors >= GEMDOS_MAX_SECTORS)
die( "GEMDOS can't handle more than 65531 sectors" );
else if (num_sectors >= OLDGEMDOS_MAX_SECTORS)
printf( "Warning: More than 32765 sector need TOS 1.04 "
"or higher.\n" );
}
if (num_sectors >= 65536)
{
bs.sectors[0] = (char) 0;
bs.sectors[1] = (char) 0;
bs.total_sect = CT_LE_L(num_sectors);
}
else
{
bs.sectors[0] = (char) (num_sectors & 0x00ff);
bs.sectors[1] = (char) ((num_sectors & 0xff00) >> 8);
if (!atari_format)
bs.total_sect = CT_LE_L(0);
}
if (!atari_format)
vi->ext_boot_sign = MSDOS_EXT_SIGN;
if (!cluster_count)
{
if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */
die ("Too many clusters for file system - try more sectors per cluster");
else
die ("Attempting to create a too large file system");
}
/* The two following vars are in hard sectors, i.e. 512 byte sectors! */
start_data_sector = (reserved_sectors + nr_fats * fat_length) *
(sector_size/HARD_SECTOR_SIZE);
start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) /
SECTORS_PER_BLOCK;
if (blocks < start_data_block + 32) /* Arbitrary undersize file system! */
die ("Too few blocks for viable file system");
if (verbose)
{
printf("%s has %d head%s and %d sector%s per track,\n",
device_name, CF_LE_W(bs.heads), (CF_LE_W(bs.heads) != 1) ? "s" : "",
CF_LE_W(bs.secs_track), (CF_LE_W(bs.secs_track) != 1) ? "s" : "");
printf("logical sector size is %d,\n",sector_size);
printf("using 0x%02x media descriptor, with %d sectors;\n",
(int) (bs.media), num_sectors);
printf("file system has %d %d-bit FAT%s and %d sector%s per cluster.\n",
(int) (bs.fats), size_fat, (bs.fats != 1) ? "s" : "",
(int) (bs.cluster_size), (bs.cluster_size != 1) ? "s" : "");
printf ("FAT size is %d sector%s, and provides %d cluster%s.\n",
fat_length, (fat_length != 1) ? "s" : "",
cluster_count, (cluster_count != 1) ? "s" : "");
if (size_fat != 32)
printf ("Root directory contains %d slots.\n",
(int) (bs.dir_entries[0]) + (int) (bs.dir_entries[1]) * 256);
printf ("Volume ID is %08lx, ", volume_id &
(atari_format ? 0x00ffffff : 0xffffffff));
if ( strcmp(volume_name, " ") )
printf("volume label %s.\n", volume_name);
else
printf("no volume label.\n");
}
/* Make the file allocation tables! */
if ((fat = (unsigned char *) malloc (fat_length * sector_size)) == NULL)
die ("unable to allocate space for FAT image in memory");
memset( fat, 0, fat_length * sector_size );
mark_FAT_cluster (0, 0xffffffff); /* Initial fat entries */
mark_FAT_cluster (1, 0xffffffff);
fat[0] = (unsigned char) bs.media; /* Put media type in first byte! */
if (size_fat == 32) {
/* Mark cluster 2 as EOF (used for root dir) */
mark_FAT_cluster (2, FAT_EOF);
}
/* Make the root directory entries */
size_root_dir = (size_fat == 32) ?
bs.cluster_size*sector_size :
(((int)bs.dir_entries[1]*256+(int)bs.dir_entries[0]) *
sizeof (struct msdos_dir_entry));
if ((root_dir = (struct msdos_dir_entry *) malloc (size_root_dir)) == NULL)
{
free (fat); /* Tidy up before we die! */
die ("unable to allocate space for root directory in memory");
}
memset(root_dir, 0, size_root_dir);
if ( memcmp(volume_name, " ", 11) )
{
struct msdos_dir_entry *de = &root_dir[0];
memcpy(de->name, volume_name, 11);
de->attr = ATTR_VOLUME;
ctime = localtime(&create_time);
de->time = CT_LE_W((unsigned short)((ctime->tm_sec >> 1) +
(ctime->tm_min << 5) + (ctime->tm_hour << 11)));
de->date = CT_LE_W((unsigned short)(ctime->tm_mday +
((ctime->tm_mon+1) << 5) +
((ctime->tm_year-80) << 9)));
de->ctime_ms = 0;
de->ctime = de->time;
de->cdate = de->date;
de->adate = de->date;
de->starthi = CT_LE_W(0);
de->start = CT_LE_W(0);
de->size = CT_LE_L(0);
}
if (size_fat == 32) {
/* For FAT32, create an info sector */
struct fat32_fsinfo *info;
if (!(info_sector = malloc( sector_size )))
die("Out of memory");
memset(info_sector, 0, sector_size);
/* fsinfo structure is at offset 0x1e0 in info sector by observation */
info = (struct fat32_fsinfo *)(info_sector + 0x1e0);
/* Info sector magic */
info_sector[0] = 'R';
info_sector[1] = 'R';
info_sector[2] = 'a';
info_sector[3] = 'A';
/* Magic for fsinfo structure */
info->signature = CT_LE_L(0x61417272);
/* We've allocated cluster 2 for the root dir. */
info->free_clusters = CT_LE_L(cluster_count - 1);
info->next_cluster = CT_LE_L(2);
/* Info sector also must have boot sign */
*(__u16 *)(info_sector + 0x1fe) = CT_LE_W(BOOT_SIGN);
}
if (!(blank_sector = malloc( sector_size )))
die( "Out of memory" );
memset(blank_sector, 0, sector_size);
}
/* Write the new filesystem's data tables to wherever they're going to end up! */
#define error(str) \
do { \
free (fat); \
if (info_sector) free (info_sector); \
free (root_dir); \
die (str); \
} while(0)
#define seekto(pos,errstr) \
do { \
loff_t __pos = (pos); \
if (llseek (dev, __pos, SEEK_SET) != __pos) \
error ("seek to " errstr " failed whilst writing tables"); \
} while(0)
#define writebuf(buf,size,errstr) \
do { \
int __size = (size); \
if (write (dev, buf, __size) != __size) \
error ("failed whilst writing " errstr); \
} while(0)
static void
write_tables (void)
{
int x;
int fat_length;
#ifdef _WIN32
int blk;
#endif
fat_length = (size_fat == 32) ?
CF_LE_L(bs.fat32.fat32_length) : CF_LE_W(bs.fat_length);
seekto( 0, "start of device" );
/* clear all reserved sectors */
for( x = 0; x < reserved_sectors; ++x )
writebuf( blank_sector, sector_size, "reserved sector" );
/* seek back to sector 0 and write the boot sector */
seekto( 0, "boot sector" );
writebuf( (char *) &bs, sizeof (struct msdos_boot_sector), "boot sector" );
/* on FAT32, write the info sector and backup boot sector */
if (size_fat == 32)
{
seekto( CF_LE_W(bs.fat32.info_sector)*sector_size, "info sector" );
writebuf( info_sector, 512, "info sector" );
if (backup_boot != 0)
{
seekto( backup_boot*sector_size, "backup boot sector" );
writebuf( (char *) &bs, sizeof (struct msdos_boot_sector),
"backup boot sector" );
}
}
/* seek to start of FATS and write them all */
seekto( reserved_sectors*sector_size, "first FAT" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -