15
15
* You should have received a copy of the GNU General Public License
16
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
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
19
* Original author: Paul McCullagh (H&G2JCtL)
20
20
* Continued development: Barry Leslie
29
29
#include "CSConfig.h"
32
#include <sys/utime.h>
33
#define utimes(f, s) _utime(f, s)
35
32
#include <unistd.h>
36
33
#include <dirent.h>
42
39
#include <string.h>
45
41
#include "CSFile.h"
46
42
#include "CSStream.h"
49
#define IS_MODE(m, s) ((m & s) == s)
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)
52
57
* ---------------------------------------------------------------
80
85
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
88
void CSFile::open(int mode)
93
CLOBBER_PROTECT(retry);
116
96
if (mode & CREATE) {
118
while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}
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))
128
sf_lock(IS_MODE(iMode, READONLY));
133
void CSFile::unlock()
140
131
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)
148
135
while (size > 0) {
149
136
if (size > (off64_t) buffer_size)
152
139
tfer = (size_t) size;
153
140
if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
155
142
dst_file->write(buffer, dst_offset, tfer);
156
143
dst_offset += tfer;
157
144
src_offset += tfer;
166
150
void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
173
154
while (size > 0) {
174
155
if (size > (off64_t) buffer_size)
182
163
src_offset += tfer;
186
release_(dst_stream);
190
168
#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);
200
170
void CSFile::close()
173
unix_file_close(iFH);
207
178
off64_t CSFile::getEOF()
182
if ((eof = lseek(iFH, 0, SEEK_END)) == (off64_t) -1)
183
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
212
188
void CSFile::setEOF(off64_t offset)
190
if (ftruncate(iFH, offset) == -1)
191
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
217
194
size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
222
read_size = sf_pread(data, size, offset);
199
read_size = pread(iFH, data, size, offset);
223
200
self->interrupted();
224
if (read_size < min_size)
202
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
203
if ((size_t) read_size < min_size)
225
204
CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
226
205
return_(read_size);
229
208
void CSFile::write(const void *data, off64_t offset, size_t size)
232
sf_pwrite(data, size, offset);
213
write_size = pwrite(iFH, (void *) data, size, offset);
233
214
self->interrupted();
215
if (write_size != size)
216
CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
263
246
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
249
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);
283
264
/* Does not make sense to truncate, and have READONLY! */
284
if (IS_MODE(mode, TRUNCATE) && !IS_MODE(mode, READONLY))
265
if ((mode & TRUNCATE) && !(mode & READONLY))
285
266
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);
310
270
* ---------------------------------------------------------------
311
271
* A READ BUFFERED FILE
352
312
iBufferDataLen = 0;
354
314
else if (offset < iFileBufferOffset + iBufferDataLen)
355
iBufferDataLen = (size_t)(offset - iFileBufferOffset);
315
iBufferDataLen = offset - iFileBufferOffset;
358
318
size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
371
331
if (offset + size > iFileBufferOffset) {
373
tfer = (size_t)(offset + size - iFileBufferOffset);
333
tfer = offset + size - iFileBufferOffset;
374
334
memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
402
362
if (offset < iFileBufferOffset + iBufferDataLen) {
403
363
// 4 We assume we are reading front to back
404
tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
364
tfer = iFileBufferOffset + iBufferDataLen - offset;
405
365
memcpy(data, iFileBuffer + (offset - iFileBufferOffset), tfer);
406
366
data = (char *) data + tfer;
442
402
else if (offset + size > iFileBufferOffset) {
444
tfer = (size_t)(offset + size - iFileBufferOffset);
404
tfer = offset + size - iFileBufferOffset;
445
405
memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
452
412
else if (offset < iFileBufferOffset + iBufferDataLen) {
453
413
// 4 We assume we are reading front to back
454
tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
414
tfer = iFileBufferOffset + iBufferDataLen - offset;
455
415
memcpy(iFileBuffer + (offset - iFileBufferOffset), data, tfer);
481
441
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;
486
500
* ---------------------------------------------------------------