xref: /aosp_15_r20/external/mtools/buffer.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes /*  Copyright 1997,2001-2003 Alain Knaff.
2*d5c9a868SElliott Hughes  *  This file is part of mtools.
3*d5c9a868SElliott Hughes  *
4*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes  *  (at your option) any later version.
8*d5c9a868SElliott Hughes  *
9*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
13*d5c9a868SElliott Hughes  *
14*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes  *
17*d5c9a868SElliott Hughes  * Buffer read/write module
18*d5c9a868SElliott Hughes  */
19*d5c9a868SElliott Hughes 
20*d5c9a868SElliott Hughes #include "sysincludes.h"
21*d5c9a868SElliott Hughes #include "msdos.h"
22*d5c9a868SElliott Hughes #include "mtools.h"
23*d5c9a868SElliott Hughes #include "buffer.h"
24*d5c9a868SElliott Hughes 
25*d5c9a868SElliott Hughes typedef struct Buffer_t {
26*d5c9a868SElliott Hughes 	struct Stream_t head;
27*d5c9a868SElliott Hughes 
28*d5c9a868SElliott Hughes 	size_t size;     	/* size of read/write buffer */
29*d5c9a868SElliott Hughes 	int dirty;	       	/* is the buffer dirty? */
30*d5c9a868SElliott Hughes 
31*d5c9a868SElliott Hughes 	size_t sectorSize;	/* sector size: all operations happen
32*d5c9a868SElliott Hughes 				 * in multiples of this */
33*d5c9a868SElliott Hughes 	size_t cylinderSize;	/* cylinder size: preferred alignment,
34*d5c9a868SElliott Hughes 				 * but for efficiency, less data may be read */
35*d5c9a868SElliott Hughes 	int ever_dirty;	       	/* was the buffer ever dirty? */
36*d5c9a868SElliott Hughes 	size_t dirty_pos;
37*d5c9a868SElliott Hughes 	size_t dirty_end;
38*d5c9a868SElliott Hughes 	mt_off_t current;	/* first sector in buffer */
39*d5c9a868SElliott Hughes 	size_t cur_size;	/* the current size */
40*d5c9a868SElliott Hughes 	char *buf;		/* disk read/write buffer */
41*d5c9a868SElliott Hughes } Buffer_t;
42*d5c9a868SElliott Hughes 
43*d5c9a868SElliott Hughes /* Convert position relative to buffer to absolute position */
abs_pos(Buffer_t * Buffer,size_t rel)44*d5c9a868SElliott Hughes static mt_off_t abs_pos(Buffer_t *Buffer, size_t rel) {
45*d5c9a868SElliott Hughes 	return Buffer->current + (mt_off_t) rel;
46*d5c9a868SElliott Hughes }
47*d5c9a868SElliott Hughes 
48*d5c9a868SElliott Hughes /* End of currently valid buffer */
cur_end(Buffer_t * Buffer)49*d5c9a868SElliott Hughes static mt_off_t cur_end(Buffer_t *Buffer) {
50*d5c9a868SElliott Hughes 	return abs_pos(Buffer, Buffer->cur_size);
51*d5c9a868SElliott Hughes }
52*d5c9a868SElliott Hughes 
53*d5c9a868SElliott Hughes /* distance from absolute position until next full cylinder. If position already
54*d5c9a868SElliott Hughes  * *is* on a full cylinder boundary, return size of full cylinder */
pos_to_next_full_cyl(Buffer_t * Buffer,mt_off_t pos)55*d5c9a868SElliott Hughes static size_t pos_to_next_full_cyl(Buffer_t *Buffer, mt_off_t pos) {
56*d5c9a868SElliott Hughes 	return Buffer->cylinderSize -
57*d5c9a868SElliott Hughes 		(size_t) (pos % (mt_off_t) Buffer->cylinderSize);
58*d5c9a868SElliott Hughes }
59*d5c9a868SElliott Hughes 
60*d5c9a868SElliott Hughes /*
61*d5c9a868SElliott Hughes  * Flush a dirty buffer to disk.  Resets Buffer->dirty to zero.
62*d5c9a868SElliott Hughes  * All errors are fatal.
63*d5c9a868SElliott Hughes  */
64*d5c9a868SElliott Hughes 
_buf_flush(Buffer_t * Buffer)65*d5c9a868SElliott Hughes static int _buf_flush(Buffer_t *Buffer)
66*d5c9a868SElliott Hughes {
67*d5c9a868SElliott Hughes 	ssize_t ret;
68*d5c9a868SElliott Hughes 
69*d5c9a868SElliott Hughes #ifdef HAVE_ASSERT_H
70*d5c9a868SElliott Hughes 	assert(Buffer->head.Next != NULL);
71*d5c9a868SElliott Hughes #endif
72*d5c9a868SElliott Hughes 
73*d5c9a868SElliott Hughes 	if (!Buffer->dirty)
74*d5c9a868SElliott Hughes 		return 0;
75*d5c9a868SElliott Hughes #ifdef DEBUG
76*d5c9a868SElliott Hughes 	fprintf(stderr, "write %08x -- %02x %08x %08x\n",
77*d5c9a868SElliott Hughes 		Buffer,
78*d5c9a868SElliott Hughes 		(unsigned char) Buffer->buf[0],
79*d5c9a868SElliott Hughes 		Buffer->current + Buffer->dirty_pos,
80*d5c9a868SElliott Hughes 		Buffer->dirty_end - Buffer->dirty_pos);
81*d5c9a868SElliott Hughes #endif
82*d5c9a868SElliott Hughes 
83*d5c9a868SElliott Hughes 	ret = force_pwrite(Buffer->head.Next,
84*d5c9a868SElliott Hughes 			   Buffer->buf + Buffer->dirty_pos,
85*d5c9a868SElliott Hughes 			   Buffer->current + (mt_off_t) Buffer->dirty_pos,
86*d5c9a868SElliott Hughes 			   Buffer->dirty_end - Buffer->dirty_pos);
87*d5c9a868SElliott Hughes 	if(ret < 0) {
88*d5c9a868SElliott Hughes 		perror("buffer_flush: write");
89*d5c9a868SElliott Hughes 		return -1;
90*d5c9a868SElliott Hughes 	}
91*d5c9a868SElliott Hughes 
92*d5c9a868SElliott Hughes 	if((size_t) ret != Buffer->dirty_end - Buffer->dirty_pos) {
93*d5c9a868SElliott Hughes 		fprintf(stderr,"buffer_flush: short write\n");
94*d5c9a868SElliott Hughes 		return -1;
95*d5c9a868SElliott Hughes 	}
96*d5c9a868SElliott Hughes 	Buffer->dirty = 0;
97*d5c9a868SElliott Hughes 	Buffer->dirty_end = 0;
98*d5c9a868SElliott Hughes 	Buffer->dirty_pos = 0;
99*d5c9a868SElliott Hughes 	return 0;
100*d5c9a868SElliott Hughes }
101*d5c9a868SElliott Hughes 
invalidate_buffer(Buffer_t * Buffer,mt_off_t start)102*d5c9a868SElliott Hughes static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
103*d5c9a868SElliott Hughes {
104*d5c9a868SElliott Hughes 	if(_buf_flush(Buffer) < 0)
105*d5c9a868SElliott Hughes 		return -1;
106*d5c9a868SElliott Hughes 
107*d5c9a868SElliott Hughes 	/* start reading at the beginning of start's sector
108*d5c9a868SElliott Hughes 	 * don't start reading too early, or we might not even reach
109*d5c9a868SElliott Hughes 	 * start */
110*d5c9a868SElliott Hughes 	Buffer->current = ROUND_DOWN(start, (mt_off_t) Buffer->sectorSize);
111*d5c9a868SElliott Hughes 	Buffer->cur_size = 0;
112*d5c9a868SElliott Hughes 	return 0;
113*d5c9a868SElliott Hughes }
114*d5c9a868SElliott Hughes 
115*d5c9a868SElliott Hughes #undef OFFSET
116*d5c9a868SElliott Hughes #define OFFSET ((size_t)(start - This->current))
117*d5c9a868SElliott Hughes 
118*d5c9a868SElliott Hughes typedef enum position_t {
119*d5c9a868SElliott Hughes 	OUTSIDE,
120*d5c9a868SElliott Hughes 	APPEND,
121*d5c9a868SElliott Hughes 	INSIDE,
122*d5c9a868SElliott Hughes 	ERROR
123*d5c9a868SElliott Hughes } position_t;
124*d5c9a868SElliott Hughes 
isInBuffer(Buffer_t * This,mt_off_t start,size_t * len)125*d5c9a868SElliott Hughes static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
126*d5c9a868SElliott Hughes {
127*d5c9a868SElliott Hughes 	if(start >= This->current && start < cur_end(This)) {
128*d5c9a868SElliott Hughes 		maximize(*len, This->cur_size - OFFSET);
129*d5c9a868SElliott Hughes 		return INSIDE;
130*d5c9a868SElliott Hughes 	} else if(start == cur_end(This) &&
131*d5c9a868SElliott Hughes 		  This->cur_size < This->size &&
132*d5c9a868SElliott Hughes 		  *len >= This->sectorSize) {
133*d5c9a868SElliott Hughes 		/* append to the buffer for this, three conditions have to
134*d5c9a868SElliott Hughes 		 * be met:
135*d5c9a868SElliott Hughes 		 *  1. The start falls exactly at the end of the currently
136*d5c9a868SElliott Hughes 		 *     loaded data
137*d5c9a868SElliott Hughes 		 *  2. There is still space
138*d5c9a868SElliott Hughes 		 *  3. We append at least one sector
139*d5c9a868SElliott Hughes 		 */
140*d5c9a868SElliott Hughes 		maximize(*len, This->size - This->cur_size);
141*d5c9a868SElliott Hughes 		*len = ROUND_DOWN(*len, This->sectorSize);
142*d5c9a868SElliott Hughes 		return APPEND;
143*d5c9a868SElliott Hughes 	} else {
144*d5c9a868SElliott Hughes 		if(invalidate_buffer(This, start) < 0)
145*d5c9a868SElliott Hughes 			return ERROR;
146*d5c9a868SElliott Hughes 		maximize(*len, This->cylinderSize - OFFSET);
147*d5c9a868SElliott Hughes 		maximize(*len, pos_to_next_full_cyl(This, This->current));
148*d5c9a868SElliott Hughes 		return OUTSIDE;
149*d5c9a868SElliott Hughes 	}
150*d5c9a868SElliott Hughes }
151*d5c9a868SElliott Hughes 
buf_pread(Stream_t * Stream,char * buf,mt_off_t start,size_t len)152*d5c9a868SElliott Hughes static ssize_t buf_pread(Stream_t *Stream, char *buf,
153*d5c9a868SElliott Hughes 			 mt_off_t start, size_t len)
154*d5c9a868SElliott Hughes {
155*d5c9a868SElliott Hughes 	size_t length;
156*d5c9a868SElliott Hughes 	size_t offset;
157*d5c9a868SElliott Hughes 	char *disk_ptr;
158*d5c9a868SElliott Hughes 	ssize_t ret;
159*d5c9a868SElliott Hughes 	DeclareThis(Buffer_t);
160*d5c9a868SElliott Hughes 
161*d5c9a868SElliott Hughes 	if(!len)
162*d5c9a868SElliott Hughes 		return 0;
163*d5c9a868SElliott Hughes 
164*d5c9a868SElliott Hughes 	/*fprintf(stderr, "buf read %x   %x %x\n", Stream, start, len);*/
165*d5c9a868SElliott Hughes 	switch(isInBuffer(This, start, &len)) {
166*d5c9a868SElliott Hughes 		case OUTSIDE:
167*d5c9a868SElliott Hughes 		case APPEND:
168*d5c9a868SElliott Hughes 			/* always load until the end of the cylinder */
169*d5c9a868SElliott Hughes 			length = pos_to_next_full_cyl(This, cur_end(This));
170*d5c9a868SElliott Hughes 			maximize(length, This->size - This->cur_size);
171*d5c9a868SElliott Hughes 
172*d5c9a868SElliott Hughes 			/* read it! */
173*d5c9a868SElliott Hughes 			ret=PREADS(This->head.Next,
174*d5c9a868SElliott Hughes 				   This->buf + This->cur_size,
175*d5c9a868SElliott Hughes 				   This->current + (mt_off_t) This->cur_size,
176*d5c9a868SElliott Hughes 				   length);
177*d5c9a868SElliott Hughes 			if ( ret < 0 )
178*d5c9a868SElliott Hughes 				return ret;
179*d5c9a868SElliott Hughes 			This->cur_size += (size_t) ret;
180*d5c9a868SElliott Hughes 			if (This->current+(mt_off_t)This->cur_size < start) {
181*d5c9a868SElliott Hughes 				fprintf(stderr, "Short buffer fill\n");
182*d5c9a868SElliott Hughes 				exit(1);
183*d5c9a868SElliott Hughes 			}
184*d5c9a868SElliott Hughes 			break;
185*d5c9a868SElliott Hughes 		case INSIDE:
186*d5c9a868SElliott Hughes 			/* nothing to do */
187*d5c9a868SElliott Hughes 			break;
188*d5c9a868SElliott Hughes 		case ERROR:
189*d5c9a868SElliott Hughes 			return -1;
190*d5c9a868SElliott Hughes 	}
191*d5c9a868SElliott Hughes 
192*d5c9a868SElliott Hughes 	offset = OFFSET;
193*d5c9a868SElliott Hughes 	disk_ptr = This->buf + offset;
194*d5c9a868SElliott Hughes 	maximize(len, This->cur_size - offset);
195*d5c9a868SElliott Hughes 	memcpy(buf, disk_ptr, len);
196*d5c9a868SElliott Hughes 	return (ssize_t) len;
197*d5c9a868SElliott Hughes }
198*d5c9a868SElliott Hughes 
buf_pwrite(Stream_t * Stream,char * buf,mt_off_t start,size_t len)199*d5c9a868SElliott Hughes static ssize_t buf_pwrite(Stream_t *Stream, char *buf,
200*d5c9a868SElliott Hughes 			  mt_off_t start, size_t len)
201*d5c9a868SElliott Hughes {
202*d5c9a868SElliott Hughes 	char *disk_ptr;
203*d5c9a868SElliott Hughes 	DeclareThis(Buffer_t);
204*d5c9a868SElliott Hughes 	size_t offset=0;
205*d5c9a868SElliott Hughes 
206*d5c9a868SElliott Hughes 	if(!len)
207*d5c9a868SElliott Hughes 		return 0;
208*d5c9a868SElliott Hughes 
209*d5c9a868SElliott Hughes 	This->ever_dirty = 1;
210*d5c9a868SElliott Hughes 
211*d5c9a868SElliott Hughes #ifdef DEBUG
212*d5c9a868SElliott Hughes 	fprintf(stderr, "buf write %x   %02x %08x %08x -- %08x %08x -- %08x\n",
213*d5c9a868SElliott Hughes 		Stream, (unsigned char) This->buf[0],
214*d5c9a868SElliott Hughes 		start, len, This->current, This->cur_size, This->size);
215*d5c9a868SElliott Hughes 	fprintf(stderr, "%d %d %d %x %x\n",
216*d5c9a868SElliott Hughes 		start == This->current + This->cur_size,
217*d5c9a868SElliott Hughes 		This->cur_size < This->size,
218*d5c9a868SElliott Hughes 		len >= This->sectorSize, len, This->sectorSize);
219*d5c9a868SElliott Hughes #endif
220*d5c9a868SElliott Hughes 	switch(isInBuffer(This, start, &len)) {
221*d5c9a868SElliott Hughes 		case OUTSIDE:
222*d5c9a868SElliott Hughes #ifdef DEBUG
223*d5c9a868SElliott Hughes 			fprintf(stderr, "outside\n");
224*d5c9a868SElliott Hughes #endif
225*d5c9a868SElliott Hughes 			if(start % (mt_off_t) This->cylinderSize ||
226*d5c9a868SElliott Hughes 			   len < This->sectorSize) {
227*d5c9a868SElliott Hughes 				size_t readSize;
228*d5c9a868SElliott Hughes 				ssize_t ret;
229*d5c9a868SElliott Hughes 				size_t bytes_read;
230*d5c9a868SElliott Hughes 
231*d5c9a868SElliott Hughes 				readSize = This->cylinderSize -
232*d5c9a868SElliott Hughes 					(size_t)(This->current % (mt_off_t) This->cylinderSize);
233*d5c9a868SElliott Hughes 
234*d5c9a868SElliott Hughes 				ret=PREADS(This->head.Next, This->buf,
235*d5c9a868SElliott Hughes 					   (mt_off_t)This->current, readSize);
236*d5c9a868SElliott Hughes 				/* read it! */
237*d5c9a868SElliott Hughes 				if ( ret < 0 )
238*d5c9a868SElliott Hughes 					return ret;
239*d5c9a868SElliott Hughes 				bytes_read = (size_t) ret;
240*d5c9a868SElliott Hughes 				if(bytes_read % This->sectorSize) {
241*d5c9a868SElliott Hughes 				  fprintf(stderr, "Weird: read size (%zd) not a multiple of sector size (%d)\n", bytes_read, (int) This->sectorSize);
242*d5c9a868SElliott Hughes 				    bytes_read -= bytes_read % This->sectorSize;
243*d5c9a868SElliott Hughes 				    if(bytes_read == 0) {
244*d5c9a868SElliott Hughes 					fprintf(stderr, "Nothing left\n");
245*d5c9a868SElliott Hughes 					exit(1);
246*d5c9a868SElliott Hughes 				    }
247*d5c9a868SElliott Hughes 				}
248*d5c9a868SElliott Hughes 				This->cur_size = bytes_read;
249*d5c9a868SElliott Hughes 				/* for dosemu. Autoextend size */
250*d5c9a868SElliott Hughes 				if(!This->cur_size) {
251*d5c9a868SElliott Hughes 					memset(This->buf,0,readSize);
252*d5c9a868SElliott Hughes 					This->cur_size = readSize;
253*d5c9a868SElliott Hughes 				}
254*d5c9a868SElliott Hughes 				offset = OFFSET;
255*d5c9a868SElliott Hughes 				break;
256*d5c9a868SElliott Hughes 			}
257*d5c9a868SElliott Hughes 			/* FALL THROUGH */
258*d5c9a868SElliott Hughes 		case APPEND:
259*d5c9a868SElliott Hughes #ifdef DEBUG
260*d5c9a868SElliott Hughes 			fprintf(stderr, "append\n");
261*d5c9a868SElliott Hughes #endif
262*d5c9a868SElliott Hughes 			len = ROUND_DOWN(len, This->sectorSize);
263*d5c9a868SElliott Hughes 			offset = OFFSET;
264*d5c9a868SElliott Hughes 			maximize(len, This->size - offset);
265*d5c9a868SElliott Hughes 			This->cur_size += len;
266*d5c9a868SElliott Hughes 			if(This->head.Next->Class->pre_allocate)
267*d5c9a868SElliott Hughes 				PRE_ALLOCATE(This->head.Next, cur_end(This));
268*d5c9a868SElliott Hughes 			break;
269*d5c9a868SElliott Hughes 		case INSIDE:
270*d5c9a868SElliott Hughes 			/* nothing to do */
271*d5c9a868SElliott Hughes #ifdef DEBUG
272*d5c9a868SElliott Hughes 			fprintf(stderr, "inside\n");
273*d5c9a868SElliott Hughes #endif
274*d5c9a868SElliott Hughes 			offset = OFFSET;
275*d5c9a868SElliott Hughes 			maximize(len, This->cur_size - offset);
276*d5c9a868SElliott Hughes 			break;
277*d5c9a868SElliott Hughes 		case ERROR:
278*d5c9a868SElliott Hughes 			return -1;
279*d5c9a868SElliott Hughes #ifdef DEBUG
280*d5c9a868SElliott Hughes 		default:
281*d5c9a868SElliott Hughes 			fprintf(stderr, "Should not happen\n");
282*d5c9a868SElliott Hughes 			exit(1);
283*d5c9a868SElliott Hughes #endif
284*d5c9a868SElliott Hughes 	}
285*d5c9a868SElliott Hughes 
286*d5c9a868SElliott Hughes 	disk_ptr = This->buf + offset;
287*d5c9a868SElliott Hughes 
288*d5c9a868SElliott Hughes 	/* extend if we write beyond end */
289*d5c9a868SElliott Hughes 	if(offset + len > This->cur_size) {
290*d5c9a868SElliott Hughes 		len -= (offset + len) % This->sectorSize;
291*d5c9a868SElliott Hughes 		This->cur_size = len + offset;
292*d5c9a868SElliott Hughes 	}
293*d5c9a868SElliott Hughes 
294*d5c9a868SElliott Hughes 	memcpy(disk_ptr, buf, len);
295*d5c9a868SElliott Hughes 	if(!This->dirty || offset < This->dirty_pos)
296*d5c9a868SElliott Hughes 		This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
297*d5c9a868SElliott Hughes 	if(!This->dirty || offset + len > This->dirty_end)
298*d5c9a868SElliott Hughes 		This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
299*d5c9a868SElliott Hughes 
300*d5c9a868SElliott Hughes 	if(This->dirty_end > This->cur_size) {
301*d5c9a868SElliott Hughes 		fprintf(stderr,
302*d5c9a868SElliott Hughes 			"Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n",
303*d5c9a868SElliott Hughes 			(unsigned int) This->dirty_end,
304*d5c9a868SElliott Hughes 			(unsigned int) This->cur_size,
305*d5c9a868SElliott Hughes 			(unsigned int) len,
306*d5c9a868SElliott Hughes 			(int) offset, (int) This->sectorSize);
307*d5c9a868SElliott Hughes 		fprintf(stderr, "offset + len + grain - 1 = %x\n",
308*d5c9a868SElliott Hughes 				(int) (offset + len + This->sectorSize - 1));
309*d5c9a868SElliott Hughes 		fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
310*d5c9a868SElliott Hughes 				(int)ROUND_DOWN(offset + len + This->sectorSize - 1,
311*d5c9a868SElliott Hughes 								This->sectorSize));
312*d5c9a868SElliott Hughes 		fprintf(stderr, "This->dirty = %d\n", This->dirty);
313*d5c9a868SElliott Hughes 		exit(1);
314*d5c9a868SElliott Hughes 	}
315*d5c9a868SElliott Hughes 
316*d5c9a868SElliott Hughes 	This->dirty = 1;
317*d5c9a868SElliott Hughes 	return (ssize_t) len;
318*d5c9a868SElliott Hughes }
319*d5c9a868SElliott Hughes 
buf_flush(Stream_t * Stream)320*d5c9a868SElliott Hughes static int buf_flush(Stream_t *Stream)
321*d5c9a868SElliott Hughes {
322*d5c9a868SElliott Hughes 	int ret;
323*d5c9a868SElliott Hughes 	DeclareThis(Buffer_t);
324*d5c9a868SElliott Hughes 
325*d5c9a868SElliott Hughes 	if (!This->ever_dirty)
326*d5c9a868SElliott Hughes 		return 0;
327*d5c9a868SElliott Hughes 	ret = _buf_flush(This);
328*d5c9a868SElliott Hughes 	if(ret == 0)
329*d5c9a868SElliott Hughes 		This->ever_dirty = 0;
330*d5c9a868SElliott Hughes 	return ret;
331*d5c9a868SElliott Hughes }
332*d5c9a868SElliott Hughes 
333*d5c9a868SElliott Hughes 
buf_free(Stream_t * Stream)334*d5c9a868SElliott Hughes static int buf_free(Stream_t *Stream)
335*d5c9a868SElliott Hughes {
336*d5c9a868SElliott Hughes 	DeclareThis(Buffer_t);
337*d5c9a868SElliott Hughes 
338*d5c9a868SElliott Hughes 	if(This->buf)
339*d5c9a868SElliott Hughes 		free(This->buf);
340*d5c9a868SElliott Hughes 	This->buf = 0;
341*d5c9a868SElliott Hughes 	return 0;
342*d5c9a868SElliott Hughes }
343*d5c9a868SElliott Hughes 
344*d5c9a868SElliott Hughes static Class_t BufferClass = {
345*d5c9a868SElliott Hughes 	0,
346*d5c9a868SElliott Hughes 	0,
347*d5c9a868SElliott Hughes 	buf_pread,
348*d5c9a868SElliott Hughes 	buf_pwrite,
349*d5c9a868SElliott Hughes 	buf_flush,
350*d5c9a868SElliott Hughes 	buf_free,
351*d5c9a868SElliott Hughes 	0, /* set_geom */
352*d5c9a868SElliott Hughes 	get_data_pass_through, /* get_data */
353*d5c9a868SElliott Hughes 	0, /* pre-allocate */
354*d5c9a868SElliott Hughes 	get_dosConvert_pass_through, /* dos convert */
355*d5c9a868SElliott Hughes 	0, /* discard */
356*d5c9a868SElliott Hughes };
357*d5c9a868SElliott Hughes 
buf_init(Stream_t * Next,size_t size,size_t cylinderSize,size_t sectorSize)358*d5c9a868SElliott Hughes Stream_t *buf_init(Stream_t *Next, size_t size,
359*d5c9a868SElliott Hughes 		   size_t cylinderSize,
360*d5c9a868SElliott Hughes 		   size_t sectorSize)
361*d5c9a868SElliott Hughes {
362*d5c9a868SElliott Hughes 	Buffer_t *Buffer;
363*d5c9a868SElliott Hughes 
364*d5c9a868SElliott Hughes #ifdef HAVE_ASSERT_H
365*d5c9a868SElliott Hughes 	assert(size != 0);
366*d5c9a868SElliott Hughes 	assert(cylinderSize != 0);
367*d5c9a868SElliott Hughes 	assert(sectorSize != 0);
368*d5c9a868SElliott Hughes 	assert(Next != NULL);
369*d5c9a868SElliott Hughes #endif
370*d5c9a868SElliott Hughes 
371*d5c9a868SElliott Hughes 	if(size % cylinderSize != 0) {
372*d5c9a868SElliott Hughes 		fprintf(stderr, "size not multiple of cylinder size\n");
373*d5c9a868SElliott Hughes 		exit(1);
374*d5c9a868SElliott Hughes 	}
375*d5c9a868SElliott Hughes 	if(cylinderSize % sectorSize != 0) {
376*d5c9a868SElliott Hughes 		fprintf(stderr, "cylinder size not multiple of sector size\n");
377*d5c9a868SElliott Hughes 		exit(1);
378*d5c9a868SElliott Hughes 	}
379*d5c9a868SElliott Hughes 
380*d5c9a868SElliott Hughes 	Buffer = New(Buffer_t);
381*d5c9a868SElliott Hughes 	if(!Buffer)
382*d5c9a868SElliott Hughes 		return 0;
383*d5c9a868SElliott Hughes 	init_head(&Buffer->head, &BufferClass, Next);
384*d5c9a868SElliott Hughes 	Buffer->buf = malloc(size);
385*d5c9a868SElliott Hughes 	if ( !Buffer->buf){
386*d5c9a868SElliott Hughes 		Free(Buffer);
387*d5c9a868SElliott Hughes 		return 0;
388*d5c9a868SElliott Hughes 	}
389*d5c9a868SElliott Hughes 	Buffer->size = size;
390*d5c9a868SElliott Hughes 	Buffer->dirty = 0;
391*d5c9a868SElliott Hughes 	Buffer->cylinderSize = cylinderSize;
392*d5c9a868SElliott Hughes 	Buffer->sectorSize = sectorSize;
393*d5c9a868SElliott Hughes 
394*d5c9a868SElliott Hughes 	Buffer->ever_dirty = 0;
395*d5c9a868SElliott Hughes 	Buffer->dirty_pos = 0;
396*d5c9a868SElliott Hughes 	Buffer->dirty_end = 0;
397*d5c9a868SElliott Hughes 	Buffer->current = 0L;
398*d5c9a868SElliott Hughes 	Buffer->cur_size = 0; /* buffer currently empty */
399*d5c9a868SElliott Hughes 
400*d5c9a868SElliott Hughes 	return &Buffer->head;
401*d5c9a868SElliott Hughes }
402*d5c9a868SElliott Hughes 
403