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