buffer.c

Go to the documentation of this file.
00001 /*
00002  * Buffer read/write module
00003  */
00004 
00005 #include "sysincludes.h"
00006 #include "msdos.h"
00007 #include "mtools.h"
00008 #include "buffer.h"
00009 
00010 typedef struct Buffer_t {
00011         Class_t *Class;
00012         int refs;
00013         Stream_t *Next;
00014         Stream_t *Buffer;
00015         
00016         size_t size;            /* size of read/write buffer */
00017         int dirty;              /* is the buffer dirty? */
00018 
00019         int sectorSize;         /* sector size: all operations happen
00020                                  * in multiples of this */
00021         int cylinderSize;       /* cylinder size: preferred alignemnt,
00022                                  * but for efficiency, less data may be read */
00023         int ever_dirty;         /* was the buffer ever dirty? */
00024         int dirty_pos;
00025         int dirty_end;
00026         mt_off_t current;               /* first sector in buffer */
00027         size_t cur_size;                /* the current size */
00028         char *buf;              /* disk read/write buffer */
00029 } Buffer_t;
00030 
00031 /*
00032  * Flush a dirty buffer to disk.  Resets Buffer->dirty to zero.
00033  * All errors are fatal.
00034  */
00035 
00036 static int _buf_flush(Buffer_t *Buffer)
00037 {
00038         int ret;
00039 
00040         if (!Buffer->Next || !Buffer->dirty)
00041                 return 0;
00042         if(Buffer->current < 0L) {
00043                 fprintf(stderr,"Should not happen\n");
00044                 return -1;
00045         }
00046 #ifdef DEBUG
00047         fprintf(stderr, "write %08x -- %02x %08x %08x\n",
00048                 Buffer,
00049                 (unsigned char) Buffer->buf[0],
00050                 Buffer->current + Buffer->dirty_pos,
00051                 Buffer->dirty_end - Buffer->dirty_pos);
00052 #endif
00053 
00054         ret = force_write(Buffer->Next, 
00055                           Buffer->buf + Buffer->dirty_pos,
00056                           Buffer->current + Buffer->dirty_pos,
00057                           Buffer->dirty_end - Buffer->dirty_pos);
00058         if(ret != Buffer->dirty_end - Buffer->dirty_pos) {
00059                 if(ret < 0)
00060                         perror("buffer_flush: write");
00061                 else
00062                         fprintf(stderr,"buffer_flush: short write\n");
00063                 return -1;
00064         }
00065         Buffer->dirty = 0;
00066         Buffer->dirty_end = 0;
00067         Buffer->dirty_pos = 0;
00068         return 0;
00069 }
00070 
00071 static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
00072 {
00073         /*fprintf(stderr, "invalidate %x\n", Buffer);*/
00074         if(Buffer->sectorSize == 32) {
00075                 fprintf(stderr, "refreshing directory\n");
00076         }
00077 
00078         if(_buf_flush(Buffer) < 0)
00079                 return -1;
00080 
00081         /* start reading at the beginning of start's sector
00082          * don't start reading too early, or we might not even reach
00083          * start */
00084         Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
00085         Buffer->cur_size = 0;
00086         return 0;
00087 }
00088 
00089 #undef OFFSET
00090 #define OFFSET (start - This->current)
00091 
00092 typedef enum position_t {
00093         OUTSIDE,
00094         APPEND,
00095         INSIDE,
00096         ERROR 
00097 } position_t;
00098 
00099 static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
00100 {
00101         if(start >= This->current &&
00102            start < This->current + This->cur_size) {
00103                 maximize(*len, This->cur_size - OFFSET);
00104                 return INSIDE;
00105         } else if(start == This->current + This->cur_size &&
00106                   This->cur_size < This->size &&
00107                   *len >= This->sectorSize) {
00108                 /* append to the buffer for this, three conditions have to
00109                  * be met:
00110                  *  1. The start falls exactly at the end of the currently
00111                  *     loaded data
00112                  *  2. There is still space
00113                  *  3. We append at least one sector
00114                  */
00115                 maximize(*len, This->size - This->cur_size);
00116                 *len = ROUND_DOWN(*len, This->sectorSize);
00117                 return APPEND;
00118         } else {
00119                 if(invalidate_buffer(This, start) < 0)
00120                         return ERROR;
00121                 maximize(*len, This->cylinderSize - OFFSET);
00122                 maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
00123                 return OUTSIDE;
00124         }
00125 }
00126 
00127 static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
00128 {
00129         size_t length;
00130         int offset;
00131         char *disk_ptr;
00132         int ret;
00133         DeclareThis(Buffer_t);  
00134 
00135         if(!len)
00136                 return 0;       
00137 
00138         /*fprintf(stderr, "buf read %x   %x %x\n", Stream, start, len);*/
00139         switch(isInBuffer(This, start, &len)) {
00140                 case OUTSIDE:
00141                 case APPEND:
00142                         /* always load until the end of the cylinder */
00143                         length = This->cylinderSize -
00144                                 (This->current + This->cur_size) % This->cylinderSize;
00145                         maximize(length, This->size - This->cur_size);
00146 
00147                         /* read it! */
00148                         ret=READS(This->Next,
00149                                   This->buf + This->cur_size,
00150                                   This->current + This->cur_size,
00151                                   length);
00152                         if ( ret < 0 )
00153                                 return ret;
00154                         This->cur_size += ret;
00155                         if (This->current+This->cur_size < start) {
00156                                 fprintf(stderr, "Short buffer fill\n");
00157                                 exit(1);
00158                         }                                                                                                                 
00159                         break;
00160                 case INSIDE:
00161                         /* nothing to do */
00162                         break;
00163                 case ERROR:
00164                         return -1;
00165         }
00166 
00167         offset = OFFSET;
00168         disk_ptr = This->buf + offset;
00169         maximize(len, This->cur_size - offset);
00170         memcpy(buf, disk_ptr, len);
00171         return len;
00172 }
00173 
00174 static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
00175 {
00176         char *disk_ptr;
00177         DeclareThis(Buffer_t);  
00178         int offset, ret;
00179 
00180         if(!len)
00181                 return 0;
00182 
00183         This->ever_dirty = 1;
00184 
00185 #ifdef DEBUG
00186         fprintf(stderr, "buf write %x   %02x %08x %08x -- %08x %08x -- %08x\n", 
00187                 Stream, (unsigned char) This->buf[0],
00188                 start, len, This->current, This->cur_size, This->size);
00189         fprintf(stderr, "%d %d %d %x %x\n", 
00190                 start == This->current + This->cur_size,
00191                 This->cur_size < This->size,
00192                 len >= This->sectorSize, len, This->sectorSize);
00193 #endif
00194         switch(isInBuffer(This, start, &len)) {
00195                 case OUTSIDE:
00196 #ifdef DEBUG
00197                         fprintf(stderr, "outside\n");
00198 #endif
00199                         if(start % This->cylinderSize || 
00200                            len < This->sectorSize) {
00201                                 size_t readSize;
00202 
00203                                 readSize = This->cylinderSize - 
00204                                         This->current % This->cylinderSize;
00205 
00206                                 ret=READS(This->Next, This->buf, This->current, readSize);
00207                                 /* read it! */
00208                                 if ( ret < 0 )
00209                                         return ret;
00210                                 This->cur_size = ret;
00211                                 /* for dosemu. Autoextend size */
00212                                 if(!This->cur_size) {
00213                                         memset(This->buf,0,readSize);
00214                                         This->cur_size = readSize;
00215                                 }
00216                                 offset = OFFSET;
00217                                 break;
00218                         }
00219                         /* FALL THROUGH */
00220                 case APPEND:
00221 #ifdef DEBUG
00222                         fprintf(stderr, "append\n");
00223 #endif
00224                         len = ROUND_DOWN(len, This->sectorSize);
00225                         offset = OFFSET;
00226                         maximize(len, This->size - offset);
00227                         This->cur_size += len;
00228                         if(This->Next->Class->pre_allocate)
00229                                 PRE_ALLOCATE(This->Next,
00230                                                          This->current + This->cur_size);
00231                         break;
00232                 case INSIDE:
00233                         /* nothing to do */
00234 #ifdef DEBUG
00235                         fprintf(stderr, "inside\n");
00236 #endif
00237                         offset = OFFSET;
00238                         maximize(len, This->cur_size - offset);
00239                         break;
00240                 case ERROR:
00241                         return -1;
00242                 default:
00243 #ifdef DEBUG
00244                         fprintf(stderr, "Should not happen\n");
00245 #endif
00246                         exit(1);
00247         }
00248 
00249         disk_ptr = This->buf + offset;
00250 
00251         /* extend if we write beyond end */
00252         if(offset + len > This->cur_size) {
00253                 len -= (offset + len) % This->sectorSize;
00254                 This->cur_size = len + offset;
00255         }
00256 
00257         memcpy(disk_ptr, buf, len);
00258         if(!This->dirty || offset < This->dirty_pos)
00259                 This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
00260         if(!This->dirty || offset + len > This->dirty_end)
00261                 This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
00262         
00263         if(This->dirty_end > This->cur_size) {
00264                 fprintf(stderr, 
00265                         "Internal error, dirty end too big %x %x %x %d %x\n",
00266                         This->dirty_end, (unsigned int) This->cur_size, (unsigned int) len, 
00267                                 (int) offset, (int) This->sectorSize);
00268                 fprintf(stderr, "offset + len + grain - 1 = %x\n",
00269                                 (int) (offset + len + This->sectorSize - 1));
00270                 fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
00271                                 (int)ROUND_DOWN(offset + len + This->sectorSize - 1,
00272                                                                 This->sectorSize));
00273                 fprintf(stderr, "This->dirty = %d\n", This->dirty);
00274                 exit(1);
00275         }
00276 
00277         This->dirty = 1;
00278         return len;
00279 }
00280 
00281 static int buf_flush(Stream_t *Stream)
00282 {
00283         int ret;
00284         DeclareThis(Buffer_t);
00285 
00286         if (!This->ever_dirty)
00287                 return 0;
00288         ret = _buf_flush(This);
00289         if(ret == 0)
00290                 This->ever_dirty = 0;
00291         return ret;
00292 }
00293 
00294 
00295 static int buf_free(Stream_t *Stream)
00296 {
00297         DeclareThis(Buffer_t);
00298 
00299         if(This->buf)
00300                 free(This->buf);
00301         This->buf = 0;
00302         return 0;
00303 }
00304 
00305 static Class_t BufferClass = {
00306         buf_read,
00307         buf_write,
00308         buf_flush,
00309         buf_free,
00310         0, /* set_geom */
00311         get_data_pass_through, /* get_data */
00312         0, /* pre-allocate */
00313 };
00314 
00315 Stream_t *buf_init(Stream_t *Next, int size, 
00316                    int cylinderSize, 
00317                    int sectorSize)
00318 {
00319         Buffer_t *Buffer;
00320         Stream_t *Stream;
00321 
00322 
00323         if(size % cylinderSize != 0) {
00324                 fprintf(stderr, "size not multiple of cylinder size\n");
00325                 exit(1);
00326         }
00327         if(cylinderSize % sectorSize != 0) {
00328                 fprintf(stderr, "cylinder size not multiple of sector size\n");
00329                 exit(1);
00330         }
00331 
00332         if(Next->Buffer){
00333                 Next->refs--;
00334                 Next->Buffer->refs++;
00335                 return Next->Buffer;
00336         }
00337 
00338         Stream = (Stream_t *) malloc (sizeof(Buffer_t));
00339         if(!Stream)
00340                 return 0;
00341         Buffer = (Buffer_t *) Stream;
00342         Buffer->buf = malloc(size);
00343         if ( !Buffer->buf){
00344                 Free(Stream);
00345                 return 0;
00346         }
00347         Buffer->size = size;
00348         Buffer->dirty = 0;
00349         Buffer->cylinderSize = cylinderSize;
00350         Buffer->sectorSize = sectorSize;
00351 
00352         Buffer->ever_dirty = 0;
00353         Buffer->dirty_pos = 0;
00354         Buffer->dirty_end = 0;
00355         Buffer->current = 0;
00356         Buffer->cur_size = 0; /* buffer currently empty */
00357 
00358         Buffer->Next = Next;
00359         Buffer->Class = &BufferClass;
00360         Buffer->refs = 1;
00361         Buffer->Buffer = 0;
00362         Buffer->Next->Buffer = (Stream_t *) Buffer;
00363         return Stream;
00364 }
00365 

Generated on Fri Apr 14 22:56:55 2006 for minix by  doxygen 1.4.6