~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Barry.Leslie at PrimeBase
  • Date: 2010-10-18 21:21:20 UTC
  • mto: This revision was merged to the branch mainline in revision 1871.
  • Revision ID: barry.leslie@primebase.com-20101018212120-dqukgtkwhb1imt1o
Merged changes from lp:pbms. These changes should remove any danger
of longjmp() clobbering local variables.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
#include <dirent.h>
34
34
#endif
35
35
#include <stdio.h>
36
 
#include <sys/stat.h>
37
 
#include <fcntl.h>
 
36
#include <sys/time.h>
 
37
 
38
38
#include <errno.h>
39
39
#include <string.h>
40
40
 
 
41
#include "CSGlobal.h"
41
42
#include "CSFile.h"
42
43
#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
 
}
 
44
#include "CSMd5.h"
 
45
 
 
46
#define IS_MODE(m, s) ((m & s) == s)
55
47
 
56
48
/*
57
49
 * ---------------------------------------------------------------
85
77
        return CSFileInputStream::newStream(RETAIN(this), offset);
86
78
}
87
79
 
 
80
bool CSFile::try_CreateAndOpen(CSThread *self, int mode, bool retry)
 
81
{
 
82
        volatile bool rtc = true;
 
83
        
 
84
        try_(a) {
 
85
                openFile(mode);
 
86
                rtc = false; // success, do not try again.
 
87
        }
 
88
        catch_(a) {
 
89
                if (retry || !isDirNotFound(&self->myException))
 
90
                        throw_();
 
91
 
 
92
                /* Make sure the parent directory exists: */
 
93
                CSPath  *dir = CSPath::newPath(RETAIN(myFilePath), "..");
 
94
                push_(dir);
 
95
                try_(b) {
 
96
                        dir->makePath();
 
97
                }
 
98
                catch_(b) { /* Two threads may try to create the directory at the same time. */
 
99
                        if (!isDirExists(&self->myException))
 
100
                                throw_();
 
101
                }
 
102
                cont_(b);
 
103
 
 
104
                release_(dir);
 
105
        }
 
106
        cont_(a);
 
107
        return rtc; // try again.
 
108
}
 
109
 
88
110
void CSFile::open(int mode)
89
111
{
90
 
        CSPath  *dir;
91
 
        bool    retry = false;
92
 
 
93
 
        CLOBBER_PROTECT(retry);
94
 
 
95
112
        enter_();
96
113
        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);
 
114
                bool retry = false;
 
115
                while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}                
125
116
        }
126
117
        else
127
118
                openFile(mode);
128
119
        exit_();
129
120
}
130
121
 
 
122
void CSFile::lock()
 
123
{
 
124
        if (!iLocked) {
 
125
                sf_lock(IS_MODE(iMode, READONLY));
 
126
        }
 
127
        iLocked++;
 
128
}
 
129
 
 
130
void CSFile::unlock()
 
131
{
 
132
        iLocked--;
 
133
        if (!iLocked) 
 
134
                sf_unlock();
 
135
}
 
136
 
131
137
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
138
{
133
139
        size_t tfer;
 
140
        enter_();
 
141
        
 
142
        push_(dst_file);
 
143
        push_(src_file);
134
144
 
135
145
        while (size > 0) {
136
146
                if (size > (off64_t) buffer_size)
138
148
                else
139
149
                        tfer = (size_t) size;
140
150
                if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
141
 
                        return false;
 
151
                        break;
142
152
                dst_file->write(buffer, dst_offset, tfer);
143
153
                dst_offset += tfer;
144
154
                src_offset += tfer;
145
155
                size -= tfer;
146
156
        }
147
 
        return true;
 
157
        
 
158
        release_(src_file);
 
159
        release_(dst_file);
 
160
        return_(size == 0);
148
161
}
149
162
 
150
163
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
151
164
{
152
165
        size_t tfer;
 
166
        enter_();
 
167
        
 
168
        push_(dst_stream);
153
169
 
154
170
        while (size > 0) {
155
171
                if (size > (off64_t) buffer_size)
163
179
                src_offset += tfer;
164
180
                size -= tfer;
165
181
        }
 
182
        
 
183
        release_(dst_stream);
 
184
        exit_();
166
185
}
167
186
 
168
187
#define CS_MASK                         ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
169
188
 
 
189
void CSFile::touch()
 
190
{
 
191
        // don't use futimes() here. On some platforms it will fail if the 
 
192
        // file was opened readonly.
 
193
        if (utimes(myFilePath->getCString(), NULL) == -1)
 
194
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
195
}
 
196
 
170
197
void CSFile::close()
171
198
{
172
 
        if (iFH != -1) {
173
 
                unix_file_close(iFH);
174
 
                iFH = -1;
175
 
        }
 
199
        while (iLocked)
 
200
                unlock();
 
201
        sf_close();
176
202
}
177
203
 
178
204
off64_t CSFile::getEOF()
179
205
{
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;
 
206
     return sf_getEOF();
186
207
}
187
208
 
188
209
void CSFile::setEOF(off64_t offset)
189
210
{
190
 
        if (ftruncate(iFH, offset) == -1)
191
 
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
 
211
        sf_setEOF(offset);
192
212
}
193
213
 
194
214
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
195
215
{
196
 
        ssize_t read_size;
 
216
        size_t read_size;
197
217
        
198
218
        enter_();
199
 
        read_size = pread(iFH, data, size, offset);
 
219
        read_size = sf_pread(data, size, offset);
200
220
        self->interrupted();
201
 
        if (read_size ==  -1)
202
 
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
203
 
        if ((size_t) read_size < min_size)
 
221
        if (read_size < min_size)
204
222
                CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
205
223
        return_(read_size);
206
224
}
207
225
 
208
226
void CSFile::write(const void *data, off64_t offset, size_t size)
209
227
{
210
 
        size_t write_size;
211
 
 
212
228
        enter_();
213
 
    write_size = pwrite(iFH, (void *) data, size, offset);
 
229
    sf_pwrite(data, size, offset);
214
230
        self->interrupted();
215
 
        if (write_size != size)
216
 
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
217
231
        exit_();
218
232
}
219
233
 
223
237
 
224
238
void CSFile::sync()
225
239
{
226
 
        fsync(iFH);
 
240
        sf_sync();
227
241
}
228
242
 
229
243
CSFile *CSFile::newFile(CSPath *path)
246
260
        return newFile(path);
247
261
}
248
262
 
 
263
CSFile *CSFile::newFile(const char *dir_str, const char *path_str)
 
264
{
 
265
        CSPath *path;
 
266
 
 
267
        path = CSPath::newPath(dir_str, path_str);
 
268
        return newFile(path);
 
269
}
 
270
 
249
271
void CSFile::openFile(int mode)
250
272
{
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;
 
273
        if (fs_isOpen() && (iMode != mode))
 
274
                close();
 
275
                
 
276
        if (!fs_isOpen())
 
277
                sf_open(myFilePath->getCString(), IS_MODE(mode, READONLY), IS_MODE(mode, CREATE));
260
278
        
261
 
        if ((iFH = unix_file_open(myFilePath->getCString(), flags, CS_MASK)) ==  -1)
262
 
                CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
263
 
 
 
279
        iMode = mode;
264
280
        /* Does not make sense to truncate, and have READONLY! */
265
 
        if ((mode & TRUNCATE) && !(mode & READONLY))
 
281
        if (IS_MODE(mode, TRUNCATE) && !IS_MODE(mode, READONLY))
266
282
                setEOF((off64_t) 0);
267
283
}
268
284
 
 
285
void CSFile::md5Digest(Md5Digest *digest)
 
286
{
 
287
        u_char buffer[1024];
 
288
        off64_t offset = 0, size, len;
 
289
        CSMd5 md5;
 
290
        enter_();
 
291
        
 
292
        size = getEOF();
 
293
        while (size) {
 
294
                len = (size < 1024)? size:1024;
 
295
                len = read(buffer, offset, len, len);
 
296
                offset +=len;
 
297
                size -= len;
 
298
                md5.md5_append(buffer, len);
 
299
        }
 
300
        md5.md5_get_digest(digest);
 
301
        exit_();
 
302
        
 
303
}
 
304
 
269
305
/*
270
306
 * ---------------------------------------------------------------
271
307
 * A READ BUFFERED FILE
441
477
        myFile->openFile(mode);
442
478
}
443
479
 
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
480
 
499
481
/*
500
482
 * ---------------------------------------------------------------