00001
00002
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;
00017 int dirty;
00018
00019 int sectorSize;
00020
00021 int cylinderSize;
00022
00023 int ever_dirty;
00024 int dirty_pos;
00025 int dirty_end;
00026 mt_off_t current;
00027 size_t cur_size;
00028 char *buf;
00029 } Buffer_t;
00030
00031
00032
00033
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
00074 if(Buffer->sectorSize == 32) {
00075 fprintf(stderr, "refreshing directory\n");
00076 }
00077
00078 if(_buf_flush(Buffer) < 0)
00079 return -1;
00080
00081
00082
00083
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
00109
00110
00111
00112
00113
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
00139 switch(isInBuffer(This, start, &len)) {
00140 case OUTSIDE:
00141 case APPEND:
00142
00143 length = This->cylinderSize -
00144 (This->current + This->cur_size) % This->cylinderSize;
00145 maximize(length, This->size - This->cur_size);
00146
00147
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
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
00208 if ( ret < 0 )
00209 return ret;
00210 This->cur_size = ret;
00211
00212 if(!This->cur_size) {
00213 memset(This->buf,0,readSize);
00214 This->cur_size = readSize;
00215 }
00216 offset = OFFSET;
00217 break;
00218 }
00219
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
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
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,
00311 get_data_pass_through,
00312 0,
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;
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