blob: 75cc92634b7592515c6445aceddf9dafc9c63191 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* Copyright 1986-1992 Emmet P. Gray.
2 * Copyright 1994,1996-2009 Alain Knaff.
3 * This file is part of mtools.
4 *
5 * Mtools is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Mtools is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * mformat.c
19 */
20
21#define DONT_NEED_WAIT
22
23#include "sysincludes.h"
24#include "msdos.h"
25#include "mtools.h"
26#include "mainloop.h"
Yi Kong39bbd962022-01-09 19:41:38 +080027#include "device.h"
28#include "old_dos.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080029#include "fsP.h"
30#include "file.h"
31#include "plain_io.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080032#include "nameclash.h"
33#include "buffer.h"
34#ifdef HAVE_ASSERT_H
35#include <assert.h>
36#endif
Yi Kong39bbd962022-01-09 19:41:38 +080037#include "stream.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080038#include "partition.h"
Yi Kong39bbd962022-01-09 19:41:38 +080039#include "open_image.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080040#include "file_name.h"
Yi Kong39bbd962022-01-09 19:41:38 +080041#include "lba.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080042
43#ifdef OS_linux
44#include "linux/hdreg.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080045#include "linux/fs.h"
Alistair Delvabeaee832021-02-24 11:27:23 -080046
47#endif
48
Yi Kong39bbd962022-01-09 19:41:38 +080049static uint16_t init_geometry_boot(union bootsector *boot, struct device *dev,
50 uint8_t sectors0,
51 uint8_t rate_0, uint8_t rate_any,
52 uint32_t *tot_sectors, int keepBoot)
Alistair Delvabeaee832021-02-24 11:27:23 -080053{
54 int nb_renum;
55 int sector2;
56 int sum;
57
58 set_word(boot->boot.nsect, dev->sectors);
59 set_word(boot->boot.nheads, dev->heads);
60
61#ifdef HAVE_ASSERT_H
62 assert(*tot_sectors != 0);
63#endif
64
Yi Kong39bbd962022-01-09 19:41:38 +080065 if (*tot_sectors <= UINT16_MAX && dev->hidden <= UINT16_MAX){
Alistair Delvabeaee832021-02-24 11:27:23 -080066 set_word(boot->boot.psect, (uint16_t) *tot_sectors);
67 set_dword(boot->boot.bigsect, 0);
Yi Kong39bbd962022-01-09 19:41:38 +080068 set_word(boot->boot.nhs, (uint16_t) dev->hidden);
69 } else {
Alistair Delvabeaee832021-02-24 11:27:23 -080070 set_word(boot->boot.psect, 0);
71 set_dword(boot->boot.bigsect, (uint32_t) *tot_sectors);
Yi Kong39bbd962022-01-09 19:41:38 +080072 set_dword(boot->boot.nhs, dev->hidden);
Alistair Delvabeaee832021-02-24 11:27:23 -080073 }
74
75 if (dev->use_2m & 0x7f){
Yi Kong39bbd962022-01-09 19:41:38 +080076 uint16_t bootOffset;
Alistair Delvabeaee832021-02-24 11:27:23 -080077 uint8_t j;
78 uint8_t size2;
79 uint16_t i;
80 strncpy(boot->boot.banner, "2M-STV04", 8);
81 boot->boot.ext.old.res_2m = 0;
82 boot->boot.ext.old.fmt_2mf = 6;
83 if ( dev->sectors % ( ((1 << dev->ssize) + 3) >> 2 ))
84 boot->boot.ext.old.wt = 1;
85 else
86 boot->boot.ext.old.wt = 0;
87 boot->boot.ext.old.rate_0= rate_0;
88 boot->boot.ext.old.rate_any= rate_any;
89 if (boot->boot.ext.old.rate_any== 2 )
90 boot->boot.ext.old.rate_any= 1;
91 i=76;
92
93 /* Infp0 */
94 set_word(boot->boot.ext.old.Infp0, i);
95 boot->bytes[i++] = sectors0;
96 boot->bytes[i++] = 108;
97 for(j=1; j<= sectors0; j++)
98 boot->bytes[i++] = j;
99
100 set_word(boot->boot.ext.old.InfpX, i);
101
102 boot->bytes[i++] = 64;
103 boot->bytes[i++] = 3;
104 nb_renum = i++;
105 sector2 = dev->sectors;
106 size2 = dev->ssize;
107 j=1;
108 while( sector2 ){
109 while ( sector2 < (1 << size2) >> 2 )
110 size2--;
111 boot->bytes[i++] = 128 + j;
112 boot->bytes[i++] = j++;
113 boot->bytes[i++] = size2;
114 sector2 -= (1 << size2) >> 2;
115 }
Yi Kong39bbd962022-01-09 19:41:38 +0800116 boot->bytes[nb_renum] = (uint8_t)(( i - nb_renum - 1 )/3);
Alistair Delvabeaee832021-02-24 11:27:23 -0800117
118 set_word(boot->boot.ext.old.InfTm, i);
119
120 sector2 = dev->sectors;
121 size2= dev->ssize;
122 while(sector2){
123 while ( sector2 < 1 << ( size2 - 2) )
124 size2--;
125 boot->bytes[i++] = size2;
126 sector2 -= 1 << (size2 - 2 );
127 }
128
129 set_word(boot->boot.ext.old.BootP,i);
130 bootOffset = i;
131
132 /* checksum */
133 for (sum=0, j=64; j<i; j++)
134 sum += boot->bytes[j];/* checksum */
Yi Kong39bbd962022-01-09 19:41:38 +0800135 boot->boot.ext.old.CheckSum=(unsigned char)-sum;
Alistair Delvabeaee832021-02-24 11:27:23 -0800136 return bootOffset;
137 } else {
138 if(!keepBoot) {
139 boot->boot.jump[0] = 0xeb;
140 boot->boot.jump[1] = 0;
141 boot->boot.jump[2] = 0x90;
142 strncpy(boot->boot.banner, mformat_banner, 8);
143 /* It looks like some versions of DOS are
144 * rather picky about this, and assume default
145 * parameters without this, ignoring any
146 * indication about cluster size et al. */
147 }
148 return 0;
149 }
150}
151
Yi Kong39bbd962022-01-09 19:41:38 +0800152static unsigned char bootprog[]=
153{0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
154 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
155 0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
156 0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
157 0x00, 0xcd, 0x19};
Alistair Delvabeaee832021-02-24 11:27:23 -0800158
Yi Kong39bbd962022-01-09 19:41:38 +0800159static __inline__ void inst_boot_prg(union bootsector *boot, uint16_t offset)
Alistair Delvabeaee832021-02-24 11:27:23 -0800160{
Yi Kong39bbd962022-01-09 19:41:38 +0800161 memcpy(boot->bytes + offset, bootprog, sizeof(bootprog));
162 if(offset - 2 < 0x80) {
163 /* short jump */
164 boot->boot.jump[0] = 0xeb;
165 boot->boot.jump[1] = (uint8_t) (offset -2);
166 boot->boot.jump[2] = 0x90;
167 } else {
168 /* long jump, if offset is too large */
169 boot->boot.jump[0] = 0xe9;
170 boot->boot.jump[1] = (uint8_t) (offset - 3);
171 boot->boot.jump[2] = (uint8_t) ( (offset - 3) >> 8);
Alistair Delvabeaee832021-02-24 11:27:23 -0800172 }
Yi Kong39bbd962022-01-09 19:41:38 +0800173 set_word(boot->boot.jump + offset + 20, offset + 24);
Alistair Delvabeaee832021-02-24 11:27:23 -0800174}
175
Yi Kong39bbd962022-01-09 19:41:38 +0800176/* Set up the root directory */
Alistair Delvabeaee832021-02-24 11:27:23 -0800177static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot)
178{
179 Stream_t *RootDir;
180 char *buf;
181 unsigned int i;
182 struct ClashHandling_t ch;
183 unsigned int dirlen;
184
185 init_clash_handling(&ch);
186 ch.name_converter = label_name_uc;
187 ch.ignore_entry = -2;
188
189 buf = safe_malloc(Fs->sector_size);
190 RootDir = OpenRoot((Stream_t *)Fs);
191 if(!RootDir){
192 fprintf(stderr,"Could not open root directory\n");
193 exit(1);
194 }
195
196 memset(buf, '\0', Fs->sector_size);
197
198 if(Fs->fat_bits == 32) {
199 /* on a FAT32 system, we only write one sector,
200 * as the directory can be extended at will...*/
201 dirlen = Fs->cluster_size;
202 fatAllocate(Fs, Fs->rootCluster, Fs->end_fat);
203 } else
204 dirlen = Fs->dir_len;
205 for (i = 0; i < dirlen; i++)
Yi Kong39bbd962022-01-09 19:41:38 +0800206 PWRITES(RootDir, buf, sectorsToBytes(Fs, i),
207 Fs->sector_size);
Alistair Delvabeaee832021-02-24 11:27:23 -0800208
209 ch.ignore_entry = 1;
210 if(label[0])
211 mwrite_one(RootDir,label, 0, labelit, NULL,&ch);
212
213 FREE(&RootDir);
214 if(Fs->fat_bits == 32)
215 set_word(boot->boot.dirents, 0);
216 else
Yi Kong39bbd962022-01-09 19:41:38 +0800217 set_word(boot->boot.dirents,
218 (uint16_t) (Fs->dir_len * (Fs->sector_size / 32)));
Alistair Delvabeaee832021-02-24 11:27:23 -0800219 free(buf);
220}
221
Yi Kong39bbd962022-01-09 19:41:38 +0800222/*
223 * Calculate length of one FAT, in sectors, given the number of total sectors
224 * Returns
225 * -2: if there are less total sectors than even clus_start
226 * 0: if a length was successfully calculated. (in that case, it is filled
227 * into Fs->fat_len)
228 * 1: if the specified number of FAT bits cannot accomodate that many
229 * sectors => caller should raise FAT bits
230 */
231static int calc_fat_len(Fs_t *Fs, uint32_t tot_sectors)
Alistair Delvabeaee832021-02-24 11:27:23 -0800232{
Yi Kong39bbd962022-01-09 19:41:38 +0800233 uint32_t rem_sect;
234 uint32_t numerator;
235 uint32_t denominator;
236 uint32_t corr=0; /* correct numeric overflow */
237 uint32_t clus_start;
Alistair Delvabeaee832021-02-24 11:27:23 -0800238 unsigned int fat_nybbles;
Yi Kong39bbd962022-01-09 19:41:38 +0800239
240#ifdef HAVE_ASSERT_H
241 assert(Fs->fat_bits != 0);
242#endif
Alistair Delvabeaee832021-02-24 11:27:23 -0800243
244#ifdef DEBUG
245 fprintf(stderr, "Fat start=%d\n", Fs->fat_start);
246 fprintf(stderr, "tot_sectors=%lu\n", tot_sectors);
247 fprintf(stderr, "dir_len=%d\n", Fs->dir_len);
248#endif
Yi Kong39bbd962022-01-09 19:41:38 +0800249 Fs->fat_len = 0;
250 clus_start = calc_clus_start(Fs);
251 if(tot_sectors < clus_start)
252 return -2;
253 rem_sect = tot_sectors - clus_start;
Alistair Delvabeaee832021-02-24 11:27:23 -0800254
255 /* Cheat a little bit to address the _really_ common case of
256 odd number of remaining sectors while both nfat and cluster size
257 are even... */
Yi Kong39bbd962022-01-09 19:41:38 +0800258 if(rem_sect % 2 == 1 &&
259 Fs->num_fat % 2 == 0 &&
260 Fs->cluster_size % 2 == 0)
Alistair Delvabeaee832021-02-24 11:27:23 -0800261 rem_sect--;
262
263#ifdef DEBUG
264 fprintf(stderr, "Rem sect=%lu\n", rem_sect);
265#endif
266
Alistair Delvabeaee832021-02-24 11:27:23 -0800267 /* See fat_size_calculation.tex or
Yi Kong39bbd962022-01-09 19:41:38 +0800268 (https://www.gnu.org/gnu/mtools/manual/fat_size_calculation.pdf)
Alistair Delvabeaee832021-02-24 11:27:23 -0800269 for an explantation about why the stuff below works...
270 */
271
272 fat_nybbles = Fs->fat_bits / 4;
273 numerator = rem_sect+2*Fs->cluster_size;
Yi Kong39bbd962022-01-09 19:41:38 +0800274 /* Might overflow, but will be cancelled out below. As the
275 operation is unsigned, a posteriori fixup is allowable, as
276 wrap-around is part of the spec. For *signed* quantities,
277 this hack would be incorrect, as it would be "undefined
278 behavior" */
279
280 /* Initial denominator is nybbles consumed by one cluster, both in
281 * FAT and in cluster space */
Alistair Delvabeaee832021-02-24 11:27:23 -0800282 denominator =
283 Fs->cluster_size * Fs->sector_size * 2 +
284 Fs->num_fat * fat_nybbles;
285
Yi Kong39bbd962022-01-09 19:41:38 +0800286 if(fat_nybbles == 3) {
287 /* We need to do this test here, or multiplying rem_sect with
288 * fat_nybbles might overflow */
289 if(rem_sect > 256 * FAT12)
290 return 1;
Alistair Delvabeaee832021-02-24 11:27:23 -0800291 numerator *= fat_nybbles;
Yi Kong39bbd962022-01-09 19:41:38 +0800292 } else
Alistair Delvabeaee832021-02-24 11:27:23 -0800293 /* Avoid numerical overflows, divide the denominator
294 * rather than multiplying the numerator */
295 denominator = denominator / fat_nybbles;
296
Yi Kong39bbd962022-01-09 19:41:38 +0800297 /* Substract denominator from numerator to "cancel out" an
298 unsigned integer overflow which might have happened with
299 total number of sectors very near maximum (2^32-1) and huge
300 cluster size. This substraction removes 1 from the result
301 of the following division, so we will add 1 again after the
302 division. However, we only do this if (original) numerator
303 is bigger than denominator though, as otherwise we risk the
304 inverse problem of going below 0 on small disks */
305 if(rem_sect > denominator) {
306 numerator -= denominator;
307 corr++;
308 }
309
Alistair Delvabeaee832021-02-24 11:27:23 -0800310#ifdef DEBUG
311 fprintf(stderr, "Numerator=%lu denominator=%lu\n",
312 numerator, denominator);
313#endif
314
Yi Kong39bbd962022-01-09 19:41:38 +0800315 Fs->fat_len = (numerator-1)/denominator+1+corr;
316 return 0;
317}
Alistair Delvabeaee832021-02-24 11:27:23 -0800318
Yi Kong39bbd962022-01-09 19:41:38 +0800319/* Is there enough space in the FAT for the descriptors for all clusters.
320 * This only works if we assume that it is already clear that Fs->num_clus is
321 * less than FAT32, or else it might overflow */
322static inline bool clusters_fit_into_fat(Fs_t *Fs) {
323 return ((Fs->num_clus+2) * (Fs->fat_bits/4) - 1) / (Fs->sector_size*2) <
324 Fs->fat_len;
325}
Alistair Delvabeaee832021-02-24 11:27:23 -0800326
Yi Kong39bbd962022-01-09 19:41:38 +0800327/*
328 * Assert that FAT param calculation has been performed correctly, and
329 * set_fat
330 */
331static void check_fs_params_and_set_fat(Fs_t *Fs, uint32_t tot_sectors)
332{
333 unsigned int provisional_fat_bits;
334
Alistair Delvabeaee832021-02-24 11:27:23 -0800335#ifdef DEBUG
336 fprintf(stderr, "Num_clus=%d fat_len=%d nybbles=%d\n",
337 Fs->num_clus, Fs->fat_len, fat_nybbles);
338#endif
339
Alistair Delvabeaee832021-02-24 11:27:23 -0800340#ifdef HAVE_ASSERT_H
Yi Kong39bbd962022-01-09 19:41:38 +0800341 /* if FAT bits is 32, dir_len must be zero, otherwise it must be
342 * non-zero */
343 assert(Fs->fat_bits == 32 ? (Fs->dir_len == 0) : (Fs->dir_len != 0));
Alistair Delvabeaee832021-02-24 11:27:23 -0800344
Yi Kong39bbd962022-01-09 19:41:38 +0800345 /* Clusters must fill disk up entirely, except for small amount of
346 * slack smaller than one sector */
347 assert(tot_sectors >=
348 Fs->clus_start + Fs->num_clus * Fs->cluster_size);
349 assert(tot_sectors <=
350 Fs->clus_start + Fs->num_clus * Fs->cluster_size +
351 Fs->cluster_size - 1);
Alistair Delvabeaee832021-02-24 11:27:23 -0800352
Alistair Delvabeaee832021-02-24 11:27:23 -0800353 /* Fat must be big enough for all clusters */
Yi Kong39bbd962022-01-09 19:41:38 +0800354 assert(clusters_fit_into_fat(Fs));
355#endif
356 provisional_fat_bits = Fs->fat_bits;
357 set_fat(Fs);
358#ifdef HAVE_ASSERT_H
359 assert(provisional_fat_bits == Fs->fat_bits);
Alistair Delvabeaee832021-02-24 11:27:23 -0800360#endif
361}
362
Yi Kong39bbd962022-01-09 19:41:38 +0800363static void fat32_specific_init(Fs_t *Fs) {
364 Fs->primaryFat = 0;
365 Fs->writeAllFats = 1;
366 if(!Fs->backupBoot) {
367 if(Fs->fat_start <= 6)
368 Fs->backupBoot = Fs->fat_start - 1;
369 else
370 Fs->backupBoot=6;
Alistair Delvabeaee832021-02-24 11:27:23 -0800371 }
372
Yi Kong39bbd962022-01-09 19:41:38 +0800373 if(Fs->fat_start < 3) {
374 fprintf(stderr,
375 "For FAT 32, reserved sectors need to be at least 3\n");
Alistair Delvabeaee832021-02-24 11:27:23 -0800376 exit(1);
377 }
378
Yi Kong39bbd962022-01-09 19:41:38 +0800379 if(Fs->fat_start <= Fs->backupBoot) {
380 fprintf(stderr,
381 "Reserved sectors (%d) must be more than backupBoot (%d)\n", Fs->fat_start, Fs->backupBoot);
382 Fs->backupBoot = 0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800383 }
384}
385
Yi Kong39bbd962022-01-09 19:41:38 +0800386/* Try given cluster- and fat_size (and other parameters), and say whether
387 * cluster_size/fat_bits should be increased, decreased, or is fine as is.
388 * Parameters
389 * Fs the file system object
390 * tot_sectors size of file system, in sectors
391 * may_change_boot_size try_cluster_size may increase number of boot
392 * (reserved) sectors to make everything fit
393 * may_change_fat_len try_cluster_size may change (compute) FAT length
394 * may_change_root_size try_cluster_size may increase root directory size
395 * to make everything fit
396 * may_pad if there are (slightly) too many clusters,
397 * try_cluster_size may artificially inflate number of
398 * boot sectors, fat length or root_size to take up
399 * space in order to reduce number clusters below limit
400 *
401 * Return values
402 * -2 Too few sectors to contain even the header (reserved sectors, minimal
403 * FAT and root directory), or other internal error
404 * -1 This cluster size leads to too few clusters for the FAT size.
405 * Caller should either reduce cluster size or FAT size, and try again
406 * 0 Everything fits
407 * 1 This cluster size leads to too many clusters for the FAT
408 * size. Caller should either increase cluster size or FAT size, and
409 * try again
410 * 2 Fat length is set, and there are too many clusters to fit into
411 * that Fat length. Caller should either increase cluster size, or
412 * decrease FAT size, and try again
413 *
414 */
415static int try_cluster_size(Fs_t *Fs,
416 uint32_t tot_sectors,
417 bool may_change_boot_size,
418 bool may_change_fat_len,
419 bool may_change_root_size,
420 bool may_pad)
421{
422 uint32_t maxClus;
423 uint32_t minClus;
424
425 switch(Fs->fat_bits) {
426 case 12:
427 minClus = 1;
428 maxClus = FAT12;
429 break;
430 case 16:
431 minClus = 4096;
432 maxClus = FAT16;
433 break;
434 case 32:
435 minClus = FAT16;
436 maxClus = FAT32;
437 break;
438 default:
439#ifdef HAVE_ASSERT_H
440 assert(false && "Bad number of FAT bits");
441#endif
442 return -2;
443 }
444
445 if(getenv("MTOOLS_DEBUG_FAT")) {
446 fprintf(stderr, "FAT=%d Cluster=%d%s\n",
447 Fs->fat_bits, Fs->cluster_size,
448 may_pad ? " may_pad" : "");
449 }
450
451 if(may_change_fat_len) {
452 int fit=calc_fat_len(Fs, tot_sectors);
453 if(fit != 0)
454 return fit;
455 }
456
457 while(true) {
458 uint32_t bwaste; /* How many sectors we need to "waste" */
459 uint16_t waste;
460 uint16_t dir_grow=0;
461
462 if(calc_num_clus(Fs, tot_sectors) < 0)
463 return -2;
464 if(Fs->num_clus < minClus)
465 return -1; /* Not enough clusters => loop
466 * should shrink FAT bits again */
467
468 if(!may_change_fat_len) {
469 /* If fat_len has been explicitly specified by
470 * user, make sure that number of clusters
471 * fit within that fat_len */
472 if(Fs->num_clus >= FAT32 || !clusters_fit_into_fat(Fs))
473 return 2; /* Caller should should pick a
474 * bigger cluster size, but not a
475 * higher FAT bits */
476 }
477
478 if(Fs->num_clus < maxClus)
479 break;
480 if(!may_pad)
481 return 1;
482
483 /* "Pad" fat by artifically adding sectors to boot sectors,
484 FAT or root directory to diminish number of clusters */
485
486 /* This is needed when a size of a FAT fs somehow is
487 * "in between" 2 fat bits: too large for FAT12, too small
488 * for FAT16.
489
490 * This happens because if there slightly too may
491 * clusters for FAT12, the system passes to
492 * FAT16. However, this makes the space taken up by
493 * the descriptor of each sector in the FAT larger,
494 * making the FAT larger overall, leaving less space
495 * for the clusters themselves, i.e. less
496 * clusters. Sometimes this is enough to push the
497 * number of clusters *below* the minimum for FAT12.
498
499 * a similar situation happens when switching from
500 * FAT16 to FAT32.
501
502 * if this happens, we switch back to the lower FAT
503 * bits, and allow "padding", i.e. artificially
504 * "wasting" space by adding more reserved (boot)
505 * sectors, adding "useless" extra sectors to the FAT,
506 * or allowing more root directory entries.
507
508 */
509 bwaste = tot_sectors - Fs->clus_start -
510 maxClus * Fs->cluster_size + 1;
511#ifdef HAVE_ASSERT_H
512 assert(bwaste <= UINT16_MAX);
513#endif
514 waste = (uint16_t) bwaste;
515
516 if(may_change_root_size) {
517 dir_grow = 32 - Fs->dir_len;
518 if(dir_grow > waste)
519 dir_grow = waste;
520 waste -= dir_grow;
521 }
522 if(may_change_fat_len &&
523 (!may_change_boot_size || Fs->fat_bits == 12)) {
524 uint16_t fat_grow =
525 (waste + Fs->num_fat - 1) / Fs->num_fat;
526 uint16_t dir_shrink = 0;
527 Fs->fat_len += fat_grow;
528
529 /* Shrink directory again, but at most as by as much
530 * as we grew it earlyer */
531 dir_shrink = waste - fat_grow * Fs->num_fat;
532 if(dir_shrink > dir_grow)
533 dir_shrink = dir_grow;
534 dir_grow -= dir_shrink;
535 } else if(may_change_boot_size) {
536 Fs->fat_start += waste;
537 }
538 Fs->dir_len += dir_grow;
539
540 /* If padding once failed, no point in keeping on retrying */
541 may_pad=false;
542 }
543#ifdef HAVE_ASSERT_H
544 /* number of clusters must be within allowable range for fat
545 bits */
546 assert(Fs->num_clus >= minClus);
547 assert(Fs->num_clus < maxClus);
548#endif
549 return 0;
550}
551
552/* Finds a set of filesystem parameters, given the device size, and
553 * any presets specified by user
554 * On return, Fs will be initialized, or one of the following error codes
555 * will be returned:
556 * -1 Not enough sectors for any kind of FAT filesystem
557 * -2 Not enough clusters for given number of FAT bits
558 * -3 Too many clusters for given number of FAT bits
559 * -4 Too many clusters for chosen FAT length
560 */
561int calc_fs_parameters(struct device *dev, bool fat32,
562 uint32_t tot_sectors,
563 struct Fs_t *Fs, uint8_t *descr)
564{
565 bool may_change_boot_size = (Fs->fat_start == 0);
566 bool may_change_fat_bits = (dev->fat_bits == 0) && !fat32;
567 bool may_change_cluster_size = (Fs->cluster_size == 0);
568 bool may_change_root_size = (Fs->dir_len == 0);
569 bool may_change_fat_len = (Fs->fat_len == 0);
570 bool may_pad = false;
571 uint16_t saved_dir_len;
572
573 struct OldDos_t *params=NULL;
574 Fs->infoSectorLoc = 0;
575 if( (may_change_fat_bits || abs(dev->fat_bits) == 12) &&
576 (may_change_boot_size || Fs->fat_start == 1) )
577 params = getOldDosByParams(dev->tracks,dev->heads,dev->sectors,
578 Fs->dir_len, Fs->cluster_size);
579 if(params != NULL) {
580 int num_clus_valid;
581 *descr = params->media;
582 Fs->fat_start = 1;
583 Fs->cluster_size = params->cluster_size;
584 Fs->dir_len = params->dir_len;
585 Fs->fat_len = params->fat_len;
586 Fs->fat_bits = 12;
587 num_clus_valid = calc_num_clus(Fs, tot_sectors);
588#ifdef HAVE_ASSERT_H
589 assert(num_clus_valid >= 0);
590#endif
591 check_fs_params_and_set_fat(Fs, tot_sectors);
592 return 0;
593 }
594
595 /* a format described by BPB */
596 if(dev->hidden || tot_sectors % (dev->sectors * dev->heads))
597 *descr = 0xf8;
598 else
599 *descr = 0xf0;
600
601 Fs->fat_bits = abs(dev->fat_bits);
602 if(Fs->fat_bits == 0)
603 /* If fat_bits not specified by device, start with a 12-bit
604 * FAT, unless 32 bit specified on command line */
605 Fs->fat_bits = fat32 ? 32 : 12;
606 if(!Fs->cluster_size) {
607 if(tot_sectors < 2400 && dev->heads == 2)
608 /* double sided double density floppies */
609 Fs->cluster_size = 2;
610 else if(may_change_fat_len && Fs->fat_bits == 32)
611 /* FAT32 => start with 8 */
612 Fs->cluster_size = 8;
613 else
614 /* In all other cases, start with 1 */
615 Fs->cluster_size = 1;
616 }
617
618 if(!Fs->dir_len) {
619 if(tot_sectors < 1200) {
620 /* Double density floppies */
621 if (dev->heads == 1)
622 Fs->dir_len = 4;
623 else
624 Fs->dir_len = 7;
625 } else if(tot_sectors <= 3840)
626 /* High density floppies */
627 Fs->dir_len = 14;
628 else if(tot_sectors <= 7680)
629 /* extra density floppies */
630 Fs->dir_len = 15;
631 else
632 Fs->dir_len = 32;
633 }
634 saved_dir_len = Fs->dir_len;
635
636 while(true) {
637 int fit;
638 if(may_change_boot_size) {
639 if(Fs->fat_bits == 32)
640 Fs->fat_start = 32;
641 else
642 Fs->fat_start = 1;
643 }
644
645 if(Fs->fat_bits == 32)
646 Fs->dir_len = 0;
647 else if(Fs->dir_len == 0)
648 Fs->dir_len = saved_dir_len;
649
650 if(Fs->fat_bits == 32 &&
651 may_change_cluster_size && may_change_fat_len) {
652 /*
653 FAT32 cluster sizes for disks with 512 block size
654 according to Microsoft specification fatgen103.doc:
655
656 ...
657 - 8 GB cluster_size = 8
658 8 GB - 16 GB cluster_size = 16
659 16 GB - 32 GB cluster_size = 32
660 32 GB - 2 TB cluster_size = 64
661
662 Below calculation is generalized and does not depend
663 on 512 block size.
664 */
665 Fs->cluster_size = tot_sectors >= 32*1024*1024*2 ? 64 :
666 tot_sectors >= 16*1024*1024*2 ? 32 :
667 tot_sectors >= 8*1024*1024*2 ? 16 :
668 Fs->cluster_size;
669 }
670
671 fit=try_cluster_size(Fs,
672 tot_sectors,
673 may_change_boot_size,
674 may_change_fat_len,
675 may_change_root_size,
676 may_pad);
677
678 if(getenv("MTOOLS_DEBUG_FAT")) {
679 fprintf(stderr, " fit=%d\n", fit);
680 }
681 if(fit == 0)
682 break;
683 if(fit == -2)
684 return -1;
685
686#ifdef HAVE_ASSERT_H
687 assert(fit != 2 || !may_change_fat_len);
688#endif
689 if(fit < 0) {
690 if(may_change_cluster_size &&
691 may_change_fat_len &&
692 Fs->cluster_size > 1) {
693 Fs->cluster_size = Fs->cluster_size / 2;
694 continue;
695 }
696
697 /* Somehow we ended up with too few sectors
698 * for FAT size. This can only happen if
699 * cluster size is not adjustable, and if we
700 * had *barely* more clusters than allowed by
701 * previous fat bits. After raising fat bits,
702 * fat_len grew larger (due to each individual
703 * FAT entry now being larger), pushing the
704 * number of clusters *below* new limit. =>
705 * we lower fat bits again */
706 if(!may_change_fat_bits || Fs->fat_bits == 12)
707 return -2;
708
709 switch(Fs->fat_bits) {
710 case 16:
711 Fs->fat_bits=12;
712 break;
713 case 32:
714 Fs->fat_bits=16;
715 break;
716 }
717 may_pad=true;
718 continue;
719 }
720
721 if(fit == 1 && may_change_fat_bits && !may_pad) {
722 /* If cluster_size reached
723 * "maximum" for fat_bits,
724 * switch over to next
725 */
726 if(Fs->fat_bits == 12 &&
727 (!may_change_cluster_size ||
728 Fs->cluster_size >= 8)) {
729 Fs->fat_bits = 16;
730 if(may_change_cluster_size)
731 Fs->cluster_size = 1;
732 continue;
733 }
734
735 if(Fs->fat_bits == 16 &&
736 (!may_change_cluster_size ||
737 Fs->cluster_size >= 64)) {
738 Fs->fat_bits = 32;
739 if(may_change_cluster_size)
740 Fs->cluster_size =
741 may_change_fat_len ? 8 : 1;
742 continue;
743 }
744 }
745
746 if(may_change_cluster_size && Fs->cluster_size < 128) {
747 /* Double cluster size, and try again */
748 Fs->cluster_size = 2 * Fs->cluster_size;
749 continue;
750 }
751
752 if(fit == 2 && may_change_fat_bits &&
753 may_change_root_size &&
754 Fs->fat_bits == 16) {
755 Fs->fat_bits=12;
756 may_pad=true;
757 continue;
758 }
759
760 /* Still too many clusters? */
761 return (fit == 2) ? -4 : -3;
762 }
763
764 if(getenv("MTOOLS_DEBUG_FAT") || getenv("MTOOLS_DEBUG_FAT_SUMMARY")) {
765 fprintf(stderr,
766 " FAT%d Cluster_size=%d %d clusters FAT_LEN=%d\n",
767 Fs->fat_bits,
768 Fs->cluster_size,
769 Fs->num_clus,
770 Fs->fat_len);
771 }
772 check_fs_params_and_set_fat(Fs, tot_sectors);
773 if(Fs->fat_bits == 32)
774 fat32_specific_init(Fs);
775 return 0;
776}
777
778void initFsForFormat(Fs_t *Fs)
779{
780 memset(Fs, 0, sizeof(*Fs));
781 init_head(&Fs->head, &FsClass, NULL);
782
783 Fs->cluster_size = 0;
784 Fs->dir_len = 0;
785 Fs->fat_len = 0;
786 Fs->num_fat = 2;
787 Fs->backupBoot = 0;
788}
789
790void setFsSectorSize(Fs_t *Fs, struct device *dev, uint16_t msize) {
791 unsigned int j;
792 Fs->sector_size = 512;
793 if( !(dev->use_2m & 0x7f)) {
794 Fs->sector_size = (uint16_t) (128u << (dev->ssize & 0x7f));
795 }
796
797 SET_INT(Fs->sector_size, msize);
798 for(j = 0; j < 31; j++) {
799 if (Fs->sector_size == (unsigned int) (1 << j)) {
800 Fs->sectorShift = j;
801 break;
802 }
803 }
804 Fs->sectorMask = Fs->sector_size - 1;
805}
Alistair Delvabeaee832021-02-24 11:27:23 -0800806
807static int old_dos_size_to_geom(size_t size,
808 unsigned int *cyls,
809 unsigned short *heads,
810 unsigned short *sects)
811{
812 struct OldDos_t *params = getOldDosBySize(size);
813 if(params != NULL) {
814 *cyls = params->tracks;
815 *heads = params->heads;
816 *sects = params->sectors;
817 return 0;
818 } else
819 return 1;
820}
821
Alistair Delvabeaee832021-02-24 11:27:23 -0800822static void usage(int ret) NORETURN;
823static void usage(int ret)
824{
825 fprintf(stderr,
826 "Mtools version %s, dated %s\n", mversion, mdate);
827 fprintf(stderr,
828 "Usage: %s [-V] [-t tracks] [-h heads] [-n sectors] "
829 "[-v label] [-1] [-4] [-8] [-f size] "
830 "[-N serialnumber] "
831 "[-k] [-B bootsector] [-r root_dir_len] [-L fat_len] "
832 "[-F] [-I fsVersion] [-C] [-c cluster_size] "
833 "[-H hidden_sectors] "
834#ifdef USE_XDF
835 "[-X] "
836#endif
837 "[-S hardsectorsize] [-M softsectorsize] [-3] "
838 "[-2 track0sectors] [-0 rate0] [-A rateany] [-a]"
839 "device\n", progname);
840 exit(ret);
841}
842
Alistair Delvabeaee832021-02-24 11:27:23 -0800843void mformat(int argc, char **argv, int dummy UNUSEDP) NORETURN;
844void mformat(int argc, char **argv, int dummy UNUSEDP)
845{
846 int r; /* generic return value */
Yi Kong39bbd962022-01-09 19:41:38 +0800847 Fs_t *Fs;
Alistair Delvabeaee832021-02-24 11:27:23 -0800848 unsigned int hs;
849 int hs_set;
850 unsigned int arguse_2m = 0;
851 uint8_t sectors0=18; /* number of sectors on track 0 */
852 int create = 0;
853 uint8_t rate_0, rate_any;
854 int mangled;
855 uint8_t argssize=0; /* sector size */
Yi Kong39bbd962022-01-09 19:41:38 +0800856 uint16_t msize=0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800857 int fat32 = 0;
858 struct label_blk_t *labelBlock;
Yi Kong39bbd962022-01-09 19:41:38 +0800859 size_t bootOffset;
Alistair Delvabeaee832021-02-24 11:27:23 -0800860
861#ifdef USE_XDF
862 unsigned int i;
863 int format_xdf = 0;
864 struct xdf_info info;
865#endif
866 union bootsector boot;
867 char *bootSector=0;
868 int c;
869 int keepBoot = 0;
870 struct device used_dev;
871 unsigned int argtracks;
872 uint16_t argheads, argsectors;
Yi Kong39bbd962022-01-09 19:41:38 +0800873 uint32_t tot_sectors=0;
874 uint32_t blocksize;
Alistair Delvabeaee832021-02-24 11:27:23 -0800875
876 char drive, name[EXPAND_BUF];
877
878 char label[VBUFSIZE];
879
880 dos_name_t shortlabel;
881 struct device *dev;
882 char errmsg[2100];
883
884 uint32_t serial;
885 int serial_set;
Yi Kong39bbd962022-01-09 19:41:38 +0800886 uint16_t fsVersion;
887 uint8_t mediaDesc=0;
888 bool haveMediaDesc=false;
Alistair Delvabeaee832021-02-24 11:27:23 -0800889
Yi Kong39bbd962022-01-09 19:41:38 +0800890 mt_off_t maxSize;
Alistair Delvabeaee832021-02-24 11:27:23 -0800891
892 int Atari = 0; /* should we add an Atari-style serial number ? */
893
Alistair Delvabeaee832021-02-24 11:27:23 -0800894 char *endptr;
895
896 hs = hs_set = 0;
897 argtracks = 0;
898 argheads = 0;
899 argsectors = 0;
900 arguse_2m = 0;
901 argssize = 0x2;
902 label[0] = '\0';
903 serial_set = 0;
904 serial = 0;
905 fsVersion = 0;
906
Yi Kong39bbd962022-01-09 19:41:38 +0800907 Fs = New(Fs_t);
908 if (!Fs) {
909 fprintf(stderr, "Out of memory\n");
910 exit(1);
911 }
912 initFsForFormat(Fs);
Alistair Delvabeaee832021-02-24 11:27:23 -0800913 if(getenv("MTOOLS_DIR_LEN")) {
Yi Kong39bbd962022-01-09 19:41:38 +0800914 Fs->dir_len = atou16(getenv("MTOOLS_DIR_LEN"));
915 if(Fs->dir_len <= 0)
916 Fs->dir_len=0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800917 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800918 if(getenv("MTOOLS_NFATS")) {
Yi Kong39bbd962022-01-09 19:41:38 +0800919 Fs->num_fat = atou8(getenv("MTOOLS_NFATS"));
920 if(Fs->num_fat <= 0)
921 Fs->num_fat=2;
Alistair Delvabeaee832021-02-24 11:27:23 -0800922 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800923 rate_0 = mtools_rate_0;
924 rate_any = mtools_rate_any;
925
926 /* get command line options */
927 if(helpFlag(argc, argv))
928 usage(0);
929 while ((c = getopt(argc,argv,
930 "i:148f:t:n:v:qub"
931 "kK:R:B:r:L:I:FCc:Xh:s:T:l:N:H:M:S:2:30:Aad:m:"))!= EOF) {
932 errno = 0;
933 endptr = NULL;
934 switch (c) {
935 case 'i':
936 set_cmd_line_image(optarg);
937 break;
938
939 /* standard DOS flags */
940 case '1':
941 argheads = 1;
942 break;
943 case '4':
944 argsectors = 9;
945 argtracks = 40;
946 break;
947 case '8':
948 argsectors = 8;
949 argtracks = 40;
950 break;
951 case 'f':
952 r=old_dos_size_to_geom(atoul(optarg),
953 &argtracks, &argheads,
954 &argsectors);
955 if(r) {
956 fprintf(stderr,
957 "Bad size %s\n", optarg);
958 exit(1);
959 }
960 break;
961 case 't':
962 argtracks = atou16(optarg);
963 break;
964
965 case 'T':
Yi Kong39bbd962022-01-09 19:41:38 +0800966 tot_sectors = parseSize(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -0800967 break;
968
969 case 'n': /*non-standard*/
970 case 's':
971 argsectors = atou16(optarg);
972 break;
973
974 case 'l': /* non-standard */
975 case 'v':
976 strncpy(label, optarg, VBUFSIZE-1);
977 label[VBUFSIZE-1] = '\0';
978 break;
979
980 /* flags supported by Dos but not mtools */
981 case 'q':
982 case 'u':
983 case 'b':
984 /*case 's': leave this for compatibility */
985 fprintf(stderr,
986 "Flag %c not supported by mtools\n",c);
987 exit(1);
988
989
990
991 /* flags added by mtools */
992 case 'F':
993 fat32 = 1;
994 break;
995
996
997 case 'S':
998 argssize = atou8(optarg) | 0x80;
999 if(argssize < 0x80)
1000 usage(1);
1001 if(argssize >= 0x87) {
1002 fprintf(stderr, "argssize must be less than 6\n");
1003 usage(1);
1004 }
1005 break;
1006
1007#ifdef USE_XDF
1008 case 'X':
1009 format_xdf = 1;
1010 break;
1011#endif
1012
1013 case '2':
1014 arguse_2m = 0xff;
1015 sectors0 = atou8(optarg);
1016 break;
1017 case '3':
1018 arguse_2m = 0x80;
1019 break;
1020
1021 case '0': /* rate on track 0 */
1022 rate_0 = atou8(optarg);
1023 break;
1024 case 'A': /* rate on other tracks */
1025 rate_any = atou8(optarg);
1026 break;
1027
1028 case 'M':
Yi Kong39bbd962022-01-09 19:41:38 +08001029 msize = atou16(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -08001030 if(msize != 512 &&
1031 msize != 1024 &&
1032 msize != 2048 &&
1033 msize != 4096) {
1034 fprintf(stderr, "Only sector sizes of 512, 1024, 2048 or 4096 bytes are allowed\n");
1035 usage(1);
1036 }
1037 break;
1038
1039 case 'N':
1040 serial = strtou32(optarg,&endptr,16);
1041 serial_set = 1;
1042 break;
1043 case 'a': /* Atari style serial number */
1044 Atari = 1;
1045 break;
1046
1047 case 'C':
1048 create = O_CREAT | O_TRUNC;
1049 break;
1050
1051 case 'H':
1052 hs = atoui(optarg);
1053 hs_set = 1;
1054 break;
1055
1056 case 'I':
Yi Kong39bbd962022-01-09 19:41:38 +08001057 fsVersion = strtou16(optarg,&endptr,0);
Alistair Delvabeaee832021-02-24 11:27:23 -08001058 break;
1059
1060 case 'c':
Yi Kong39bbd962022-01-09 19:41:38 +08001061 Fs->cluster_size = atou8(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -08001062 break;
1063
1064 case 'r':
Yi Kong39bbd962022-01-09 19:41:38 +08001065 Fs->dir_len = strtou16(optarg,&endptr,0);
Alistair Delvabeaee832021-02-24 11:27:23 -08001066 break;
1067 case 'L':
Yi Kong39bbd962022-01-09 19:41:38 +08001068 Fs->fat_len = strtoui(optarg,&endptr,0);
Alistair Delvabeaee832021-02-24 11:27:23 -08001069 break;
1070
Alistair Delvabeaee832021-02-24 11:27:23 -08001071 case 'B':
1072 bootSector = optarg;
1073 break;
1074 case 'k':
1075 keepBoot = 1;
1076 break;
1077 case 'K':
Yi Kong39bbd962022-01-09 19:41:38 +08001078 Fs->backupBoot = atou16(optarg);
1079 if(Fs->backupBoot < 2) {
Alistair Delvabeaee832021-02-24 11:27:23 -08001080 fprintf(stderr, "Backupboot must be greater than 2\n");
1081 exit(1);
1082 }
1083 break;
1084 case 'R':
Yi Kong39bbd962022-01-09 19:41:38 +08001085 Fs->fat_start = atou8(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -08001086 break;
1087 case 'h':
1088 argheads = atou16(optarg);
1089 break;
1090 case 'd':
Yi Kong39bbd962022-01-09 19:41:38 +08001091 Fs->num_fat = atou8(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -08001092 break;
1093 case 'm':
Yi Kong39bbd962022-01-09 19:41:38 +08001094 mediaDesc = strtou8(optarg,&endptr,0);
Alistair Delvabeaee832021-02-24 11:27:23 -08001095 if(*endptr)
Yi Kong39bbd962022-01-09 19:41:38 +08001096 mediaDesc = strtou8(optarg,&endptr,16);
1097 if(optarg == endptr || *endptr) {
1098 fprintf(stderr, "Bad mediadesc %s\n", optarg);
1099 exit(1);
1100 }
1101 haveMediaDesc=true;
Alistair Delvabeaee832021-02-24 11:27:23 -08001102 break;
1103 default:
1104 usage(1);
1105 }
Yi Kong39bbd962022-01-09 19:41:38 +08001106 check_number_parse_errno((char)c, optarg, endptr);
Alistair Delvabeaee832021-02-24 11:27:23 -08001107 }
1108
1109 if (argc - optind > 1)
1110 usage(1);
1111 if(argc - optind == 1) {
1112 if(!argv[optind][0] || argv[optind][1] != ':')
1113 usage(1);
1114 drive = ch_toupper(argv[argc -1][0]);
1115 } else {
1116 drive = get_default_drive();
1117 if(drive != ':') {
1118 /* Use default drive only if it is ":" (image file), as else
1119 it would be too dangerous... */
1120 fprintf(stderr, "Drive letter missing\n");
1121 exit(1);
1122 }
1123 }
1124
1125 if(argtracks && tot_sectors) {
1126 fprintf(stderr, "Only one of -t or -T may be specified\n");
1127 usage(1);
1128 }
1129
1130#ifdef USE_XDF
1131 if(create && format_xdf) {
1132 fprintf(stderr,"Create and XDF can't be used together\n");
1133 exit(1);
1134 }
1135#endif
1136
1137 /* check out a drive whose letter and parameters match */
1138 sprintf(errmsg, "Drive '%c:' not supported", drive);
Alistair Delvabeaee832021-02-24 11:27:23 -08001139 blocksize = 0;
1140 for(dev=devices;dev->drive;dev++) {
Yi Kong39bbd962022-01-09 19:41:38 +08001141 FREE(&(Fs->head.Next));
Alistair Delvabeaee832021-02-24 11:27:23 -08001142 /* drive letter */
1143 if (dev->drive != drive)
1144 continue;
1145 used_dev = *dev;
1146
1147 SET_INT(used_dev.tracks, argtracks);
1148 SET_INT(used_dev.heads, argheads);
1149 SET_INT(used_dev.sectors, argsectors);
1150 SET_INT(used_dev.use_2m, arguse_2m);
1151 SET_INT(used_dev.ssize, argssize);
1152 if(hs_set)
1153 used_dev.hidden = hs;
1154
1155 expand(dev->name, name);
1156#ifdef USING_NEW_VOLD
1157 strcpy(name, getVoldName(dev, name));
1158#endif
1159
1160#ifdef USE_XDF
Yi Kong39bbd962022-01-09 19:41:38 +08001161 if(format_xdf)
Alistair Delvabeaee832021-02-24 11:27:23 -08001162 used_dev.misc_flags |= USE_XDF_FLAG;
Yi Kong39bbd962022-01-09 19:41:38 +08001163 info.FatSize=0;
1164#endif
1165 if(tot_sectors)
1166 used_dev.tot_sectors = tot_sectors;
1167 Fs->head.Next = OpenImage(&used_dev, dev, name,
1168 O_RDWR|create, errmsg,
1169 ALWAYS_GET_GEOMETRY,
1170 O_RDWR,
1171 &maxSize, NULL,
1172#ifdef USE_XDF
1173 &info
1174#else
1175 NULL
1176#endif
1177 );
1178
1179#ifdef USE_XDF
1180 if(Fs->head.Next && info.FatSize) {
1181 if(!Fs->fat_len)
1182 Fs->fat_len = info.FatSize;
1183 if(!Fs->dir_len)
1184 Fs->dir_len = info.RootDirSize;
Alistair Delvabeaee832021-02-24 11:27:23 -08001185 }
1186#endif
1187
Yi Kong39bbd962022-01-09 19:41:38 +08001188 if (!Fs->head.Next)
Alistair Delvabeaee832021-02-24 11:27:23 -08001189 continue;
1190
Yi Kong39bbd962022-01-09 19:41:38 +08001191 if(tot_sectors)
1192 used_dev.tot_sectors = tot_sectors;
Alistair Delvabeaee832021-02-24 11:27:23 -08001193
Yi Kong39bbd962022-01-09 19:41:38 +08001194 setFsSectorSize(Fs, &used_dev, msize);
Alistair Delvabeaee832021-02-24 11:27:23 -08001195
Yi Kong39bbd962022-01-09 19:41:38 +08001196 if(!used_dev.blocksize || used_dev.blocksize < Fs->sector_size)
1197 blocksize = Fs->sector_size;
Alistair Delvabeaee832021-02-24 11:27:23 -08001198 else
1199 blocksize = used_dev.blocksize;
1200
1201 if(blocksize > MAX_SECTOR)
1202 blocksize = MAX_SECTOR;
1203
Yi Kong39bbd962022-01-09 19:41:38 +08001204 if(chs_to_totsectors(&used_dev, errmsg) < 0 ||
1205 check_if_sectors_fit(dev->tot_sectors, maxSize, blocksize,
1206 errmsg) < 0) {
1207 FREE(&Fs->head.Next);
1208 continue;
1209 }
1210
1211 if(!tot_sectors)
1212 tot_sectors = used_dev.tot_sectors;
1213
Alistair Delvabeaee832021-02-24 11:27:23 -08001214 /* do a "test" read */
1215 if (!create &&
Yi Kong39bbd962022-01-09 19:41:38 +08001216 PREADS(Fs->head.Next,
1217 &boot.characters, 0, Fs->sector_size) !=
1218 (signed int) Fs->sector_size) {
Alistair Delvabeaee832021-02-24 11:27:23 -08001219#ifdef HAVE_SNPRINTF
1220 snprintf(errmsg, sizeof(errmsg)-1,
1221 "Error reading from '%s', wrong parameters?",
1222 name);
1223#else
1224 sprintf(errmsg,
1225 "Error reading from '%s', wrong parameters?",
1226 name);
1227#endif
Yi Kong39bbd962022-01-09 19:41:38 +08001228 FREE(&Fs->head.Next);
Alistair Delvabeaee832021-02-24 11:27:23 -08001229 continue;
1230 }
1231 break;
1232 }
1233
Alistair Delvabeaee832021-02-24 11:27:23 -08001234 /* print error msg if needed */
1235 if ( dev->drive == 0 ){
Yi Kong39bbd962022-01-09 19:41:38 +08001236 FREE(&Fs->head.Next);
Alistair Delvabeaee832021-02-24 11:27:23 -08001237 fprintf(stderr,"%s: %s\n", argv[0],errmsg);
1238 exit(1);
1239 }
1240
Alistair Delvabeaee832021-02-24 11:27:23 -08001241 if(tot_sectors == 0) {
Yi Kong39bbd962022-01-09 19:41:38 +08001242 fprintf(stderr, "Number of sectors not known\n");
1243 exit(1);
Alistair Delvabeaee832021-02-24 11:27:23 -08001244 }
1245
1246 /* create the image file if needed */
1247 if (create) {
Yi Kong39bbd962022-01-09 19:41:38 +08001248 PWRITES(Fs->head.Next, &boot.characters,
1249 sectorsToBytes(Fs, tot_sectors-1),
1250 Fs->sector_size);
Alistair Delvabeaee832021-02-24 11:27:23 -08001251 }
1252
1253 /* the boot sector */
1254 if(bootSector) {
1255 int fd;
Yi Kong39bbd962022-01-09 19:41:38 +08001256 ssize_t ret;
Alistair Delvabeaee832021-02-24 11:27:23 -08001257
1258 fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
1259 if(fd < 0) {
1260 perror("open boot sector");
1261 exit(1);
1262 }
Yi Kong39bbd962022-01-09 19:41:38 +08001263 ret=read(fd, &boot.bytes, blocksize);
1264 if(ret < 0 || (size_t) ret < blocksize) {
Alistair Delvabeaee832021-02-24 11:27:23 -08001265 perror("short read on boot sector");
1266 exit(1);
1267 }
1268 keepBoot = 1;
1269 close(fd);
1270 }
1271 if(!keepBoot && !(used_dev.use_2m & 0x7f))
Yi Kong39bbd962022-01-09 19:41:38 +08001272 memset(boot.characters, '\0', Fs->sector_size);
Alistair Delvabeaee832021-02-24 11:27:23 -08001273
Yi Kong39bbd962022-01-09 19:41:38 +08001274 Fs->head.Next = buf_init(Fs->head.Next,
1275 blocksize * used_dev.heads * used_dev.sectors,
1276 blocksize * used_dev.heads * used_dev.sectors,
1277 blocksize);
Alistair Delvabeaee832021-02-24 11:27:23 -08001278
Yi Kong39bbd962022-01-09 19:41:38 +08001279 boot.boot.nfat = Fs->num_fat;
Alistair Delvabeaee832021-02-24 11:27:23 -08001280 if(!keepBoot)
1281 set_word(&boot.bytes[510], 0xaa55);
1282
1283 /* Initialize the remaining parameters */
1284 set_word(boot.boot.nsect, used_dev.sectors);
1285 set_word(boot.boot.nheads, used_dev.heads);
1286
Yi Kong39bbd962022-01-09 19:41:38 +08001287 switch(calc_fs_parameters(&used_dev, fat32, tot_sectors, Fs,
1288 &boot.boot.descr)) {
1289 case -1:
1290 fprintf(stderr, "Too few sectors\n");
1291 exit(1);
1292 case -2:
1293 fprintf(stderr, "Too few clusters for %d bit fat\n",
1294 Fs->fat_bits);
1295 exit(1);
1296 case -3:
1297 fprintf(stderr, "Too many clusters for %d bit FAT\n",
1298 Fs->fat_bits);
1299 exit(1);
1300 case -4:
1301 fprintf(stderr, "Too many clusters for fat length %d\n",
1302 Fs->fat_len);
1303 exit(1);
1304 }
Alistair Delvabeaee832021-02-24 11:27:23 -08001305
1306 if(!keepBoot && !(used_dev.use_2m & 0x7f)) {
1307 if(!used_dev.partition) {
1308 /* install fake partition table pointing to itself */
1309 struct partition *partTable=(struct partition *)
1310 (&boot.bytes[0x1ae]);
1311 setBeginEnd(&partTable[1], 0,
1312 used_dev.heads * used_dev.sectors *
1313 used_dev.tracks,
Yi Kong39bbd962022-01-09 19:41:38 +08001314 (uint8_t) used_dev.heads,
1315 (uint8_t) used_dev.sectors, 1, 0,
1316 Fs->fat_bits);
Alistair Delvabeaee832021-02-24 11:27:23 -08001317 }
1318 }
1319
Yi Kong39bbd962022-01-09 19:41:38 +08001320 if(Fs->fat_bits == 32) {
1321 set_word(boot.boot.fatlen, 0);
1322 set_dword(boot.boot.ext.fat32.bigFat, Fs->fat_len);
Alistair Delvabeaee832021-02-24 11:27:23 -08001323
Yi Kong39bbd962022-01-09 19:41:38 +08001324 Fs->clus_start = Fs->num_fat * Fs->fat_len + Fs->fat_start;
Alistair Delvabeaee832021-02-24 11:27:23 -08001325
1326 /* extension flags: mirror fats, and use #0 as primary */
1327 set_word(boot.boot.ext.fat32.extFlags,0);
1328
1329 /* fs version. What should go here? */
1330 set_word(boot.boot.ext.fat32.fsVersion,fsVersion);
1331
1332 /* root directory */
Yi Kong39bbd962022-01-09 19:41:38 +08001333 set_dword(boot.boot.ext.fat32.rootCluster, Fs->rootCluster = 2);
Alistair Delvabeaee832021-02-24 11:27:23 -08001334
1335 /* info sector */
Yi Kong39bbd962022-01-09 19:41:38 +08001336 set_word(boot.boot.ext.fat32.infoSector, Fs->infoSectorLoc = 1);
1337 Fs->infoSectorLoc = 1;
Alistair Delvabeaee832021-02-24 11:27:23 -08001338
1339 /* no backup boot sector */
Yi Kong39bbd962022-01-09 19:41:38 +08001340 set_word(boot.boot.ext.fat32.backupBoot, Fs->backupBoot);
Alistair Delvabeaee832021-02-24 11:27:23 -08001341
1342 labelBlock = & boot.boot.ext.fat32.labelBlock;
1343 } else {
Yi Kong39bbd962022-01-09 19:41:38 +08001344 set_word(boot.boot.fatlen, (uint16_t) Fs->fat_len);
1345 Fs->dir_start = Fs->num_fat * Fs->fat_len + Fs->fat_start;
1346 Fs->clus_start = Fs->dir_start + Fs->dir_len;
Alistair Delvabeaee832021-02-24 11:27:23 -08001347 labelBlock = & boot.boot.ext.old.labelBlock;
Alistair Delvabeaee832021-02-24 11:27:23 -08001348 }
1349
1350 /* Set the codepage */
Yi Kong39bbd962022-01-09 19:41:38 +08001351 Fs->cp = cp_open(used_dev.codepage);
1352 if(Fs->cp == NULL)
Alistair Delvabeaee832021-02-24 11:27:23 -08001353 exit(1);
1354
1355 if (!keepBoot)
1356 /* only zero out physdrive if we don't have a template
1357 * bootsector */
1358 labelBlock->physdrive = 0x00;
1359 labelBlock->reserved = 0;
1360 labelBlock->dos4 = 0x29;
1361
1362 if (!serial_set || Atari)
1363 init_random();
1364 if (!serial_set)
1365 serial=(uint32_t) random();
1366 set_dword(labelBlock->serial, serial);
Yi Kong39bbd962022-01-09 19:41:38 +08001367 label_name_pc(GET_DOSCONVERT((Stream_t *)Fs),
Alistair Delvabeaee832021-02-24 11:27:23 -08001368 label[0] ? label : "NO NAME ", 0,
1369 &mangled, &shortlabel);
1370 strncpy(labelBlock->label, shortlabel.base, 8);
1371 strncpy(labelBlock->label+8, shortlabel.ext, 3);
Yi Kong39bbd962022-01-09 19:41:38 +08001372 sprintf(labelBlock->fat_type, "FAT%2.2d ", Fs->fat_bits);
Alistair Delvabeaee832021-02-24 11:27:23 -08001373 labelBlock->fat_type[7] = ' ';
1374
Yi Kong39bbd962022-01-09 19:41:38 +08001375 set_word(boot.boot.secsiz, Fs->sector_size);
1376 boot.boot.clsiz = (unsigned char) Fs->cluster_size;
1377 set_word(boot.boot.nrsvsect, Fs->fat_start);
Alistair Delvabeaee832021-02-24 11:27:23 -08001378
1379 bootOffset = init_geometry_boot(&boot, &used_dev, sectors0,
1380 rate_0, rate_any,
1381 &tot_sectors, keepBoot);
1382 if(!bootOffset) {
Yi Kong39bbd962022-01-09 19:41:38 +08001383 bootOffset = ptrdiff((char *) labelBlock, (char*)boot.bytes) +
Alistair Delvabeaee832021-02-24 11:27:23 -08001384 sizeof(struct label_blk_t);
1385 }
1386 if(Atari) {
1387 boot.boot.banner[4] = 0;
1388 boot.boot.banner[5] = (char) random();
1389 boot.boot.banner[6] = (char) random();
1390 boot.boot.banner[7] = (char) random();
1391 }
1392
Yi Kong39bbd962022-01-09 19:41:38 +08001393 if(!keepBoot && bootOffset <= UINT16_MAX)
1394 inst_boot_prg(&boot, (uint16_t)bootOffset);
Alistair Delvabeaee832021-02-24 11:27:23 -08001395 /* Mimic 3.8 behavior, else 2m disk do not work (???)
1396 * luferbu@fluidsignal.com (Luis Bustamante), Fri, 14 Jun 2002
1397 */
1398 if(used_dev.use_2m & 0x7f) {
1399 boot.boot.jump[0] = 0xeb;
1400 boot.boot.jump[1] = 0x80;
1401 boot.boot.jump[2] = 0x90;
1402 }
1403 if(used_dev.use_2m & 0x7f)
Yi Kong39bbd962022-01-09 19:41:38 +08001404 Fs->num_fat = 1;
1405 if(haveMediaDesc)
Alistair Delvabeaee832021-02-24 11:27:23 -08001406 boot.boot.descr=mediaDesc;
Yi Kong39bbd962022-01-09 19:41:38 +08001407 Fs->lastFatSectorNr = 0;
1408 Fs->lastFatSectorData = 0;
1409 zero_fat(Fs, boot.boot.descr);
1410 Fs->freeSpace = Fs->num_clus;
1411 Fs->last = 2;
Alistair Delvabeaee832021-02-24 11:27:23 -08001412
1413#ifdef USE_XDF
Yi Kong39bbd962022-01-09 19:41:38 +08001414 if(used_dev.misc_flags & USE_XDF_FLAG)
Alistair Delvabeaee832021-02-24 11:27:23 -08001415 for(i=0;
Yi Kong39bbd962022-01-09 19:41:38 +08001416 i < (info.BadSectors+Fs->cluster_size-1)/Fs->cluster_size;
Alistair Delvabeaee832021-02-24 11:27:23 -08001417 i++)
Yi Kong39bbd962022-01-09 19:41:38 +08001418 fatEncode(Fs, i+2, 0xfff7);
Alistair Delvabeaee832021-02-24 11:27:23 -08001419#endif
1420
Yi Kong39bbd962022-01-09 19:41:38 +08001421 format_root(Fs, label, &boot);
1422 if(PWRITES((Stream_t *)Fs, boot.characters, 0, Fs->sector_size) < 0) {
1423 fprintf(stderr, "Error writing boot sector\n");
1424 exit(1);
Alistair Delvabeaee832021-02-24 11:27:23 -08001425 }
1426
Yi Kong39bbd962022-01-09 19:41:38 +08001427 if(Fs->fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) {
1428 if(PWRITES((Stream_t *)Fs, boot.characters,
1429 sectorsToBytes(Fs, WORD_S(ext.fat32.backupBoot)),
1430 Fs->sector_size) < 0) {
1431 fprintf(stderr, "Error writing backup boot sector\n");
1432 exit(1);
1433 }
Alistair Delvabeaee832021-02-24 11:27:23 -08001434 }
Yi Kong39bbd962022-01-09 19:41:38 +08001435
1436 FREE((Stream_t **)&Fs);
Alistair Delvabeaee832021-02-24 11:27:23 -08001437#ifdef USE_XDF
1438 if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
1439 fprintf(stderr,
1440 "Note:\n"
1441 "Remember to set the \"MTOOLS_USE_XDF\" environmental\n"
1442 "variable before accessing this disk\n\n"
1443 "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n"
1444 " export MTOOLS_USE_XDF=1\n\n"
1445 "C shell syntax (csh and tcsh):\n"
1446 " setenv MTOOLS_USE_XDF 1\n" );
1447#endif
1448 exit(0);
1449}