aboutsummaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c172
1 files changed, 93 insertions, 79 deletions
diff --git a/buffer.c b/buffer.c
index e129ac4..9b40727 100644
--- a/buffer.c
+++ b/buffer.c
@@ -23,11 +23,8 @@
#include "buffer.h"
typedef struct Buffer_t {
- Class_t *Class;
- int refs;
- Stream_t *Next;
- Stream_t *Buffer;
-
+ struct Stream_t head;
+
size_t size; /* size of read/write buffer */
int dirty; /* is the buffer dirty? */
@@ -38,11 +35,28 @@ typedef struct Buffer_t {
int ever_dirty; /* was the buffer ever dirty? */
size_t dirty_pos;
size_t dirty_end;
- mt_off_t current; /* first sector in buffer */
- size_t cur_size; /* the current size */
+ mt_off_t current; /* first sector in buffer */
+ size_t cur_size; /* the current size */
char *buf; /* disk read/write buffer */
} Buffer_t;
+/* Convert position relative to buffer to absolute position */
+static mt_off_t abs_pos(Buffer_t *Buffer, size_t rel) {
+ return Buffer->current + (mt_off_t) rel;
+}
+
+/* End of currently valid buffer */
+static mt_off_t cur_end(Buffer_t *Buffer) {
+ return abs_pos(Buffer, Buffer->cur_size);
+}
+
+/* distance from absolute position until next full cylinder. If position already
+ * *is* on a full cylinder boundary, return size of full cylinder */
+static size_t pos_to_next_full_cyl(Buffer_t *Buffer, mt_off_t pos) {
+ return Buffer->cylinderSize -
+ (size_t) (pos % (mt_off_t) Buffer->cylinderSize);
+}
+
/*
* Flush a dirty buffer to disk. Resets Buffer->dirty to zero.
* All errors are fatal.
@@ -50,14 +64,14 @@ typedef struct Buffer_t {
static int _buf_flush(Buffer_t *Buffer)
{
- int ret;
+ ssize_t ret;
- if (!Buffer->Next || !Buffer->dirty)
+#ifdef HAVE_ASSERT_H
+ assert(Buffer->head.Next != NULL);
+#endif
+
+ if (!Buffer->dirty)
return 0;
- if(Buffer->current < 0L) {
- fprintf(stderr,"Should not happen\n");
- return -1;
- }
#ifdef DEBUG
fprintf(stderr, "write %08x -- %02x %08x %08x\n",
Buffer,
@@ -66,15 +80,17 @@ static int _buf_flush(Buffer_t *Buffer)
Buffer->dirty_end - Buffer->dirty_pos);
#endif
- ret = force_write(Buffer->Next,
- Buffer->buf + Buffer->dirty_pos,
- Buffer->current + Buffer->dirty_pos,
- Buffer->dirty_end - Buffer->dirty_pos);
- if(ret != (signed int) (Buffer->dirty_end - Buffer->dirty_pos)) {
- if(ret < 0)
- perror("buffer_flush: write");
- else
- fprintf(stderr,"buffer_flush: short write\n");
+ ret = force_pwrite(Buffer->head.Next,
+ Buffer->buf + Buffer->dirty_pos,
+ Buffer->current + (mt_off_t) Buffer->dirty_pos,
+ Buffer->dirty_end - Buffer->dirty_pos);
+ if(ret < 0) {
+ perror("buffer_flush: write");
+ return -1;
+ }
+
+ if((size_t) ret != Buffer->dirty_end - Buffer->dirty_pos) {
+ fprintf(stderr,"buffer_flush: short write\n");
return -1;
}
Buffer->dirty = 0;
@@ -91,13 +107,13 @@ static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
/* start reading at the beginning of start's sector
* don't start reading too early, or we might not even reach
* start */
- Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
+ Buffer->current = ROUND_DOWN(start, (mt_off_t) Buffer->sectorSize);
Buffer->cur_size = 0;
return 0;
}
#undef OFFSET
-#define OFFSET (start - This->current)
+#define OFFSET ((size_t)(start - This->current))
typedef enum position_t {
OUTSIDE,
@@ -108,11 +124,10 @@ typedef enum position_t {
static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
{
- if(start >= This->current &&
- start < This->current + (mt_off_t) This->cur_size) {
+ if(start >= This->current && start < cur_end(This)) {
maximize(*len, This->cur_size - OFFSET);
return INSIDE;
- } else if(start == This->current + (mt_off_t) This->cur_size &&
+ } else if(start == cur_end(This) &&
This->cur_size < This->size &&
*len >= This->sectorSize) {
/* append to the buffer for this, three conditions have to
@@ -129,39 +144,39 @@ static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
if(invalidate_buffer(This, start) < 0)
return ERROR;
maximize(*len, This->cylinderSize - OFFSET);
- maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
+ maximize(*len, pos_to_next_full_cyl(This, This->current));
return OUTSIDE;
}
}
-static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+static ssize_t buf_pread(Stream_t *Stream, char *buf,
+ mt_off_t start, size_t len)
{
size_t length;
- mt_off_t offset;
+ size_t offset;
char *disk_ptr;
- int ret;
- DeclareThis(Buffer_t);
+ ssize_t ret;
+ DeclareThis(Buffer_t);
if(!len)
- return 0;
+ return 0;
/*fprintf(stderr, "buf read %x %x %x\n", Stream, start, len);*/
switch(isInBuffer(This, start, &len)) {
case OUTSIDE:
case APPEND:
/* always load until the end of the cylinder */
- length = This->cylinderSize -
- (This->current + This->cur_size) % This->cylinderSize;
+ length = pos_to_next_full_cyl(This, cur_end(This));
maximize(length, This->size - This->cur_size);
/* read it! */
- ret=READS(This->Next,
- This->buf + This->cur_size,
- This->current + This->cur_size,
- length);
+ ret=PREADS(This->head.Next,
+ This->buf + This->cur_size,
+ This->current + (mt_off_t) This->cur_size,
+ length);
if ( ret < 0 )
return ret;
- This->cur_size += ret;
+ This->cur_size += (size_t) ret;
if (This->current+(mt_off_t)This->cur_size < start) {
fprintf(stderr, "Short buffer fill\n");
exit(1);
@@ -178,13 +193,14 @@ static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
disk_ptr = This->buf + offset;
maximize(len, This->cur_size - offset);
memcpy(buf, disk_ptr, len);
- return len;
+ return (ssize_t) len;
}
-static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+static ssize_t buf_pwrite(Stream_t *Stream, char *buf,
+ mt_off_t start, size_t len)
{
char *disk_ptr;
- DeclareThis(Buffer_t);
+ DeclareThis(Buffer_t);
size_t offset=0;
if(!len)
@@ -206,27 +222,30 @@ static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
#ifdef DEBUG
fprintf(stderr, "outside\n");
#endif
- if(start % This->cylinderSize ||
+ if(start % (mt_off_t) This->cylinderSize ||
len < This->sectorSize) {
size_t readSize;
- int ret;
+ ssize_t ret;
+ size_t bytes_read;
readSize = This->cylinderSize -
- This->current % This->cylinderSize;
+ (size_t)(This->current % (mt_off_t) This->cylinderSize);
- ret=READS(This->Next, This->buf, This->current, readSize);
+ ret=PREADS(This->head.Next, This->buf,
+ (mt_off_t)This->current, readSize);
/* read it! */
if ( ret < 0 )
return ret;
- if(ret % This->sectorSize) {
- fprintf(stderr, "Weird: read size (%d) not a multiple of sector size (%d)\n", ret, (int) This->sectorSize);
- ret -= ret % This->sectorSize;
- if(ret == 0) {
+ bytes_read = (size_t) ret;
+ if(bytes_read % This->sectorSize) {
+ fprintf(stderr, "Weird: read size (%zd) not a multiple of sector size (%d)\n", bytes_read, (int) This->sectorSize);
+ bytes_read -= bytes_read % This->sectorSize;
+ if(bytes_read == 0) {
fprintf(stderr, "Nothing left\n");
exit(1);
}
}
- This->cur_size = ret;
+ This->cur_size = bytes_read;
/* for dosemu. Autoextend size */
if(!This->cur_size) {
memset(This->buf,0,readSize);
@@ -244,9 +263,8 @@ static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
offset = OFFSET;
maximize(len, This->size - offset);
This->cur_size += len;
- if(This->Next->Class->pre_allocate)
- PRE_ALLOCATE(This->Next,
- This->current + This->cur_size);
+ if(This->head.Next->Class->pre_allocate)
+ PRE_ALLOCATE(This->head.Next, cur_end(This));
break;
case INSIDE:
/* nothing to do */
@@ -278,7 +296,7 @@ static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
if(!This->dirty || offset + len > This->dirty_end)
This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
-
+
if(This->dirty_end > This->cur_size) {
fprintf(stderr,
"Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n",
@@ -296,7 +314,7 @@ static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
}
This->dirty = 1;
- return len;
+ return (ssize_t) len;
}
static int buf_flush(Stream_t *Stream)
@@ -324,8 +342,10 @@ static int buf_free(Stream_t *Stream)
}
static Class_t BufferClass = {
- buf_read,
- buf_write,
+ 0,
+ 0,
+ buf_pread,
+ buf_pwrite,
buf_flush,
buf_free,
0, /* set_geom */
@@ -335,13 +355,18 @@ static Class_t BufferClass = {
0, /* discard */
};
-Stream_t *buf_init(Stream_t *Next, int size,
- int cylinderSize,
- int sectorSize)
+Stream_t *buf_init(Stream_t *Next, size_t size,
+ size_t cylinderSize,
+ size_t sectorSize)
{
Buffer_t *Buffer;
- Stream_t *Stream;
+#ifdef HAVE_ASSERT_H
+ assert(size != 0);
+ assert(cylinderSize != 0);
+ assert(sectorSize != 0);
+ assert(Next != NULL);
+#endif
if(size % cylinderSize != 0) {
fprintf(stderr, "size not multiple of cylinder size\n");
@@ -352,19 +377,13 @@ Stream_t *buf_init(Stream_t *Next, int size,
exit(1);
}
- if(Next->Buffer){
- Next->refs--;
- Next->Buffer->refs++;
- return Next->Buffer;
- }
-
- Stream = (Stream_t *) malloc (sizeof(Buffer_t));
- if(!Stream)
+ Buffer = New(Buffer_t);
+ if(!Buffer)
return 0;
- Buffer = (Buffer_t *) Stream;
+ init_head(&Buffer->head, &BufferClass, Next);
Buffer->buf = malloc(size);
if ( !Buffer->buf){
- Free(Stream);
+ Free(Buffer);
return 0;
}
Buffer->size = size;
@@ -378,11 +397,6 @@ Stream_t *buf_init(Stream_t *Next, int size,
Buffer->current = 0L;
Buffer->cur_size = 0; /* buffer currently empty */
- Buffer->Next = Next;
- Buffer->Class = &BufferClass;
- Buffer->refs = 1;
- Buffer->Buffer = 0;
- Buffer->Next->Buffer = (Stream_t *) Buffer;
- return Stream;
+ return &Buffer->head;
}