diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2013-01-09 19:04:18 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2013-01-09 19:04:18 +0000 |
commit | af0c3edb9706e470b45a9c8dd6debcc9e2d543c2 (patch) | |
tree | 340ee9c0f1b504061d4206d05d9fcc265c1302eb /init.c | |
download | mtools-master.tar.gz |
mtools-4.0.18HEADmtools-4.0.18master
Diffstat (limited to 'init.c')
-rw-r--r-- | init.c | 426 |
1 files changed, 426 insertions, 0 deletions
@@ -0,0 +1,426 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2006-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see <http://www.gnu.org/licenses/>. + * + * Initialize an MSDOS diskette. Read the boot sector, and switch to the + * proper floppy disk device to match the format on the disk. Sets a bunch + * of global variables. Returns 0 on success, or 1 on failure. + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "plain_io.h" +#include "floppyd_io.h" +#include "xdf_io.h" +#include "buffer.h" +#include "file_name.h" + +#define FULL_CYL + +unsigned int num_clus; /* total number of cluster */ + + +/* + * Read the boot sector. We glean the disk parameters from this sector. + */ +static int read_boot(Stream_t *Stream, union bootsector * boot, int size) +{ + short boot_sector_size; /* sector size, as stored in boot sector */ + + /* read the first sector, or part of it */ + if(!size) + size = BOOTSIZE; + if(size > MAX_BOOT) + size = MAX_BOOT; + + if (force_read(Stream, boot->characters, 0, size) != size) + return -1; + + boot_sector_size = WORD(secsiz); + if(boot_sector_size >= 0 && + boot_sector_size < sizeof(boot->bytes)) { + /* zero rest of in-memory boot sector */ + memset(boot->bytes+boot_sector_size, 0, + sizeof(boot->bytes) - boot_sector_size); + } + + return 0; +} + +static int fs_flush(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + fat_write(This); + return 0; +} + +static doscp_t *get_dosConvert(Stream_t *Stream) +{ + DeclareThis(Fs_t); + return This->cp; +} + +Class_t FsClass = { + read_pass_through, /* read */ + write_pass_through, /* write */ + fs_flush, + fs_free, /* free */ + 0, /* set geometry */ + get_data_pass_through, + 0, /* pre allocate */ + get_dosConvert, /* dosconvert */ +}; + +static int get_media_type(Stream_t *St, union bootsector *boot) +{ + int media; + + media = boot->boot.descr; + if(media < 0xf0){ + char temp[512]; + /* old DOS disk. Media descriptor in the first FAT byte */ + /* old DOS disk always have 512-byte sectors */ + if (force_read(St,temp,(mt_off_t) 512,512) == 512) + media = (unsigned char) temp[0]; + else + media = 0; + } else + media += 0x100; + return media; +} + + +Stream_t *GetFs(Stream_t *Fs) +{ + while(Fs && Fs->Class != &FsClass) + Fs = Fs->Next; + return Fs; +} + +Stream_t *find_device(char drive, int mode, struct device *out_dev, + union bootsector *boot, + char *name, int *media, mt_size_t *maxSize, + int *isRop) +{ + char errmsg[200]; + Stream_t *Stream; + struct device *dev; + int r; + int isRo=0; + + Stream = NULL; + sprintf(errmsg, "Drive '%c:' not supported", drive); + /* open the device */ + for (dev=devices; dev->name; dev++) { + FREE(&Stream); + if (dev->drive != drive) + continue; + *out_dev = *dev; + expand(dev->name,name); +#ifdef USING_NEW_VOLD + strcpy(name, getVoldName(dev, name)); +#endif + + Stream = 0; + if(out_dev->misc_flags & FLOPPYD_FLAG) { + Stream = 0; +#ifdef USE_FLOPPYD + Stream = FloppydOpen(out_dev, name, mode, + errmsg, maxSize); +#endif + } else { + +#ifdef USE_XDF + Stream = XdfOpen(out_dev, name, mode, errmsg, 0); + if(Stream) { + out_dev->use_2m = 0x7f; + if(maxSize) + *maxSize = max_off_t_31; + } +#endif + + + if (!Stream) + Stream = SimpleFileOpen(out_dev, dev, name, + isRop ? mode | O_RDWR: mode, + errmsg, 0, 1, maxSize); + + if(Stream) { + isRo=0; + } else if(isRop && + (errno == EPERM || errno == EACCES || errno == EROFS)) { + Stream = SimpleFileOpen(out_dev, dev, name, + mode | O_RDONLY, + errmsg, 0, 1, maxSize); + if(Stream) { + isRo=1; + } + } + } + + if( !Stream) + continue; + + /* read the boot sector */ + if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){ + sprintf(errmsg, + "init %c: could not read boot sector", + drive); + continue; + } + + if((*media= get_media_type(Stream, boot)) <= 0xf0 ){ + if (boot->boot.jump[2]=='L') + sprintf(errmsg, + "diskette %c: is Linux LILO, not DOS", + drive); + else + sprintf(errmsg,"init %c: non DOS media", drive); + continue; + } + + /* set new parameters, if needed */ + errno = 0; + if(SET_GEOM(Stream, out_dev, dev, *media, boot)){ + if(errno) +#ifdef HAVE_SNPRINTF + snprintf(errmsg, 199, + "Can't set disk parameters for %c: %s", + drive, strerror(errno)); +#else + sprintf(errmsg, + "Can't set disk parameters for %c: %s", + drive, strerror(errno)); +#endif + else + sprintf(errmsg, + "Can't set disk parameters for %c", + drive); + continue; + } + break; + } + + /* print error msg if needed */ + if ( dev->drive == 0 ){ + FREE(&Stream); + fprintf(stderr,"%s\n",errmsg); + return NULL; + } + if(isRop) + *isRop = isRo; + return Stream; +} + + +Stream_t *fs_init(char drive, int mode, int *isRop) +{ + int blocksize; + int media,i; + int disk_size = 0; /* In case we don't happen to set this below */ + size_t tot_sectors; + char name[EXPAND_BUF]; + int cylinder_size; + struct device dev; + mt_size_t maxSize; + + union bootsector boot; + + Fs_t *This; + + This = New(Fs_t); + if (!This) + return NULL; + + This->Direct = NULL; + This->Next = NULL; + This->refs = 1; + This->Buffer = 0; + This->Class = &FsClass; + This->preallocatedClusters = 0; + This->lastFatSectorNr = 0; + This->lastFatAccessMode = 0; + This->lastFatSectorData = 0; + This->drive = drive; + This->last = 0; + + This->Direct = find_device(drive, mode, &dev, &boot, name, &media, + &maxSize, isRop); + if(!This->Direct) + return NULL; + + This->sector_size = WORD_S(secsiz); + if(This->sector_size > MAX_SECTOR){ + fprintf(stderr,"init %c: sector size too big\n", drive); + return NULL; + } + + i = log_2(This->sector_size); + + if(i == 24) { + fprintf(stderr, + "init %c: sector size (%d) not a small power of two\n", + drive, This->sector_size); + return NULL; + } + This->sectorShift = i; + This->sectorMask = This->sector_size - 1; + + cylinder_size = dev.heads * dev.sectors; + This->serialized = 0; + if ((media & ~7) == 0xf8){ + i = media & 3; + This->cluster_size = old_dos[i].cluster_size; + tot_sectors = cylinder_size * old_dos[i].tracks; + This->fat_start = 1; + This->fat_len = old_dos[i].fat_len; + This->dir_len = old_dos[i].dir_len; + This->num_fat = 2; + This->sector_size = 512; + This->sectorShift = 9; + This->sectorMask = 511; + This->fat_bits = 12; + } else { + struct label_blk_t *labelBlock; + /* + * all numbers are in sectors, except num_clus + * (which is in clusters) + */ + tot_sectors = WORD_S(psect); + if(!tot_sectors) + tot_sectors = DWORD_S(bigsect); + + This->cluster_size = boot.boot.clsiz; + This->fat_start = WORD_S(nrsvsect); + This->fat_len = WORD_S(fatlen); + This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size; + This->num_fat = boot.boot.nfat; + + if (This->fat_len) { + labelBlock = &boot.boot.ext.old.labelBlock; + } else { + labelBlock = &boot.boot.ext.fat32.labelBlock; + } + + if(labelBlock->dos4 == 0x29) { + This->serialized = 1; + This->serial_number = _DWORD(labelBlock->serial); + } + } + + if (tot_sectors >= (maxSize >> This->sectorShift)) { + fprintf(stderr, "Big disks not supported on this architecture\n"); + exit(1); + } + + if(!mtools_skip_check && (tot_sectors % dev.sectors)){ + fprintf(stderr, + "Total number of sectors (%d) not a multiple of" + " sectors per track (%d)!\n", (int) tot_sectors, + dev.sectors); + fprintf(stderr, + "Add mtools_skip_check=1 to your .mtoolsrc file " + "to skip this test\n"); + exit(1); + } + + /* full cylinder buffering */ +#ifdef FULL_CYL + disk_size = (dev.tracks) ? cylinder_size : 512; +#else /* FULL_CYL */ + disk_size = (dev.tracks) ? dev.sectors : 512; +#endif /* FULL_CYL */ + +#if (defined OS_sysv4 && !defined OS_solaris) + /* + * The driver in Dell's SVR4 v2.01 is unreliable with large writes. + */ + disk_size = 0; +#endif /* (defined sysv4 && !defined(solaris)) */ + +#ifdef OS_linux + disk_size = cylinder_size; +#endif + +#if 1 + if(disk_size > 256) { + disk_size = dev.sectors; + if(dev.sectors % 2) + disk_size <<= 1; + } +#endif + if (disk_size % 2) + disk_size *= 2; + + if(!dev.blocksize || dev.blocksize < This->sector_size) + blocksize = This->sector_size; + else + blocksize = dev.blocksize; + if (disk_size) + This->Next = buf_init(This->Direct, + 8 * disk_size * blocksize, + disk_size * blocksize, + This->sector_size); + else + This->Next = This->Direct; + + if (This->Next == NULL) { + perror("init: allocate buffer"); + This->Next = This->Direct; + } + + /* read the FAT sectors */ + if(fat_read(This, &boot, tot_sectors, dev.use_2m&0x7f)){ + This->num_fat = 1; + FREE(&This->Next); + Free(This->Next); + return NULL; + } + + /* Set the codepage */ + This->cp = cp_open(dev.codepage); + if(This->cp == NULL) { + fs_free((Stream_t *)This); + FREE(&This->Next); + Free(This->Next); + return NULL; + } + + return (Stream_t *) This; +} + +char getDrive(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + if(This->Class != &FsClass) + return getDrive(GetFs(Stream)); + else + return This->drive; +} + +int fsPreallocateClusters(Fs_t *Fs, long size) +{ + if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1) + return -1; + + Fs->preallocatedClusters += size; + return 0; +} |