~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/cslib/CSFile.cc

Added the PBMS daemon plugin.

(Augen zu und durch!)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
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
 
 
41
static int unix_file_open(const char *path, int flags, mode_t mode)
 
42
{
 
43
        return open(path, flags, mode);
 
44
}
 
45
 
 
46
int unix_file_close(int fh)
 
47
{
 
48
        return close(fh);
 
49
}
 
50
 
 
51
#include "CSFile.h"
 
52
#include "CSStream.h"
 
53
#include "CSGlobal.h"
 
54
 
 
55
/*
 
56
 * ---------------------------------------------------------------
 
57
 * CORE SYSTEM FILES
 
58
 */
 
59
 
 
60
CSFile::~CSFile()
 
61
{
 
62
        close();
 
63
        if (myFilePath)
 
64
                myFilePath->release();
 
65
}
 
66
 
 
67
CSOutputStream *CSFile::getOutputStream()
 
68
{
 
69
        return CSFileOutputStream::newStream(RETAIN(this));
 
70
}
 
71
 
 
72
CSOutputStream *CSFile::getOutputStream(off_t offset)
 
73
{
 
74
        return CSFileOutputStream::newStream(RETAIN(this), offset);
 
75
}
 
76
 
 
77
CSInputStream *CSFile::getInputStream()
 
78
{
 
79
        return CSFileInputStream::newStream(RETAIN(this));
 
80
}
 
81
 
 
82
CSInputStream *CSFile::getInputStream(off_t offset)
 
83
{
 
84
        return CSFileInputStream::newStream(RETAIN(this), offset);
 
85
}
 
86
 
 
87
void CSFile::open(int mode)
 
88
{
 
89
        CSPath  *dir;
 
90
        bool    retry = false;
 
91
 
 
92
        enter_();
 
93
        if (mode & CREATE) {
 
94
                /* Create and open the file: */
 
95
                do {
 
96
                        try_(a) {
 
97
                                openFile(mode);
 
98
                                retry = false;
 
99
                        }
 
100
                        catch_(a) {
 
101
                                if (retry || !isDirNotFound(&self->myException))
 
102
                                        throw_();
 
103
 
 
104
                                /* Make sure the parent directory exists: */
 
105
                                dir = CSPath::newPath(RETAIN(myFilePath), "..");
 
106
                                push_(dir);
 
107
                                try_(b) {
 
108
                                        dir->makePath();
 
109
                                }
 
110
                                catch_(b) { /* Two threads may try to create the directory at the same time. */
 
111
                                        if (!isDirExists(&self->myException))
 
112
                                                throw_();
 
113
                                }
 
114
                                cont_(b);
 
115
 
 
116
                                release_(dir);
 
117
                                retry = true;
 
118
                        }
 
119
                        cont_(a);
 
120
                }
 
121
                while (retry);
 
122
        }
 
123
        else
 
124
                openFile(mode);
 
125
        exit_();
 
126
}
 
127
 
 
128
bool CSFile::transfer(CSFile *dst_file, off_t dst_offset, CSFile *src_file, off_t src_offset, off_t size, char *buffer, size_t buffer_size)
 
129
{
 
130
        size_t tfer;
 
131
 
 
132
        while (size > 0) {
 
133
                if (size > (off_t) buffer_size)
 
134
                        tfer = buffer_size;
 
135
                else
 
136
                        tfer = (size_t) size;
 
137
                if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
 
138
                        return false;
 
139
                dst_file->write(buffer, dst_offset, tfer);
 
140
                dst_offset += tfer;
 
141
                src_offset += tfer;
 
142
                size -= tfer;
 
143
        }
 
144
        return true;
 
145
}
 
146
 
 
147
 
 
148
#define CS_MASK                         ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
 
149
 
 
150
void CSFile::close()
 
151
{
 
152
        if (iFH != -1) {
 
153
                unix_file_close(iFH);
 
154
                iFH = -1;
 
155
        }
 
156
}
 
157
 
 
158
off_t CSFile::getEOF()
 
159
{
 
160
        off_t eof;
 
161
 
 
162
        if ((eof = lseek(iFH, 0, SEEK_END)) == -1)
 
163
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
164
 
 
165
     return eof;
 
166
}
 
167
 
 
168
void CSFile::setEOF(off_t offset)
 
169
{
 
170
        if (ftruncate(iFH, offset) == -1)
 
171
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
172
}
 
173
 
 
174
size_t CSFile::read(void *data, off_t offset, size_t size, size_t min_size)
 
175
{
 
176
        ssize_t read_size;
 
177
        
 
178
        enter_();
 
179
        read_size = pread(iFH, data, size, offset);
 
180
        self->interrupted();
 
181
        if (read_size ==  -1)
 
182
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
183
        if ((size_t) read_size < min_size)
 
184
                CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
 
185
        return_(read_size);
 
186
}
 
187
 
 
188
void CSFile::write(const void *data, off_t offset, size_t size)
 
189
{
 
190
        size_t write_size;
 
191
 
 
192
        enter_();
 
193
    write_size = pwrite(iFH, (void *) data, size, offset);
 
194
        self->interrupted();
 
195
        if (write_size != size)
 
196
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
197
        exit_();
 
198
}
 
199
 
 
200
void CSFile::flush()
 
201
{
 
202
}
 
203
 
 
204
void CSFile::sync()
 
205
{
 
206
        fsync(iFH);
 
207
}
 
208
 
 
209
CSFile *CSFile::newFile(CSPath *path)
 
210
{
 
211
        CSFile *f;
 
212
 
 
213
        if (!(f = new CSFile())) {
 
214
                path->release();
 
215
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
 
216
        }
 
217
        f->myFilePath = path;
 
218
        return f;
 
219
}
 
220
 
 
221
CSFile *CSFile::newFile(const char *path_str)
 
222
{
 
223
        CSPath *path;
 
224
 
 
225
        path = CSPath::newPath(path_str);
 
226
        return newFile(path);
 
227
}
 
228
 
 
229
void CSFile::openFile(int mode)
 
230
{
 
231
        int flags = 0;
 
232
 
 
233
        if (mode & READONLY)
 
234
                flags = O_RDONLY;
 
235
        else
 
236
                flags = O_RDWR;
 
237
 
 
238
        if (mode & CREATE)
 
239
                flags |= O_CREAT;
 
240
        
 
241
        if ((iFH = unix_file_open(myFilePath->getCString(), flags, CS_MASK)) ==  -1)
 
242
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
243
 
 
244
        /* Does not make sense to truncate, and have READONLY! */
 
245
        if ((mode & TRUNCATE) && !(mode & READONLY))
 
246
                setEOF((off_t) 0);
 
247
}
 
248
 
 
249
/*
 
250
 * ---------------------------------------------------------------
 
251
 * A READ BUFFERED FILE
 
252
 */
 
253
 
 
254
CSReadBufferedFile::CSReadBufferedFile():
 
255
myFile(NULL),
 
256
iFileBufferOffset(0),
 
257
iBufferDataLen(0)
 
258
{
 
259
}
 
260
 
 
261
CSReadBufferedFile::~CSReadBufferedFile()
 
262
{
 
263
        if (myFile) {
 
264
                close();
 
265
                myFile->release();
 
266
                myFile = NULL;
 
267
        }
 
268
}
 
269
 
 
270
void CSReadBufferedFile::close()
 
271
{
 
272
        flush();
 
273
        myFile->close();
 
274
        iFileBufferOffset = 0;
 
275
        iBufferDataLen = 0;
 
276
}
 
277
 
 
278
off_t CSReadBufferedFile::getEOF()
 
279
{
 
280
        off_t eof = myFile->getEOF();
 
281
 
 
282
        if (eof < iFileBufferOffset + iBufferDataLen)
 
283
                return iFileBufferOffset + iBufferDataLen;
 
284
        return eof;
 
285
}
 
286
 
 
287
void CSReadBufferedFile::setEOF(off_t offset)
 
288
{
 
289
        myFile->setEOF(offset);
 
290
        if (offset < iFileBufferOffset) {
 
291
                iFileBufferOffset = 0;
 
292
                iBufferDataLen = 0;
 
293
        }
 
294
        else if (offset < iFileBufferOffset + iBufferDataLen)
 
295
                iBufferDataLen = offset - iFileBufferOffset;
 
296
}
 
297
 
 
298
size_t CSReadBufferedFile::read(void *data, off_t offset, size_t size, size_t min_size)
 
299
{
 
300
        size_t result;
 
301
        size_t tfer = 0;
 
302
 
 
303
        if (iBufferDataLen > 0) {
 
304
                if (offset < iFileBufferOffset) {
 
305
                        //  case 1, 2, 6
 
306
                        if (offset + size > iFileBufferOffset + iBufferDataLen) {
 
307
                                // 6 (would have to do 2 reads and a memcpy (better is just one read)
 
308
                                flush();
 
309
                                goto readit;
 
310
                        }
 
311
                        if (offset + size > iFileBufferOffset) {
 
312
                                // 2
 
313
                                tfer = offset + size - iFileBufferOffset;
 
314
                                memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
 
315
                                size -= tfer;
 
316
                        }
 
317
                        // We assume we are reading back to front: 
 
318
                        if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
 
319
                                size_t mins;
 
320
 
 
321
                                if (offset + size >= SC_DEFAULT_FILE_BUFFER_SIZE) {
 
322
                                        iFileBufferOffset = offset + size - SC_DEFAULT_FILE_BUFFER_SIZE;
 
323
                                        mins = SC_DEFAULT_FILE_BUFFER_SIZE;
 
324
                                }
 
325
                                else {
 
326
                                        iFileBufferOffset = 0;
 
327
                                        mins = (size_t) offset + size;
 
328
                                }
 
329
                                result = myFile->read(iFileBuffer, iFileBufferOffset, SC_DEFAULT_FILE_BUFFER_SIZE, mins);
 
330
                                iBufferDataLen = result;
 
331
                                memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
 
332
                        }
 
333
                        else
 
334
                                result = myFile->read(data, offset, size, size);
 
335
                        return size + tfer;
 
336
                }
 
337
                if (offset + size <= iFileBufferOffset + iBufferDataLen) {
 
338
                        // 3
 
339
                        memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
 
340
                        return size;
 
341
                }
 
342
                if (offset < iFileBufferOffset + iBufferDataLen) {
 
343
                        // 4 We assume we are reading front to back
 
344
                        tfer = iFileBufferOffset + iBufferDataLen - offset;
 
345
                        memcpy(data, iFileBuffer + (offset - iFileBufferOffset), tfer);
 
346
                        data = (char *) data + tfer;
 
347
                        size -= tfer;
 
348
                        offset += tfer;
 
349
                        if (min_size >= tfer)
 
350
                                min_size -= tfer;
 
351
                        else
 
352
                                min_size = 0;
 
353
                }
 
354
                // else 5
 
355
        }
 
356
 
 
357
        readit:
 
358
        if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
 
359
                result = myFile->read(iFileBuffer, offset, SC_DEFAULT_FILE_BUFFER_SIZE, min_size);
 
360
                iFileBufferOffset = offset;
 
361
                iBufferDataLen = result;
 
362
                if (result > size)
 
363
                        result = size;
 
364
                memcpy(data, iFileBuffer, result);
 
365
        }
 
366
        else
 
367
                result = myFile->read(data, offset, size, min_size);
 
368
        return result + tfer;
 
369
}
 
370
 
 
371
void CSReadBufferedFile::write(const void *data, off_t offset, size_t size)
 
372
{
 
373
        if (iBufferDataLen > 0) {
 
374
                size_t tfer;
 
375
 
 
376
                if (offset < iFileBufferOffset) {
 
377
                        //  case 1, 2, 6
 
378
                        if (offset + size > iFileBufferOffset + iBufferDataLen) {
 
379
                                // 6 (would have to do 2 reads and a memcpy (better is just one read)
 
380
                                memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, iBufferDataLen);
 
381
                        }
 
382
                        else if (offset + size > iFileBufferOffset) {
 
383
                                // 2
 
384
                                tfer = offset + size - iFileBufferOffset;
 
385
                                memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
 
386
                        }
 
387
                }
 
388
                else if (offset + size <= iFileBufferOffset + iBufferDataLen) {
 
389
                        // 3
 
390
                        memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
 
391
                }
 
392
                else if (offset < iFileBufferOffset + iBufferDataLen) {
 
393
                        // 4 We assume we are reading front to back
 
394
                        tfer = iFileBufferOffset + iBufferDataLen - offset;
 
395
                        memcpy(iFileBuffer + (offset - iFileBufferOffset), data, tfer);
 
396
                }
 
397
                // else 5
 
398
        }
 
399
 
 
400
        writeit:
 
401
        myFile->write(data, offset, size);
 
402
}
 
403
 
 
404
void CSReadBufferedFile::flush()
 
405
{
 
406
        myFile->flush();
 
407
}
 
408
 
 
409
void CSReadBufferedFile::sync()
 
410
{
 
411
        flush();
 
412
        myFile->sync();
 
413
}
 
414
 
 
415
const char *CSReadBufferedFile::getEOL()
 
416
{
 
417
        return myFile->getEOL();
 
418
}
 
419
 
 
420
void CSReadBufferedFile::openFile(int mode)
 
421
{
 
422
        myFile->openFile(mode);
 
423
}
 
424
 
 
425
CSFile *CSReadBufferedFile::newFile(CSFile *file)
 
426
{
 
427
        CSReadBufferedFile *f;
 
428
 
 
429
        if (!(f = new CSReadBufferedFile())) {
 
430
                file->release();
 
431
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
 
432
        }
 
433
        f->myFile = file;
 
434
        f->myFilePath = file->myFilePath;
 
435
        f->myFilePath->retain();
 
436
        return (CSFile *) f;
 
437
}
 
438
 
 
439
/*
 
440
 * ---------------------------------------------------------------
 
441
 * A BUFFERED FILE
 
442
 */
 
443
 
 
444
void CSBufferedFile::write(const void *data, off_t offset, size_t size)
 
445
{
 
446
        if (iBufferDataLen > 0) {
 
447
                if (offset < iFileBufferOffset && offset <= iFileBufferOffset + iBufferDataLen) {
 
448
                        size_t tfer;
 
449
 
 
450
                        tfer = iFileBufferOffset + SC_DEFAULT_FILE_BUFFER_SIZE - offset;
 
451
                        if (tfer >= size) {
 
452
                                memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
 
453
                                size;
 
454
                        }
 
455
                        size -= tfer;
 
456
                        data = (char *) data + tfer;
 
457
                }
 
458
                flush();
 
459
        }
 
460
 
 
461
        writeit:
 
462
        if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
 
463
                iFileBufferOffset = offset;
 
464
                iBufferDataLen = size;
 
465
                memcpy(iFileBuffer, data, size);
 
466
                iBufferDirty = true;
 
467
        }
 
468
        else
 
469
                myFile->write(data, offset, size);
 
470
}
 
471
 
 
472
void CSBufferedFile::flush()
 
473
{
 
474
        if (iBufferDirty && iBufferDataLen) {
 
475
                myFile->write(iFileBuffer, iFileBufferOffset, iBufferDataLen);
 
476
                iBufferDirty = false;
 
477
                
 
478
        }
 
479
        myFile->flush();
 
480
}
 
481
 
 
482
/*
 
483
 * ---------------------------------------------------------------
 
484
 * FILE BASED ON THE STANDARD C FILE
 
485
 */