~drizzle-trunk/drizzle/development

1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
2
 *
3
 * PrimeBase Media Stream for MySQL
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
18
 *
19
 * Original author: Paul McCullagh (H&G2JCtL)
20
 * Continued development: Barry Leslie
21
 *
22
 * 2007-06-07
23
 *
24
 * CORE SYSTEM:
25
 * Basic file I/O.
26
 *
27
 */
28
29
#include "CSConfig.h"
30
31
#ifndef XT_WIN
32
#include <unistd.h>
33
#include <dirent.h>
34
#endif
35
#include <stdio.h>
36
#include <sys/stat.h>
37
#include <fcntl.h>
38
#include <errno.h>
39
#include <string.h>
40
1548.2.23 by Barry.Leslie at PrimeBase
And more cleanup.
41
#include "CSFile.h"
42
#include "CSStream.h"
43
#include "CSGlobal.h"
44
45
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
46
static int unix_file_open(const char *path, int flags, mode_t mode)
47
{
48
	return open(path, flags, mode);
49
}
50
51
int unix_file_close(int fh)
52
{
53
	return close(fh);
54
}
55
56
/*
57
 * ---------------------------------------------------------------
58
 * CORE SYSTEM FILES
59
 */
60
61
CSFile::~CSFile()
62
{
63
	close();
64
	if (myFilePath)
65
		myFilePath->release();
66
}
67
68
CSOutputStream *CSFile::getOutputStream()
69
{
70
	return CSFileOutputStream::newStream(RETAIN(this));
71
}
72
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
73
CSOutputStream *CSFile::getOutputStream(off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
74
{
75
	return CSFileOutputStream::newStream(RETAIN(this), offset);
76
}
77
78
CSInputStream *CSFile::getInputStream()
79
{
80
	return CSFileInputStream::newStream(RETAIN(this));
81
}
82
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
83
CSInputStream *CSFile::getInputStream(off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
84
{
85
	return CSFileInputStream::newStream(RETAIN(this), offset);
86
}
87
88
void CSFile::open(int mode)
89
{
90
	CSPath	*dir;
91
	bool	retry = false;
92
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
93
	CLOBBER_PROTECT(retry);
94
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
95
	enter_();
96
	if (mode & CREATE) {
97
		/* Create and open the file: */
98
		do {
99
			try_(a) {
100
				openFile(mode);
101
				retry = false;
102
			}
103
			catch_(a) {
104
				if (retry || !isDirNotFound(&self->myException))
105
					throw_();
106
107
				/* Make sure the parent directory exists: */
108
				dir = CSPath::newPath(RETAIN(myFilePath), "..");
109
				push_(dir);
110
				try_(b) {
111
					dir->makePath();
112
				}
113
				catch_(b) { /* Two threads may try to create the directory at the same time. */
114
					if (!isDirExists(&self->myException))
115
						throw_();
116
				}
117
				cont_(b);
118
119
				release_(dir);
120
				retry = true;
121
			}
122
			cont_(a);
123
		}
124
		while (retry);
125
	}
126
	else
127
		openFile(mode);
128
	exit_();
129
}
130
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
131
bool CSFile::transfer(CSFile *dst_file, off64_t dst_offset, CSFile *src_file, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
132
{
133
	size_t tfer;
134
135
	while (size > 0) {
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
136
		if (size > (off64_t) buffer_size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
137
			tfer = buffer_size;
138
		else
139
			tfer = (size_t) size;
140
		if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
141
			return false;
142
		dst_file->write(buffer, dst_offset, tfer);
143
		dst_offset += tfer;
144
		src_offset += tfer;
145
		size -= tfer;
146
	}
147
	return true;
148
}
149
1548.2.11 by Barry.Leslie at PrimeBase
Removed libxml reqirement by using a home grown xml parser.
150
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
151
{
152
	size_t tfer;
153
154
	while (size > 0) {
155
		if (size > (off64_t) buffer_size)
156
			tfer = buffer_size;
157
		else
158
			tfer = (size_t) size;
159
      
160
		read(buffer, src_offset, tfer, tfer);
161
		dst_stream->write(buffer, tfer);
162
    
163
		src_offset += tfer;
164
		size -= tfer;
165
	}
166
}
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
167
168
#define CS_MASK				((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
169
170
void CSFile::close()
171
{
172
	if (iFH != -1) {
173
		unix_file_close(iFH);
174
		iFH = -1;
175
	}
176
}
177
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
178
off64_t CSFile::getEOF()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
179
{
1548.2.11 by Barry.Leslie at PrimeBase
Removed libxml reqirement by using a home grown xml parser.
180
	off64_t eof;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
181
1548.2.11 by Barry.Leslie at PrimeBase
Removed libxml reqirement by using a home grown xml parser.
182
	if ((eof = lseek(iFH, 0, SEEK_END)) == (off64_t) -1)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
183
		CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
184
185
     return eof;
186
}
187
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
188
void CSFile::setEOF(off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
189
{
190
	if (ftruncate(iFH, offset) == -1)
191
		CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
192
}
193
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
194
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
195
{
196
	ssize_t read_size;
197
	
198
	enter_();
199
	read_size = pread(iFH, data, size, offset);
200
	self->interrupted();
201
	if (read_size ==  -1)
202
		CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
203
	if ((size_t) read_size < min_size)
204
		CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
205
	return_(read_size);
206
}
207
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
208
void CSFile::write(const void *data, off64_t offset, size_t size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
209
{
210
	size_t write_size;
211
212
	enter_();
213
    write_size = pwrite(iFH, (void *) data, size, offset);
214
	self->interrupted();
215
	if (write_size != size)
216
		CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
217
	exit_();
218
}
219
220
void CSFile::flush()
221
{
222
}
223
224
void CSFile::sync()
225
{
226
	fsync(iFH);
227
}
228
229
CSFile *CSFile::newFile(CSPath *path)
230
{
231
	CSFile *f;
232
233
	if (!(f = new CSFile())) {
234
		path->release();
235
		CSException::throwOSError(CS_CONTEXT, ENOMEM);
236
	}
237
	f->myFilePath = path;
238
	return f;
239
}
240
241
CSFile *CSFile::newFile(const char *path_str)
242
{
243
	CSPath *path;
244
245
	path = CSPath::newPath(path_str);
246
	return newFile(path);
247
}
248
249
void CSFile::openFile(int mode)
250
{
251
	int flags = 0;
252
253
	if (mode & READONLY)
254
		flags = O_RDONLY;
255
	else
256
		flags = O_RDWR;
257
258
	if (mode & CREATE)
259
		flags |= O_CREAT;
260
	
261
	if ((iFH = unix_file_open(myFilePath->getCString(), flags, CS_MASK)) ==  -1)
262
		CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
263
264
	/* Does not make sense to truncate, and have READONLY! */
265
	if ((mode & TRUNCATE) && !(mode & READONLY))
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
266
		setEOF((off64_t) 0);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
267
}
268
269
/*
270
 * ---------------------------------------------------------------
271
 * A READ BUFFERED FILE
272
 */
273
274
CSReadBufferedFile::CSReadBufferedFile():
275
myFile(NULL),
276
iFileBufferOffset(0),
277
iBufferDataLen(0)
278
{
279
}
280
281
CSReadBufferedFile::~CSReadBufferedFile()
282
{
283
	if (myFile) {
284
		close();
285
		myFile->release();
286
		myFile = NULL;
287
	}
288
}
289
290
void CSReadBufferedFile::close()
291
{
292
	flush();
293
	myFile->close();
294
	iFileBufferOffset = 0;
295
	iBufferDataLen = 0;
296
}
297
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
298
off64_t CSReadBufferedFile::getEOF()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
299
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
300
	off64_t eof = myFile->getEOF();
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
301
302
	if (eof < iFileBufferOffset + iBufferDataLen)
303
		return iFileBufferOffset + iBufferDataLen;
304
	return eof;
305
}
306
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
307
void CSReadBufferedFile::setEOF(off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
308
{
309
	myFile->setEOF(offset);
310
	if (offset < iFileBufferOffset) {
311
		iFileBufferOffset = 0;
312
		iBufferDataLen = 0;
313
	}
314
	else if (offset < iFileBufferOffset + iBufferDataLen)
315
		iBufferDataLen = offset - iFileBufferOffset;
316
}
317
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
318
size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
319
{
320
	size_t result;
321
	size_t tfer = 0;
322
323
	if (iBufferDataLen > 0) {
324
		if (offset < iFileBufferOffset) {
325
			//  case 1, 2, 6
326
			if (offset + size > iFileBufferOffset + iBufferDataLen) {
327
				// 6 (would have to do 2 reads and a memcpy (better is just one read)
328
				flush();
329
				goto readit;
330
			}
331
			if (offset + size > iFileBufferOffset) {
332
				// 2
333
				tfer = offset + size - iFileBufferOffset;
334
				memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
335
				size -= tfer;
336
			}
337
			// We assume we are reading back to front: 
338
			if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
339
				size_t mins;
340
341
				if (offset + size >= SC_DEFAULT_FILE_BUFFER_SIZE) {
342
					iFileBufferOffset = offset + size - SC_DEFAULT_FILE_BUFFER_SIZE;
343
					mins = SC_DEFAULT_FILE_BUFFER_SIZE;
344
				}
345
				else {
346
					iFileBufferOffset = 0;
347
					mins = (size_t) offset + size;
348
				}
349
				result = myFile->read(iFileBuffer, iFileBufferOffset, SC_DEFAULT_FILE_BUFFER_SIZE, mins);
350
				iBufferDataLen = result;
351
				memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
352
			}
353
			else
354
				result = myFile->read(data, offset, size, size);
355
			return size + tfer;
356
		}
357
		if (offset + size <= iFileBufferOffset + iBufferDataLen) {
358
			// 3
359
			memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
360
			return size;
361
		}
362
		if (offset < iFileBufferOffset + iBufferDataLen) {
363
			// 4 We assume we are reading front to back
364
			tfer = iFileBufferOffset + iBufferDataLen - offset;
365
			memcpy(data, iFileBuffer + (offset - iFileBufferOffset), tfer);
366
			data = (char *) data + tfer;
367
			size -= tfer;
368
			offset += tfer;
369
			if (min_size >= tfer)
370
				min_size -= tfer;
371
			else
372
				min_size = 0;
373
		}
374
		// else 5
375
	}
376
377
	readit:
378
	if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
379
		result = myFile->read(iFileBuffer, offset, SC_DEFAULT_FILE_BUFFER_SIZE, min_size);
380
		iFileBufferOffset = offset;
381
		iBufferDataLen = result;
382
		if (result > size)
383
			result = size;
384
		memcpy(data, iFileBuffer, result);
385
	}
386
	else
387
		result = myFile->read(data, offset, size, min_size);
388
	return result + tfer;
389
}
390
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
391
void CSReadBufferedFile::write(const void *data, off64_t offset, size_t size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
392
{
393
	if (iBufferDataLen > 0) {
394
		size_t tfer;
395
396
		if (offset < iFileBufferOffset) {
397
			//  case 1, 2, 6
398
			if (offset + size > iFileBufferOffset + iBufferDataLen) {
399
				// 6 (would have to do 2 reads and a memcpy (better is just one read)
400
				memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, iBufferDataLen);
401
			}
402
			else if (offset + size > iFileBufferOffset) {
403
				// 2
404
				tfer = offset + size - iFileBufferOffset;
405
				memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
406
			}
407
		}
408
		else if (offset + size <= iFileBufferOffset + iBufferDataLen) {
409
			// 3
410
			memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
411
		}
412
		else if (offset < iFileBufferOffset + iBufferDataLen) {
413
			// 4 We assume we are reading front to back
414
			tfer = iFileBufferOffset + iBufferDataLen - offset;
415
			memcpy(iFileBuffer + (offset - iFileBufferOffset), data, tfer);
416
		}
417
		// else 5
418
	}
419
420
	myFile->write(data, offset, size);
421
}
422
423
void CSReadBufferedFile::flush()
424
{
425
	myFile->flush();
426
}
427
428
void CSReadBufferedFile::sync()
429
{
430
	flush();
431
	myFile->sync();
432
}
433
434
const char *CSReadBufferedFile::getEOL()
435
{
436
	return myFile->getEOL();
437
}
438
439
void CSReadBufferedFile::openFile(int mode)
440
{
441
	myFile->openFile(mode);
442
}
443
444
CSFile *CSReadBufferedFile::newFile(CSFile *file)
445
{
446
	CSReadBufferedFile *f;
447
448
	if (!(f = new CSReadBufferedFile())) {
449
		file->release();
450
		CSException::throwOSError(CS_CONTEXT, ENOMEM);
451
	}
452
	f->myFile = file;
453
	f->myFilePath = file->myFilePath;
454
	f->myFilePath->retain();
455
	return (CSFile *) f;
456
}
457
458
/*
459
 * ---------------------------------------------------------------
460
 * A BUFFERED FILE
461
 */
462
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
463
void CSBufferedFile::write(const void *data, off64_t offset, size_t size)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
464
{
465
	if (iBufferDataLen > 0) {
466
		if (offset < iFileBufferOffset && offset <= iFileBufferOffset + iBufferDataLen) {
467
			size_t tfer;
468
469
			tfer = iFileBufferOffset + SC_DEFAULT_FILE_BUFFER_SIZE - offset;
470
			if (tfer >= size) {
471
				memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
472
			}
473
			size -= tfer;
474
			data = (char *) data + tfer;
475
		}
476
		flush();
477
	}
478
479
	if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
480
		iFileBufferOffset = offset;
481
		iBufferDataLen = size;
482
		memcpy(iFileBuffer, data, size);
483
		iBufferDirty = true;
484
	}
485
	else
486
		myFile->write(data, offset, size);
487
}
488
489
void CSBufferedFile::flush()
490
{
491
	if (iBufferDirty && iBufferDataLen) {
492
		myFile->write(iFileBuffer, iFileBufferOffset, iBufferDataLen);
493
		iBufferDirty = false;
494
		
495
	}
496
	myFile->flush();
497
}
498
499
/*
500
 * ---------------------------------------------------------------
501
 * FILE BASED ON THE STANDARD C FILE
502
 */