aboutsummaryrefslogtreecommitdiff
path: root/mformat.c
diff options
context:
space:
mode:
Diffstat (limited to 'mformat.c')
-rw-r--r--mformat.c1503
1 files changed, 702 insertions, 801 deletions
diff --git a/mformat.c b/mformat.c
index cd2e5f3..75cc926 100644
--- a/mformat.c
+++ b/mformat.c
@@ -24,40 +24,32 @@
#include "msdos.h"
#include "mtools.h"
#include "mainloop.h"
+#include "device.h"
+#include "old_dos.h"
#include "fsP.h"
#include "file.h"
#include "plain_io.h"
-#include "floppyd_io.h"
#include "nameclash.h"
#include "buffer.h"
#ifdef HAVE_ASSERT_H
#include <assert.h>
#endif
-#ifdef USE_XDF
-#include "xdf_io.h"
-#endif
+#include "stream.h"
#include "partition.h"
+#include "open_image.h"
#include "file_name.h"
-
-#ifndef abs
-#define abs(x) ((x)>0?(x):-(x))
-#endif
+#include "lba.h"
#ifdef OS_linux
#include "linux/hdreg.h"
-
-#define _LINUX_STRING_H_
-#define kdev_t int
#include "linux/fs.h"
-#undef _LINUX_STRING_H_
#endif
-
-static int init_geometry_boot(union bootsector *boot, struct device *dev,
- uint8_t sectors0,
- uint8_t rate_0, uint8_t rate_any,
- unsigned long *tot_sectors, int keepBoot)
+static uint16_t init_geometry_boot(union bootsector *boot, struct device *dev,
+ uint8_t sectors0,
+ uint8_t rate_0, uint8_t rate_any,
+ uint32_t *tot_sectors, int keepBoot)
{
int nb_renum;
int sector2;
@@ -70,19 +62,18 @@ static int init_geometry_boot(union bootsector *boot, struct device *dev,
assert(*tot_sectors != 0);
#endif
- if (*tot_sectors <= UINT16_MAX){
+ if (*tot_sectors <= UINT16_MAX && dev->hidden <= UINT16_MAX){
set_word(boot->boot.psect, (uint16_t) *tot_sectors);
set_dword(boot->boot.bigsect, 0);
- } else if(*tot_sectors <= UINT32_MAX){
+ set_word(boot->boot.nhs, (uint16_t) dev->hidden);
+ } else {
set_word(boot->boot.psect, 0);
set_dword(boot->boot.bigsect, (uint32_t) *tot_sectors);
- } else {
- fprintf(stderr, "Too many sectors %ld\n", *tot_sectors);
- exit(1);
+ set_dword(boot->boot.nhs, dev->hidden);
}
if (dev->use_2m & 0x7f){
- int bootOffset;
+ uint16_t bootOffset;
uint8_t j;
uint8_t size2;
uint16_t i;
@@ -122,7 +113,7 @@ static int init_geometry_boot(union bootsector *boot, struct device *dev,
boot->bytes[i++] = size2;
sector2 -= (1 << size2) >> 2;
}
- boot->bytes[nb_renum] = ( i - nb_renum - 1 ) / 3;
+ boot->bytes[nb_renum] = (uint8_t)(( i - nb_renum - 1 )/3);
set_word(boot->boot.ext.old.InfTm, i);
@@ -141,7 +132,7 @@ static int init_geometry_boot(union bootsector *boot, struct device *dev,
/* checksum */
for (sum=0, j=64; j<i; j++)
sum += boot->bytes[j];/* checksum */
- boot->boot.ext.old.CheckSum=-sum;
+ boot->boot.ext.old.CheckSum=(unsigned char)-sum;
return bootOffset;
} else {
if(!keepBoot) {
@@ -158,133 +149,31 @@ static int init_geometry_boot(union bootsector *boot, struct device *dev,
}
}
+static unsigned char bootprog[]=
+{0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
+ 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
+ 0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
+ 0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
+ 0x00, 0xcd, 0x19};
-static int comp_fat_bits(Fs_t *Fs, int estimate,
- unsigned long tot_sectors, int fat32)
-{
- int needed_fat_bits;
-
- needed_fat_bits = 12;
-
-#define MAX_DISK_SIZE(bits,clusters) \
- TOTAL_DISK_SIZE((bits), Fs->sector_size, (clusters), \
- Fs->num_fat, MAX_BYTES_PER_CLUSTER/Fs->sector_size)
-
- if(tot_sectors > MAX_DISK_SIZE(12, FAT12-1))
- needed_fat_bits = 16;
- if(fat32 || tot_sectors > MAX_DISK_SIZE(16, FAT16-1))
- needed_fat_bits = 32;
-
-#undef MAX_DISK_SIZE
-
- if(abs(estimate) && abs(estimate) < needed_fat_bits) {
- if(fat32) {
- fprintf(stderr,
- "Contradiction between FAT size on command line and FAT size in conf file\n");
- exit(1);
- }
- fprintf(stderr,
- "Device too big for a %d bit FAT\n",
- estimate);
- exit(1);
- }
-
- if(!estimate) {
- unsigned int min_fat16_size;
-
- if(needed_fat_bits > 12)
- return needed_fat_bits;
- min_fat16_size = DISK_SIZE(16, Fs->sector_size, FAT12,
- Fs->num_fat, 1);
- if(tot_sectors < min_fat16_size)
- return 12;
- else if(Fs->cluster_size == 0 &&
- tot_sectors >= 2* min_fat16_size)
- return 16; /* heuristics */
- }
-
- return estimate;
-}
-
-
-/*
- * According to Microsoft "Hardware White Paper", "Microsoft
- * Extensible Formware Initiative", "FAT32 File System Specification",
- * Version 1.03, December 6, 2000:
- * If (CountofClusters < 4085) { // 0x0ff5
- * // Volume is FAT12
- * } else if (CountofClusters < 65525) { // 0xfff5
- * // Volume is FAT16
- * } else {
- * //Volume is FAT32
- * }
- *
- * This document can be found at the following URL:
- * https://staff.washington.edu/dittrich/misc/fatgen103.pdf
- * The relevant passus is on page 15.
- *
- * Actually, experimentations with Windows NT 4 show that the
- * cutoff is 4087 rather than 4085... This is Microsoft after all.
- * Not sure what the other Microsoft OS'es do though...
- */
-static void calc_fat_bits2(Fs_t *Fs, unsigned long tot_sectors, int fat_bits,
- int may_change_cluster_size,
- int may_change_root_size)
+static __inline__ void inst_boot_prg(union bootsector *boot, uint16_t offset)
{
- unsigned long rem_sect;
-
- /*
- * the "remaining sectors" after directory and boot
- * hasve been accounted for.
- */
- rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
- switch(abs(fat_bits)) {
- case 0:
-
-#define MY_DISK_SIZE(bits,clusters) \
- DISK_SIZE( (bits), Fs->sector_size, (clusters), \
- Fs->num_fat, Fs->cluster_size)
-
- if(rem_sect >= MY_DISK_SIZE(16, FAT12+2))
- /* big enough for FAT16
- * We take a margin of 2, because NT4
- * misbehaves, and starts considering a disk
- * as FAT16 only if it is larger than 4086
- * sectors, rather than 4084 as it should
- */
- set_fat16(Fs);
- else if(rem_sect <= MY_DISK_SIZE(12, FAT12-1))
- /* small enough for FAT12 */
- set_fat12(Fs);
- else {
- /* "between two chairs",
- * augment cluster size, and
- * settle it */
- if(may_change_cluster_size &&
- Fs->cluster_size * Fs->sector_size * 2
- <= MAX_BYTES_PER_CLUSTER)
- Fs->cluster_size <<= 1;
- else if(may_change_root_size) {
- Fs->dir_len +=
- rem_sect - MY_DISK_SIZE(12, FAT12-1);
- }
- set_fat12(Fs);
- }
- break;
-#undef MY_DISK_SIZE
-
- case 12:
- set_fat12(Fs);
- break;
- case 16:
- set_fat16(Fs);
- break;
- case 32:
- set_fat32(Fs);
- break;
+ memcpy(boot->bytes + offset, bootprog, sizeof(bootprog));
+ if(offset - 2 < 0x80) {
+ /* short jump */
+ boot->boot.jump[0] = 0xeb;
+ boot->boot.jump[1] = (uint8_t) (offset -2);
+ boot->boot.jump[2] = 0x90;
+ } else {
+ /* long jump, if offset is too large */
+ boot->boot.jump[0] = 0xe9;
+ boot->boot.jump[1] = (uint8_t) (offset - 3);
+ boot->boot.jump[2] = (uint8_t) ( (offset - 3) >> 8);
}
+ set_word(boot->boot.jump + offset + 20, offset + 24);
}
+/* Set up the root directory */
static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot)
{
Stream_t *RootDir;
@@ -314,8 +203,8 @@ static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot
} else
dirlen = Fs->dir_len;
for (i = 0; i < dirlen; i++)
- WRITES(RootDir, buf, sectorsToBytes((Stream_t*)Fs, i),
- Fs->sector_size);
+ PWRITES(RootDir, buf, sectorsToBytes(Fs, i),
+ Fs->sector_size);
ch.ignore_entry = 1;
if(label[0])
@@ -325,375 +214,610 @@ static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot
if(Fs->fat_bits == 32)
set_word(boot->boot.dirents, 0);
else
- set_word(boot->boot.dirents, Fs->dir_len * (Fs->sector_size / 32));
+ set_word(boot->boot.dirents,
+ (uint16_t) (Fs->dir_len * (Fs->sector_size / 32)));
free(buf);
}
-
-#ifdef USE_XDF
-static void xdf_calc_fat_size(Fs_t *Fs, unsigned long tot_sectors,
- int fat_bits)
-{
- unsigned int rem_sect;
-
- rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start - 2 * Fs->fat_len;
-
- if(Fs->fat_len) {
- /* an XDF disk, we know the fat_size and have to find
- * out the rest. We start with a cluster size of 1 and
- * keep doubling until everything fits into the
- * FAT. This will occur eventually, as our FAT has a
- * minimal size of 1 */
- for(Fs->cluster_size = 1; 1 ; Fs->cluster_size <<= 1) {
- Fs->num_clus = rem_sect / Fs->cluster_size;
- if(abs(fat_bits) == 16 || Fs->num_clus >= FAT12)
- set_fat16(Fs);
- else
- set_fat12(Fs);
- if (Fs->fat_len >= NEEDED_FAT_SIZE(Fs))
- return;
- }
- }
- fprintf(stderr,"Internal error while calculating Xdf fat size\n");
- exit(1);
-}
-#endif
-
-static void calc_fat_size(Fs_t *Fs, unsigned long tot_sectors)
+/*
+ * Calculate length of one FAT, in sectors, given the number of total sectors
+ * Returns
+ * -2: if there are less total sectors than even clus_start
+ * 0: if a length was successfully calculated. (in that case, it is filled
+ * into Fs->fat_len)
+ * 1: if the specified number of FAT bits cannot accomodate that many
+ * sectors => caller should raise FAT bits
+ */
+static int calc_fat_len(Fs_t *Fs, uint32_t tot_sectors)
{
- unsigned long rem_sect;
- unsigned long real_rem_sect;
- unsigned long numerator;
- unsigned long denominator;
+ uint32_t rem_sect;
+ uint32_t numerator;
+ uint32_t denominator;
+ uint32_t corr=0; /* correct numeric overflow */
+ uint32_t clus_start;
unsigned int fat_nybbles;
- unsigned int slack;
- int printGrowMsg=1; /* Should we print "growing FAT" messages ?*/
+
+#ifdef HAVE_ASSERT_H
+ assert(Fs->fat_bits != 0);
+#endif
#ifdef DEBUG
fprintf(stderr, "Fat start=%d\n", Fs->fat_start);
fprintf(stderr, "tot_sectors=%lu\n", tot_sectors);
fprintf(stderr, "dir_len=%d\n", Fs->dir_len);
#endif
- real_rem_sect = rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+ Fs->fat_len = 0;
+ clus_start = calc_clus_start(Fs);
+ if(tot_sectors < clus_start)
+ return -2;
+ rem_sect = tot_sectors - clus_start;
/* Cheat a little bit to address the _really_ common case of
odd number of remaining sectors while both nfat and cluster size
are even... */
- if(rem_sect %2 == 1 &&
- Fs->num_fat %2 == 0 &&
- Fs->cluster_size %2 == 0)
+ if(rem_sect % 2 == 1 &&
+ Fs->num_fat % 2 == 0 &&
+ Fs->cluster_size % 2 == 0)
rem_sect--;
#ifdef DEBUG
fprintf(stderr, "Rem sect=%lu\n", rem_sect);
#endif
- if(Fs->fat_bits == 0) {
- fprintf(stderr, "Weird, fat bits = 0\n");
- exit(1);
- }
-
-
/* See fat_size_calculation.tex or
- (http://ftp.gnu.org/software/mtools/manual/fat_size_calculation.pdf)
+ (https://www.gnu.org/gnu/mtools/manual/fat_size_calculation.pdf)
for an explantation about why the stuff below works...
*/
fat_nybbles = Fs->fat_bits / 4;
numerator = rem_sect+2*Fs->cluster_size;
+ /* Might overflow, but will be cancelled out below. As the
+ operation is unsigned, a posteriori fixup is allowable, as
+ wrap-around is part of the spec. For *signed* quantities,
+ this hack would be incorrect, as it would be "undefined
+ behavior" */
+
+ /* Initial denominator is nybbles consumed by one cluster, both in
+ * FAT and in cluster space */
denominator =
Fs->cluster_size * Fs->sector_size * 2 +
Fs->num_fat * fat_nybbles;
- if(fat_nybbles == 3)
+ if(fat_nybbles == 3) {
+ /* We need to do this test here, or multiplying rem_sect with
+ * fat_nybbles might overflow */
+ if(rem_sect > 256 * FAT12)
+ return 1;
numerator *= fat_nybbles;
- else
+ } else
/* Avoid numerical overflows, divide the denominator
* rather than multiplying the numerator */
denominator = denominator / fat_nybbles;
+ /* Substract denominator from numerator to "cancel out" an
+ unsigned integer overflow which might have happened with
+ total number of sectors very near maximum (2^32-1) and huge
+ cluster size. This substraction removes 1 from the result
+ of the following division, so we will add 1 again after the
+ division. However, we only do this if (original) numerator
+ is bigger than denominator though, as otherwise we risk the
+ inverse problem of going below 0 on small disks */
+ if(rem_sect > denominator) {
+ numerator -= denominator;
+ corr++;
+ }
+
#ifdef DEBUG
fprintf(stderr, "Numerator=%lu denominator=%lu\n",
numerator, denominator);
#endif
- Fs->fat_len = (numerator-1)/denominator+1;
- Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/Fs->cluster_size;
+ Fs->fat_len = (numerator-1)/denominator+1+corr;
+ return 0;
+}
- /* Apply upper bounds for FAT bits */
- if(Fs->fat_bits == 16 && Fs->num_clus >= FAT16)
- Fs->num_clus = FAT16-1;
- if(Fs->fat_bits == 12 && Fs->num_clus >= FAT12)
- Fs->num_clus = FAT12-1;
+/* Is there enough space in the FAT for the descriptors for all clusters.
+ * This only works if we assume that it is already clear that Fs->num_clus is
+ * less than FAT32, or else it might overflow */
+static inline bool clusters_fit_into_fat(Fs_t *Fs) {
+ return ((Fs->num_clus+2) * (Fs->fat_bits/4) - 1) / (Fs->sector_size*2) <
+ Fs->fat_len;
+}
+
+/*
+ * Assert that FAT param calculation has been performed correctly, and
+ * set_fat
+ */
+static void check_fs_params_and_set_fat(Fs_t *Fs, uint32_t tot_sectors)
+{
+ unsigned int provisional_fat_bits;
- /* A safety, if above math is correct, this should not be happen...*/
- if(Fs->num_clus > (Fs->fat_len * Fs->sector_size * 2 /
- fat_nybbles - 2)) {
- fprintf(stderr,
- "Fat size miscalculation, shrinking num_clus from %d ",
- Fs->num_clus);
- Fs->num_clus = (Fs->fat_len * Fs->sector_size * 2 /
- fat_nybbles - 2);
- fprintf(stderr, " to %d\n", Fs->num_clus);
- }
#ifdef DEBUG
fprintf(stderr, "Num_clus=%d fat_len=%d nybbles=%d\n",
Fs->num_clus, Fs->fat_len, fat_nybbles);
#endif
- if ( Fs->num_clus < FAT16 && Fs->fat_bits > 16 ){
- fprintf(stderr,"Too few clusters for this fat size."
- " Please choose a 16-bit fat in your /etc/mtools.conf"
- " or .mtoolsrc file\n");
- exit(1);
- }
-
- /* As the number of clusters is specified nowhere in the boot sector,
- * it will be calculated by removing everything else from total number
- * of sectors. This means that if we reduced the number of clusters
- * above, we will have to grow the FAT in order to take up any excess
- * sectors... */
#ifdef HAVE_ASSERT_H
- assert(rem_sect >= Fs->num_clus * Fs->cluster_size +
- Fs->fat_len * Fs->num_fat);
-#endif
- slack = rem_sect -
- Fs->num_clus * Fs->cluster_size -
- Fs->fat_len * Fs->num_fat;
- if(slack >= Fs->cluster_size) {
- /* This can happen under two circumstances:
- 1. We had to reduce num_clus because we reached maximum
- number of cluster for FAT12 or FAT16
- */
- if(printGrowMsg) {
- fprintf(stderr, "Slack=%d\n", slack);
- fprintf(stderr, "Growing fat size from %d",
- Fs->fat_len);
- }
- Fs->fat_len +=
- (slack - Fs->cluster_size) / Fs->num_fat + 1;
- if(printGrowMsg) {
- fprintf(stderr,
- " to %d in order to take up excess cluster area\n",
- Fs->fat_len);
- }
- Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/
- Fs->cluster_size;
-
- }
+ /* if FAT bits is 32, dir_len must be zero, otherwise it must be
+ * non-zero */
+ assert(Fs->fat_bits == 32 ? (Fs->dir_len == 0) : (Fs->dir_len != 0));
+
+ /* Clusters must fill disk up entirely, except for small amount of
+ * slack smaller than one sector */
+ assert(tot_sectors >=
+ Fs->clus_start + Fs->num_clus * Fs->cluster_size);
+ assert(tot_sectors <=
+ Fs->clus_start + Fs->num_clus * Fs->cluster_size +
+ Fs->cluster_size - 1);
-#ifdef HAVE_ASSERT_H
/* Fat must be big enough for all clusters */
- assert( ((Fs->num_clus+2) * fat_nybbles) <=
- (Fs->fat_len*Fs->sector_size*2));
-
- /* num_clus must be big enough to cover rest of disk, or else further
- * users of the filesystem will assume a bigger num_clus, which might
- * be too big for fat_len */
- assert(Fs->num_clus ==
- (real_rem_sect - Fs->num_fat * Fs->fat_len) / Fs->cluster_size);
+ assert(clusters_fit_into_fat(Fs));
+#endif
+ provisional_fat_bits = Fs->fat_bits;
+ set_fat(Fs);
+#ifdef HAVE_ASSERT_H
+ assert(provisional_fat_bits == Fs->fat_bits);
#endif
}
+static void fat32_specific_init(Fs_t *Fs) {
+ Fs->primaryFat = 0;
+ Fs->writeAllFats = 1;
+ if(!Fs->backupBoot) {
+ if(Fs->fat_start <= 6)
+ Fs->backupBoot = Fs->fat_start - 1;
+ else
+ Fs->backupBoot=6;
+ }
-static unsigned char bootprog[]=
-{0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
- 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
- 0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
- 0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
- 0x00, 0xcd, 0x19};
+ if(Fs->fat_start < 3) {
+ fprintf(stderr,
+ "For FAT 32, reserved sectors need to be at least 3\n");
+ exit(1);
+ }
-static __inline__ void inst_boot_prg(union bootsector *boot, int offset)
-{
- memcpy((char *) boot->boot.jump + offset,
- (char *) bootprog, sizeof(bootprog) /sizeof(bootprog[0]));
- if(offset - 2 < 0x80) {
- /* short jump */
- boot->boot.jump[0] = 0xeb;
- boot->boot.jump[1] = offset -2;
- boot->boot.jump[2] = 0x90;
- } else {
- /* long jump, if offset is too large */
- boot->boot.jump[0] = 0xe9;
- boot->boot.jump[1] = offset -3;
- boot->boot.jump[2] = 0x00;
+ if(Fs->fat_start <= Fs->backupBoot) {
+ fprintf(stderr,
+ "Reserved sectors (%d) must be more than backupBoot (%d)\n", Fs->fat_start, Fs->backupBoot);
+ Fs->backupBoot = 0;
}
- set_word(boot->boot.jump + offset + 20, offset + 24);
}
-static void calc_cluster_size(struct Fs_t *Fs, unsigned long tot_sectors,
- int fat_bits)
-
+/* Try given cluster- and fat_size (and other parameters), and say whether
+ * cluster_size/fat_bits should be increased, decreased, or is fine as is.
+ * Parameters
+ * Fs the file system object
+ * tot_sectors size of file system, in sectors
+ * may_change_boot_size try_cluster_size may increase number of boot
+ * (reserved) sectors to make everything fit
+ * may_change_fat_len try_cluster_size may change (compute) FAT length
+ * may_change_root_size try_cluster_size may increase root directory size
+ * to make everything fit
+ * may_pad if there are (slightly) too many clusters,
+ * try_cluster_size may artificially inflate number of
+ * boot sectors, fat length or root_size to take up
+ * space in order to reduce number clusters below limit
+ *
+ * Return values
+ * -2 Too few sectors to contain even the header (reserved sectors, minimal
+ * FAT and root directory), or other internal error
+ * -1 This cluster size leads to too few clusters for the FAT size.
+ * Caller should either reduce cluster size or FAT size, and try again
+ * 0 Everything fits
+ * 1 This cluster size leads to too many clusters for the FAT
+ * size. Caller should either increase cluster size or FAT size, and
+ * try again
+ * 2 Fat length is set, and there are too many clusters to fit into
+ * that Fat length. Caller should either increase cluster size, or
+ * decrease FAT size, and try again
+ *
+ */
+static int try_cluster_size(Fs_t *Fs,
+ uint32_t tot_sectors,
+ bool may_change_boot_size,
+ bool may_change_fat_len,
+ bool may_change_root_size,
+ bool may_pad)
{
- unsigned int max_clusters; /* maximal possible number of sectors for
- * this FAT entry length (12/16/32) */
- unsigned int max_fat_size; /* maximal size of the FAT for this FAT
- * entry length (12/16/32) */
- unsigned int rem_sect; /* remaining sectors after we accounted for
- * the root directory and boot sector(s) */
-
- switch(abs(fat_bits)) {
- case 12:
- max_clusters = FAT12-1;
- max_fat_size = Fs->num_fat *
- FAT_SIZE(12, Fs->sector_size, max_clusters);
- break;
- case 16:
- case 0: /* still hesititating between 12 and 16 */
- max_clusters = FAT16-1;
- max_fat_size = Fs->num_fat *
- FAT_SIZE(16, Fs->sector_size, max_clusters);
- break;
- case 32:
- /*
- FAT32 cluster sizes for disks with 512 block size
- according to Microsoft specification fatgen103.doc:
-
- 32.5 MB - 260 MB cluster_size = 1
- 260 MB - 8 GB cluster_size = 8
- 8 GB - 16 GB cluster_size = 16
- 16 GB - 32 GB cluster_size = 32
- 32 GB - 2 TB cluster_size = 64
-
- Below calculation is generalized and does not depend
- on 512 block size.
- */
- Fs->cluster_size = tot_sectors > 32*1024*1024*2 ? 64 :
- tot_sectors > 16*1024*1024*2 ? 32 :
- tot_sectors > 8*1024*1024*2 ? 16 :
- tot_sectors > 260*1024*2 ? 8 : 1;
- return;
- default:
- fprintf(stderr,"Bad fat size\n");
- exit(1);
+ uint32_t maxClus;
+ uint32_t minClus;
+
+ switch(Fs->fat_bits) {
+ case 12:
+ minClus = 1;
+ maxClus = FAT12;
+ break;
+ case 16:
+ minClus = 4096;
+ maxClus = FAT16;
+ break;
+ case 32:
+ minClus = FAT16;
+ maxClus = FAT32;
+ break;
+ default:
+#ifdef HAVE_ASSERT_H
+ assert(false && "Bad number of FAT bits");
+#endif
+ return -2;
}
- if(tot_sectors <= Fs->fat_start + Fs->num_fat + Fs->dir_len) {
- /* we need at least enough sectors to fit boot, fat and root
- * dir */
- fprintf(stderr, "Not enough sectors\n");
- exit(1);
+ if(getenv("MTOOLS_DEBUG_FAT")) {
+ fprintf(stderr, "FAT=%d Cluster=%d%s\n",
+ Fs->fat_bits, Fs->cluster_size,
+ may_pad ? " may_pad" : "");
}
- rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+ if(may_change_fat_len) {
+ int fit=calc_fat_len(Fs, tot_sectors);
+ if(fit != 0)
+ return fit;
+ }
- /* double the cluster size until we can fill up the disk with
- * the maximal number of sectors of this size */
- while(Fs->cluster_size * max_clusters + max_fat_size < rem_sect) {
- if(Fs->cluster_size > 64) {
- /* bigger than 64. Should fit */
- fprintf(stderr,
- "Internal error while calculating cluster size\n");
- exit(1);
+ while(true) {
+ uint32_t bwaste; /* How many sectors we need to "waste" */
+ uint16_t waste;
+ uint16_t dir_grow=0;
+
+ if(calc_num_clus(Fs, tot_sectors) < 0)
+ return -2;
+ if(Fs->num_clus < minClus)
+ return -1; /* Not enough clusters => loop
+ * should shrink FAT bits again */
+
+ if(!may_change_fat_len) {
+ /* If fat_len has been explicitly specified by
+ * user, make sure that number of clusters
+ * fit within that fat_len */
+ if(Fs->num_clus >= FAT32 || !clusters_fit_into_fat(Fs))
+ return 2; /* Caller should should pick a
+ * bigger cluster size, but not a
+ * higher FAT bits */
}
- Fs->cluster_size <<= 1;
- }
-}
+ if(Fs->num_clus < maxClus)
+ break;
+ if(!may_pad)
+ return 1;
+
+ /* "Pad" fat by artifically adding sectors to boot sectors,
+ FAT or root directory to diminish number of clusters */
+
+ /* This is needed when a size of a FAT fs somehow is
+ * "in between" 2 fat bits: too large for FAT12, too small
+ * for FAT16.
+
+ * This happens because if there slightly too may
+ * clusters for FAT12, the system passes to
+ * FAT16. However, this makes the space taken up by
+ * the descriptor of each sector in the FAT larger,
+ * making the FAT larger overall, leaving less space
+ * for the clusters themselves, i.e. less
+ * clusters. Sometimes this is enough to push the
+ * number of clusters *below* the minimum for FAT12.
+
+ * a similar situation happens when switching from
+ * FAT16 to FAT32.
+
+ * if this happens, we switch back to the lower FAT
+ * bits, and allow "padding", i.e. artificially
+ * "wasting" space by adding more reserved (boot)
+ * sectors, adding "useless" extra sectors to the FAT,
+ * or allowing more root directory entries.
+
+ */
+ bwaste = tot_sectors - Fs->clus_start -
+ maxClus * Fs->cluster_size + 1;
+#ifdef HAVE_ASSERT_H
+ assert(bwaste <= UINT16_MAX);
+#endif
+ waste = (uint16_t) bwaste;
-static int old_dos_size_to_geom(size_t size,
- unsigned int *cyls,
- unsigned short *heads,
- unsigned short *sects)
-{
- struct OldDos_t *params = getOldDosBySize(size);
- if(params != NULL) {
- *cyls = params->tracks;
- *heads = params->heads;
- *sects = params->sectors;
- return 0;
- } else
- return 1;
-}
+ if(may_change_root_size) {
+ dir_grow = 32 - Fs->dir_len;
+ if(dir_grow > waste)
+ dir_grow = waste;
+ waste -= dir_grow;
+ }
+ if(may_change_fat_len &&
+ (!may_change_boot_size || Fs->fat_bits == 12)) {
+ uint16_t fat_grow =
+ (waste + Fs->num_fat - 1) / Fs->num_fat;
+ uint16_t dir_shrink = 0;
+ Fs->fat_len += fat_grow;
+
+ /* Shrink directory again, but at most as by as much
+ * as we grew it earlyer */
+ dir_shrink = waste - fat_grow * Fs->num_fat;
+ if(dir_shrink > dir_grow)
+ dir_shrink = dir_grow;
+ dir_grow -= dir_shrink;
+ } else if(may_change_boot_size) {
+ Fs->fat_start += waste;
+ }
+ Fs->dir_len += dir_grow;
+ /* If padding once failed, no point in keeping on retrying */
+ may_pad=false;
+ }
+#ifdef HAVE_ASSERT_H
+ /* number of clusters must be within allowable range for fat
+ bits */
+ assert(Fs->num_clus >= minClus);
+ assert(Fs->num_clus < maxClus);
+#endif
+ return 0;
+}
-static void calc_fs_parameters(struct device *dev, unsigned long tot_sectors,
- struct Fs_t *Fs, union bootsector *boot)
+/* Finds a set of filesystem parameters, given the device size, and
+ * any presets specified by user
+ * On return, Fs will be initialized, or one of the following error codes
+ * will be returned:
+ * -1 Not enough sectors for any kind of FAT filesystem
+ * -2 Not enough clusters for given number of FAT bits
+ * -3 Too many clusters for given number of FAT bits
+ * -4 Too many clusters for chosen FAT length
+ */
+int calc_fs_parameters(struct device *dev, bool fat32,
+ uint32_t tot_sectors,
+ struct Fs_t *Fs, uint8_t *descr)
{
+ bool may_change_boot_size = (Fs->fat_start == 0);
+ bool may_change_fat_bits = (dev->fat_bits == 0) && !fat32;
+ bool may_change_cluster_size = (Fs->cluster_size == 0);
+ bool may_change_root_size = (Fs->dir_len == 0);
+ bool may_change_fat_len = (Fs->fat_len == 0);
+ bool may_pad = false;
+ uint16_t saved_dir_len;
+
struct OldDos_t *params=NULL;
- if(dev->fat_bits == 0 || abs(dev->fat_bits) == 12)
+ Fs->infoSectorLoc = 0;
+ if( (may_change_fat_bits || abs(dev->fat_bits) == 12) &&
+ (may_change_boot_size || Fs->fat_start == 1) )
params = getOldDosByParams(dev->tracks,dev->heads,dev->sectors,
Fs->dir_len, Fs->cluster_size);
if(params != NULL) {
- boot->boot.descr = params->media;
+ int num_clus_valid;
+ *descr = params->media;
+ Fs->fat_start = 1;
Fs->cluster_size = params->cluster_size;
Fs->dir_len = params->dir_len;
Fs->fat_len = params->fat_len;
Fs->fat_bits = 12;
- } else {
- int may_change_cluster_size = (Fs->cluster_size == 0);
- int may_change_root_size = (Fs->dir_len == 0);
+ num_clus_valid = calc_num_clus(Fs, tot_sectors);
+#ifdef HAVE_ASSERT_H
+ assert(num_clus_valid >= 0);
+#endif
+ check_fs_params_and_set_fat(Fs, tot_sectors);
+ return 0;
+ }
- /* a non-standard format */
- if(DWORD(nhs) || tot_sectors % (dev->sectors * dev->heads))
- boot->boot.descr = 0xf8;
+ /* a format described by BPB */
+ if(dev->hidden || tot_sectors % (dev->sectors * dev->heads))
+ *descr = 0xf8;
+ else
+ *descr = 0xf0;
+
+ Fs->fat_bits = abs(dev->fat_bits);
+ if(Fs->fat_bits == 0)
+ /* If fat_bits not specified by device, start with a 12-bit
+ * FAT, unless 32 bit specified on command line */
+ Fs->fat_bits = fat32 ? 32 : 12;
+ if(!Fs->cluster_size) {
+ if(tot_sectors < 2400 && dev->heads == 2)
+ /* double sided double density floppies */
+ Fs->cluster_size = 2;
+ else if(may_change_fat_len && Fs->fat_bits == 32)
+ /* FAT32 => start with 8 */
+ Fs->cluster_size = 8;
else
- boot->boot.descr = 0xf0;
-
+ /* In all other cases, start with 1 */
+ Fs->cluster_size = 1;
+ }
- if(!Fs->cluster_size) {
+ if(!Fs->dir_len) {
+ if(tot_sectors < 1200) {
+ /* Double density floppies */
if (dev->heads == 1)
- Fs->cluster_size = 1;
- else {
- Fs->cluster_size = (tot_sectors > 2000 ) ? 1:2;
- if (dev->use_2m & 0x7f)
+ Fs->dir_len = 4;
+ else
+ Fs->dir_len = 7;
+ } else if(tot_sectors <= 3840)
+ /* High density floppies */
+ Fs->dir_len = 14;
+ else if(tot_sectors <= 7680)
+ /* extra density floppies */
+ Fs->dir_len = 15;
+ else
+ Fs->dir_len = 32;
+ }
+ saved_dir_len = Fs->dir_len;
+
+ while(true) {
+ int fit;
+ if(may_change_boot_size) {
+ if(Fs->fat_bits == 32)
+ Fs->fat_start = 32;
+ else
+ Fs->fat_start = 1;
+ }
+
+ if(Fs->fat_bits == 32)
+ Fs->dir_len = 0;
+ else if(Fs->dir_len == 0)
+ Fs->dir_len = saved_dir_len;
+
+ if(Fs->fat_bits == 32 &&
+ may_change_cluster_size && may_change_fat_len) {
+ /*
+ FAT32 cluster sizes for disks with 512 block size
+ according to Microsoft specification fatgen103.doc:
+
+ ...
+ - 8 GB cluster_size = 8
+ 8 GB - 16 GB cluster_size = 16
+ 16 GB - 32 GB cluster_size = 32
+ 32 GB - 2 TB cluster_size = 64
+
+ Below calculation is generalized and does not depend
+ on 512 block size.
+ */
+ Fs->cluster_size = tot_sectors >= 32*1024*1024*2 ? 64 :
+ tot_sectors >= 16*1024*1024*2 ? 32 :
+ tot_sectors >= 8*1024*1024*2 ? 16 :
+ Fs->cluster_size;
+ }
+
+ fit=try_cluster_size(Fs,
+ tot_sectors,
+ may_change_boot_size,
+ may_change_fat_len,
+ may_change_root_size,
+ may_pad);
+
+ if(getenv("MTOOLS_DEBUG_FAT")) {
+ fprintf(stderr, " fit=%d\n", fit);
+ }
+ if(fit == 0)
+ break;
+ if(fit == -2)
+ return -1;
+
+#ifdef HAVE_ASSERT_H
+ assert(fit != 2 || !may_change_fat_len);
+#endif
+ if(fit < 0) {
+ if(may_change_cluster_size &&
+ may_change_fat_len &&
+ Fs->cluster_size > 1) {
+ Fs->cluster_size = Fs->cluster_size / 2;
+ continue;
+ }
+
+ /* Somehow we ended up with too few sectors
+ * for FAT size. This can only happen if
+ * cluster size is not adjustable, and if we
+ * had *barely* more clusters than allowed by
+ * previous fat bits. After raising fat bits,
+ * fat_len grew larger (due to each individual
+ * FAT entry now being larger), pushing the
+ * number of clusters *below* new limit. =>
+ * we lower fat bits again */
+ if(!may_change_fat_bits || Fs->fat_bits == 12)
+ return -2;
+
+ switch(Fs->fat_bits) {
+ case 16:
+ Fs->fat_bits=12;
+ break;
+ case 32:
+ Fs->fat_bits=16;
+ break;
+ }
+ may_pad=true;
+ continue;
+ }
+
+ if(fit == 1 && may_change_fat_bits && !may_pad) {
+ /* If cluster_size reached
+ * "maximum" for fat_bits,
+ * switch over to next
+ */
+ if(Fs->fat_bits == 12 &&
+ (!may_change_cluster_size ||
+ Fs->cluster_size >= 8)) {
+ Fs->fat_bits = 16;
+ if(may_change_cluster_size)
Fs->cluster_size = 1;
+ continue;
+ }
+
+ if(Fs->fat_bits == 16 &&
+ (!may_change_cluster_size ||
+ Fs->cluster_size >= 64)) {
+ Fs->fat_bits = 32;
+ if(may_change_cluster_size)
+ Fs->cluster_size =
+ may_change_fat_len ? 8 : 1;
+ continue;
}
}
- if(!Fs->dir_len) {
- if (dev->heads == 1)
- Fs->dir_len = 4;
- else
- Fs->dir_len = (tot_sectors > 2000) ? 32 : 7;
+ if(may_change_cluster_size && Fs->cluster_size < 128) {
+ /* Double cluster size, and try again */
+ Fs->cluster_size = 2 * Fs->cluster_size;
+ continue;
}
- calc_cluster_size(Fs, tot_sectors, dev->fat_bits);
-#ifdef USE_XDF
- if(Fs->fat_len)
- xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits);
- else
-#endif
- {
- calc_fat_bits2(Fs, tot_sectors, dev->fat_bits,
- may_change_cluster_size,
- may_change_root_size);
- calc_fat_size(Fs, tot_sectors);
+ if(fit == 2 && may_change_fat_bits &&
+ may_change_root_size &&
+ Fs->fat_bits == 16) {
+ Fs->fat_bits=12;
+ may_pad=true;
+ continue;
}
+
+ /* Still too many clusters? */
+ return (fit == 2) ? -4 : -3;
}
- set_word(boot->boot.fatlen, Fs->fat_len);
+ if(getenv("MTOOLS_DEBUG_FAT") || getenv("MTOOLS_DEBUG_FAT_SUMMARY")) {
+ fprintf(stderr,
+ " FAT%d Cluster_size=%d %d clusters FAT_LEN=%d\n",
+ Fs->fat_bits,
+ Fs->cluster_size,
+ Fs->num_clus,
+ Fs->fat_len);
+ }
+ check_fs_params_and_set_fat(Fs, tot_sectors);
+ if(Fs->fat_bits == 32)
+ fat32_specific_init(Fs);
+ return 0;
}
-
-
-static void calc_fs_parameters_32(unsigned long tot_sectors,
- struct Fs_t *Fs, union bootsector *boot)
+void initFsForFormat(Fs_t *Fs)
{
- unsigned long num_clus;
- if(DWORD(nhs))
- boot->boot.descr = 0xf8;
- else
- boot->boot.descr = 0xf0;
+ memset(Fs, 0, sizeof(*Fs));
+ init_head(&Fs->head, &FsClass, NULL);
- if(!Fs->cluster_size)
- calc_cluster_size(Fs, tot_sectors, 32);
+ Fs->cluster_size = 0;
Fs->dir_len = 0;
- num_clus = tot_sectors / Fs->cluster_size;
- /* Maximal number of clusters on FAT32 is 0xffffff6 */
- if (num_clus > 0xffffff6) {
- fprintf(stderr, "Too many clusters\n");
- exit(1);
- }
- Fs->num_clus = (unsigned int) num_clus;
- set_fat32(Fs);
- calc_fat_size(Fs, tot_sectors);
- set_word(boot->boot.fatlen, 0);
- set_dword(boot->boot.ext.fat32.bigFat, Fs->fat_len);
+ Fs->fat_len = 0;
+ Fs->num_fat = 2;
+ Fs->backupBoot = 0;
}
+void setFsSectorSize(Fs_t *Fs, struct device *dev, uint16_t msize) {
+ unsigned int j;
+ Fs->sector_size = 512;
+ if( !(dev->use_2m & 0x7f)) {
+ Fs->sector_size = (uint16_t) (128u << (dev->ssize & 0x7f));
+ }
+ SET_INT(Fs->sector_size, msize);
+ for(j = 0; j < 31; j++) {
+ if (Fs->sector_size == (unsigned int) (1 << j)) {
+ Fs->sectorShift = j;
+ break;
+ }
+ }
+ Fs->sectorMask = Fs->sector_size - 1;
+}
+static int old_dos_size_to_geom(size_t size,
+ unsigned int *cyls,
+ unsigned short *heads,
+ unsigned short *sects)
+{
+ struct OldDos_t *params = getOldDosBySize(size);
+ if(params != NULL) {
+ *cyls = params->tracks;
+ *heads = params->heads;
+ *sects = params->sectors;
+ return 0;
+ } else
+ return 1;
+}
static void usage(int ret) NORETURN;
static void usage(int ret)
@@ -716,165 +840,11 @@ static void usage(int ret)
exit(ret);
}
-#ifdef OS_linux
-static int get_sector_size(int fd, char *errmsg) {
- int sec_size;
- if (ioctl(fd, BLKSSZGET, &sec_size) != 0 || sec_size <= 0) {
- sprintf(errmsg, "Could not get sector size of device (%s)",
- strerror(errno));
- return -1;
- }
-
- /* Cap sector size at 4096 */
- if(sec_size > 4096)
- sec_size = 4096;
- return sec_size;
-}
-
-static int get_block_geom(int fd, struct device *dev, char *errmsg) {
- struct hd_geometry geom;
- int sec_size;
- long size;
- uint16_t heads=dev->heads;
- uint16_t sectors=dev->sectors;
- unsigned int sect_per_track;
-
- if (ioctl(fd, HDIO_GETGEO, &geom) < 0) {
- sprintf(errmsg, "Could not get geometry of device (%s)",
- strerror(errno));
- return -1;
- }
-
- if (ioctl(fd, BLKGETSIZE, &size) < 0) {
- sprintf(errmsg, "Could not get size of device (%s)",
- strerror(errno));
- return -1;
- }
-
- sec_size = get_sector_size(fd, errmsg);
- if(sec_size < 0)
- return -1;
-
- dev->ssize = 0;
- while (dev->ssize < 0x7F && (128 << dev->ssize) < sec_size)
- dev->ssize++;
-
- if(!heads)
- heads = geom.heads;
- if(!sectors)
- sectors = geom.sectors;
-
- sect_per_track = heads * sectors;
- if(!dev->hidden) {
- unsigned long hidden;
- hidden = geom.start % sect_per_track;
- if(hidden && hidden != sectors) {
- sprintf(errmsg,
- "Hidden (%ld) does not match sectors (%d)\n",
- hidden, sectors);
- return -1;
- }
- dev->hidden = hidden;
- }
- dev->heads = heads;
- dev->sectors = sectors;
- if(!dev->tracks)
- dev->tracks = (size + dev->hidden % sect_per_track) / sect_per_track;
- return 0;
-}
-#endif
-
-static int get_lba_geom(Stream_t *Direct, unsigned long tot_sectors, struct device *dev, char *errmsg) {
- int sect_per_track;
- unsigned long tracks;
-
- /* if one value is already specified we do not want to overwrite it */
- if (dev->heads || dev->sectors || dev->tracks) {
- sprintf(errmsg, "Number of heads or sectors or tracks was already specified");
- return -1;
- }
-
- if (!tot_sectors) {
-#ifdef OS_linux
- int fd;
- int sec_size;
- long size;
- struct MT_STAT stbuf;
-
- fd = get_fd(Direct);
- if (MT_FSTAT(fd, &stbuf) < 0) {
- sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
- return -1;
- }
-
- if (S_ISBLK(stbuf.st_mode)) {
- if (ioctl(fd, BLKGETSIZE, &size) != 0) {
- sprintf(errmsg, "Could not get size of device (%s)",
- strerror(errno));
- return -1;
- }
- sec_size = get_sector_size(fd, errmsg);
- if(sec_size < 0)
- return -1;
-
- if (!(dev->ssize & 0x80)) {
- dev->ssize = 0;
- while (dev->ssize < 0x7F && (128 << dev->ssize) < sec_size)
- dev->ssize++;
- }
- if ((dev->ssize & 0x7f) > 2)
- tot_sectors = size >> ((dev->ssize & 0x7f) - 2);
- else
- tot_sectors = size << (2 - (dev->ssize & 0x7f));
- } else if (S_ISREG(stbuf.st_mode)) {
- tot_sectors = stbuf.st_size >> ((dev->ssize & 0x7f) + 7);
- } else {
- sprintf(errmsg, "Could not get size of device (%s)",
- "No method available");
- return -1;
- }
-#else
- mt_size_t size;
- GET_DATA(Direct, 0, &size, 0, 0);
- if (size == 0) {
- sprintf(errmsg, "Could not get size of device (%s)",
- "No method available");
- return -1;
- }
- tot_sectors = size >> ((dev->ssize & 0x7f) + 7);
-#endif
- }
-
- dev->sectors = 63;
-
- if (tot_sectors < 16*63*1024)
- dev->heads = 16;
- else if (tot_sectors < 32*63*1024)
- dev->heads = 32;
- else if (tot_sectors < 64*63*1024)
- dev->heads = 64;
- else if (tot_sectors < 128*63*1024)
- dev->heads = 128;
- else
- dev->heads = 255;
-
- sect_per_track = dev->heads * dev->sectors;
- tracks = (tot_sectors + dev->hidden % sect_per_track) / sect_per_track;
- if (tracks > 0xFFFFFFFF) {
- sprintf(errmsg, "Device is too big, it has too many tracks");
- return -1;
- }
-
- dev->tracks = (uint32_t) tracks;
-
- return 0;
-}
-
void mformat(int argc, char **argv, int dummy UNUSEDP) NORETURN;
void mformat(int argc, char **argv, int dummy UNUSEDP)
{
int r; /* generic return value */
- Fs_t Fs;
+ Fs_t *Fs;
unsigned int hs;
int hs_set;
unsigned int arguse_2m = 0;
@@ -883,10 +853,10 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
uint8_t rate_0, rate_any;
int mangled;
uint8_t argssize=0; /* sector size */
- int msize=0;
+ uint16_t msize=0;
int fat32 = 0;
struct label_blk_t *labelBlock;
- int bootOffset;
+ size_t bootOffset;
#ifdef USE_XDF
unsigned int i;
@@ -900,8 +870,8 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
struct device used_dev;
unsigned int argtracks;
uint16_t argheads, argsectors;
- unsigned long tot_sectors=0;
- int blocksize;
+ uint32_t tot_sectors=0;
+ uint32_t blocksize;
char drive, name[EXPAND_BUF];
@@ -913,18 +883,14 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
uint32_t serial;
int serial_set;
- int fsVersion;
- int mediaDesc=-1;
+ uint16_t fsVersion;
+ uint8_t mediaDesc=0;
+ bool haveMediaDesc=false;
- mt_size_t maxSize;
+ mt_off_t maxSize;
int Atari = 0; /* should we add an Atari-style serial number ? */
- unsigned int backupBoot = 6;
- int backupBootSet = 0;
-
- unsigned int resvSects = 0;
-
char *endptr;
hs = hs_set = 0;
@@ -938,22 +904,22 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
serial = 0;
fsVersion = 0;
- Fs.cluster_size = 0;
- Fs.refs = 1;
- Fs.dir_len = 0;
+ Fs = New(Fs_t);
+ if (!Fs) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ initFsForFormat(Fs);
if(getenv("MTOOLS_DIR_LEN")) {
- Fs.dir_len = atoui(getenv("MTOOLS_DIR_LEN"));
- if(Fs.dir_len <= 0)
- Fs.dir_len=0;
+ Fs->dir_len = atou16(getenv("MTOOLS_DIR_LEN"));
+ if(Fs->dir_len <= 0)
+ Fs->dir_len=0;
}
- Fs.fat_len = 0;
- Fs.num_fat = 2;
if(getenv("MTOOLS_NFATS")) {
- Fs.num_fat = atoui(getenv("MTOOLS_NFATS"));
- if(Fs.num_fat <= 0)
- Fs.num_fat=2;
+ Fs->num_fat = atou8(getenv("MTOOLS_NFATS"));
+ if(Fs->num_fat <= 0)
+ Fs->num_fat=2;
}
- Fs.Class = &FsClass;
rate_0 = mtools_rate_0;
rate_any = mtools_rate_any;
@@ -997,7 +963,7 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
break;
case 'T':
- tot_sectors = atoui(optarg);
+ tot_sectors = parseSize(optarg);
break;
case 'n': /*non-standard*/
@@ -1060,7 +1026,7 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
break;
case 'M':
- msize = atoi(optarg);
+ msize = atou16(optarg);
if(msize != 512 &&
msize != 1024 &&
msize != 2048 &&
@@ -1088,21 +1054,20 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
break;
case 'I':
- fsVersion = strtoi(optarg,&endptr,0);
+ fsVersion = strtou16(optarg,&endptr,0);
break;
case 'c':
- Fs.cluster_size = atoui(optarg);
+ Fs->cluster_size = atou8(optarg);
break;
case 'r':
- Fs.dir_len = strtoui(optarg,&endptr,0);
+ Fs->dir_len = strtou16(optarg,&endptr,0);
break;
case 'L':
- Fs.fat_len = strtoui(optarg,&endptr,0);
+ Fs->fat_len = strtoui(optarg,&endptr,0);
break;
-
case 'B':
bootSector = optarg;
break;
@@ -1110,31 +1075,35 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
keepBoot = 1;
break;
case 'K':
- backupBoot = atoui(optarg);
- backupBootSet=1;
- if(backupBoot < 2) {
+ Fs->backupBoot = atou16(optarg);
+ if(Fs->backupBoot < 2) {
fprintf(stderr, "Backupboot must be greater than 2\n");
exit(1);
}
break;
case 'R':
- resvSects = atoui(optarg);
+ Fs->fat_start = atou8(optarg);
break;
case 'h':
argheads = atou16(optarg);
break;
case 'd':
- Fs.num_fat = atoui(optarg);
+ Fs->num_fat = atou8(optarg);
break;
case 'm':
- mediaDesc = strtoi(optarg,&endptr,0);
+ mediaDesc = strtou8(optarg,&endptr,0);
if(*endptr)
- mediaDesc = strtoi(optarg,&endptr,16);
+ mediaDesc = strtou8(optarg,&endptr,16);
+ if(optarg == endptr || *endptr) {
+ fprintf(stderr, "Bad mediadesc %s\n", optarg);
+ exit(1);
+ }
+ haveMediaDesc=true;
break;
default:
usage(1);
}
- check_number_parse_errno(c, optarg, endptr);
+ check_number_parse_errno((char)c, optarg, endptr);
}
if (argc - optind > 1)
@@ -1167,10 +1136,9 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
/* check out a drive whose letter and parameters match */
sprintf(errmsg, "Drive '%c:' not supported", drive);
- Fs.Direct = NULL;
blocksize = 0;
for(dev=devices;dev->drive;dev++) {
- FREE(&(Fs.Direct));
+ FREE(&(Fs->head.Next));
/* drive letter */
if (dev->drive != drive)
continue;
@@ -1190,108 +1158,64 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
#endif
#ifdef USE_XDF
- if(!format_xdf) {
-#endif
- Fs.Direct = 0;
-#ifdef USE_FLOPPYD
- Fs.Direct = FloppydOpen(&used_dev, name,
- O_RDWR | create,
- errmsg, &maxSize);
+ if(format_xdf)
+ used_dev.misc_flags |= USE_XDF_FLAG;
+ info.FatSize=0;
#endif
- if(!Fs.Direct) {
- Fs.Direct = SimpleFileOpen(&used_dev, dev, name,
- O_RDWR | create,
- errmsg, 0, 1,
- &maxSize);
- }
+ if(tot_sectors)
+ used_dev.tot_sectors = tot_sectors;
+ Fs->head.Next = OpenImage(&used_dev, dev, name,
+ O_RDWR|create, errmsg,
+ ALWAYS_GET_GEOMETRY,
+ O_RDWR,
+ &maxSize, NULL,
#ifdef USE_XDF
- } else {
- used_dev.misc_flags |= USE_XDF_FLAG;
- Fs.Direct = XdfOpen(&used_dev, name, O_RDWR,
- errmsg, &info);
- if(Fs.Direct && !Fs.fat_len)
- Fs.fat_len = info.FatSize;
- if(Fs.Direct && !Fs.dir_len)
- Fs.dir_len = info.RootDirSize;
- }
+ &info
+#else
+ NULL
#endif
+ );
- if (!Fs.Direct)
- continue;
-
-#ifdef OS_linux
- if ((!used_dev.tracks || !used_dev.heads || !used_dev.sectors) &&
- (!IS_SCSI(dev))) {
- int fd= get_fd(Fs.Direct);
- struct MT_STAT stbuf;
-
- if (MT_FSTAT(fd, &stbuf) < 0) {
- sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
- continue;
- }
-
- if (S_ISBLK(stbuf.st_mode))
- /* If the following get_block_geom fails, do not
- * continue to next drive description, but allow
- * get_lba_geom to kick in
- */
- get_block_geom(fd, &used_dev, errmsg);
+#ifdef USE_XDF
+ if(Fs->head.Next && info.FatSize) {
+ if(!Fs->fat_len)
+ Fs->fat_len = info.FatSize;
+ if(!Fs->dir_len)
+ Fs->dir_len = info.RootDirSize;
}
#endif
- if ((!used_dev.tracks && !tot_sectors) ||
- !used_dev.heads || !used_dev.sectors){
- if (get_lba_geom(Fs.Direct, tot_sectors, &used_dev,
- errmsg) < 0) {
- sprintf(errmsg, "%s: "
- "Complete geometry of the disk "
- "was not specified, \n"
- "neither in /etc/mtools.conf nor "
- "on the command line. \n"
- "LBA Assist Translation for "
- "calculating CHS geometry "
- "of the disk failed.\n", argv[0]);
- continue;
- }
- }
-
-#if 0
- /* set parameters, if needed */
- if(SET_GEOM(Fs.Direct, &used_dev, 0xf0, boot)){
- sprintf(errmsg,"Can't set disk parameters: %s",
- strerror(errno));
+ if (!Fs->head.Next)
continue;
- }
-#endif
- Fs.sector_size = 512;
- if( !(used_dev.use_2m & 0x7f)) {
- Fs.sector_size = 128 << (used_dev.ssize & 0x7f);
- }
- SET_INT(Fs.sector_size, msize);
- {
- unsigned int j;
- for(j = 0; j < 31; j++) {
- if (Fs.sector_size == (unsigned int) (1 << j)) {
- Fs.sectorShift = j;
- break;
- }
- }
- Fs.sectorMask = Fs.sector_size - 1;
- }
+ if(tot_sectors)
+ used_dev.tot_sectors = tot_sectors;
+
+ setFsSectorSize(Fs, &used_dev, msize);
- if(!used_dev.blocksize || used_dev.blocksize < Fs.sector_size)
- blocksize = Fs.sector_size;
+ if(!used_dev.blocksize || used_dev.blocksize < Fs->sector_size)
+ blocksize = Fs->sector_size;
else
blocksize = used_dev.blocksize;
if(blocksize > MAX_SECTOR)
blocksize = MAX_SECTOR;
+ if(chs_to_totsectors(&used_dev, errmsg) < 0 ||
+ check_if_sectors_fit(dev->tot_sectors, maxSize, blocksize,
+ errmsg) < 0) {
+ FREE(&Fs->head.Next);
+ continue;
+ }
+
+ if(!tot_sectors)
+ tot_sectors = used_dev.tot_sectors;
+
/* do a "test" read */
if (!create &&
- READS(Fs.Direct, &boot.characters, 0, Fs.sector_size) !=
- (signed int) Fs.sector_size) {
+ PREADS(Fs->head.Next,
+ &boot.characters, 0, Fs->sector_size) !=
+ (signed int) Fs->sector_size) {
#ifdef HAVE_SNPRINTF
snprintf(errmsg, sizeof(errmsg)-1,
"Error reading from '%s', wrong parameters?",
@@ -1301,47 +1225,43 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
"Error reading from '%s', wrong parameters?",
name);
#endif
+ FREE(&Fs->head.Next);
continue;
}
break;
}
-
/* print error msg if needed */
if ( dev->drive == 0 ){
- FREE(&Fs.Direct);
+ FREE(&Fs->head.Next);
fprintf(stderr,"%s: %s\n", argv[0],errmsg);
exit(1);
}
- /* calculate the total number of sectors */
if(tot_sectors == 0) {
- unsigned long sect_per_track = used_dev.heads*used_dev.sectors;
- tot_sectors = used_dev.tracks*sect_per_track - used_dev.hidden%sect_per_track;
- /* Number of sectors must fit into 32bit value */
- if (tot_sectors > 0xFFFFFFFF) {
- fprintf(stderr, "Too many sectors\n");
- exit(1);
- }
+ fprintf(stderr, "Number of sectors not known\n");
+ exit(1);
}
/* create the image file if needed */
if (create) {
- WRITES(Fs.Direct, &boot.characters,
- sectorsToBytes((Stream_t*)&Fs, tot_sectors-1),
- Fs.sector_size);
+ PWRITES(Fs->head.Next, &boot.characters,
+ sectorsToBytes(Fs, tot_sectors-1),
+ Fs->sector_size);
}
/* the boot sector */
if(bootSector) {
int fd;
+ ssize_t ret;
fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
if(fd < 0) {
perror("open boot sector");
exit(1);
}
- if(read(fd, &boot.bytes, blocksize) < blocksize) {
+ ret=read(fd, &boot.bytes, blocksize);
+ if(ret < 0 || (size_t) ret < blocksize) {
perror("short read on boot sector");
exit(1);
}
@@ -1349,16 +1269,14 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
close(fd);
}
if(!keepBoot && !(used_dev.use_2m & 0x7f))
- memset(boot.characters, '\0', Fs.sector_size);
- set_dword(boot.boot.nhs, used_dev.hidden);
+ memset(boot.characters, '\0', Fs->sector_size);
- Fs.Next = buf_init(Fs.Direct,
- blocksize * used_dev.heads * used_dev.sectors,
- blocksize * used_dev.heads * used_dev.sectors,
- blocksize);
- Fs.Buffer = 0;
+ Fs->head.Next = buf_init(Fs->head.Next,
+ blocksize * used_dev.heads * used_dev.sectors,
+ blocksize * used_dev.heads * used_dev.sectors,
+ blocksize);
- boot.boot.nfat = Fs.num_fat;
+ boot.boot.nfat = Fs->num_fat;
if(!keepBoot)
set_word(&boot.bytes[510], 0xaa55);
@@ -1366,7 +1284,24 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
set_word(boot.boot.nsect, used_dev.sectors);
set_word(boot.boot.nheads, used_dev.heads);
- used_dev.fat_bits = comp_fat_bits(&Fs,used_dev.fat_bits, tot_sectors, fat32);
+ switch(calc_fs_parameters(&used_dev, fat32, tot_sectors, Fs,
+ &boot.boot.descr)) {
+ case -1:
+ fprintf(stderr, "Too few sectors\n");
+ exit(1);
+ case -2:
+ fprintf(stderr, "Too few clusters for %d bit fat\n",
+ Fs->fat_bits);
+ exit(1);
+ case -3:
+ fprintf(stderr, "Too many clusters for %d bit FAT\n",
+ Fs->fat_bits);
+ exit(1);
+ case -4:
+ fprintf(stderr, "Too many clusters for fat length %d\n",
+ Fs->fat_len);
+ exit(1);
+ }
if(!keepBoot && !(used_dev.use_2m & 0x7f)) {
if(!used_dev.partition) {
@@ -1376,37 +1311,17 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
setBeginEnd(&partTable[1], 0,
used_dev.heads * used_dev.sectors *
used_dev.tracks,
- used_dev.heads, used_dev.sectors, 1, 0,
- used_dev.fat_bits);
+ (uint8_t) used_dev.heads,
+ (uint8_t) used_dev.sectors, 1, 0,
+ Fs->fat_bits);
}
}
- if(used_dev.fat_bits == 32) {
- Fs.primaryFat = 0;
- Fs.writeAllFats = 1;
- if(resvSects) {
- if(resvSects < 3) {
- fprintf(stderr,
- "For FAT 32, reserved sectors need to be at least 3\n");
- resvSects = 32;
- }
-
- if(resvSects <= backupBoot && !backupBootSet)
- backupBoot = resvSects - 1;
- Fs.fat_start = resvSects;
- } else
- Fs.fat_start = 32;
-
- if(Fs.fat_start <= backupBoot) {
- fprintf(stderr,
- "Reserved sectors (%d) must be more than backupBoot (%d)\n", Fs.fat_start, backupBoot);
- backupBoot = 6;
- Fs.fat_start = 32;
- }
-
- calc_fs_parameters_32(tot_sectors, &Fs, &boot);
+ if(Fs->fat_bits == 32) {
+ set_word(boot.boot.fatlen, 0);
+ set_dword(boot.boot.ext.fat32.bigFat, Fs->fat_len);
- Fs.clus_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
+ Fs->clus_start = Fs->num_fat * Fs->fat_len + Fs->fat_start;
/* extension flags: mirror fats, and use #0 as primary */
set_word(boot.boot.ext.fat32.extFlags,0);
@@ -1415,37 +1330,26 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
set_word(boot.boot.ext.fat32.fsVersion,fsVersion);
/* root directory */
- set_dword(boot.boot.ext.fat32.rootCluster, Fs.rootCluster = 2);
+ set_dword(boot.boot.ext.fat32.rootCluster, Fs->rootCluster = 2);
/* info sector */
- set_word(boot.boot.ext.fat32.infoSector, Fs.infoSectorLoc = 1);
- Fs.infoSectorLoc = 1;
+ set_word(boot.boot.ext.fat32.infoSector, Fs->infoSectorLoc = 1);
+ Fs->infoSectorLoc = 1;
/* no backup boot sector */
- set_word(boot.boot.ext.fat32.backupBoot, backupBoot);
+ set_word(boot.boot.ext.fat32.backupBoot, Fs->backupBoot);
labelBlock = & boot.boot.ext.fat32.labelBlock;
} else {
- Fs.infoSectorLoc = 0;
- if(resvSects) {
- if(resvSects < 1) {
- fprintf(stderr,
- "Reserved sectors need to be at least 1\n");
- resvSects = 1;
- }
- Fs.fat_start = resvSects;
- } else
- Fs.fat_start = 1;
- calc_fs_parameters(&used_dev, tot_sectors, &Fs, &boot);
- Fs.dir_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
- Fs.clus_start = Fs.dir_start + Fs.dir_len;
+ set_word(boot.boot.fatlen, (uint16_t) Fs->fat_len);
+ Fs->dir_start = Fs->num_fat * Fs->fat_len + Fs->fat_start;
+ Fs->clus_start = Fs->dir_start + Fs->dir_len;
labelBlock = & boot.boot.ext.old.labelBlock;
-
}
/* Set the codepage */
- Fs.cp = cp_open(used_dev.codepage);
- if(Fs.cp == NULL)
+ Fs->cp = cp_open(used_dev.codepage);
+ if(Fs->cp == NULL)
exit(1);
if (!keepBoot)
@@ -1460,23 +1364,23 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
if (!serial_set)
serial=(uint32_t) random();
set_dword(labelBlock->serial, serial);
- label_name_pc(GET_DOSCONVERT((Stream_t *)&Fs),
+ label_name_pc(GET_DOSCONVERT((Stream_t *)Fs),
label[0] ? label : "NO NAME ", 0,
&mangled, &shortlabel);
strncpy(labelBlock->label, shortlabel.base, 8);
strncpy(labelBlock->label+8, shortlabel.ext, 3);
- sprintf(labelBlock->fat_type, "FAT%2.2d ", Fs.fat_bits);
+ sprintf(labelBlock->fat_type, "FAT%2.2d ", Fs->fat_bits);
labelBlock->fat_type[7] = ' ';
- set_word(boot.boot.secsiz, Fs.sector_size);
- boot.boot.clsiz = (unsigned char) Fs.cluster_size;
- set_word(boot.boot.nrsvsect, Fs.fat_start);
+ set_word(boot.boot.secsiz, Fs->sector_size);
+ boot.boot.clsiz = (unsigned char) Fs->cluster_size;
+ set_word(boot.boot.nrsvsect, Fs->fat_start);
bootOffset = init_geometry_boot(&boot, &used_dev, sectors0,
rate_0, rate_any,
&tot_sectors, keepBoot);
if(!bootOffset) {
- bootOffset = ((unsigned char *) labelBlock) - boot.bytes +
+ bootOffset = ptrdiff((char *) labelBlock, (char*)boot.bytes) +
sizeof(struct label_blk_t);
}
if(Atari) {
@@ -1486,8 +1390,8 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
boot.boot.banner[7] = (char) random();
}
- if(!keepBoot)
- inst_boot_prg(&boot, bootOffset);
+ if(!keepBoot && bootOffset <= UINT16_MAX)
+ inst_boot_prg(&boot, (uint16_t)bootOffset);
/* Mimic 3.8 behavior, else 2m disk do not work (???)
* luferbu@fluidsignal.com (Luis Bustamante), Fri, 14 Jun 2002
*/
@@ -1497,42 +1401,39 @@ void mformat(int argc, char **argv, int dummy UNUSEDP)
boot.boot.jump[2] = 0x90;
}
if(used_dev.use_2m & 0x7f)
- Fs.num_fat = 1;
- if(mediaDesc != -1)
+ Fs->num_fat = 1;
+ if(haveMediaDesc)
boot.boot.descr=mediaDesc;
- Fs.lastFatSectorNr = 0;
- Fs.lastFatSectorData = 0;
- zero_fat(&Fs, boot.boot.descr);
- Fs.freeSpace = Fs.num_clus;
- Fs.last = 2;
+ Fs->lastFatSectorNr = 0;
+ Fs->lastFatSectorData = 0;
+ zero_fat(Fs, boot.boot.descr);
+ Fs->freeSpace = Fs->num_clus;
+ Fs->last = 2;
#ifdef USE_XDF
- if(format_xdf)
+ if(used_dev.misc_flags & USE_XDF_FLAG)
for(i=0;
- i < (info.BadSectors+Fs.cluster_size-1)/Fs.cluster_size;
+ i < (info.BadSectors+Fs->cluster_size-1)/Fs->cluster_size;
i++)
- fatEncode(&Fs, i+2, 0xfff7);
+ fatEncode(Fs, i+2, 0xfff7);
#endif
- format_root(&Fs, label, &boot);
- WRITES((Stream_t *)&Fs, boot.characters,
- (mt_off_t) 0, Fs.sector_size);
-
- if(used_dev.fat_bits == 32) {
- WRITES((Stream_t *)&Fs, boot.characters,
- (mt_off_t) backupBoot * Fs.sector_size, Fs.sector_size);
+ format_root(Fs, label, &boot);
+ if(PWRITES((Stream_t *)Fs, boot.characters, 0, Fs->sector_size) < 0) {
+ fprintf(stderr, "Error writing boot sector\n");
+ exit(1);
}
- if(Fs.fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) {
- WRITES((Stream_t *)&Fs, boot.characters,
- sectorsToBytes((Stream_t*)&Fs,
- WORD_S(ext.fat32.backupBoot)),
- Fs.sector_size);
+ if(Fs->fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) {
+ if(PWRITES((Stream_t *)Fs, boot.characters,
+ sectorsToBytes(Fs, WORD_S(ext.fat32.backupBoot)),
+ Fs->sector_size) < 0) {
+ fprintf(stderr, "Error writing backup boot sector\n");
+ exit(1);
+ }
}
- FLUSH((Stream_t *)&Fs); /* flushes Fs.
- * This triggers the writing of the FAT */
- FREE(&Fs.Next);
- Fs.Class->freeFunc((Stream_t *)&Fs);
+
+ FREE((Stream_t **)&Fs);
#ifdef USE_XDF
if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
fprintf(stderr,