home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / buffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-03  |  4.4 KB  |  204 lines

  1. /*
  2.  * Buffer read/write module
  3.  */
  4.  
  5. #include "sysincludes.h"
  6. #include "msdos.h"
  7. #include "mtools.h"
  8. #include "buffer.h"
  9.  
  10. typedef struct Buffer_t {
  11.     Class_t *Class;
  12.     int refs;
  13.     Stream_t *Next;
  14.     Stream_t *Buffer;
  15.     
  16.     unsigned int size;         /* size of read/write buffer */
  17.     int dirty;               /* is the buffer dirty? */
  18.     int grain;
  19.     int grain2;
  20.     int ever_dirty;               /* was the buffer ever dirty? */
  21.     int dirty_pos;
  22.     int dirty_end;
  23.     long current;        /* first sector in buffer */
  24.     long cur_size;        /* the current size */
  25.     char *buf;        /* disk read/write buffer */
  26. } Buffer_t;
  27.  
  28. /*
  29.  * Flush a dirty buffer to disk.  Resets Buffer->dirty to zero.
  30.  * All errors are fatal.
  31.  */
  32.  
  33. static int _buf_flush(Buffer_t *Buffer)
  34. {
  35.     int ret;
  36.  
  37.     if (!Buffer->Next || Buffer->current < 0L || !Buffer->dirty)
  38.         return 0;
  39.     ret = force_write(Buffer->Next, 
  40.               Buffer->buf + Buffer->dirty_pos,
  41.               Buffer->current + Buffer->dirty_pos,
  42.               Buffer->dirty_end - Buffer->dirty_pos);
  43.     if(ret != Buffer->dirty_end - Buffer->dirty_pos) {
  44.         if(ret < 0)
  45.             perror("buffer_flush: write");
  46.         else
  47.             fprintf(stderr,"buffer_flush: short write");
  48.         return -1;
  49.     }
  50.     Buffer->dirty = 0;
  51.     return 0;
  52. }
  53.  
  54. static void invalidate_buffer(Buffer_t *Buffer, int start)
  55. {
  56.     _buf_flush(Buffer);
  57.     Buffer->current = start - start % Buffer->grain;
  58.     Buffer->cur_size = 0;
  59. }
  60.  
  61. static int buf_read(Stream_t *Stream, char *buf, int start, int len)
  62. {
  63.     int length, offset;
  64.     char *disk_ptr;
  65.     int ret;
  66.     DeclareThis(Buffer_t);    
  67.  
  68.     if(!len)
  69.         return 0;    
  70.     /* a "cache" miss, load buffer */
  71.     if (start < This->current || start >= This->current + This->cur_size) {
  72.         invalidate_buffer(This, start);
  73.  
  74.         /* always load aligned */
  75.         length = This->size - (This->current % This->grain2);
  76.  
  77.         /* read it! */
  78.         ret=This->Next->Class->read(This->Next,
  79.                         This->buf,
  80.                         This->current,
  81.                         length);
  82.         if ( ret < 0 )
  83.             return ret;
  84.         This->cur_size = ret;
  85.     }
  86.  
  87.     offset = start - This->current;
  88.     disk_ptr = This->buf + offset;
  89.     maximize(&len, This->cur_size - offset);
  90.     memcpy(buf, disk_ptr, len);
  91.     return len;
  92. }
  93.  
  94. static int buf_write(Stream_t *Stream, char *buf, int start, int len)
  95. {
  96.     char *disk_ptr;
  97.     DeclareThis(Buffer_t);    
  98.     int offset, ret;
  99.  
  100.     if(!len)
  101.         return 0;
  102.  
  103.     This->ever_dirty = 1;
  104.  
  105.     /* a cache miss... */
  106.     if (start < This->current ||
  107.         start >= This->current + This->size ||
  108.         start > This->current + This->cur_size ||
  109.         (start == This->current + This->cur_size &&
  110.          (len < This->grain || !(start % This->grain2)))) {
  111.         invalidate_buffer(This, start);
  112.                if(start % This->grain || len < This->grain) {
  113.             /* read it! */
  114.             ret=This->Next->Class->read(This->Next,
  115.                             This->buf,
  116.                             This->current,
  117.                             This->grain);
  118.             if ( ret < 0 )
  119.                 return ret;
  120.             This->cur_size = ret;
  121.         }
  122.     }
  123.  
  124.     maximize(&len,This->size - (start % This->size));
  125.     offset = start - This->current;
  126.     if(len + offset > This->cur_size) {
  127.         /* enforce aligned writes */
  128.         len -= (len + offset ) % This->grain;
  129.         This->cur_size = len + offset;
  130.     }
  131.     disk_ptr = This->buf + offset;
  132.     memcpy(disk_ptr, buf, len);
  133.     if(!This->dirty || disk_ptr - This->buf < This->dirty_pos){
  134.         This->dirty_pos = disk_ptr - This->buf;
  135.         This->dirty_pos -= This->dirty_pos % This->grain;
  136.     }
  137.     if(!This->dirty || disk_ptr - This->buf + len > This->dirty_end){
  138.         This->dirty_end = disk_ptr - This->buf + len;
  139.         This->dirty_end += This->grain - 1;
  140.         This->dirty_end -= This->dirty_end % This->grain;
  141.     }
  142.     This->dirty = 1;
  143.     return len;
  144. }
  145.  
  146. static int buf_flush(Stream_t *Stream)
  147. {
  148.     int ret;
  149.     DeclareThis(Buffer_t);    
  150.  
  151.     if (!This->ever_dirty)
  152.         return 0;
  153.     ret = _buf_flush(This);
  154.     This->ever_dirty = 0;
  155.     return ret;
  156. }
  157.  
  158. static Class_t BufferClass = {
  159.     buf_read,
  160.     buf_write,
  161.     buf_flush,
  162.     0, /* buf_free */
  163.     0, /* set_geom */
  164.     get_data_pass_through, /* get_data */
  165. };
  166.  
  167. Stream_t *buf_init(Stream_t *Next, int size, int grain, int grain2)
  168. {
  169.     Buffer_t *Buffer;
  170.     Stream_t *Stream;
  171.  
  172. #if 0
  173.     return Next;
  174. #else
  175.  
  176.     if(Next->Buffer){
  177.         Next->refs--;
  178.         Next->Buffer->refs++;
  179.         return Next->Buffer;
  180.     }
  181.  
  182.     Stream = (Stream_t *) malloc (sizeof(Buffer_t));
  183.     Buffer = (Buffer_t *) Stream;
  184.     Buffer->buf = malloc(size);
  185.     Buffer->size = size;
  186.     Buffer->grain = grain;
  187.     Buffer->grain2 = grain2;
  188.     Buffer->cur_size = 0; /* buffer currently empty */
  189.     Buffer->dirty = 0;
  190.     Buffer->ever_dirty = 0;
  191.     if ( !Buffer->buf){
  192.         Free(Stream);
  193.         return 0;
  194.     }
  195.     Buffer->Next = Next;
  196.     Buffer->Class = &BufferClass;
  197.     Buffer->refs = 1;
  198.     Buffer->Buffer = 0;
  199.     Buffer->Next->Buffer = (Stream_t *) Buffer;
  200.     return Stream;
  201. #endif
  202. }
  203.  
  204.