~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2010-07-06 00:44:32 UTC
  • mfrom: (1643.1.13 build)
  • Revision ID: mordred@inaugust.com-20100706004432-843uftc92rc2497l
Merged in PBMS, translation updates, a few build fixes and a few bug fixes.

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
#include "CSFile.h"
 
42
#include "CSStream.h"
 
43
#include "CSGlobal.h"
 
44
 
 
45
 
 
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
 
 
73
CSOutputStream *CSFile::getOutputStream(off64_t offset)
 
74
{
 
75
        return CSFileOutputStream::newStream(RETAIN(this), offset);
 
76
}
 
77
 
 
78
CSInputStream *CSFile::getInputStream()
 
79
{
 
80
        return CSFileInputStream::newStream(RETAIN(this));
 
81
}
 
82
 
 
83
CSInputStream *CSFile::getInputStream(off64_t offset)
 
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
 
 
93
        CLOBBER_PROTECT(retry);
 
94
 
 
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
 
 
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)
 
132
{
 
133
        size_t tfer;
 
134
 
 
135
        while (size > 0) {
 
136
                if (size > (off64_t) buffer_size)
 
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
 
 
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
}
 
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
 
 
178
off64_t CSFile::getEOF()
 
179
{
 
180
        off64_t eof;
 
181
 
 
182
        if ((eof = lseek(iFH, 0, SEEK_END)) == (off64_t) -1)
 
183
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
184
 
 
185
     return eof;
 
186
}
 
187
 
 
188
void CSFile::setEOF(off64_t offset)
 
189
{
 
190
        if (ftruncate(iFH, offset) == -1)
 
191
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
192
}
 
193
 
 
194
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
 
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
 
 
208
void CSFile::write(const void *data, off64_t offset, size_t size)
 
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))
 
266
                setEOF((off64_t) 0);
 
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
 
 
298
off64_t CSReadBufferedFile::getEOF()
 
299
{
 
300
        off64_t eof = myFile->getEOF();
 
301
 
 
302
        if (eof < iFileBufferOffset + iBufferDataLen)
 
303
                return iFileBufferOffset + iBufferDataLen;
 
304
        return eof;
 
305
}
 
306
 
 
307
void CSReadBufferedFile::setEOF(off64_t offset)
 
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
 
 
318
size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
 
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
 
 
391
void CSReadBufferedFile::write(const void *data, off64_t offset, size_t size)
 
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
 
 
463
void CSBufferedFile::write(const void *data, off64_t offset, size_t size)
 
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
 */