00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "CSConfig.h"
00030
00031 #ifdef OS_WINDOWS
00032 #include <sys/utime.h>
00033 #define utimes(f, s) _utime(f, s)
00034 #else
00035 #include <unistd.h>
00036 #include <dirent.h>
00037 #include <sys/time.h>
00038 #endif
00039 #include <stdio.h>
00040
00041 #include <errno.h>
00042 #include <string.h>
00043
00044 #include "CSGlobal.h"
00045 #include "CSFile.h"
00046 #include "CSStream.h"
00047 #include "CSMd5.h"
00048
00049 #define IS_MODE(m, s) ((m & s) == s)
00050
00051
00052
00053
00054
00055
00056 CSFile::~CSFile()
00057 {
00058 close();
00059 if (myFilePath)
00060 myFilePath->release();
00061 }
00062
00063 CSOutputStream *CSFile::getOutputStream()
00064 {
00065 return CSFileOutputStream::newStream(RETAIN(this));
00066 }
00067
00068 CSOutputStream *CSFile::getOutputStream(off64_t offset)
00069 {
00070 return CSFileOutputStream::newStream(RETAIN(this), offset);
00071 }
00072
00073 CSInputStream *CSFile::getInputStream()
00074 {
00075 return CSFileInputStream::newStream(RETAIN(this));
00076 }
00077
00078 CSInputStream *CSFile::getInputStream(off64_t offset)
00079 {
00080 return CSFileInputStream::newStream(RETAIN(this), offset);
00081 }
00082
00083 bool CSFile::try_CreateAndOpen(CSThread *self, int mode, bool retry)
00084 {
00085 volatile bool rtc = true;
00086
00087 try_(a) {
00088 openFile(mode);
00089 rtc = false;
00090 }
00091 catch_(a) {
00092 if (retry || !isDirNotFound(&self->myException))
00093 throw_();
00094
00095
00096 CSPath *dir = CSPath::newPath(RETAIN(myFilePath), "..");
00097 push_(dir);
00098 try_(b) {
00099 dir->makePath();
00100 }
00101 catch_(b) {
00102 if (!isDirExists(&self->myException))
00103 throw_();
00104 }
00105 cont_(b);
00106
00107 release_(dir);
00108 }
00109 cont_(a);
00110 return rtc;
00111 }
00112
00113 void CSFile::open(int mode)
00114 {
00115 enter_();
00116 if (mode & CREATE) {
00117 bool retry = false;
00118 while ((retry = try_CreateAndOpen(self, mode, retry)) == true){}
00119 }
00120 else
00121 openFile(mode);
00122 exit_();
00123 }
00124
00125 void CSFile::lock()
00126 {
00127 if (!iLocked) {
00128 sf_lock(IS_MODE(iMode, READONLY));
00129 }
00130 iLocked++;
00131 }
00132
00133 void CSFile::unlock()
00134 {
00135 iLocked--;
00136 if (!iLocked)
00137 sf_unlock();
00138 }
00139
00140 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)
00141 {
00142 size_t tfer;
00143 enter_();
00144
00145 push_(dst_file);
00146 push_(src_file);
00147
00148 while (size > 0) {
00149 if (size > (off64_t) buffer_size)
00150 tfer = buffer_size;
00151 else
00152 tfer = (size_t) size;
00153 if (!(tfer = src_file->read(buffer, src_offset, tfer, 0)))
00154 break;
00155 dst_file->write(buffer, dst_offset, tfer);
00156 dst_offset += tfer;
00157 src_offset += tfer;
00158 size -= tfer;
00159 }
00160
00161 release_(src_file);
00162 release_(dst_file);
00163 return_(size == 0);
00164 }
00165
00166 void CSFile::streamOut(CSOutputStream *dst_stream, off64_t src_offset, off64_t size, char *buffer, size_t buffer_size)
00167 {
00168 size_t tfer;
00169 enter_();
00170
00171 push_(dst_stream);
00172
00173 while (size > 0) {
00174 if (size > (off64_t) buffer_size)
00175 tfer = buffer_size;
00176 else
00177 tfer = (size_t) size;
00178
00179 read(buffer, src_offset, tfer, tfer);
00180 dst_stream->write(buffer, tfer);
00181
00182 src_offset += tfer;
00183 size -= tfer;
00184 }
00185
00186 release_(dst_stream);
00187 exit_();
00188 }
00189
00190 #define CS_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
00191
00192 void CSFile::touch()
00193 {
00194
00195
00196 if (utimes(myFilePath->getCString(), NULL) == -1)
00197 CSException::throwFileError(CS_CONTEXT, myFilePath->getCString(), errno);
00198 }
00199
00200 void CSFile::close()
00201 {
00202 while (iLocked)
00203 unlock();
00204 sf_close();
00205 }
00206
00207 off64_t CSFile::getEOF()
00208 {
00209 return sf_getEOF();
00210 }
00211
00212 void CSFile::setEOF(off64_t offset)
00213 {
00214 sf_setEOF(offset);
00215 }
00216
00217 size_t CSFile::read(void *data, off64_t offset, size_t size, size_t min_size)
00218 {
00219 size_t read_size;
00220
00221 enter_();
00222 read_size = sf_pread(data, size, offset);
00223 self->interrupted();
00224 if (read_size < min_size)
00225 CSException::throwEOFError(CS_CONTEXT, myFilePath->getCString());
00226 return_(read_size);
00227 }
00228
00229 void CSFile::write(const void *data, off64_t offset, size_t size)
00230 {
00231 enter_();
00232 sf_pwrite(data, size, offset);
00233 self->interrupted();
00234 exit_();
00235 }
00236
00237 void CSFile::flush()
00238 {
00239 }
00240
00241 void CSFile::sync()
00242 {
00243 sf_sync();
00244 }
00245
00246 CSFile *CSFile::newFile(CSPath *path)
00247 {
00248 CSFile *f;
00249
00250 if (!(f = new CSFile())) {
00251 path->release();
00252 CSException::throwOSError(CS_CONTEXT, ENOMEM);
00253 }
00254 f->myFilePath = path;
00255 return f;
00256 }
00257
00258 CSFile *CSFile::newFile(const char *path_str)
00259 {
00260 CSPath *path;
00261
00262 path = CSPath::newPath(path_str);
00263 return newFile(path);
00264 }
00265
00266 CSFile *CSFile::newFile(const char *dir_str, const char *path_str)
00267 {
00268 CSPath *path;
00269
00270 path = CSPath::newPath(dir_str, path_str);
00271 return newFile(path);
00272 }
00273
00274 void CSFile::openFile(int mode)
00275 {
00276 if (fs_isOpen() && (iMode != mode))
00277 close();
00278
00279 if (!fs_isOpen())
00280 sf_open(myFilePath->getCString(), IS_MODE(mode, READONLY), IS_MODE(mode, CREATE));
00281
00282 iMode = mode;
00283
00284 if (IS_MODE(mode, TRUNCATE) && !IS_MODE(mode, READONLY))
00285 setEOF((off64_t) 0);
00286 }
00287
00288 void CSFile::md5Digest(Md5Digest *digest)
00289 {
00290 u_char buffer[1024];
00291 off64_t offset = 0, size;
00292 size_t len;
00293 CSMd5 md5;
00294 enter_();
00295
00296 size = getEOF();
00297 while (size) {
00298 len = (size_t)((size < 1024)? size:1024);
00299 len = read(buffer, offset, len, len);
00300 offset +=len;
00301 size -= len;
00302 md5.md5_append(buffer, len);
00303 }
00304 md5.md5_get_digest(digest);
00305 exit_();
00306
00307 }
00308
00309
00310
00311
00312
00313
00314 CSReadBufferedFile::CSReadBufferedFile():
00315 myFile(NULL),
00316 iFileBufferOffset(0),
00317 iBufferDataLen(0)
00318 {
00319 }
00320
00321 CSReadBufferedFile::~CSReadBufferedFile()
00322 {
00323 if (myFile) {
00324 close();
00325 myFile->release();
00326 myFile = NULL;
00327 }
00328 }
00329
00330 void CSReadBufferedFile::close()
00331 {
00332 flush();
00333 myFile->close();
00334 iFileBufferOffset = 0;
00335 iBufferDataLen = 0;
00336 }
00337
00338 off64_t CSReadBufferedFile::getEOF()
00339 {
00340 off64_t eof = myFile->getEOF();
00341
00342 if (eof < iFileBufferOffset + iBufferDataLen)
00343 return iFileBufferOffset + iBufferDataLen;
00344 return eof;
00345 }
00346
00347 void CSReadBufferedFile::setEOF(off64_t offset)
00348 {
00349 myFile->setEOF(offset);
00350 if (offset < iFileBufferOffset) {
00351 iFileBufferOffset = 0;
00352 iBufferDataLen = 0;
00353 }
00354 else if (offset < iFileBufferOffset + iBufferDataLen)
00355 iBufferDataLen = (size_t)(offset - iFileBufferOffset);
00356 }
00357
00358 size_t CSReadBufferedFile::read(void *data, off64_t offset, size_t size, size_t min_size)
00359 {
00360 size_t result;
00361 size_t tfer = 0;
00362
00363 if (iBufferDataLen > 0) {
00364 if (offset < iFileBufferOffset) {
00365
00366 if (offset + size > iFileBufferOffset + iBufferDataLen) {
00367
00368 flush();
00369 goto readit;
00370 }
00371 if (offset + size > iFileBufferOffset) {
00372
00373 tfer = (size_t)(offset + size - iFileBufferOffset);
00374 memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, tfer);
00375 size -= tfer;
00376 }
00377
00378 if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
00379 size_t mins;
00380
00381 if (offset + size >= SC_DEFAULT_FILE_BUFFER_SIZE) {
00382 iFileBufferOffset = offset + size - SC_DEFAULT_FILE_BUFFER_SIZE;
00383 mins = SC_DEFAULT_FILE_BUFFER_SIZE;
00384 }
00385 else {
00386 iFileBufferOffset = 0;
00387 mins = (size_t) offset + size;
00388 }
00389 result = myFile->read(iFileBuffer, iFileBufferOffset, SC_DEFAULT_FILE_BUFFER_SIZE, mins);
00390 iBufferDataLen = result;
00391 memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
00392 }
00393 else
00394 result = myFile->read(data, offset, size, size);
00395 return size + tfer;
00396 }
00397 if (offset + size <= iFileBufferOffset + iBufferDataLen) {
00398
00399 memcpy(data, iFileBuffer + (offset - iFileBufferOffset), size);
00400 return size;
00401 }
00402 if (offset < iFileBufferOffset + iBufferDataLen) {
00403
00404 tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
00405 memcpy(data, iFileBuffer + (offset - iFileBufferOffset), tfer);
00406 data = (char *) data + tfer;
00407 size -= tfer;
00408 offset += tfer;
00409 if (min_size >= tfer)
00410 min_size -= tfer;
00411 else
00412 min_size = 0;
00413 }
00414
00415 }
00416
00417 readit:
00418 if (size < SC_DEFAULT_FILE_BUFFER_SIZE) {
00419 result = myFile->read(iFileBuffer, offset, SC_DEFAULT_FILE_BUFFER_SIZE, min_size);
00420 iFileBufferOffset = offset;
00421 iBufferDataLen = result;
00422 if (result > size)
00423 result = size;
00424 memcpy(data, iFileBuffer, result);
00425 }
00426 else
00427 result = myFile->read(data, offset, size, min_size);
00428 return result + tfer;
00429 }
00430
00431 void CSReadBufferedFile::write(const void *data, off64_t offset, size_t size)
00432 {
00433 if (iBufferDataLen > 0) {
00434 size_t tfer;
00435
00436 if (offset < iFileBufferOffset) {
00437
00438 if (offset + size > iFileBufferOffset + iBufferDataLen) {
00439
00440 memcpy((char *) data + (iFileBufferOffset - offset), iFileBuffer, iBufferDataLen);
00441 }
00442 else if (offset + size > iFileBufferOffset) {
00443
00444 tfer = (size_t)(offset + size - iFileBufferOffset);
00445 memcpy(iFileBuffer, (char *) data + (iFileBufferOffset - offset), tfer);
00446 }
00447 }
00448 else if (offset + size <= iFileBufferOffset + iBufferDataLen) {
00449
00450 memcpy(iFileBuffer + (offset - iFileBufferOffset), data, size);
00451 }
00452 else if (offset < iFileBufferOffset + iBufferDataLen) {
00453
00454 tfer = (size_t)(iFileBufferOffset + iBufferDataLen - offset);
00455 memcpy(iFileBuffer + (offset - iFileBufferOffset), data, tfer);
00456 }
00457
00458 }
00459
00460 myFile->write(data, offset, size);
00461 }
00462
00463 void CSReadBufferedFile::flush()
00464 {
00465 myFile->flush();
00466 }
00467
00468 void CSReadBufferedFile::sync()
00469 {
00470 flush();
00471 myFile->sync();
00472 }
00473
00474 const char *CSReadBufferedFile::getEOL()
00475 {
00476 return myFile->getEOL();
00477 }
00478
00479 void CSReadBufferedFile::openFile(int mode)
00480 {
00481 myFile->openFile(mode);
00482 }
00483
00484
00485
00486
00487
00488