00001
00002
00003
00004
00005
00006
00007 #include "sysincludes.h"
00008 #include "msdos.h"
00009 #include "stream.h"
00010 #include "mtools.h"
00011 #include "fsP.h"
00012 #include "plain_io.h"
00013 #include "floppyd_io.h"
00014 #include "xdf_io.h"
00015 #include "buffer.h"
00016
00017 extern int errno;
00018
00019
00020 #ifndef OS_Minix
00021 #define FULL_CYL
00022 #endif
00023
00024 unsigned int num_clus;
00025
00026
00027
00028
00029
00030 static int read_boot(Stream_t *Stream, struct bootsector * boot, int size)
00031 {
00032
00033 if(!size)
00034 size = BOOTSIZE;
00035 if(size > 1024)
00036 size = 1024;
00037
00038 if (force_read(Stream, (char *) boot, 0, size) != size)
00039 return -1;
00040 return 0;
00041 }
00042
00043 static int fs_flush(Stream_t *Stream)
00044 {
00045 DeclareThis(Fs_t);
00046
00047 fat_write(This);
00048 return 0;
00049 }
00050
00051 Class_t FsClass = {
00052 read_pass_through,
00053 write_pass_through,
00054 fs_flush,
00055 fs_free,
00056 0,
00057 get_data_pass_through,
00058 0
00059 };
00060
00061 static int get_media_type(Stream_t *St, struct bootsector *boot)
00062 {
00063 int media;
00064
00065 media = boot->descr;
00066 if(media < 0xf0){
00067 char temp[512];
00068
00069
00070 if (force_read(St,temp,(mt_off_t) 512,512) == 512)
00071 media = (unsigned char) temp[0];
00072 else
00073 media = 0;
00074 } else
00075 media += 0x100;
00076 return media;
00077 }
00078
00079
00080 Stream_t *GetFs(Stream_t *Fs)
00081 {
00082 while(Fs && Fs->Class != &FsClass)
00083 Fs = Fs->Next;
00084 return Fs;
00085 }
00086
00087 Stream_t *find_device(char *drive, int mode, struct device *out_dev,
00088 struct bootsector *boot,
00089 char *name, int *media, mt_size_t *maxSize)
00090 {
00091 char errmsg[200];
00092 Stream_t *Stream;
00093 struct device *dev;
00094 int r;
00095 #ifdef OS_Minix
00096 static char *devname;
00097 struct device onedevice[2];
00098 struct stat stbuf;
00099
00100 free(devname);
00101 devname = safe_malloc((9 + strlen(drive)) * sizeof(devname[0]));
00102 strcpy(devname, "/dev/dosX");
00103 if (isupper(drive[0]) && drive[1] == 0) {
00104
00105 devname[8]= drive[0];
00106 } else
00107 if (strchr(drive, '/') == NULL) {
00108
00109 strcpy(devname+5, drive);
00110 } else {
00111
00112 strcpy(devname, drive);
00113 }
00114 if (stat(devname, &stbuf) != -1) {
00115 memset(onedevice, 0, sizeof(onedevice));
00116 onedevice[0].name = devname;
00117 onedevice[0].drive = drive;
00118 onedevice[1].name = NULL;
00119 onedevice[1].drive = NULL;
00120 dev = onedevice;
00121 } else {
00122 dev = devices;
00123 }
00124 #else
00125 dev = devices;
00126 #endif
00127
00128 Stream = NULL;
00129 sprintf(errmsg, "Drive '%s:' not supported", drive);
00130
00131 for (; dev->name; dev++) {
00132 FREE(&Stream);
00133 if (strcmp(dev->drive, drive) != 0)
00134 continue;
00135 *out_dev = *dev;
00136 expand(dev->name,name);
00137 #ifdef USING_NEW_VOLD
00138 strcpy(name, getVoldName(dev, name));
00139 #endif
00140
00141 Stream = 0;
00142 #ifdef USE_XDF
00143 Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
00144 if(Stream) {
00145 out_dev->use_2m = 0x7f;
00146 if(maxSize)
00147 *maxSize = max_off_t_31;
00148 }
00149 #endif
00150
00151 #ifdef USE_FLOPPYD
00152 if(!Stream) {
00153 Stream = FloppydOpen(out_dev, dev, name, mode, errmsg, 0, 1);
00154 if(Stream && maxSize)
00155 *maxSize = max_off_t_31;
00156 }
00157 #endif
00158
00159 if (!Stream)
00160 Stream = SimpleFileOpen(out_dev, dev, name, mode,
00161 errmsg, 0, 1, maxSize);
00162
00163 if( !Stream)
00164 continue;
00165
00166
00167 if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
00168 sprintf(errmsg,
00169 "init %s: could not read boot sector",
00170 drive);
00171 continue;
00172 }
00173
00174 if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
00175 if (boot->jump[2]=='L')
00176 sprintf(errmsg,
00177 "diskette %s: is Linux LILO, not DOS",
00178 drive);
00179 else
00180 sprintf(errmsg,"init %s: non DOS media", drive);
00181 continue;
00182 }
00183
00184
00185 errno = 0;
00186 if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
00187 if(errno)
00188 #ifdef HAVE_SNPRINTF
00189 snprintf(errmsg, 199,
00190 "Can't set disk parameters for %s: %s",
00191 drive, strerror(errno));
00192 #else
00193 sprintf(errmsg,
00194 "Can't set disk parameters for %s: %s",
00195 drive, strerror(errno));
00196 #endif
00197 else
00198 sprintf(errmsg,
00199 "Can't set disk parameters for %s",
00200 drive);
00201 continue;
00202 }
00203 break;
00204 }
00205
00206
00207 if ( dev->drive == 0 ){
00208 FREE(&Stream);
00209 fprintf(stderr,"%s\n",errmsg);
00210 return NULL;
00211 }
00212 #ifdef OS_Minix
00213
00214 if (maxSize) *maxSize = 0xFFFFFFFFUL;
00215 #endif
00216 return Stream;
00217 }
00218
00219
00220 Stream_t *fs_init(char *drive, int mode)
00221 {
00222 int blocksize;
00223 int media,i;
00224 int nhs;
00225 int disk_size = 0;
00226 size_t tot_sectors;
00227 char name[EXPAND_BUF];
00228 int cylinder_size;
00229 struct device dev;
00230 mt_size_t maxSize;
00231
00232 struct bootsector boot0;
00233 #define boot (&boot0)
00234 Fs_t *This;
00235
00236 This = New(Fs_t);
00237 if (!This)
00238 return NULL;
00239
00240 This->Direct = NULL;
00241 This->Next = NULL;
00242 This->refs = 1;
00243 This->Buffer = 0;
00244 This->Class = &FsClass;
00245 This->preallocatedClusters = 0;
00246 This->lastFatSectorNr = 0;
00247 This->lastFatAccessMode = 0;
00248 This->lastFatSectorData = 0;
00249 This->drive = drive;
00250 This->last = 0;
00251
00252 This->Direct = find_device(drive, mode, &dev, &boot0, name, &media,
00253 &maxSize);
00254 if(!This->Direct)
00255 return NULL;
00256
00257 This->sector_size = WORD(secsiz);
00258 if(This->sector_size > MAX_SECTOR){
00259 fprintf(stderr,"init %s: sector size too big\n", drive);
00260 return NULL;
00261 }
00262
00263 i = log_2(This->sector_size);
00264
00265 if(i == 24) {
00266 fprintf(stderr,
00267 "init %c: sector size (%d) not a small power of two\n",
00268 drive, This->sector_size);
00269 return NULL;
00270 }
00271 This->sectorShift = i;
00272 This->sectorMask = This->sector_size - 1;
00273
00274
00275 cylinder_size = dev.heads * dev.sectors;
00276 if (!tot_sectors) tot_sectors = dev.tracks * cylinder_size;
00277
00278 This->serialized = 0;
00279 if ((media & ~7) == 0xf8){
00280 i = media & 3;
00281 This->cluster_size = old_dos[i].cluster_size;
00282 tot_sectors = cylinder_size * old_dos[i].tracks;
00283 This->fat_start = 1;
00284 This->fat_len = old_dos[i].fat_len;
00285 This->dir_len = old_dos[i].dir_len;
00286 This->num_fat = 2;
00287 This->sector_size = 512;
00288 This->sectorShift = 9;
00289 This->sectorMask = 511;
00290 This->fat_bits = 12;
00291 nhs = 0;
00292 } else {
00293 struct label_blk_t *labelBlock;
00294
00295
00296
00297
00298 tot_sectors = WORD(psect);
00299 if(!tot_sectors) {
00300 tot_sectors = DWORD(bigsect);
00301 nhs = DWORD(nhs);
00302 } else
00303 nhs = WORD(nhs);
00304
00305
00306 This->cluster_size = boot0.clsiz;
00307 This->fat_start = WORD(nrsvsect);
00308 This->fat_len = WORD(fatlen);
00309 This->dir_len = WORD(dirents) * MDIR_SIZE / This->sector_size;
00310 This->num_fat = boot0.nfat;
00311
00312 if (This->fat_len) {
00313 labelBlock = &boot0.ext.old.labelBlock;
00314 } else {
00315 labelBlock = &boot0.ext.fat32.labelBlock;
00316 }
00317
00318 if(labelBlock->dos4 == 0x29) {
00319 This->serialized = 1;
00320 This->serial_number = _DWORD(labelBlock->serial);
00321 }
00322 }
00323
00324 if (tot_sectors >= (maxSize >> This->sectorShift)) {
00325 fprintf(stderr, "Big disks not supported on this architecture\n");
00326 exit(1);
00327 }
00328
00329 #ifndef OS_Minix
00330
00331 if(!mtools_skip_check && (tot_sectors % dev.sectors)){
00332 fprintf(stderr,
00333 "Total number of sectors not a multiple of"
00334 " sectors per track!\n");
00335 fprintf(stderr,
00336 "Add mtools_skip_check=1 to your .mtoolsrc file "
00337 "to skip this test\n");
00338 exit(1);
00339 }
00340 #endif
00341
00342
00343 #ifdef FULL_CYL
00344 disk_size = (dev.tracks) ? cylinder_size : 512;
00345 #else
00346 disk_size = (dev.tracks) ? dev.sectors : 512;
00347 #endif
00348
00349 #if (defined OS_sysv4 && !defined OS_solaris)
00350
00351
00352
00353 disk_size = 0;
00354 #endif
00355
00356 #ifdef OS_linux
00357 disk_size = cylinder_size;
00358 #endif
00359
00360 #if 1
00361 if(disk_size > 256) {
00362 disk_size = dev.sectors;
00363 if(dev.sectors % 2)
00364 disk_size <<= 1;
00365 }
00366 #endif
00367 if (disk_size % 2)
00368 disk_size *= 2;
00369
00370 if(!dev.blocksize || dev.blocksize < This->sector_size)
00371 blocksize = This->sector_size;
00372 else
00373 blocksize = dev.blocksize;
00374 if (disk_size)
00375 This->Next = buf_init(This->Direct,
00376 8 * disk_size * blocksize,
00377 disk_size * blocksize,
00378 This->sector_size);
00379 else
00380 This->Next = This->Direct;
00381
00382 if (This->Next == NULL) {
00383 perror("init: allocate buffer");
00384 This->Next = This->Direct;
00385 }
00386
00387
00388 if(fat_read(This, &boot0, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){
00389 This->num_fat = 1;
00390 FREE(&This->Next);
00391 Free(This->Next);
00392 return NULL;
00393 }
00394 return (Stream_t *) This;
00395 }
00396
00397 char *getDrive(Stream_t *Stream)
00398 {
00399 DeclareThis(Fs_t);
00400
00401 if(This->Class != &FsClass)
00402 return getDrive(GetFs(Stream));
00403 else
00404 return This->drive;
00405 }
00406
00407 int fsPreallocateClusters(Fs_t *Fs, long size)
00408 {
00409 if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
00410 return -1;
00411
00412 Fs->preallocatedClusters += size;
00413 return 0;
00414 }