29
29
#include "CSConfig.h"
32
#include <sys/utime.h>
33
#define utimes(f, s) _utime(f, s)
32
35
#include <unistd.h>
33
36
#include <dirent.h>
39
42
#include <string.h>
41
45
#include "CSFile.h"
42
46
#include "CSStream.h"
46
static int unix_file_open(const char *path, int flags, mode_t mode)
48
return open(path, flags, mode);
51
int unix_file_close(int fh)
49
#define IS_MODE(m, s) ((m & s) == s)
57
52
* ---------------------------------------------------------------
85
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.
88
113
void CSFile::open(int mode)
93
CLOBBER_PROTECT(retry);
96
116
if (mode & CREATE) {
97
/* Create and open the file: */
104
if (retry || !isDirNotFound(&self->myException))
107
/* Make sure the parent directory exists: */
108
dir = CSPath::newPath(RETAIN(myFilePath), "..");
113
catch_(b) { /* Two threads may try to create the directory at the same time. */
114
if (!isDirExists(&self->myException))
118
while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}
128
sf_lock(IS_MODE(iMode, READONLY));
133
void CSFile::unlock()
131
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)
135
148
while (size > 0) {
136
149
if (size > (off64_t) buffer_size)
139
152
tfer = (size_t) size;
140
153
if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
142
155
dst_file->write(buffer, dst_offset, tfer);
143
156
dst_offset += tfer;
144
157
src_offset += tfer;
150
166
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
154
173
while (size > 0) {
155
174
if (size > (off64_t) buffer_size)
163
182
src_offset += tfer;
186
release_(dst_stream);
168
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);
170
200
void CSFile::close()
173
unix_file_close(iFH);
178
207
off64_t CSFile::getEOF()
182
if ((eof = lseek(iFH, 0, SEEK_END)) == (off64_t) -1)
183
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
188
212
void CSFile::setEOF(off64_t offset)
190
if (ftruncate(iFH, offset) == -1)
191
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
194
217
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
199
read_size = pread(iFH, data, size, offset);
222
read_size = sf_pread(data, size, offset);
200
223
self->interrupted();
202
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
203
if ((size_t) read_size < min_size)
224
if (read_size < min_size)
204
225
CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
205
226
return_(read_size);
208
229
void CSFile::write(const void *data, off64_t offset, size_t size)
213
write_size = pwrite(iFH, (void *) data, size, offset);
232
sf_pwrite(data, size, offset);
214
233
self->interrupted();
215
if (write_size != size)
216
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
246
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);
249
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));
261
if ((iFH = unix_file_open(myFilePath->getCString(), flags, CS_MASK)) == -1)
262
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
264
283
/* Does not make sense to truncate, and have READONLY! */
265
if ((mode & TRUNCATE) && !(mode & READONLY))
284
if (IS_MODE(mode, TRUNCATE) && !IS_MODE(mode, READONLY))
266
285
setEOF((off64_t) 0);
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);
270
310
* ---------------------------------------------------------------
271
311
* A READ BUFFERED FILE
312
352
iBufferDataLen = 0;
314
354
else if (offset < iFileBufferOffset + iBufferDataLen)
315
iBufferDataLen = offset - iFileBufferOffset;
355
iBufferDataLen = (size_t)(offset - iFileBufferOffset);
318
358
size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
331
371
if (offset + size > iFileBufferOffset) {
333
tfer = offset + size - iFileBufferOffset;
373
tfer = (size_t)(offset + size - iFileBufferOffset);
334
374
memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
362
402
if (offset < iFileBufferOffset + iBufferDataLen) {
363
403
// 4 We assume we are reading front to back
364
tfer = iFileBufferOffset + iBufferDataLen - offset;
404
tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
365
405
memcpy(data, iFileBuffer + (offset - iFileBufferOffset), tfer);
366
406
data = (char *) data + tfer;
402
442
else if (offset + size > iFileBufferOffset) {
404
tfer = offset + size - iFileBufferOffset;
444
tfer = (size_t)(offset + size - iFileBufferOffset);
405
445
memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
412
452
else if (offset < iFileBufferOffset + iBufferDataLen) {
413
453
// 4 We assume we are reading front to back
414
tfer = iFileBufferOffset + iBufferDataLen - offset;
454
tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
415
455
memcpy(iFileBuffer + (offset - iFileBufferOffset), data, tfer);
441
481
myFile->openFile(mode);
444
CSFile *CSReadBufferedFile::newFile(CSFile *file)
446
CSReadBufferedFile *f;
448
if (!(f = new CSReadBufferedFile())) {
450
CSException::throwOSError(CS_CONTEXT, ENOMEM);
453
f->myFilePath = file->myFilePath;
454
f->myFilePath->retain();
459
* ---------------------------------------------------------------
463
void CSBufferedFile::write(const void *data, off64_t offset, size_t size)
465
if (iBufferDataLen > 0) {
466
if (offset < iFileBufferOffset && offset <= iFileBufferOffset + iBufferDataLen) {
469
tfer = iFileBufferOffset + SC_DEFAULT_FILE_BUFFER_SIZE - offset;
471
memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
474
data = (char *) data + tfer;
479
if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
480
iFileBufferOffset = offset;
481
iBufferDataLen = size;
482
memcpy(iFileBuffer, data, size);
486
myFile->write(data, offset, size);
489
void CSBufferedFile::flush()
491
if (iBufferDirty && iBufferDataLen) {
492
myFile->write(iFileBuffer, iFileBufferOffset, iBufferDataLen);
493
iBufferDirty = false;
500
486
* ---------------------------------------------------------------