1 /* Copyright 1986-1992 Emmet P. Gray.
2 * Copyright 1996-2002,2006-2009 Alain Knaff.
3 * This file is part of mtools.
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.
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.
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/>.
18 * Initialize an MSDOS diskette. Read the boot sector, and switch to the
19 * proper floppy disk device to match the format on the disk. Sets a bunch
20 * of global variables. Returns 0 on success, or 1 on failure.
23 #include "sysincludes.h"
29 #include "floppyd_io.h"
32 #include "file_name.h"
36 unsigned int num_clus; /* total number of cluster */
40 * Read the boot sector. We glean the disk parameters from this sector.
42 static int read_boot(Stream_t *Stream, union bootsector * boot, int size)
44 short boot_sector_size; /* sector size, as stored in boot sector */
46 /* read the first sector, or part of it */
52 if (force_read(Stream, boot->characters, 0, size) != size)
55 boot_sector_size = WORD(secsiz);
56 if(boot_sector_size >= 0 &&
57 boot_sector_size < sizeof(boot->bytes)) {
58 /* zero rest of in-memory boot sector */
59 memset(boot->bytes+boot_sector_size, 0,
60 sizeof(boot->bytes) - boot_sector_size);
66 static int fs_flush(Stream_t *Stream)
74 static doscp_t *get_dosConvert(Stream_t *Stream)
81 read_pass_through, /* read */
82 write_pass_through, /* write */
86 get_data_pass_through,
88 get_dosConvert, /* dosconvert */
91 static int get_media_type(Stream_t *St, union bootsector *boot)
95 media = boot->boot.descr;
98 /* old DOS disk. Media descriptor in the first FAT byte */
99 /* old DOS disk always have 512-byte sectors */
100 if (force_read(St,temp,(mt_off_t) 512,512) == 512)
101 media = (unsigned char) temp[0];
110 Stream_t *GetFs(Stream_t *Fs)
112 while(Fs && Fs->Class != &FsClass)
117 Stream_t *find_device(char drive, int mode, struct device *out_dev,
118 union bootsector *boot,
119 char *name, int *media, mt_size_t *maxSize,
129 sprintf(errmsg, "Drive '%c:' not supported", drive);
130 /* open the device */
131 for (dev=devices; dev->name; dev++) {
133 if (dev->drive != drive)
136 expand(dev->name,name);
137 #ifdef USING_NEW_VOLD
138 strcpy(name, getVoldName(dev, name));
142 if(out_dev->misc_flags & FLOPPYD_FLAG) {
145 Stream = FloppydOpen(out_dev, name, mode,
151 Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
153 out_dev->use_2m = 0x7f;
155 *maxSize = max_off_t_31;
161 Stream = SimpleFileOpen(out_dev, dev, name,
162 isRop ? mode | O_RDWR: mode,
163 errmsg, 0, 1, maxSize);
168 (errno == EPERM || errno == EACCES || errno == EROFS)) {
169 Stream = SimpleFileOpen(out_dev, dev, name,
171 errmsg, 0, 1, maxSize);
181 /* read the boot sector */
182 if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
184 "init %c: could not read boot sector",
189 if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
190 if (boot->boot.jump[2]=='L')
192 "diskette %c: is Linux LILO, not DOS",
195 sprintf(errmsg,"init %c: non DOS media", drive);
199 /* set new parameters, if needed */
201 if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
204 snprintf(errmsg, 199,
205 "Can't set disk parameters for %c: %s",
206 drive, strerror(errno));
209 "Can't set disk parameters for %c: %s",
210 drive, strerror(errno));
214 "Can't set disk parameters for %c",
221 /* print error msg if needed */
222 if ( dev->drive == 0 ){
224 fprintf(stderr,"%s\n",errmsg);
233 Stream_t *fs_init(char drive, int mode, int *isRop)
237 int disk_size = 0; /* In case we don't happen to set this below */
239 char name[EXPAND_BUF];
244 union bootsector boot;
256 This->Class = &FsClass;
257 This->preallocatedClusters = 0;
258 This->lastFatSectorNr = 0;
259 This->lastFatAccessMode = 0;
260 This->lastFatSectorData = 0;
264 This->Direct = find_device(drive, mode, &dev, &boot, name, &media,
269 This->sector_size = WORD_S(secsiz);
270 if(This->sector_size > MAX_SECTOR){
271 fprintf(stderr,"init %c: sector size too big\n", drive);
275 i = log_2(This->sector_size);
279 "init %c: sector size (%d) not a small power of two\n",
280 drive, This->sector_size);
283 This->sectorShift = i;
284 This->sectorMask = This->sector_size - 1;
286 cylinder_size = dev.heads * dev.sectors;
287 This->serialized = 0;
288 if ((media & ~7) == 0xf8){
290 This->cluster_size = old_dos[i].cluster_size;
291 tot_sectors = cylinder_size * old_dos[i].tracks;
293 This->fat_len = old_dos[i].fat_len;
294 This->dir_len = old_dos[i].dir_len;
296 This->sector_size = 512;
297 This->sectorShift = 9;
298 This->sectorMask = 511;
301 struct label_blk_t *labelBlock;
303 * all numbers are in sectors, except num_clus
304 * (which is in clusters)
306 tot_sectors = WORD_S(psect);
308 tot_sectors = DWORD_S(bigsect);
310 This->cluster_size = boot.boot.clsiz;
311 This->fat_start = WORD_S(nrsvsect);
312 This->fat_len = WORD_S(fatlen);
313 This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size;
314 This->num_fat = boot.boot.nfat;
317 labelBlock = &boot.boot.ext.old.labelBlock;
319 labelBlock = &boot.boot.ext.fat32.labelBlock;
322 if(labelBlock->dos4 == 0x29) {
323 This->serialized = 1;
324 This->serial_number = _DWORD(labelBlock->serial);
328 if (tot_sectors >= (maxSize >> This->sectorShift)) {
329 fprintf(stderr, "Big disks not supported on this architecture\n");
333 if(!mtools_skip_check && (tot_sectors % dev.sectors)){
335 "Total number of sectors (%d) not a multiple of"
336 " sectors per track (%d)!\n", (int) tot_sectors,
339 "Add mtools_skip_check=1 to your .mtoolsrc file "
340 "to skip this test\n");
344 /* full cylinder buffering */
346 disk_size = (dev.tracks) ? cylinder_size : 512;
348 disk_size = (dev.tracks) ? dev.sectors : 512;
349 #endif /* FULL_CYL */
351 #if (defined OS_sysv4 && !defined OS_solaris)
353 * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
356 #endif /* (defined sysv4 && !defined(solaris)) */
359 disk_size = cylinder_size;
363 if(disk_size > 256) {
364 disk_size = dev.sectors;
372 if(!dev.blocksize || dev.blocksize < This->sector_size)
373 blocksize = This->sector_size;
375 blocksize = dev.blocksize;
377 This->Next = buf_init(This->Direct,
378 8 * disk_size * blocksize,
379 disk_size * blocksize,
382 This->Next = This->Direct;
384 if (This->Next == NULL) {
385 perror("init: allocate buffer");
386 This->Next = This->Direct;
389 /* read the FAT sectors */
390 if(fat_read(This, &boot, tot_sectors, dev.use_2m&0x7f)){
397 /* Set the codepage */
398 This->cp = cp_open(dev.codepage);
399 if(This->cp == NULL) {
400 fs_free((Stream_t *)This);
406 return (Stream_t *) This;
409 char getDrive(Stream_t *Stream)
413 if(This->Class != &FsClass)
414 return getDrive(GetFs(Stream));
419 int fsPreallocateClusters(Fs_t *Fs, long size)
421 if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
424 Fs->preallocatedClusters += size;