source: trunk/minix/commands/i386/mtools-3.9.7/buffer.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 8.3 KB
Line 
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
10typedef struct Buffer_t {
11 Class_t *Class;
12 int refs;
13 Stream_t *Next;
14 Stream_t *Buffer;
15
16 size_t size; /* size of read/write buffer */
17 int dirty; /* is the buffer dirty? */
18
19 int sectorSize; /* sector size: all operations happen
20 * in multiples of this */
21 int cylinderSize; /* cylinder size: preferred alignemnt,
22 * but for efficiency, less data may be read */
23 int ever_dirty; /* was the buffer ever dirty? */
24 int dirty_pos;
25 int dirty_end;
26 mt_off_t current; /* first sector in buffer */
27 size_t cur_size; /* the current size */
28 char *buf; /* disk read/write buffer */
29} Buffer_t;
30
31/*
32 * Flush a dirty buffer to disk. Resets Buffer->dirty to zero.
33 * All errors are fatal.
34 */
35
36static int _buf_flush(Buffer_t *Buffer)
37{
38 int ret;
39
40 if (!Buffer->Next || !Buffer->dirty)
41 return 0;
42 if(Buffer->current < 0L) {
43 fprintf(stderr,"Should not happen\n");
44 return -1;
45 }
46#ifdef DEBUG
47 fprintf(stderr, "write %08x -- %02x %08x %08x\n",
48 Buffer,
49 (unsigned char) Buffer->buf[0],
50 Buffer->current + Buffer->dirty_pos,
51 Buffer->dirty_end - Buffer->dirty_pos);
52#endif
53
54 ret = force_write(Buffer->Next,
55 Buffer->buf + Buffer->dirty_pos,
56 Buffer->current + Buffer->dirty_pos,
57 Buffer->dirty_end - Buffer->dirty_pos);
58 if(ret != Buffer->dirty_end - Buffer->dirty_pos) {
59 if(ret < 0)
60 perror("buffer_flush: write");
61 else
62 fprintf(stderr,"buffer_flush: short write\n");
63 return -1;
64 }
65 Buffer->dirty = 0;
66 Buffer->dirty_end = 0;
67 Buffer->dirty_pos = 0;
68 return 0;
69}
70
71static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
72{
73 /*fprintf(stderr, "invalidate %x\n", Buffer);*/
74 if(Buffer->sectorSize == 32) {
75 fprintf(stderr, "refreshing directory\n");
76 }
77
78 if(_buf_flush(Buffer) < 0)
79 return -1;
80
81 /* start reading at the beginning of start's sector
82 * don't start reading too early, or we might not even reach
83 * start */
84 Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
85 Buffer->cur_size = 0;
86 return 0;
87}
88
89#undef OFFSET
90#define OFFSET (start - This->current)
91
92typedef enum position_t {
93 OUTSIDE,
94 APPEND,
95 INSIDE,
96 ERROR
97} position_t;
98
99static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
100{
101 if(start >= This->current &&
102 start < This->current + This->cur_size) {
103 maximize(*len, This->cur_size - OFFSET);
104 return INSIDE;
105 } else if(start == This->current + This->cur_size &&
106 This->cur_size < This->size &&
107 *len >= This->sectorSize) {
108 /* append to the buffer for this, three conditions have to
109 * be met:
110 * 1. The start falls exactly at the end of the currently
111 * loaded data
112 * 2. There is still space
113 * 3. We append at least one sector
114 */
115 maximize(*len, This->size - This->cur_size);
116 *len = ROUND_DOWN(*len, This->sectorSize);
117 return APPEND;
118 } else {
119 if(invalidate_buffer(This, start) < 0)
120 return ERROR;
121 maximize(*len, This->cylinderSize - OFFSET);
122 maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
123 return OUTSIDE;
124 }
125}
126
127static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
128{
129 size_t length;
130 int offset;
131 char *disk_ptr;
132 int ret;
133 DeclareThis(Buffer_t);
134
135 if(!len)
136 return 0;
137
138 /*fprintf(stderr, "buf read %x %x %x\n", Stream, start, len);*/
139 switch(isInBuffer(This, start, &len)) {
140 case OUTSIDE:
141 case APPEND:
142 /* always load until the end of the cylinder */
143 length = This->cylinderSize -
144 (This->current + This->cur_size) % This->cylinderSize;
145 maximize(length, This->size - This->cur_size);
146
147 /* read it! */
148 ret=READS(This->Next,
149 This->buf + This->cur_size,
150 This->current + This->cur_size,
151 length);
152 if ( ret < 0 )
153 return ret;
154 This->cur_size += ret;
155 if (This->current+This->cur_size < start) {
156 fprintf(stderr, "Short buffer fill\n");
157 exit(1);
158 }
159 break;
160 case INSIDE:
161 /* nothing to do */
162 break;
163 case ERROR:
164 return -1;
165 }
166
167 offset = OFFSET;
168 disk_ptr = This->buf + offset;
169 maximize(len, This->cur_size - offset);
170 memcpy(buf, disk_ptr, len);
171 return len;
172}
173
174static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
175{
176 char *disk_ptr;
177 DeclareThis(Buffer_t);
178 int offset, ret;
179
180 if(!len)
181 return 0;
182
183 This->ever_dirty = 1;
184
185#ifdef DEBUG
186 fprintf(stderr, "buf write %x %02x %08x %08x -- %08x %08x -- %08x\n",
187 Stream, (unsigned char) This->buf[0],
188 start, len, This->current, This->cur_size, This->size);
189 fprintf(stderr, "%d %d %d %x %x\n",
190 start == This->current + This->cur_size,
191 This->cur_size < This->size,
192 len >= This->sectorSize, len, This->sectorSize);
193#endif
194 switch(isInBuffer(This, start, &len)) {
195 case OUTSIDE:
196#ifdef DEBUG
197 fprintf(stderr, "outside\n");
198#endif
199 if(start % This->cylinderSize ||
200 len < This->sectorSize) {
201 size_t readSize;
202
203 readSize = This->cylinderSize -
204 This->current % This->cylinderSize;
205
206 ret=READS(This->Next, This->buf, This->current, readSize);
207 /* read it! */
208 if ( ret < 0 )
209 return ret;
210 This->cur_size = ret;
211 /* for dosemu. Autoextend size */
212 if(!This->cur_size) {
213 memset(This->buf,0,readSize);
214 This->cur_size = readSize;
215 }
216 offset = OFFSET;
217 break;
218 }
219 /* FALL THROUGH */
220 case APPEND:
221#ifdef DEBUG
222 fprintf(stderr, "append\n");
223#endif
224 len = ROUND_DOWN(len, This->sectorSize);
225 offset = OFFSET;
226 maximize(len, This->size - offset);
227 This->cur_size += len;
228 if(This->Next->Class->pre_allocate)
229 PRE_ALLOCATE(This->Next,
230 This->current + This->cur_size);
231 break;
232 case INSIDE:
233 /* nothing to do */
234#ifdef DEBUG
235 fprintf(stderr, "inside\n");
236#endif
237 offset = OFFSET;
238 maximize(len, This->cur_size - offset);
239 break;
240 case ERROR:
241 return -1;
242 default:
243#ifdef DEBUG
244 fprintf(stderr, "Should not happen\n");
245#endif
246 exit(1);
247 }
248
249 disk_ptr = This->buf + offset;
250
251 /* extend if we write beyond end */
252 if(offset + len > This->cur_size) {
253 len -= (offset + len) % This->sectorSize;
254 This->cur_size = len + offset;
255 }
256
257 memcpy(disk_ptr, buf, len);
258 if(!This->dirty || offset < This->dirty_pos)
259 This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
260 if(!This->dirty || offset + len > This->dirty_end)
261 This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
262
263 if(This->dirty_end > This->cur_size) {
264 fprintf(stderr,
265 "Internal error, dirty end too big %x %x %x %d %x\n",
266 This->dirty_end, (unsigned int) This->cur_size, (unsigned int) len,
267 (int) offset, (int) This->sectorSize);
268 fprintf(stderr, "offset + len + grain - 1 = %x\n",
269 (int) (offset + len + This->sectorSize - 1));
270 fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
271 (int)ROUND_DOWN(offset + len + This->sectorSize - 1,
272 This->sectorSize));
273 fprintf(stderr, "This->dirty = %d\n", This->dirty);
274 exit(1);
275 }
276
277 This->dirty = 1;
278 return len;
279}
280
281static int buf_flush(Stream_t *Stream)
282{
283 int ret;
284 DeclareThis(Buffer_t);
285
286 if (!This->ever_dirty)
287 return 0;
288 ret = _buf_flush(This);
289 if(ret == 0)
290 This->ever_dirty = 0;
291 return ret;
292}
293
294
295static int buf_free(Stream_t *Stream)
296{
297 DeclareThis(Buffer_t);
298
299 if(This->buf)
300 free(This->buf);
301 This->buf = 0;
302 return 0;
303}
304
305static Class_t BufferClass = {
306 buf_read,
307 buf_write,
308 buf_flush,
309 buf_free,
310 0, /* set_geom */
311 get_data_pass_through, /* get_data */
312 0, /* pre-allocate */
313};
314
315Stream_t *buf_init(Stream_t *Next, int size,
316 int cylinderSize,
317 int sectorSize)
318{
319 Buffer_t *Buffer;
320 Stream_t *Stream;
321
322
323 if(size % cylinderSize != 0) {
324 fprintf(stderr, "size not multiple of cylinder size\n");
325 exit(1);
326 }
327 if(cylinderSize % sectorSize != 0) {
328 fprintf(stderr, "cylinder size not multiple of sector size\n");
329 exit(1);
330 }
331
332 if(Next->Buffer){
333 Next->refs--;
334 Next->Buffer->refs++;
335 return Next->Buffer;
336 }
337
338 Stream = (Stream_t *) malloc (sizeof(Buffer_t));
339 if(!Stream)
340 return 0;
341 Buffer = (Buffer_t *) Stream;
342 Buffer->buf = malloc(size);
343 if ( !Buffer->buf){
344 Free(Stream);
345 return 0;
346 }
347 Buffer->size = size;
348 Buffer->dirty = 0;
349 Buffer->cylinderSize = cylinderSize;
350 Buffer->sectorSize = sectorSize;
351
352 Buffer->ever_dirty = 0;
353 Buffer->dirty_pos = 0;
354 Buffer->dirty_end = 0;
355 Buffer->current = 0;
356 Buffer->cur_size = 0; /* buffer currently empty */
357
358 Buffer->Next = Next;
359 Buffer->Class = &BufferClass;
360 Buffer->refs = 1;
361 Buffer->Buffer = 0;
362 Buffer->Next->Buffer = (Stream_t *) Buffer;
363 return Stream;
364}
365
Note: See TracBrowser for help on using the repository browser.