File: stream.h

package info (click to toggle)
snapraid 13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,656 kB
  • sloc: ansic: 46,018; makefile: 1,004; sh: 154
file content (416 lines) | stat: -rw-r--r-- 9,382 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*
 * Copyright (C) 2011 Andrea Mazzoleni
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __STREAM_H
#define __STREAM_H

#include "util.h"

/****************************************************************************/
/* stream */

/**
 * Size of the buffer of the stream.
 *
 * It's not a constant for testing purpose.
 */
extern unsigned STREAM_SIZE;

#define STREAM_STATE_READ 0 /**< The stream is in a normal state of read. */
#define STREAM_STATE_WRITE 1 /**< The stream is in a normal state of write. */
#define STREAM_STATE_ERROR -1 /**< An error was encountered. */
#define STREAM_STATE_EOF 2 /**< The end of file was encountered. */

struct stream_handle {
	int f; /**< Handle of the file. */
	char path[PATH_MAX]; /**< Path of the file. */
};

struct stream {
	unsigned char* buffer; /**< Buffer of the stream. */
	unsigned char* pos; /**< Current position in the buffer. */
	unsigned char* end; /**< End position of the buffer. */
	int state; /**< State of the stream. One of STREAM_STATE. */
	int state_index; /**< Index of the handle causing a state change. */
	unsigned handle_size; /**< Number of handles. */
	struct stream_handle* handle; /**< Set of handles. */
	off_t offset; /**< Offset into the file. */
	off_t offset_uncached; /**< Offset into the file excluding the cached data. */

	/**
	 * CRC of the data read or written in the file.
	 *
	 * If reading, it's the CRC of all data read from the file,
	 * including the one in the buffer.
	 * If writing it's all the data wrote to the file,
	 * excluding the one still in buffer yet to be written.
	 */
	uint32_t crc;

	/**
	 * CRC of the file excluding the cached data in the buffer.
	 *
	 * If reading, it's the CRC of the data read from the file,
	 * excluding the one in the buffer.
	 * If writing it's all the data wrote to the file,
	 * excluding the one still in buffer yet to be written.
	 */
	uint32_t crc_uncached;

	/**
	 * CRC of the data written to the stream.
	 *
	 * This is an extra check of the data that is written to
	 * file to ensure that it's consistent even in case
	 * of memory errors.
	 *
	 * This extra check takes about 2 seconds for each GB of
	 * content file with the Intel CRC instruction,
	 * and about 4 seconds without it.
	 * But usually this doesn't slow down the write process,
	 * as the disk is the bottle-neck.
	 *
	 * Note that this CRC doesn't have the IV processing.
	 *
	 * Not used in reading.
	 * In writing, it's all the data wrote calling sput() functions.
	 */
	uint32_t crc_stream;
};

/**
 * Opaque STREAM type. Like ::FILE.
 */
typedef struct stream STREAM;

/**
 * Open a stream for reading. Like fopen("r").
 */
STREAM* sopen_read(const char* file);

/**
 * Open a stream for writing. Like fopen("w").
 */
STREAM* sopen_write(const char* file);

/**
 * Open a set of streams for writing. Like fopen("w").
 */
STREAM* sopen_multi_write(unsigned count);

/**
 * Specify the file to open.
 */
int sopen_multi_file(STREAM* s, unsigned i, const char* file);

/**
 * Close a stream. Like fclose().
 */
int sclose(STREAM* s);

/**
 * Return the handle of the file.
 * In case of multi file, the first one is returned.
 */
int shandle(STREAM* s);

/**
 * Read the stream until the end, and return the latest 4 chars.
 * The CRC of the file is also computed, and you can get it using scrc().
 * \return 0 on success, or EOF on error.
 */
int sdeplete(STREAM* s, unsigned char* last);

/**
 * Flush the write stream buffer.
 * \return 0 on success, or EOF on error.
 */
int sflush(STREAM* s);

/**
 * Get the file pointer.
 */
int64_t stell(STREAM* s);

/**
 * Get the CRC of the processed data.
 */
uint32_t scrc(STREAM* s);

/**
 * Get the CRC of the processed data in put.
 */
uint32_t scrc_stream(STREAM* s);

/**
 * Check if the buffer has enough data loaded.
 */
static inline int sptrlookup(STREAM* s, int size)
{
	return s->pos + size <= s->end;
}

/**
 * Get the current stream ptr.
 */
static inline unsigned char* sptrget(STREAM* s)
{
	return s->pos;
}

/**
 * Set the current stream ptr.
 */
static inline void sptrset(STREAM* s, unsigned char* ptr)
{
	s->pos = ptr;
}

/**
 * Check the error status. Like ferror().
 */
static inline int serror(STREAM* s)
{
	return s->state == STREAM_STATE_ERROR;
}

/**
 * Check the eof status. Like feof().
 */
static inline int seof(STREAM* s)
{
	return s->state == STREAM_STATE_EOF;
}

/**
 * Get the index of the handle that caused the error.
 */
static inline int serrorindex(STREAM* s)
{
	return s->state_index;
}

/**
 * Get the path of the handle that caused the error.
 */
static inline const char* serrorfile(STREAM* s)
{
	return s->handle[s->state_index].path;
}

/**
 * Sync the stream. Like fsync().
 */
int ssync(STREAM* s);

/****************************************************************************/
/* get */

/**
 * \internal Used by sgetc().
 * \note Don't call this directly, but use sgetc().
 */
int sgetc_uncached(STREAM* s);

/**
 * Read a char. Like fgetc().
 */
static inline int sgetc(STREAM* s)
{
	if (tommy_unlikely(s->pos == s->end))
		return sgetc_uncached(s);
	return *s->pos++;
}

/**
 * Unread a char.
 * Like ungetc() but you have to unget the same char read.
 */
static inline void sungetc(int c, STREAM* s)
{
	if (c != EOF)
		--s->pos;
}

/**
 * Read a fixed amount of chars.
 * Return 0 on success, or -1 on error.
 */
int sread(STREAM* f, void* void_data, unsigned size);

/**
 * Get a char from a stream, ignoring one '\r'.
 */
static inline int sgeteol(STREAM* f)
{
	int c;

	c = sgetc(f);
	if (c == '\r')
		c = sgetc(f);

	return c;
}

/**
 * Read all the spaces and tabs.
 * Return the number of spaces and tabs read.
 */
static inline int sgetspace(STREAM* f)
{
	int count = 0;
	int c;

	c = sgetc(f);
	while (c == ' ' || c == '\t') {
		++count;
		c = sgetc(f);
	}

	sungetc(c, f);
	return count;
}

/**
 * Read until the first space or tab.
 * Stop at the first ' ', '\t', '\n' or EOF.
 * Return <0 if the buffer is too small, or the number of chars read.
 */
int sgettok(STREAM* f, char* str, int size);

/**
 * Read until the end of line.
 * Stop at the first '\n' or EOF. Note that '\n' is left in the stream.
 * Return <0 if the buffer is too small, or the number of chars read.
 */
int sgetline(STREAM* f, char* str, int size);

/**
 * Like sgetline() but remove ' ' and '\t' at the end.
 */
int sgetlasttok(STREAM* f, char* str, int size);

/**
 * Read a 32 bit number.
 * Stop at the first not digit char or EOF.
 * Return <0 if there isn't enough to read.
 */
int sgetu32(STREAM* f, uint32_t* value);

/****************************************************************************/
/* binary get */

/**
 * Read a binary 32 bit number in packet format.
 * Return <0 if there isn't enough to read.
 */
int sgetb32(STREAM* f, uint32_t* value);

/**
 * Read a binary 64 bit number in packet format.
 * Return <0 if there isn't enough to read.
 */
int sgetb64(STREAM* f, uint64_t* value);

/**
 * Read a binary 32 bit number in little endian format.
 * Return <0 if there isn't enough to read.
 */
int sgetble32(STREAM* f, uint32_t* value);

/**
 * Read a binary string.
 * Return -1 on error or if the buffer is too small, or the number of chars read.
 */
int sgetbs(STREAM* f, char* str, int size);

/****************************************************************************/
/* put */

/**
 * Write a char. Like fputc().
 * Return 0 on success or -1 on error.
 */
static inline int sputc(int c, STREAM* s)
{
	if (s->pos == s->end) {
		if (sflush(s) != 0)
			return -1;
	}

	/**
	 * Update the crc *before* writing the data in the buffer
	 *
	 * This must be done before the memory write,
	 * to be able to detect memory errors on the buffer,
	 * happening before we write it on the file.
	 */
	s->crc_stream = crc32c_plain_char(s->crc_stream, c);

	*s->pos++ = c;

	return 0;
}

/**
 * Write a end of line.
 * Return 0 on success or -1 on error.
 */
static inline int sputeol(STREAM* s)
{
#ifdef _WIN32
	if (sputc('\r', s) != 0)
		return -1;
#endif
	return sputc('\n', s);
}

/**
 * Write a sized string.
 * Return 0 on success or -1 on error.
 */
int swrite(const void* data, unsigned size, STREAM* f);

/****************************************************************************/
/* binary put */

/**
 * Write a binary 32 bit number in packed format.
 * Return 0 on success or -1 on error.
 */
int sputb32(uint32_t value, STREAM* s);

/**
 * Write a binary 64 bit number in packed format.
 * Return 0 on success or -1 on error.
 */
int sputb64(uint64_t value, STREAM* s);

/**
 * Write a binary 32 bit number in little endian format.
 * Return 0 on success or -1 on error.
 */
int sputble32(uint32_t value, STREAM* s);

/**
 * Write a binary string.
 * Return 0 on success or -1 on error.
 */
int sputbs(const char* str, STREAM* s);

#endif