1
/* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
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.
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.
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
19
* Original author: Paul McCullagh (H&G2JCtL)
20
* Continued development: Barry Leslie
32
#include <sys/utime.h>
33
#define utimes(f, s) _utime(f, s)
49
#define IS_MODE(m, s) ((m & s) == s)
52
* ---------------------------------------------------------------
60
myFilePath->release();
63
CSOutputStream *CSFile::getOutputStream()
65
return CSFileOutputStream::newStream(RETAIN(this));
68
CSOutputStream *CSFile::getOutputStream(off64_t offset)
70
return CSFileOutputStream::newStream(RETAIN(this), offset);
73
CSInputStream *CSFile::getInputStream()
75
return CSFileInputStream::newStream(RETAIN(this));
78
CSInputStream *CSFile::getInputStream(off64_t offset)
80
return CSFileInputStream::newStream(RETAIN(this), offset);
83
bool CSFile::try_CreateAndOpen(CSThread *self, int mode, bool retry)
85
volatile bool rtc = true;
89
rtc = false; // success, do not try again.
92
if (retry || !isDirNotFound(&self->myException))
95
/* Make sure the parent directory exists: */
96
CSPath *dir = CSPath::newPath(RETAIN(myFilePath), "..");
101
catch_(b) { /* Two threads may try to create the directory at the same time. */
102
if (!isDirExists(&self->myException))
110
return rtc; // try again.
113
void CSFile::open(int mode)
118
while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}
128
sf_lock(IS_MODE(iMode, READONLY));
133
void CSFile::unlock()
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)
149
if (size > (off64_t) buffer_size)
152
tfer = (size_t) size;
153
if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
155
dst_file->write(buffer, dst_offset, tfer);
166
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
174
if (size > (off64_t) buffer_size)
177
tfer = (size_t) size;
179
read(buffer, src_offset, tfer, tfer);
180
dst_stream->write(buffer, tfer);
186
release_(dst_stream);
190
#define CS_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
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);
207
off64_t CSFile::getEOF()
212
void CSFile::setEOF(off64_t offset)
217
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
222
read_size = sf_pread(data, size, offset);
224
if (read_size < min_size)
225
CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
229
void CSFile::write(const void *data, off64_t offset, size_t size)
232
sf_pwrite(data, size, offset);
246
CSFile *CSFile::newFile(CSPath *path)
250
if (!(f = new CSFile())) {
252
CSException::throwOSError(CS_CONTEXT, ENOMEM);
254
f->myFilePath = path;
258
CSFile *CSFile::newFile(const char *path_str)
262
path = CSPath::newPath(path_str);
263
return newFile(path);
266
CSFile *CSFile::newFile(const char *dir_str, const char *path_str)
270
path = CSPath::newPath(dir_str, path_str);
271
return newFile(path);
274
void CSFile::openFile(int mode)
276
if (fs_isOpen() && (iMode != mode))
280
sf_open(myFilePath->getCString(), IS_MODE(mode, READONLY), IS_MODE(mode, CREATE));
283
/* Does not make sense to truncate, and have READONLY! */
284
if (IS_MODE(mode, TRUNCATE) && !IS_MODE(mode, READONLY))
288
void CSFile::md5Digest(Md5Digest *digest)
291
off64_t offset = 0, size;
298
len = (size_t)((size < 1024)? size:1024);
299
len = read(buffer, offset, len, len);
302
md5.md5_append(buffer, len);
304
md5.md5_get_digest(digest);
310
* ---------------------------------------------------------------
311
* A READ BUFFERED FILE
314
CSReadBufferedFile::CSReadBufferedFile():
316
iFileBufferOffset(0),
321
CSReadBufferedFile::~CSReadBufferedFile()
330
void CSReadBufferedFile::close()
334
iFileBufferOffset = 0;
338
off64_t CSReadBufferedFile::getEOF()
340
off64_t eof = myFile->getEOF();
342
if (eof < iFileBufferOffset + iBufferDataLen)
343
return iFileBufferOffset + iBufferDataLen;
347
void CSReadBufferedFile::setEOF(off64_t offset)
349
myFile->setEOF(offset);
350
if (offset < iFileBufferOffset) {
351
iFileBufferOffset = 0;
354
else if (offset < iFileBufferOffset + iBufferDataLen)
355
iBufferDataLen = (size_t)(offset - iFileBufferOffset);
358
size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
363
if (iBufferDataLen > 0) {
364
if (offset < iFileBufferOffset) {
366
if (offset + size > iFileBufferOffset + iBufferDataLen) {
367
// 6 (would have to do 2 reads and a memcpy (better is just one read)
371
if (offset + size > iFileBufferOffset) {
373
tfer = (size_t)(offset + size - iFileBufferOffset);
374
memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
377
// We assume we are reading back to front:
378
if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
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;
386
iFileBufferOffset = 0;
387
mins = (size_t) offset + size;
389
result = myFile->read(iFileBuffer, iFileBufferOffset, SC_DEFAULT_FILE_BUFFER_SIZE, mins);
390
iBufferDataLen = result;
391
memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
394
result = myFile->read(data, offset, size, size);
397
if (offset + size <= iFileBufferOffset + iBufferDataLen) {
399
memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
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;
409
if (min_size >= tfer)
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;
424
memcpy(data, iFileBuffer, result);
427
result = myFile->read(data, offset, size, min_size);
428
return result + tfer;
431
void CSReadBufferedFile::write(const void *data, off64_t offset, size_t size)
433
if (iBufferDataLen > 0) {
436
if (offset < iFileBufferOffset) {
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);
442
else if (offset + size > iFileBufferOffset) {
444
tfer = (size_t)(offset + size - iFileBufferOffset);
445
memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
448
else if (offset + size <= iFileBufferOffset + iBufferDataLen) {
450
memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
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);
460
myFile->write(data, offset, size);
463
void CSReadBufferedFile::flush()
468
void CSReadBufferedFile::sync()
474
const char *CSReadBufferedFile::getEOL()
476
return myFile->getEOL();
479
void CSReadBufferedFile::openFile(int mode)
481
myFile->openFile(mode);
486
* ---------------------------------------------------------------
487
* FILE BASED ON THE STANDARD C FILE