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