33
33
#include <dirent.h>
39
39
#include <string.h>
41
42
#include "CSFile.h"
42
43
#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)
46
#define IS_MODE(m, s) ((m & s) == s)
57
49
* ---------------------------------------------------------------
85
77
return CSFileInputStream::newStream(RETAIN(this), offset);
80
bool CSFile::try_CreateAndOpen(CSThread *self, int mode, bool retry)
82
volatile bool rtc = true;
86
rtc = false; // success, do not try again.
89
if (retry || !isDirNotFound(&self->myException))
92
/* Make sure the parent directory exists: */
93
CSPath *dir = CSPath::newPath(RETAIN(myFilePath), "..");
98
catch_(b) { /* Two threads may try to create the directory at the same time. */
99
if (!isDirExists(&self->myException))
107
return rtc; // try again.
88
110
void CSFile::open(int mode)
93
CLOBBER_PROTECT(retry);
96
113
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))
115
while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}
125
sf_lock(IS_MODE(iMode, READONLY));
130
void CSFile::unlock()
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)
135
145
while (size > 0) {
136
146
if (size > (off64_t) buffer_size)
139
149
tfer = (size_t) size;
140
150
if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
142
152
dst_file->write(buffer, dst_offset, tfer);
143
153
dst_offset += tfer;
144
154
src_offset += tfer;
150
163
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
154
170
while (size > 0) {
155
171
if (size > (off64_t) buffer_size)
163
179
src_offset += tfer;
183
release_(dst_stream);
168
187
#define CS_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
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);
170
197
void CSFile::close()
173
unix_file_close(iFH);
178
204
off64_t CSFile::getEOF()
182
if ((eof = lseek(iFH, 0, SEEK_END)) == (off64_t) -1)
183
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
188
209
void CSFile::setEOF(off64_t offset)
190
if (ftruncate(iFH, offset) == -1)
191
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
194
214
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
199
read_size = pread(iFH, data, size, offset);
219
read_size = sf_pread(data, size, offset);
200
220
self->interrupted();
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);
208
226
void CSFile::write(const void *data, off64_t offset, size_t size)
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);
246
260
return newFile(path);
263
CSFile *CSFile::newFile(const char *dir_str, const char *path_str)
267
path = CSPath::newPath(dir_str, path_str);
268
return newFile(path);
249
271
void CSFile::openFile(int mode)
273
if (fs_isOpen() && (iMode != mode))
277
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
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);
285
void CSFile::md5Digest(Md5Digest *digest)
288
off64_t offset = 0, size, len;
294
len = (size < 1024)? size:1024;
295
len = read(buffer, offset, len, len);
298
md5.md5_append(buffer, len);
300
md5.md5_get_digest(digest);
270
306
* ---------------------------------------------------------------
271
307
* A READ BUFFERED FILE
441
477
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
482
* ---------------------------------------------------------------