1/* Copyright 1995-2007,2009 Alain Knaff. 2 * This file is part of mtools. 3 * 4 * Mtools is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * Mtools is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>. 16 * 17 * Io to a plain file or device 18 * 19 * written by: 20 * 21 * Alain L. Knaff 22 * alain@knaff.lu 23 * 24 */ 25 26#include "sysincludes.h" 27#include "stream.h" 28#include "mtools.h" 29#include "msdos.h" 30#include "plain_io.h" 31#include "scsi.h" 32#include "partition.h" 33#include "llong.h" 34 35typedef struct SimpleFile_t { 36 Class_t *Class; 37 int refs; 38 Stream_t *Next; 39 Stream_t *Buffer; 40 struct MT_STAT statbuf; 41 int fd; 42 mt_off_t offset; 43 mt_off_t lastwhere; 44 int seekable; 45 int privileged; 46#ifdef OS_hpux 47 int size_limited; 48#endif 49 int scsi_sector_size; 50 void *extra_data; /* extra system dependant information for scsi */ 51 int swap; /* do the word swapping */ 52} SimpleFile_t; 53 54 55#include "lockdev.h" 56 57typedef int (*iofn) (int, char *, int); 58 59 60static void swap_buffer(char *buf, size_t len) 61{ 62 unsigned int i; 63 for (i=0; i<len; i+=2) { 64 char temp = buf[i]; 65 buf[i] = buf[i+1]; 66 buf[i+1] = temp; 67 } 68} 69 70 71static int file_io(Stream_t *Stream, char *buf, mt_off_t where, int len, 72 iofn io) 73{ 74 DeclareThis(SimpleFile_t); 75 int ret; 76 77 where += This->offset; 78 79 if (This->seekable && where != This->lastwhere ){ 80 if(mt_lseek( This->fd, where, SEEK_SET) < 0 ){ 81 perror("seek"); 82 This->lastwhere = (mt_off_t) -1; 83 return -1; 84 } 85 } 86 87#ifdef OS_hpux 88 /* 89 * On HP/UX, we can not write more than MAX_LEN bytes in one go. 90 * If more are written, the write fails with EINVAL 91 */ 92 #define MAX_SCSI_LEN (127*1024) 93 if(This->size_limited && len > MAX_SCSI_LEN) 94 len = MAX_SCSI_LEN; 95#endif 96 ret = io(This->fd, buf, len); 97 98#ifdef OS_hpux 99 if (ret == -1 && 100 errno == EINVAL && /* if we got EINVAL */ 101 len > MAX_SCSI_LEN) { 102 This->size_limited = 1; 103 len = MAX_SCSI_LEN; 104 ret = io(This->fd, buf, len); 105 } 106#endif 107 108 if ( ret == -1 ){ 109 perror("plain_io"); 110 This->lastwhere = (mt_off_t) -1; 111 return -1; 112 } 113 This->lastwhere = where + ret; 114 return ret; 115} 116 117 118 119static int file_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) 120{ 121 DeclareThis(SimpleFile_t); 122 123 int result = file_io(Stream, buf, where, len, (iofn) read); 124 125 if ( This->swap ) 126 swap_buffer( buf, len ); 127 return result; 128} 129 130static int file_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) 131{ 132 DeclareThis(SimpleFile_t); 133 134 if ( !This->swap ) 135 return file_io(Stream, buf, where, len, (iofn) write); 136 else { 137 int result; 138 char *swapping = malloc( len ); 139 memcpy( swapping, buf, len ); 140 swap_buffer( swapping, len ); 141 142 result = file_io(Stream, swapping, where, len, (iofn) write); 143 144 free(swapping); 145 return result; 146 } 147} 148 149static int file_flush(Stream_t *Stream) 150{ 151#if 0 152 DeclareThis(SimpleFile_t); 153 154 return fsync(This->fd); 155#endif 156 return 0; 157} 158 159static int file_free(Stream_t *Stream) 160{ 161 DeclareThis(SimpleFile_t); 162 163 if (This->fd > 2) 164 return close(This->fd); 165 else 166 return 0; 167} 168 169static int file_geom(Stream_t *Stream, struct device *dev, 170 struct device *orig_dev, 171 int media, struct bootsector *boot) 172{ 173 int ret; 174 DeclareThis(SimpleFile_t); 175 size_t tot_sectors; 176 int BootP, Infp0, InfpX, InfTm; 177 int sectors, j; 178 unsigned char sum; 179 int sect_per_track; 180 struct label_blk_t *labelBlock; 181 182 dev->ssize = 2; /* allow for init_geom to change it */ 183 dev->use_2m = 0x80; /* disable 2m mode to begin */ 184 185 if(media == 0xf0 || media >= 0x100){ 186 dev->heads = WORD(nheads); 187 dev->sectors = WORD(nsect); 188 tot_sectors = DWORD(bigsect); 189 SET_INT(tot_sectors, WORD(psect)); 190 sect_per_track = dev->heads * dev->sectors; 191 if(sect_per_track == 0) { 192 if(mtools_skip_check) { 193 /* add some fake values if sect_per_track is 194 * zero. Indeed, some atari disks lack the 195 * geometry values (i.e. have zeroes in their 196 * place). In order to avoid division by zero 197 * errors later on, plug 1 everywhere 198 */ 199 dev->heads = 1; 200 dev->sectors = 1; 201 sect_per_track = 1; 202 } else { 203 fprintf(stderr, "The devil is in the details: zero number of heads or sectors\n"); 204 exit(1); 205 } 206 } 207 tot_sectors += sect_per_track - 1; /* round size up */ 208 dev->tracks = tot_sectors / sect_per_track; 209 210 BootP = WORD(ext.old.BootP); 211 Infp0 = WORD(ext.old.Infp0); 212 InfpX = WORD(ext.old.InfpX); 213 InfTm = WORD(ext.old.InfTm); 214 215 if(WORD(fatlen)) { 216 labelBlock = &boot->ext.old.labelBlock; 217 } else { 218 labelBlock = &boot->ext.fat32.labelBlock; 219 } 220 221 if (boot->descr >= 0xf0 && 222 labelBlock->dos4 == 0x29 && 223 strncmp( boot->banner,"2M", 2 ) == 0 && 224 BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 && 225 BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && 226 Infp0 >= 76 ){ 227 for (sum=0, j=63; j < BootP; j++) 228 sum += uchr(boot)[j];/* checksum */ 229 dev->ssize = boot->jump[InfTm]; 230 if (!sum && dev->ssize <= 7){ 231 dev->use_2m = 0xff; 232 dev->ssize |= 0x80; /* is set */ 233 } 234 } 235 } else if (media >= 0xf8){ 236 media &= 3; 237 dev->heads = old_dos[media].heads; 238 dev->tracks = old_dos[media].tracks; 239 dev->sectors = old_dos[media].sectors; 240 dev->ssize = 0x80; 241 dev->use_2m = ~1; 242 } else { 243 fprintf(stderr,"Unknown media type\n"); 244 exit(1); 245 } 246 247 sectors = dev->sectors; 248 dev->sectors = dev->sectors * WORD(secsiz) / 512; 249 250#ifdef JPD 251 printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n", 252 media, dev->tracks, dev->heads, dev->sectors, dev->ssize, 253 dev->use_2m); 254#endif 255 ret = init_geom(This->fd,dev, orig_dev, &This->statbuf); 256 dev->sectors = sectors; 257#ifdef JPD 258 printf("f_geom: after init_geom(), sects=%d\n", dev->sectors); 259#endif 260 return ret; 261} 262 263 264static int file_data(Stream_t *Stream, time_t *date, mt_size_t *size, 265 int *type, int *address) 266{ 267 DeclareThis(SimpleFile_t); 268 269 if(date) 270 *date = This->statbuf.st_mtime; 271 if(size) 272 *size = This->statbuf.st_size; 273 if(type) 274 *type = S_ISDIR(This->statbuf.st_mode); 275 if(address) 276 *address = 0; 277 return 0; 278} 279 280/* ZIP or other scsi device on Solaris or SunOS system. 281 Since Sun won't accept a non-Sun label on a scsi disk, we must 282 bypass Sun's disk interface and use low-level SCSI commands to read 283 or write the ZIP drive. We thus replace the file_read and file_write 284 routines with our own scsi_read and scsi_write routines, that use the 285 uscsi ioctl interface. By James Dugal, jpd@usl.edu, 11-96. Tested 286 under Solaris 2.5 and SunOS 4.3.1_u1 using GCC. 287 288 Note: the mtools.conf entry for a ZIP drive would look like this: 289(solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4 FAT=16 nodelay exclusive scsi=& 290(sunos) drive C: file="/dev/rsd5c" partition=4 FAT=16 nodelay exclusive scsi=1 291 292 Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl. SunOS is 293 happy if we just have access to the device, so making mtools sgid to a 294 group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine. 295 */ 296 297#define MAXBLKSPERCMD 255 298 299static void scsi_init(SimpleFile_t *This) 300{ 301 int fd = This->fd; 302 unsigned char cdb[10],buf[8]; 303 304 memset(cdb, 0, sizeof cdb); 305 memset(buf,0, sizeof(buf)); 306 cdb[0]=SCSI_READ_CAPACITY; 307 if (scsi_cmd(fd, (unsigned char *)cdb, 308 sizeof(cdb), SCSI_IO_READ, buf, sizeof(buf), This->extra_data)==0) 309 { 310 This->scsi_sector_size= 311 ((unsigned)buf[5]<<16)|((unsigned)buf[6]<<8)|(unsigned)buf[7]; 312 if (This->scsi_sector_size != 512) 313 fprintf(stderr," (scsi_sector_size=%d)\n",This->scsi_sector_size); 314 } 315} 316 317static int scsi_io(Stream_t *Stream, char *buf, 318 mt_off_t where, size_t len, int rwcmd) 319{ 320 unsigned int firstblock, nsect; 321 int clen,r; 322 size_t max; 323 off_t offset; 324 unsigned char cdb[10]; 325 DeclareThis(SimpleFile_t); 326 327 firstblock=truncBytes32((where + This->offset)/This->scsi_sector_size); 328 /* 512,1024,2048,... bytes/sector supported */ 329 offset=truncBytes32(where + This->offset - 330 firstblock*This->scsi_sector_size); 331 nsect=(offset+len+This->scsi_sector_size-1)/ This->scsi_sector_size; 332#if defined(OS_sun) && defined(OS_i386) 333 if (This->scsi_sector_size>512) 334 firstblock*=This->scsi_sector_size/512; /* work around a uscsi bug */ 335#endif /* sun && i386 */ 336 337 if (len>512) { 338 /* avoid buffer overruns. The transfer MUST be smaller or 339 * equal to the requested size! */ 340 while (nsect*This->scsi_sector_size>len) 341 --nsect; 342 if(!nsect) { 343 fprintf(stderr,"Scsi buffer too small\n"); 344 exit(1); 345 } 346 if(rwcmd == SCSI_IO_WRITE && offset) { 347 /* there seems to be no memmove before a write */ 348 fprintf(stderr,"Unaligned write\n"); 349 exit(1); 350 } 351 /* a better implementation should use bounce buffers. 352 * However, in normal operation no buffer overruns or 353 * unaligned writes should happen anyways, as the logical 354 * sector size is (hopefully!) equal to the physical one 355 */ 356 } 357 358 359 max = scsi_max_length(); 360 361 if (nsect > max) 362 nsect=max; 363 364 /* set up SCSI READ/WRITE command */ 365 memset(cdb, 0, sizeof cdb); 366 367 switch(rwcmd) { 368 case SCSI_IO_READ: 369 cdb[0] = SCSI_READ; 370 break; 371 case SCSI_IO_WRITE: 372 cdb[0] = SCSI_WRITE; 373 break; 374 } 375 376 cdb[1] = 0; 377 378 if (firstblock > 0x1fffff || nsect > 0xff) { 379 /* I suspect that the ZIP drive also understands Group 1 380 * commands. If that is indeed true, we may chose Group 1 381 * more agressively in the future */ 382 383 cdb[0] |= SCSI_GROUP1; 384 clen=10; /* SCSI Group 1 cmd */ 385 386 /* this is one of the rare case where explicit coding is 387 * more portable than macros... The meaning of scsi command 388 * bytes is standardised, whereas the preprocessor macros 389 * handling it might be not... */ 390 391 cdb[2] = (unsigned char) (firstblock >> 24) & 0xff; 392 cdb[3] = (unsigned char) (firstblock >> 16) & 0xff; 393 cdb[4] = (unsigned char) (firstblock >> 8) & 0xff; 394 cdb[5] = (unsigned char) firstblock & 0xff; 395 cdb[6] = 0; 396 cdb[7] = (unsigned char) (nsect >> 8) & 0xff; 397 cdb[8] = (unsigned char) nsect & 0xff; 398 cdb[9] = 0; 399 } else { 400 clen = 6; /* SCSI Group 0 cmd */ 401 cdb[1] |= (unsigned char) ((firstblock >> 16) & 0x1f); 402 cdb[2] = (unsigned char) ((firstblock >> 8) & 0xff); 403 cdb[3] = (unsigned char) firstblock & 0xff; 404 cdb[4] = (unsigned char) nsect; 405 cdb[5] = 0; 406 } 407 408 if(This->privileged) 409 reclaim_privs(); 410 411 r=scsi_cmd(This->fd, (unsigned char *)cdb, clen, rwcmd, buf, 412 nsect*This->scsi_sector_size, This->extra_data); 413 414 if(This->privileged) 415 drop_privs(); 416 417 if(r) { 418 perror(rwcmd == SCSI_IO_READ ? "SCMD_READ" : "SCMD_WRITE"); 419 return -1; 420 } 421#ifdef JPD 422 printf("finished %u for %u\n", firstblock, nsect); 423#endif 424 425#ifdef JPD 426 printf("zip: read or write OK\n"); 427#endif 428 if (offset>0) memmove(buf,buf+offset,nsect*This->scsi_sector_size-offset); 429 if (len==256) return 256; 430 else if (len==512) return 512; 431 else return nsect*This->scsi_sector_size-offset; 432} 433 434static int scsi_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) 435{ 436 437#ifdef JPD 438 printf("zip: to read %d bytes at %d\n", len, where); 439#endif 440 return scsi_io(Stream, buf, where, len, SCSI_IO_READ); 441} 442 443static int scsi_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) 444{ 445#ifdef JPD 446 Printf("zip: to write %d bytes at %d\n", len, where); 447#endif 448 return scsi_io(Stream, buf, where, len, SCSI_IO_WRITE); 449} 450 451static Class_t ScsiClass = { 452 scsi_read, 453 scsi_write, 454 file_flush, 455 file_free, 456 file_geom, 457 file_data, 458 0 /* pre-allocate */ 459}; 460 461 462static Class_t SimpleFileClass = { 463 file_read, 464 file_write, 465 file_flush, 466 file_free, 467 file_geom, 468 file_data, 469 0 /* pre_allocate */ 470}; 471 472 473Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev, 474 const char *name, int mode, char *errmsg, 475 int mode2, int locked, mt_size_t *maxSize) 476{ 477 SimpleFile_t *This; 478#ifdef __EMX__ 479HFILE FileHandle; 480ULONG Action; 481APIRET rc; 482#endif 483 This = New(SimpleFile_t); 484 if (!This){ 485 printOom(); 486 return 0; 487 } 488 This->scsi_sector_size = 512; 489 This->seekable = 1; 490#ifdef OS_hpux 491 This->size_limited = 0; 492#endif 493 This->Class = &SimpleFileClass; 494 if (!name || strcmp(name,"-") == 0 ){ 495 if (mode == O_RDONLY) 496 This->fd = 0; 497 else 498 This->fd = 1; 499 This->seekable = 0; 500 This->refs = 1; 501 This->Next = 0; 502 This->Buffer = 0; 503 if (MT_FSTAT(This->fd, &This->statbuf) < 0) { 504 Free(This); 505 if(errmsg) 506#ifdef HAVE_SNPRINTF 507 snprintf(errmsg,199,"Can't stat -: %s", 508 strerror(errno)); 509#else 510 sprintf(errmsg,"Can't stat -: %s", 511 strerror(errno)); 512#endif 513 return NULL; 514 } 515 516 return (Stream_t *) This; 517 } 518 519 520 if(dev) { 521 if(!(mode2 & NO_PRIV)) 522 This->privileged = IS_PRIVILEGED(dev); 523 mode |= dev->mode; 524 } 525 526 precmd(dev); 527 if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) 528 reclaim_privs(); 529 530#ifdef __EMX__ 531#define DOSOPEN_FLAGS (OPEN_FLAGS_DASD | OPEN_FLAGS_WRITE_THROUGH | \ 532 OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_RANDOM | \ 533 OPEN_FLAGS_NO_CACHE) 534#define DOSOPEN_FD_ACCESS (OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE) 535#define DOSOPEN_HD_ACCESS (OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY) 536 537 if (isalpha(*name) && (*(name+1) == ':')) { 538 rc = DosOpen( 539 name, &FileHandle, &Action, 0L, FILE_NORMAL, 540 OPEN_ACTION_OPEN_IF_EXISTS, DOSOPEN_FLAGS | 541 (IS_NOLOCK(dev)?DOSOPEN_HD_ACCESS:DOSOPEN_FD_ACCESS), 542 0L); 543#if DEBUG 544 if (rc != NO_ERROR) fprintf (stderr, "DosOpen() returned %d\n", rc); 545#endif 546 if (!IS_NOLOCK(dev)) { 547 rc = DosDevIOCtl( 548 FileHandle, 0x08L, DSK_LOCKDRIVE, 0, 0, 0, 0, 0, 0); 549#if DEBUG 550 if (rc != NO_ERROR) fprintf (stderr, "DosDevIOCtl() returned %d\n", rc); 551#endif 552 } 553 if (rc == NO_ERROR) 554 This->fd = _imphandle(FileHandle); else This->fd = -1; 555 } else 556#endif 557 { 558 if (IS_SCSI(dev)) 559 This->fd = scsi_open(name, mode, IS_NOLOCK(dev)?0444:0666, 560 &This->extra_data); 561 else 562 This->fd = open(name, mode | O_LARGEFILE | O_BINARY, 563 IS_NOLOCK(dev)?0444:0666); 564 } 565 566 if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) 567 drop_privs(); 568 569 if (This->fd < 0) { 570 Free(This); 571 if(errmsg) 572#ifdef HAVE_SNPRINTF 573 snprintf(errmsg, 199, "Can't open %s: %s", 574 name, strerror(errno)); 575#else 576 sprintf(errmsg, "Can't open %s: %s", 577 name, strerror(errno)); 578#endif 579 return NULL; 580 } 581 582 if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) 583 closeExec(This->fd); 584 585#ifdef __EMX__ 586 if (*(name+1) != ':') 587#endif 588 if (MT_FSTAT(This->fd, &This->statbuf) < 0){ 589 Free(This); 590 if(errmsg) { 591#ifdef HAVE_SNPRINTF 592 snprintf(errmsg,199,"Can't stat %s: %s", 593 name, strerror(errno)); 594#else 595 if(strlen(name) > 50) { 596 sprintf(errmsg,"Can't stat file: %s", 597 strerror(errno)); 598 } else { 599 sprintf(errmsg,"Can't stat %s: %s", 600 name, strerror(errno)); 601 } 602#endif 603 } 604 return NULL; 605 } 606#ifndef __EMX__ 607#ifndef __CYGWIN__ 608#ifndef OS_mingw32msvc 609 /* lock the device on writes */ 610 if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) { 611 if(errmsg) 612#ifdef HAVE_SNPRINTF 613 snprintf(errmsg,199, 614 "plain floppy: device \"%s\" busy (%s):", 615 dev ? dev->name : "unknown", strerror(errno)); 616#else 617 sprintf(errmsg, 618 "plain floppy: device \"%s\" busy (%s):", 619 (dev && strlen(dev->name) < 50) ? 620 dev->name : "unknown", strerror(errno)); 621#endif 622 623 close(This->fd); 624 Free(This); 625 return NULL; 626 } 627#endif 628#endif 629#endif 630 /* set default parameters, if needed */ 631 if (dev){ 632 if ((!IS_MFORMAT_ONLY(dev) && dev->tracks) && 633 init_geom(This->fd, dev, orig_dev, &This->statbuf)){ 634 close(This->fd); 635 Free(This); 636 if(errmsg) 637 sprintf(errmsg,"init: set default params"); 638 return NULL; 639 } 640 This->offset = (mt_off_t) dev->offset; 641 } else 642 This->offset = 0; 643 644 This->refs = 1; 645 This->Next = 0; 646 This->Buffer = 0; 647 648 if(maxSize) { 649 if (IS_SCSI(dev)) { 650 *maxSize = MAX_OFF_T_B(31+log_2(This->scsi_sector_size)); 651 } else { 652 *maxSize = max_off_t_seek; 653 } 654 if(This->offset > *maxSize) { 655 close(This->fd); 656 Free(This); 657 if(errmsg) 658 sprintf(errmsg,"init: Big disks not supported"); 659 return NULL; 660 } 661 662 *maxSize -= This->offset; 663 } 664 /* partitioned drive */ 665 666 /* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/ 667 /* or similar drive that must be accessed by low-level scsi commands */ 668 /* AK: introduce new "scsi=1" statement to specifically set 669 * this option. Indeed, there could conceivably be partitioned 670 * devices where low level scsi commands will not be needed */ 671 if(IS_SCSI(dev)) { 672 This->Class = &ScsiClass; 673 if(This->privileged) 674 reclaim_privs(); 675 scsi_init(This); 676 if(This->privileged) 677 drop_privs(); 678 } 679 680 This->swap = DO_SWAP( dev ); 681 682 if(!(mode2 & NO_OFFSET) && 683 dev && (dev->partition > 4 || dev->partition < 0)) 684 fprintf(stderr, 685 "Invalid partition %d (must be between 0 and 4), ignoring it\n", 686 dev->partition); 687 688 while(!(mode2 & NO_OFFSET) && 689 dev && dev->partition && dev->partition <= 4) { 690 int has_activated; 691 unsigned int last_end, j; 692 unsigned char buf[2048]; 693 struct partition *partTable=(struct partition *)(buf+ 0x1ae); 694 size_t partOff; 695 696 /* read the first sector, or part of it */ 697 if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512) 698 break; 699 if( _WORD(buf+510) != 0xaa55) 700 break; 701 702 partOff = BEGIN(partTable[dev->partition]); 703 if (maxSize) { 704 if (partOff > *maxSize >> 9) { 705 close(This->fd); 706 Free(This); 707 if(errmsg) 708 sprintf(errmsg,"init: Big disks not supported"); 709 return NULL; 710 } 711 *maxSize -= (mt_off_t) partOff << 9; 712 } 713 714 This->offset += (mt_off_t) partOff << 9; 715 if(!partTable[dev->partition].sys_ind) { 716 if(errmsg) 717 sprintf(errmsg, 718 "init: non-existant partition"); 719 close(This->fd); 720 Free(This); 721 return NULL; 722 } 723 724 if(!dev->tracks) { 725 dev->heads = head(partTable[dev->partition].end)+1; 726 dev->sectors = sector(partTable[dev->partition].end); 727 dev->tracks = cyl(partTable[dev->partition].end) - 728 cyl(partTable[dev->partition].start)+1; 729 } 730 dev->hidden= 731 dev->sectors*head(partTable[dev->partition].start) + 732 sector(partTable[dev->partition].start)-1; 733 if(!mtools_skip_check && 734 consistencyCheck((struct partition *)(buf+0x1ae), 0, 0, 735 &has_activated, &last_end, &j, dev, 0)) { 736 fprintf(stderr, 737 "Warning: inconsistent partition table\n"); 738 fprintf(stderr, 739 "Possibly unpartitioned device\n"); 740 fprintf(stderr, 741 "\n*** Maybe try without partition=%d in " 742 "device definition ***\n\n", 743 dev->partition); 744 fprintf(stderr, 745 "If this is a PCMCIA card, or a disk " 746 "partitioned on another computer, this " 747 "message may be in error: add " 748 "mtools_skip_check=1 to your .mtoolsrc " 749 "file to suppress this warning\n"); 750 751 } 752 break; 753 /* NOTREACHED */ 754 } 755 756 This->lastwhere = -This->offset; 757 /* provoke a seek on those devices that don't start on a partition 758 * boundary */ 759 760 return (Stream_t *) This; 761} 762 763int get_fd(Stream_t *Stream) 764{ 765 Class_t *clazz; 766 DeclareThis(SimpleFile_t); 767 clazz = This->Class; 768 if(clazz != &ScsiClass && 769 clazz != &SimpleFileClass) 770 return -1; 771 else 772 return This->fd; 773} 774 775void *get_extra_data(Stream_t *Stream) 776{ 777 DeclareThis(SimpleFile_t); 778 779 return This->extra_data; 780} 781