~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Mark Atwood
  • Date: 2011-12-20 02:32:53 UTC
  • mfrom: (2469.1.1 drizzle-build)
  • Revision ID: me@mark.atwood.name-20111220023253-bvu0kr14kwsdvz7g
mergeĀ lp:~brianaker/drizzle/deprecate-pbms

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