~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-11-08 18:24:58 UTC
  • mto: (1921.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 1916.
  • Revision ID: brian@tangent.org-20101108182458-twv4hyix43ojno80
Merge in changes such that lock is now broken out into its own directory.

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