• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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