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 /* read the first sector, or part of it */
50 if (force_read(Stream, boot->characters, 0, size) != size)
55 static int fs_flush(Stream_t *Stream)
63 static doscp_t *get_dosConvert(Stream_t *Stream)
70 read_pass_through, /* read */
71 write_pass_through, /* write */
75 get_data_pass_through,
77 get_dosConvert, /* dosconvert */
80 static int get_media_type(Stream_t *St, union bootsector *boot)
84 media = boot->boot.descr;
87 /* old DOS disk. Media descriptor in the first FAT byte */
88 /* old DOS disk always have 512-byte sectors */
89 if (force_read(St,temp,(mt_off_t) 512,512) == 512)
90 media = (unsigned char) temp[0];
99 Stream_t *GetFs(Stream_t *Fs)
101 while(Fs && Fs->Class != &FsClass)
106 Stream_t *find_device(char drive, int mode, struct device *out_dev,
107 union bootsector *boot,
108 char *name, int *media, mt_size_t *maxSize,
118 sprintf(errmsg, "Drive '%c:' not supported", drive);
119 /* open the device */
120 for (dev=devices; dev->name; dev++) {
122 if (dev->drive != drive)
125 expand(dev->name,name);
126 #ifdef USING_NEW_VOLD
127 strcpy(name, getVoldName(dev, name));
131 if(out_dev->misc_flags & FLOPPYD_FLAG) {
134 Stream = FloppydOpen(out_dev, dev, name, mode,
136 if(Stream && maxSize)
137 *maxSize = max_off_t_31;
142 Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
144 out_dev->use_2m = 0x7f;
146 *maxSize = max_off_t_31;
152 Stream = SimpleFileOpen(out_dev, dev, name,
153 isRop ? mode | O_RDWR: mode,
154 errmsg, 0, 1, maxSize);
159 (errno == EPERM || errno == EACCES || errno == EROFS)) {
160 Stream = SimpleFileOpen(out_dev, dev, name,
162 errmsg, 0, 1, maxSize);
172 /* read the boot sector */
173 if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
175 "init %c: could not read boot sector",
180 if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
181 if (boot->boot.jump[2]=='L')
183 "diskette %c: is Linux LILO, not DOS",
186 sprintf(errmsg,"init %c: non DOS media", drive);
190 /* set new parameters, if needed */
192 if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
195 snprintf(errmsg, 199,
196 "Can't set disk parameters for %c: %s",
197 drive, strerror(errno));
200 "Can't set disk parameters for %c: %s",
201 drive, strerror(errno));
205 "Can't set disk parameters for %c",
212 /* print error msg if needed */
213 if ( dev->drive == 0 ){
215 fprintf(stderr,"%s\n",errmsg);
224 Stream_t *fs_init(char drive, int mode, int *isRop)
229 int disk_size = 0; /* In case we don't happen to set this below */
231 char name[EXPAND_BUF];
236 union bootsector boot;
248 This->Class = &FsClass;
249 This->preallocatedClusters = 0;
250 This->lastFatSectorNr = 0;
251 This->lastFatAccessMode = 0;
252 This->lastFatSectorData = 0;
256 This->Direct = find_device(drive, mode, &dev, &boot, name, &media,
261 This->sector_size = WORD_S(secsiz);
262 if(This->sector_size > MAX_SECTOR){
263 fprintf(stderr,"init %c: sector size too big\n", drive);
267 i = log_2(This->sector_size);
271 "init %c: sector size (%d) not a small power of two\n",
272 drive, This->sector_size);
275 This->sectorShift = i;
276 This->sectorMask = This->sector_size - 1;
279 cylinder_size = dev.heads * dev.sectors;
280 This->serialized = 0;
281 if ((media & ~7) == 0xf8){
283 This->cluster_size = old_dos[i].cluster_size;
284 tot_sectors = cylinder_size * old_dos[i].tracks;
286 This->fat_len = old_dos[i].fat_len;
287 This->dir_len = old_dos[i].dir_len;
289 This->sector_size = 512;
290 This->sectorShift = 9;
291 This->sectorMask = 511;
295 struct label_blk_t *labelBlock;
297 * all numbers are in sectors, except num_clus
298 * (which is in clusters)
300 tot_sectors = WORD_S(psect);
302 tot_sectors = DWORD_S(bigsect);
308 This->cluster_size = boot.boot.clsiz;
309 This->fat_start = WORD_S(nrsvsect);
310 This->fat_len = WORD_S(fatlen);
311 This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size;
312 This->num_fat = boot.boot.nfat;
315 labelBlock = &boot.boot.ext.old.labelBlock;
317 labelBlock = &boot.boot.ext.fat32.labelBlock;
320 if(labelBlock->dos4 == 0x29) {
321 This->serialized = 1;
322 This->serial_number = _DWORD(labelBlock->serial);
326 if (tot_sectors >= (maxSize >> This->sectorShift)) {
327 fprintf(stderr, "Big disks not supported on this architecture\n");
331 if(!mtools_skip_check && (tot_sectors % dev.sectors)){
333 "Total number of sectors (%d) not a multiple of"
334 " sectors per track (%d)!\n", (int) tot_sectors,
337 "Add mtools_skip_check=1 to your .mtoolsrc file "
338 "to skip this test\n");
342 /* full cylinder buffering */
344 disk_size = (dev.tracks) ? cylinder_size : 512;
346 disk_size = (dev.tracks) ? dev.sectors : 512;
347 #endif /* FULL_CYL */
349 #if (defined OS_sysv4 && !defined OS_solaris)
351 * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
354 #endif /* (defined sysv4 && !defined(solaris)) */
357 disk_size = cylinder_size;
361 if(disk_size > 256) {
362 disk_size = dev.sectors;
370 if(!dev.blocksize || dev.blocksize < This->sector_size)
371 blocksize = This->sector_size;
373 blocksize = dev.blocksize;
375 This->Next = buf_init(This->Direct,
376 8 * disk_size * blocksize,
377 disk_size * blocksize,
380 This->Next = This->Direct;
382 if (This->Next == NULL) {
383 perror("init: allocate buffer");
384 This->Next = This->Direct;
387 /* read the FAT sectors */
388 if(fat_read(This, &boot, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){
395 /* Set the codepage */
396 This->cp = cp_open(dev.codepage);
397 if(This->cp == NULL) {
398 fs_free((Stream_t *)This);
404 return (Stream_t *) This;
407 char getDrive(Stream_t *Stream)
411 if(This->Class != &FsClass)
412 return getDrive(GetFs(Stream));
417 int fsPreallocateClusters(Fs_t *Fs, long size)
419 if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
422 Fs->preallocatedClusters += size;