~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-08-05 19:01:20 UTC
  • mto: (266.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 266.
  • Revision ID: monty@inaugust.com-20080805190120-tsuziqz2mfqcw7pe
Removed libmysyslt.la, made mysys a noinst_ and made everything use it. It's
not a standalone lib, there's no reason to pretend otherwise.

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
 
 */