home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / plain_io.c < prev    next >
Text File  |  1997-11-13  |  14KB  |  602 lines

  1. /*
  2.  * Io to a plain file or device
  3.  *
  4.  * written by:
  5.  *
  6.  * Alain L. Knaff            
  7.  * Alain.Knaff@poboxes.com
  8.  *
  9.  */
  10.  
  11. #include "sysincludes.h"
  12. #include "stream.h"
  13. #include "mtools.h"
  14. #include "msdos.h"
  15. #include "plain_io.h"
  16. #include "patchlevel.h"
  17. #include "scsi.h"
  18. #include "partition.h"
  19. typedef struct SimpleFile_t {
  20.     Class_t *Class;
  21.     int refs;
  22.     Stream_t *Next;
  23.     Stream_t *Buffer;
  24.     struct stat stat;
  25.     int fd;
  26.     int offset;
  27.     int lastwhere;
  28.     int seekable;
  29.     int privileged;
  30. } SimpleFile_t;
  31.  
  32. #ifdef _OSK
  33. #define S_ISDIR(x) (x&S_IFDIR)
  34. #define S_ISREG(x) (!(x&S_IFDIR))
  35. #endif
  36.  
  37. /*
  38.  * Create an advisory lock on the device to prevent concurrent writes.
  39.  * Uses either lockf, flock, or fcntl locking methods.  See the Makefile
  40.  * and the Configure files for how to specify the proper method.
  41.  */
  42.  
  43. int lock_dev(int fd, int mode, struct device *dev)
  44. {
  45. #ifndef _OSK
  46. #if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
  47.     /**/
  48. #else /* FLOCK */
  49.  
  50. #if (defined(HAVE_LOCKF) && defined(F_TLOCK))
  51.     /**/
  52. #else /* LOCKF */
  53.  
  54. #if (defined(F_SETLK) && defined(F_WRLCK))
  55.     struct flock flk;
  56.  
  57. #endif /* FCNTL */
  58. #endif /* LOCKF */
  59. #endif /* FLOCK */
  60.  
  61.     if(dev && dev->nolock)
  62.         return 0;
  63.  
  64. #if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
  65.     if (flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB) < 0)
  66. #else /* FLOCK */
  67.  
  68. #if (defined(HAVE_LOCKF) && defined(F_TLOCK))
  69.     if (mode && lockf(fd, F_TLOCK, 0) < 0)
  70. #else /* LOCKF */
  71.  
  72. #if (defined(F_SETLK) && defined(F_WRLCK))
  73.     flk.l_type = mode ? F_WRLCK : F_RDLCK;
  74.     flk.l_whence = 0;
  75.     flk.l_start = 0L;
  76.     flk.l_len = 0L;
  77.  
  78.     if (fcntl(fd, F_SETLK, &flk) < 0)
  79. #endif /* FCNTL */
  80. #endif /* LOCKF */
  81. #endif /* FLOCK */
  82.     {
  83.         if(errno == EINVAL
  84. #ifdef  EOPNOTSUPP 
  85.            || errno ==  EOPNOTSUPP
  86. #endif
  87.           )
  88.             return 0;
  89.         else
  90.             return 1;
  91.     }
  92. #endif
  93.     return 0;
  94. }
  95.  
  96. typedef int (*iofn) (int, char *, int);
  97.  
  98. static int file_io(Stream_t *Stream, char *buf, int where, int len,
  99.            iofn io)
  100. {
  101.     DeclareThis(SimpleFile_t);
  102.     int ret;
  103.  
  104.     where += This->offset;
  105.     if (This->seekable && where != This->lastwhere ){
  106.         if(lseek( This->fd, where, SEEK_SET) < 0 ){
  107.             perror("seek");
  108.             This->lastwhere = -1;
  109.             return -1;
  110.         }
  111.     }
  112.     ret = io(This->fd, buf, len);
  113.     if ( ret == -1 ){
  114.         perror("read");
  115.         This->lastwhere = -1;
  116.         return -1;
  117.     }
  118.     This->lastwhere = where + ret;
  119.     return ret;
  120. }
  121.     
  122.  
  123.  
  124. static int file_read(Stream_t *Stream, char *buf, off_t where, size_t len)
  125. {    
  126.     return file_io(Stream, buf, where, len, (iofn) read);
  127. }
  128.  
  129. static int file_write(Stream_t *Stream, char *buf, off_t where, size_t len)
  130. {
  131.     return file_io(Stream, buf, where, len, (iofn) write);
  132. }
  133.  
  134. static int file_flush(Stream_t *Stream)
  135. {
  136. #if 0
  137.     DeclareThis(SimpleFile_t);
  138.  
  139.     return fsync(This->fd);
  140. #endif
  141.     return 0;
  142. }
  143.  
  144. static int file_free(Stream_t *Stream)
  145. {
  146.     DeclareThis(SimpleFile_t);
  147.  
  148.     if (This->fd > 2)
  149.         return close(This->fd);
  150.     else
  151.         return 0;
  152. }
  153.  
  154. static int file_geom(Stream_t *Stream, struct device *dev, 
  155.              struct device *orig_dev,
  156.              int media, struct bootsector *boot)
  157. {
  158.     int ret;
  159.     DeclareThis(SimpleFile_t);
  160.     size_t tot_sectors;
  161.     int BootP, Infp0, InfpX, InfTm;
  162.     int sectors, j;
  163.     unsigned char sum;
  164.     int sect_per_track;
  165.  
  166.     dev->ssize = 2; /* allow for init_geom to change it */
  167.     dev->use_2m = 0x80; /* disable 2m mode to begin */
  168.  
  169.     if(media == 0xf0 || media >= 0x100){        
  170.         dev->heads = CHAR(nheads);
  171.         dev->sectors = CHAR(nsect);
  172.         tot_sectors = DWORD(bigsect);
  173.         SET_INT(tot_sectors, WORD(psect));
  174.         sect_per_track = dev->heads * dev->sectors;
  175.         tot_sectors += sect_per_track - 1; /* round size up */
  176.         dev->tracks = tot_sectors / sect_per_track;
  177.  
  178.         BootP = WORD(ext.old.BootP);
  179.         Infp0 = WORD(ext.old.Infp0);
  180.         InfpX = WORD(ext.old.InfpX);
  181.         InfTm = WORD(ext.old.InfTm);
  182.         
  183.         if (boot->descr >= 0xf0 &&
  184.             boot->ext.old.dos4 == 0x29 &&
  185.             WORD(fatlen) &&
  186.             strncmp( boot->banner,"2M", 2 ) == 0 &&
  187.             BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 &&
  188.             BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && 
  189.             Infp0 >= 76 ){
  190.             for (sum=0, j=63; j < BootP; j++) 
  191.                 sum += boot->jump[j];/* checksum */
  192.             dev->ssize = boot->jump[InfTm];
  193.             if (!sum && dev->ssize <= 7){
  194.                 dev->use_2m = 0xff;
  195.                 dev->ssize |= 0x80; /* is set */
  196.             }
  197.         }
  198.     } else if (media >= 0xf8){
  199.         media &= 3;
  200.         dev->heads = old_dos[media].heads;
  201.         dev->tracks = old_dos[media].tracks;
  202.         dev->sectors = old_dos[media].sectors;
  203.         dev->ssize = 0x80;
  204.         dev->use_2m = ~1;
  205.     } else {
  206.         fprintf(stderr,"Unknown media type\n");
  207.         exit(1);
  208.     }
  209.  
  210.     sectors = dev->sectors;
  211.     dev->sectors = dev->sectors * WORD(secsiz) / 512;
  212.  
  213. #ifdef JPD
  214.     printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n",
  215.            media, dev->tracks, dev->heads, dev->sectors, dev->ssize,
  216.            dev->use_2m);
  217. #endif
  218.     ret = init_geom(This->fd,dev, orig_dev, &This->stat);
  219.     dev->sectors = sectors;
  220. #ifdef JPD
  221.     printf("f_geom: after init_geom(), sects=%d\n", dev->sectors);
  222. #endif
  223.     return ret;
  224. }
  225.  
  226.  
  227. static int file_data(Stream_t *Stream, long *date, size_t *size,
  228.              int *type, int *address)
  229. {
  230.     DeclareThis(SimpleFile_t);
  231.  
  232.     if(date)
  233.         *date = This->stat.st_mtime;
  234.     if(size)
  235.         *size = This->stat.st_size;
  236.     if(type)
  237.         *type = S_ISDIR(This->stat.st_mode);
  238.     if(address)
  239.         *address = 0;
  240.     return 0;
  241. }
  242.  
  243. /* ZIP or other scsi device on Solaris or SunOS system.
  244.    Since Sun won't accept a non-Sun label on a scsi disk, we must
  245.    bypass Sun's disk interface and use low-level SCSI commands to read
  246.    or write the ZIP drive.  We thus replace the file_read and file_write
  247.    routines with our own scsi_read and scsi_write routines, that use the
  248.    uscsi ioctl interface.  By James Dugal, jpd@usl.edu, 11-96.  Tested
  249.    under Solaris 2.5 and SunOS 4.3.1_u1 using GCC.
  250.  
  251.    Note: the mtools.conf entry for a ZIP drive would look like this:
  252. (solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4  FAT=16 nodelay  exclusive scsi=&
  253. (sunos) drive C: file="/dev/rsd5c" partition=4  FAT=16 nodelay  exclusive scsi=1
  254.  
  255.    Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl.  SunOS is
  256.    happy if we just have access to the device, so making mtools sgid to a
  257.    group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine.
  258.  */
  259.  
  260. #define MAXBLKSPERCMD 255
  261.  
  262. static void scsi_init(int);
  263. static scsi_sector_size=512;
  264.  
  265. static void scsi_init(int fd)
  266. {
  267. #ifndef _OSK
  268.    unsigned char cdb[6],buf[255];
  269.  
  270.    memset(&cdb, 0, sizeof cdb);
  271.    memset(buf,0,255);
  272.    cdb[0]=SCSI_MODE_SENSE;
  273.    cdb[4]=255;
  274.    if (scsi_cmd(fd, (unsigned char *)cdb, 6, SCSI_IO_READ, buf,255)==0)
  275.    {
  276.        scsi_sector_size=
  277.        ((unsigned)buf[9]<<16)|((unsigned)buf[10]<<8)|(unsigned)buf[11];
  278.        if (scsi_sector_size>512)
  279.        fprintf(stderr,"  (scsi_sector_size=%d)\n",scsi_sector_size);
  280.    }
  281. #endif
  282. }
  283.  
  284. int scsi_io(Stream_t *Stream, char *buf,  off_t where, size_t len, int rwcmd)
  285. {
  286. #ifndef _OSK
  287.     unsigned int firstblock, nsect;
  288.     int clen,r,max,offset;
  289.     unsigned char cdb[10];
  290.     DeclareThis(SimpleFile_t);
  291.         
  292.     firstblock=(where + This->offset)/scsi_sector_size;
  293.     /* 512,1024,2048,... bytes/sector supported */
  294.     offset=where + This->offset - firstblock*scsi_sector_size;
  295.     nsect=(offset+len+scsi_sector_size-1)/scsi_sector_size;
  296. #if defined(sun) && defined(i386)
  297.     if (scsi_sector_size>512)
  298.         firstblock*=scsi_sector_size/512; /* work around a uscsi bug */
  299. #endif /* sun && i386 */
  300.  
  301.     if (len>512) {
  302.         /* avoid buffer overruns. The transfer MUST be smaller or
  303.         * equal to the requested size! */
  304.         while (nsect*scsi_sector_size>len)
  305.             --nsect;
  306.         if(!nsect) {            
  307.             fprintf(stderr,"Scsi buffer too small\n");
  308.             exit(1);
  309.         }
  310.         if(SCSI_IO_WRITE && offset) {
  311.             /* there seems to be no memmove before a write */
  312.             fprintf(stderr,"Unaligned write\n");
  313.             exit(1);
  314.         }
  315.         /* a better implementation should use bounce buffers.
  316.          * However, in normal operation no buffer overruns or
  317.          * unaligned writes should happen anyways, as the logical
  318.          * sector size is (hopefully!) equal to the physical one
  319.          */
  320.     }
  321.  
  322.  
  323.     max = scsi_max_length();
  324.     
  325.     if (nsect > max)
  326.         nsect=max;
  327.     
  328.     /* set up SCSI READ/WRITE command */
  329.     memset(&cdb, 0, sizeof cdb);
  330.  
  331.     switch(rwcmd) {
  332.         case SCSI_IO_READ:
  333.             cdb[0] = SCSI_READ;
  334.             break;
  335.         case SCSI_IO_WRITE:
  336.             cdb[0] = SCSI_WRITE;
  337.             break;
  338.     }
  339.  
  340.     cdb[1] = 0;
  341.  
  342.     if (firstblock > 0x1fffff || nsect > 0xff) {
  343.         /* I suspect that the ZIP drive also understands Group 1
  344.          * commands. If that is indeed true, we may chose Group 1
  345.          * more agressively in the future */
  346.  
  347.         cdb[0] |= SCSI_GROUP1;
  348.         clen=10; /* SCSI Group 1 cmd */
  349.  
  350.         /* this is one of the rare case where explicit coding is
  351.          * more portable than macros... The meaning of scsi command
  352.          * bytes is standardised, whereas the preprocessor macros
  353.          * handling it might be not... */
  354.  
  355.         cdb[2] = (unsigned char) (firstblock >> 24) & 0xff;
  356.         cdb[3] = (unsigned char) (firstblock >> 16) & 0xff;
  357.         cdb[4] = (unsigned char) (firstblock >> 8) & 0xff;
  358.         cdb[5] = (unsigned char) firstblock & 0xff;
  359.         cdb[6] = 0;
  360.         cdb[7] = (unsigned char) (nsect >> 8) & 0xff;
  361.         cdb[8] = (unsigned char) nsect & 0xff;
  362.         cdb[9] = 0;
  363.     } else {
  364.         clen = 6; /* SCSI Group 0 cmd */
  365.         cdb[1] |= (unsigned char) ((firstblock >> 16) & 0x1f);
  366.         cdb[2] = (unsigned char) ((firstblock >> 8) & 0xff);
  367.         cdb[3] = (unsigned char) firstblock & 0xff;
  368.         cdb[4] = (unsigned char) nsect;
  369.         cdb[5] = 0;
  370.     }
  371.     
  372.     if(This->privileged)
  373.         reclaim_privs();
  374.  
  375.     r=scsi_cmd(This->fd, (unsigned char *)cdb, clen, rwcmd, buf,
  376.            nsect*scsi_sector_size);
  377.  
  378.     if(This->privileged)
  379.         drop_privs();
  380.  
  381.     if(r) {
  382.         perror(rwcmd == SCSI_IO_READ ? "SCMD_READ" : "SCMD_WRITE");
  383.         return -1;
  384.     }
  385. #ifdef JPD
  386.     printf("finished %u for %u\n", firstblock, nsect);
  387. #endif
  388.  
  389. #ifdef JPD
  390.     printf("zip: read or write OK\n");
  391. #endif
  392.     if (offset>0) memmove(buf,buf+offset,nsect*scsi_sector_size-offset);
  393.     if (len==256) return 256;
  394.     else if (len==512) return 512;
  395.     else return nsect*scsi_sector_size-offset;
  396. #else
  397.     return -1;
  398. #endif
  399. }
  400.  
  401. int scsi_read(Stream_t *Stream, char *buf, off_t where, size_t len)
  402. {
  403.     
  404. #ifdef JPD
  405.     printf("zip: to read %d bytes at %d\n", len, where);
  406. #endif
  407.     return scsi_io(Stream, buf, where, len, SCSI_IO_READ);
  408. }
  409.  
  410. int scsi_write(Stream_t *Stream, char *buf, off_t where, size_t len)
  411. {
  412. #ifdef JPD
  413.     Printf("zip: to write %d bytes at %d\n", len, where);
  414. #endif
  415.     return scsi_io(Stream, buf, where, len, SCSI_IO_WRITE);
  416. }
  417.  
  418. static Class_t ScsiClass = {
  419.     scsi_read, 
  420.     scsi_write,
  421.     file_flush,
  422.     file_free,
  423.     file_geom,
  424.     file_data
  425. };
  426.  
  427.  
  428. static Class_t SimpleFileClass = {
  429.     file_read, 
  430.     file_write,
  431.     file_flush,
  432.     file_free,
  433.     file_geom,
  434.     file_data
  435. };
  436.  
  437.  
  438. Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
  439.              const char *name, int mode, char *errmsg, int mode2)
  440. {
  441.     SimpleFile_t *This;
  442.  
  443.     This = New(SimpleFile_t);
  444.     if (!This){
  445.         fprintf(stderr,"Out of memory error\n");
  446.         exit(1);
  447.     }
  448.     This->seekable = 1;
  449.  
  450.     This->Class = &SimpleFileClass;
  451.     if (!name || strcmp(name,"-") == 0 ){
  452.         if (mode == O_RDONLY)
  453.             This->fd = 0;
  454.         else
  455.             This->fd = 1;
  456.         This->seekable = 0;
  457.         This->refs = 1;
  458.         This->Next = 0;
  459.         This->Buffer = 0;
  460.         return (Stream_t *) This;
  461.     }
  462.  
  463.     
  464.     if(dev) {
  465.         if(!(mode2 & NO_PRIV))
  466.             This->privileged = dev->privileged;
  467.         mode |= dev->mode;
  468.     }
  469.  
  470. #ifndef _OSK
  471.     precmd(dev);
  472.     if(dev && dev->privileged && !(mode2 & NO_PRIV))
  473.         reclaim_privs();
  474.  
  475.     This->fd = open(name, mode, 0666);
  476. #else
  477.     if ( mode == (O_WRONLY | O_CREAT | O_TRUNC) )
  478.        This->fd = creat(name, mode & 0xff);
  479.     else {
  480.        This->fd = open(name, mode & 0xff);
  481.        if ( This->fd == -1 )
  482.           This->fd = creat(name, mode & 0xff);
  483.        else
  484.           if ( mode & O_TRUNC )
  485. #ifdef _UCC
  486.              _os_ss_size(This->fd, 0);
  487. #else
  488.              _ss_size(This->fd, 0);
  489. #endif
  490.     }
  491. #endif
  492.  
  493.     if(dev && dev->privileged && !(mode2 & NO_PRIV))
  494.         drop_privs();
  495.         
  496.     if (This->fd < 0) {
  497.         Free(This);
  498.         if(errmsg)
  499.             sprintf(errmsg, "Can't open %s: %s",
  500.                 name, strerror(errno));
  501.         return NULL;
  502.     }
  503.  
  504.     closeExec(This->fd);
  505.  
  506. /* this didn't work on BeOS, so I just removed it */
  507. #ifdef __BEOS__
  508.     if(strncmp("/dev/",name,5))
  509. #endif
  510.     if (fstat(This->fd, &This->stat) < 0){
  511.         Free(This);
  512.         if(errmsg)
  513.             sprintf(errmsg,"Can't stat %s: %s", 
  514.                 name, strerror(errno));
  515.  
  516.         return NULL;
  517.     }
  518.  
  519.     /* lock the device on writes */
  520.     if (lock_dev(This->fd, mode == O_RDWR, dev)) {
  521.         close(This->fd);
  522.         Free(This);
  523.         if(errmsg)
  524.             sprintf(errmsg,
  525.                 "plain floppy: device \"%s\" busy:",
  526.                 dev->name);
  527.         return NULL;
  528.     }
  529.         
  530.     /* set default parameters, if needed */
  531.     if (dev){
  532.         if (init_geom(This->fd, dev, orig_dev, &This->stat)){
  533.             close(This->fd);
  534.             Free(This);
  535.             if(errmsg)
  536.                 sprintf(errmsg,"init: set default params");
  537.             return NULL;
  538.         }
  539.         This->offset = dev->offset;
  540.     } else
  541.         This->offset = 0;
  542.  
  543.     This->lastwhere = -This->offset;
  544.     /* provoke a seek on those devices that don't start on a partition
  545.      * boundary */
  546.  
  547.     This->refs = 1;
  548.     This->Next = 0;
  549.     This->Buffer = 0;
  550.  
  551.     /* partitioned drive */
  552.  
  553.     /* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/
  554.     /* or similar drive that must be accessed by low-level scsi commands */
  555.     /* AK: introduce new "scsi=1" statement to specifically set
  556.      * this option. Indeed, there could conceivably be partitioned
  557.      * devices where low level scsi commands will not be needed */
  558.     if(dev && dev->scsi) {
  559.         This->Class = &ScsiClass;
  560.         scsi_init(This->fd);
  561.     }
  562.     while(!(mode2 & NO_OFFSET) &&
  563.           dev && dev->partition && dev->partition <= 4) {
  564.         unsigned char buf[2048];
  565.         struct partition *partTable=(struct partition *)(buf+ 0x1ae);
  566.         
  567.         /* read the first sector, or part of it */
  568.         if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512)
  569.             break;
  570.         if( _WORD(buf+510) != 0xaa55)
  571.             break;
  572.         This->offset += BEGIN(partTable[dev->partition]) << 9;
  573.         if(!partTable[dev->partition].sys_ind) {
  574.             if(errmsg)
  575.                 sprintf(errmsg,
  576.                     "init: non-existant partition");
  577.             close(This->fd);
  578.             Free(This);
  579.             return NULL;
  580.         }
  581.  
  582.         if(!dev->tracks) {
  583.             dev->heads = head(partTable[dev->partition].end)+1;
  584.             dev->sectors = sector(partTable[dev->partition].end);
  585.             dev->tracks = cyl(partTable[dev->partition].end) -
  586.                 cyl(partTable[dev->partition].start)+1;
  587.         }
  588.         dev->hidden=dev->sectors*head(partTable[dev->partition].start);
  589.         break;
  590.         /* NOTREACHED */
  591.     }
  592.     return (Stream_t *) This;
  593. }
  594.  
  595. int get_fd(Stream_t *Stream)
  596. {
  597.     DeclareThis(SimpleFile_t);
  598.     
  599.     return This->fd;
  600. }
  601.  
  602.