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
00030
00031
00032
00033
00041 #include "blocxx/BLOCXX_config.h"
00042 #include "blocxx/FileSystem.hpp"
00043 #include "blocxx/Mutex.hpp"
00044 #include "blocxx/MutexLock.hpp"
00045 #include "blocxx/GlobalMutex.hpp"
00046 #include "blocxx/File.hpp"
00047 #include "blocxx/Array.hpp"
00048 #include "blocxx/Format.hpp"
00049 #include "blocxx/ExceptionIds.hpp"
00050 #include "blocxx/Assertion.hpp"
00051 #include "blocxx/GlobalPtr.hpp"
00052 #include "blocxx/FileSystemMockObject.hpp"
00053 #include "blocxx/AutoPtr.hpp"
00054 #include "blocxx/SafeCString.hpp"
00055 #include "blocxx/Logger.hpp"
00056 #include "blocxx/GlobalString.hpp"
00057
00058 extern "C"
00059 {
00060 #ifdef BLOCXX_WIN32
00061
00062 #include <direct.h>
00063 #include <io.h>
00064 #include <share.h>
00065 #include <AccCtrl.h.>
00066 #include <Aclapi.h>
00067 #include "blocxx/PathSecurity.hpp"
00068 using namespace BLOCXX_NAMESPACE;
00069
00071 static unsigned long MapPosixPermissionsMask( PACCESS_ALLOWED_ACE pAce, int PermissionMask )
00072 {
00073 pAce->Mask = 0;
00074 pAce->Mask |= ((PermissionMask & S_IROTH) == S_IROTH) ? BLOCXX_WIN32_ACCESSMASK_GENERIC_READ : 0;
00075 pAce->Mask |= ((PermissionMask & S_IWOTH) == S_IWOTH) ? BLOCXX_WIN32_ACCESSMASK_GENERIC_WRITE : 0;
00076 pAce->Mask |= ((PermissionMask & S_IXOTH) == S_IXOTH) ? BLOCXX_WIN32_ACCESSMASK_GENERIC_EXEC : 0;
00077 return pAce->Mask;
00078 }
00079
00081
00082
00083
00084
00085
00086 static int posix_chmod(const char* path, int mode)
00087 {
00088 int result, nLenghtNeeded;
00089 PSID ppOwnerSid = NULL, ppGroupSid = NULL, pSecurityDescriptor = NULL;
00090 PACL pAcl = NULL;
00091 if ( (result = GetNamedSecurityInfo( (LPTSTR)path,
00092 SE_FILE_OBJECT,
00093 DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
00094 &ppOwnerSid,
00095 &ppGroupSid,
00096 &pAcl,
00097 NULL,
00098 &pSecurityDescriptor) ) )
00099 {
00100 return result;
00101 }
00102
00103
00104
00105
00106 for (unsigned short aceIdx = 0; aceIdx < pAcl->AceCount; aceIdx++)
00107 {
00108 ACE_HEADER* pAce;
00109 if (!::GetAce(pAcl, aceIdx, (void**)&pAce))
00110 {
00111 continue;
00112 }
00113 switch( pAce->AceType )
00114 {
00115 case ACCESS_ALLOWED_ACE_TYPE:
00116 {
00117 PACCESS_ALLOWED_ACE pAllowedAce = (PACCESS_ALLOWED_ACE) pAce;
00118 unsigned long sNameLen, sDNameLen = sNameLen = MAX_PATH;
00119 char sName[MAX_PATH] = {0}, sDName[MAX_PATH] = {0};
00120 SID_NAME_USE eUse;
00121
00122 if ( !::LookupAccountSid( NULL, &(pAllowedAce->SidStart), sName, &sNameLen, sDName, &sDNameLen, &eUse) )
00123 {
00124 continue;
00125 }
00126
00127 if ( EqualSid( ppOwnerSid, &pAllowedAce->SidStart ) || (eUse == SidTypeWellKnownGroup && !strcmp(sName, "CREATOR OWNER")) )
00128 {
00129
00130 int hundreds = mode / 100;
00131 MapPosixPermissionsMask( pAllowedAce, (hundreds - (hundreds/10)*10) );
00132 break;
00133 }
00134 if ( EqualSid( ppGroupSid, &pAllowedAce->SidStart ) || eUse == WinCreatorGroupSid )
00135 {
00136
00137 int decimals = mode / 10;
00138 MapPosixPermissionsMask( pAllowedAce, (decimals - (decimals/10)*10) );
00139 break;
00140 }
00141
00142 MapPosixPermissionsMask( pAllowedAce, (mode - (mode/10)*10) );
00143 }
00144 break;
00145
00146 case ACCESS_DENIED_ACE_TYPE:
00147 {
00148
00149
00150
00151
00152 DeleteAce(pAcl, aceIdx);
00153 }
00154 break;
00155 }
00156 }
00157
00158
00159
00160
00161
00162 result = SetNamedSecurityInfo((LPTSTR)path,
00163 SE_FILE_OBJECT,
00164 PROTECTED_DACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
00165 ppOwnerSid,
00166 ppGroupSid,
00167 pAcl,
00168 NULL);
00169
00170 if (pSecurityDescriptor) LocalFree((HLOCAL)pSecurityDescriptor);
00171
00172 return result;
00173 }
00174
00176 static int posix_mkdir(const char* path, int mode)
00177 {
00178 int result;
00179 if ( result = _mkdir(path) ) return result;
00185 return ((mode!=-1) ? result = posix_chmod(path, mode) : result);
00186 }
00187
00189 #define _ACCESS ::_access
00190 #define R_OK 4
00191 #define F_OK 0
00192 #define W_OK 2
00193 #define _CHDIR _chdir
00194 #define _MKDIR(a,b) posix_mkdir((a), (b))
00195 #define _RMDIR _rmdir
00196 #define _UNLINK _unlink
00197
00198 #else
00199
00200 #ifdef BLOCXX_HAVE_UNISTD_H
00201 #include <unistd.h>
00202 #endif
00203 #ifdef BLOCXX_HAVE_DIRENT_H
00204 #include <dirent.h>
00205 #endif
00206
00207 #define _ACCESS ::access
00208 #define _CHDIR chdir
00209 #define _MKDIR(a,b) mkdir((a),(b))
00210 #define _RMDIR rmdir
00211 #define _UNLINK unlink
00212
00213 #ifdef BLOCXX_NETWARE
00214 #define MAXSYMLINKS 20
00215 #endif
00216
00217 #endif
00218
00219 #include <sys/stat.h>
00220 #include <sys/types.h>
00221 #include <fcntl.h>
00222 }
00223
00224 #include <cstdio>
00225 #include <fstream>
00226 #include <cerrno>
00227
00228 namespace BLOCXX_NAMESPACE
00229 {
00230
00231 BLOCXX_DEFINE_EXCEPTION_WITH_ID(FileSystem);
00232
00233 namespace FileSystem
00234 {
00235
00236 typedef GlobalPtr<FileSystemMockObject, NullFactory> FileSystemMockObject_t;
00237 FileSystemMockObject_t g_fileSystemMockObject = BLOCXX_GLOBAL_PTR_INIT;
00238
00239 GlobalString COMPONENT_NAME = BLOCXX_GLOBAL_STRING_INIT("blocxx");
00240
00242
00243 int
00244 changeFileOwner(const String& filename,
00245 const UserId& userId)
00246 {
00247 #ifdef BLOCXX_WIN32
00248 return 0;
00249 #else
00250 return ::chown(filename.c_str(), userId, gid_t(-1));
00251 #endif
00252 }
00254
00255 File
00256 openFile(const String& path)
00257 {
00258 if (g_fileSystemMockObject)
00259 {
00260 return g_fileSystemMockObject->openFile(path);
00261 }
00262 #ifdef BLOCXX_WIN32
00263 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00264 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
00265 FILE_ATTRIBUTE_NORMAL, NULL);
00266
00267 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00268 #else
00269 return File(::open(path.c_str(), O_RDWR));
00270 #endif
00271 }
00273
00274 File
00275 createFile(const String& path)
00276 {
00277 if (g_fileSystemMockObject)
00278 {
00279 return g_fileSystemMockObject->createFile(path);
00280 }
00281 #ifdef BLOCXX_WIN32
00282 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00283 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW,
00284 FILE_ATTRIBUTE_NORMAL, NULL);
00285 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00286 #else
00287 int fd = ::open(path.c_str(), O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0660);
00288 if (fd != -1)
00289 {
00290 return File(fd);
00291 }
00292 return File();
00293 #endif
00294
00295 }
00297
00298 File
00299 openOrCreateFile(const String& path)
00300 {
00301 if (g_fileSystemMockObject)
00302 {
00303 return g_fileSystemMockObject->openOrCreateFile(path);
00304 }
00305 #ifdef BLOCXX_WIN32
00306 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00307 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
00308 FILE_ATTRIBUTE_NORMAL, NULL);
00309 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00310 #else
00311 return File(::open(path.c_str(), O_RDWR | O_CREAT, 0660));
00312 #endif
00313 }
00314
00316
00317 File
00318 openForAppendOrCreateFile(const String& path)
00319 {
00320 if (g_fileSystemMockObject)
00321 {
00322 return g_fileSystemMockObject->openForAppendOrCreateFile(path);
00323 }
00324 #ifdef BLOCXX_WIN32
00325
00326
00327 HANDLE fh = ::CreateFile(path.c_str(), FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE,
00328 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS,
00329 FILE_ATTRIBUTE_NORMAL, NULL);
00330 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00331 #else
00332 return File(::open(path.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0660));
00333 #endif
00334 }
00335
00337 namespace
00338 {
00339 GlobalMutex tmpfileMutex = BLOCXX_GLOBAL_MUTEX_INIT();
00340 }
00341
00342 #ifndef BLOCXX_WIN32
00343
00344 File
00345 createTempFile(String& filePath, const String& dir)
00346 {
00347 filePath.erase();
00348 if (g_fileSystemMockObject)
00349 {
00350 return g_fileSystemMockObject->createTempFile(filePath, dir);
00351 }
00352
00353 String sfname;
00354 if (dir.empty())
00355 {
00356 const char* envtmp = ::getenv("TMPDIR");
00357 if (!envtmp)
00358 {
00359 sfname = "/tmp/";
00360 }
00361 else
00362 {
00363 sfname = envtmp;
00364 if (!sfname.endsWith('/'))
00365 sfname += '/';
00366 }
00367 }
00368 else
00369 {
00370 sfname = (dir.endsWith('/')) ? dir : dir+"/";
00371 }
00372
00373 sfname += "blocxxtmpfileXXXXXX";
00374 size_t len = sfname.length();
00375
00376 AutoPtrVec<char> filename(new char[len + 1]);
00377 SafeCString::strcpy_check(filename.get(), len + 1, sfname.c_str());
00378 MutexLock tmpfileML(tmpfileMutex);
00379 int hdl = mkstemp(filename.get());
00380 if (hdl == -1)
00381 {
00382 return File();
00383 }
00384 filePath = filename.get();
00385 return File(hdl);
00386 }
00387
00389 File
00390 createAutoDeleteTempFile(const String& dir)
00391 {
00392 if (g_fileSystemMockObject)
00393 {
00394 return g_fileSystemMockObject->createTempFile(dir);
00395 }
00396
00397 String sfname;
00398 if (dir.empty())
00399 {
00400 const char* envtmp = ::getenv("TMPDIR");
00401 if (!envtmp)
00402 {
00403 sfname = "/tmp/";
00404 }
00405 else
00406 {
00407 sfname = envtmp;
00408 if (!sfname.endsWith('/'))
00409 sfname += '/';
00410 }
00411 }
00412 else
00413 {
00414 sfname = (dir.endsWith('/')) ? dir : dir+"/";
00415 }
00416
00417 sfname += "blocxxtmpfileXXXXXX";
00418 size_t len = sfname.length();
00419 AutoPtrVec<char> filename(new char[len + 1]);
00420 SafeCString::strcpy_check(filename.get(), len + 1, sfname.c_str());
00421 MutexLock tmpfileML(tmpfileMutex);
00422 int hdl = mkstemp(filename.get());
00423 if (hdl == -1)
00424 {
00425 return File();
00426 }
00427 else
00428 {
00429 if (::unlink(filename.get()) != 0)
00430 {
00431 Logger lgr(COMPONENT_NAME);
00432 BLOCXX_LOG_ERROR(lgr, Format("PosixFileSystem::createTempFile: unlink failed: %1", errno));
00433 }
00434 }
00435 return File(hdl);
00436 }
00437 #else
00438
00439 File
00440 createTempFile(String& filePath, const String& dir)
00441 {
00442 filePath.erase();
00443 if (g_fileSystemMockObject)
00444 {
00445 return g_fileSystemMockObject->createTempFile(filePath, dir);
00446 }
00447
00448 int rc = 0 ;
00449 String sfname;
00450 if (dir.empty())
00451 {
00452 char envtmp[MAX_PATH];
00453 rc = ::GetTempPath(MAX_PATH, envtmp);
00454 if (rc == 0)
00455 {
00456 sfname = "c:/tmp/";
00457 }
00458 else
00459 {
00460 sfname = envtmp;
00461 if (!sfname.endsWith('/'))
00462 sfname += '/';
00463 }
00464 }
00465 else
00466 {
00467 sfname = (dir.endsWith('/')) ? dir : dir+"/";
00468 }
00469
00470 char szTempName[MAX_PATH];
00471
00472 rc = ::GetTempFileName(sfname.c_str(),
00473 "blocxxtmpfile",
00474 0,
00475 szTempName);
00476 if (rc == 0)
00477 {
00478 return File();
00479 }
00480
00481 sfname = szTempName;
00482 size_t len = sfname.length();
00483 AutoPtrVec<char> filename(new char[len + 1]);
00484 SafeCString::strcpy_check(filename.get(), len + 1, sfname.c_str());
00485 MutexLock tmpfileML(tmpfileMutex);
00486
00487
00488 FileHandle hdl = ::CreateFile((LPTSTR)sfname.c_str(),
00489 GENERIC_READ | GENERIC_WRITE,
00490 0,
00491 NULL,
00492 CREATE_ALWAYS,
00493 FILE_ATTRIBUTE_NORMAL,
00494 NULL);
00495 if (hdl == INVALID_HANDLE_VALUE)
00496 {
00497 return File();
00498 }
00499
00500 filePath = filename.get();
00501 return File(hdl);
00502 }
00503
00504 File
00505 createAutoDeleteTempFile(const String& dir)
00506 {
00507 if (g_fileSystemMockObject)
00508 {
00509 return g_fileSystemMockObject->createTempFile(dir);
00510 }
00511
00512 int rc = 0 ;
00513 String sfname;
00514 if (dir.empty())
00515 {
00516 char envtmp[MAX_PATH];
00517 rc = ::GetTempPath(MAX_PATH, envtmp);
00518 if (rc == 0)
00519 {
00520 sfname = "c:/tmp/";
00521 }
00522 else
00523 {
00524 sfname = envtmp;
00525 if (!sfname.endsWith('/'))
00526 sfname += '/';
00527 }
00528 }
00529 else
00530 {
00531 sfname = (dir.endsWith('/')) ? dir : dir+"/";
00532 }
00533
00534 char szTempName[MAX_PATH];
00535
00536 rc = ::GetTempFileName(sfname.c_str(),
00537 "blocxxtmpfile",
00538 0,
00539 szTempName);
00540 if (rc == 0)
00541 {
00542 return File();
00543 }
00544
00545 sfname = szTempName;
00546 size_t len = sfname.length();
00547 AutoPtrVec<char> filename(new char[len + 1]);
00548 SafeCString::strcpy_check(filename.get(), len + 1, sfname.c_str());
00549 MutexLock tmpfileML(tmpfileMutex);
00550
00551
00552 FileHandle hdl = ::CreateFile((LPTSTR)sfname.c_str(),
00553 GENERIC_READ | GENERIC_WRITE,
00554 0,
00555 NULL,
00556 CREATE_ALWAYS,
00557 FILE_ATTRIBUTE_NORMAL,
00558 NULL);
00559 if (hdl == INVALID_HANDLE_VALUE)
00560 {
00561 return File();
00562 }
00563 else
00564 {
00565 if (::unlink(filename.get()) != 0)
00566 {
00567 Logger lgr(COMPONENT_NAME);
00568 BLOCXX_LOG_ERROR(lgr, Format("PosixFileSystem::createTempFile: unlink failed: %1", errno));
00569 }
00570 }
00571 return File(hdl);
00572 }
00573 #endif
00574
00576 bool
00577 exists(const String& path)
00578 {
00579 if (g_fileSystemMockObject)
00580 {
00581 return g_fileSystemMockObject->exists(path);
00582 }
00583 return _ACCESS(path.c_str(), F_OK) == 0;
00584 }
00585
00587 #ifndef BLOCXX_WIN32
00588 bool
00589 isExecutable(const String& path)
00590 {
00591 if (g_fileSystemMockObject)
00592 {
00593 return g_fileSystemMockObject->isExecutable(path);
00594 }
00595 return _ACCESS(path.c_str(), X_OK) == 0;
00596 }
00597 #endif
00598
00600 bool
00601 canRead(const String& path)
00602 {
00603 if (g_fileSystemMockObject)
00604 {
00605 return g_fileSystemMockObject->canRead(path);
00606 }
00607 return _ACCESS(path.c_str(), R_OK) == 0;
00608 }
00610 bool
00611 canWrite(const String& path)
00612 {
00613 if (g_fileSystemMockObject)
00614 {
00615 return g_fileSystemMockObject->canWrite(path);
00616 }
00617 return _ACCESS(path.c_str(), W_OK) == 0;
00618 }
00620 #ifndef BLOCXX_WIN32
00621 bool
00622 isLink(const String& path)
00623 {
00624 if (g_fileSystemMockObject)
00625 {
00626 return g_fileSystemMockObject->isLink(path);
00627 }
00628 struct stat st;
00629 if (lstat(path.c_str(), &st) != 0)
00630 {
00631 return false;
00632 }
00633 return S_ISLNK(st.st_mode);
00634 }
00635 #endif
00636
00637 bool
00638 isDirectory(const String& path)
00639 {
00640 if (g_fileSystemMockObject)
00641 {
00642 return g_fileSystemMockObject->isDirectory(path);
00643 }
00644 #ifdef BLOCXX_WIN32
00645 struct _stat st;
00646 if (_stat(path.c_str(), &st) != 0)
00647 {
00648 return false;
00649 }
00650 return ((st.st_mode & _S_IFDIR) != 0);
00651 #else
00652 struct stat st;
00653 if (stat(path.c_str(), &st) != 0)
00654 {
00655 return false;
00656 }
00657 return S_ISDIR(st.st_mode);
00658 #endif
00659 }
00661 bool
00662 changeDirectory(const String& path)
00663 {
00664 if (g_fileSystemMockObject)
00665 {
00666 return g_fileSystemMockObject->changeDirectory(path);
00667 }
00668 return _CHDIR(path.c_str()) == 0;
00669 }
00671 bool
00672 makeDirectory(const String& path, int mode)
00673 {
00674 if (g_fileSystemMockObject)
00675 {
00676 return g_fileSystemMockObject->makeDirectory(path, mode);
00677 }
00678 return _MKDIR(path.c_str(), mode) == 0;
00679 }
00681 bool
00682 getFileSize(const String& path, Int64& size)
00683 {
00684 if (g_fileSystemMockObject)
00685 {
00686 return g_fileSystemMockObject->getFileSize(path, size);
00687 }
00688 #ifdef BLOCXX_WIN32
00689 struct _stat st;
00690 if (_stat(path.c_str(), &st) != 0)
00691 {
00692 return false;
00693 }
00694 #else
00695 struct stat st;
00696 if (stat(path.c_str(), &st) != 0)
00697 {
00698 return false;
00699 }
00700 #endif
00701 size = st.st_size;
00702 return true;
00703 }
00705 bool
00706 removeDirectory(const String& path)
00707 {
00708 if (g_fileSystemMockObject)
00709 {
00710 return g_fileSystemMockObject->removeDirectory(path);
00711 }
00712 return _RMDIR(path.c_str()) == 0;
00713 }
00715 bool
00716 removeFile(const String& path)
00717 {
00718 if (g_fileSystemMockObject)
00719 {
00720 return g_fileSystemMockObject->removeFile(path);
00721 }
00722 return _UNLINK(path.c_str()) == 0;
00723 }
00725 bool
00726 getDirectoryContents(const String& path,
00727 StringArray& dirEntries)
00728 {
00729 if (g_fileSystemMockObject)
00730 {
00731 return g_fileSystemMockObject->getDirectoryContents(path, dirEntries);
00732 }
00733 static Mutex readdirGuard;
00734 MutexLock lock(readdirGuard);
00735
00736 #ifdef BLOCXX_WIN32
00737 struct _finddata_t dentry;
00738 long hFile;
00739 String _path = path;
00740
00741
00742 if (!_path.endsWith(BLOCXX_FILENAME_SEPARATOR))
00743 {
00744 _path += BLOCXX_FILENAME_SEPARATOR;
00745 }
00746 _path += "*";
00747 if ((hFile = _findfirst( _path.c_str(), &dentry)) == -1L)
00748 {
00749 return false;
00750 }
00751 dirEntries.clear();
00752 while (_findnext(hFile, &dentry) == 0)
00753 {
00754 dirEntries.append(String(dentry.name));
00755 }
00756 _findclose(hFile);
00757 #else
00758 DIR* dp(0);
00759 struct dirent* dentry(0);
00760 if ((dp = opendir(path.c_str())) == NULL)
00761 {
00762 return false;
00763 }
00764 dirEntries.clear();
00765 while ((dentry = readdir(dp)) != NULL)
00766 {
00767 dirEntries.append(String(dentry->d_name));
00768 }
00769 closedir(dp);
00770 #endif
00771 return true;
00772 }
00774 bool
00775 renameFile(const String& oldFileName,
00776 const String& newFileName)
00777 {
00778 if (g_fileSystemMockObject)
00779 {
00780 return g_fileSystemMockObject->renameFile(oldFileName, newFileName);
00781 }
00782 return ::rename(oldFileName.c_str(), newFileName.c_str()) == 0;
00783 }
00785 size_t
00786 read(const FileHandle& hdl, void* bfr, size_t numberOfBytes,
00787 Int64 offset)
00788 {
00789 if (g_fileSystemMockObject)
00790 {
00791 return g_fileSystemMockObject->read(hdl, bfr, numberOfBytes, offset);
00792 }
00793 #ifdef BLOCXX_WIN32
00794 OVERLAPPED ov = { 0, 0, 0, 0, NULL };
00795 OVERLAPPED *pov = NULL;
00796 if(offset != -1L)
00797 {
00798 ov.Offset = (DWORD) offset;
00799
00800 if (ov.Offset != offset)
00801 {
00802 BLOCXX_THROW(FileSystemException, "offset out of range");
00803 }
00804 pov = &ov;
00805 }
00806
00807 DWORD bytesRead;
00808 size_t cc = (size_t)-1;
00809 if(::ReadFile(hdl, bfr, (DWORD)numberOfBytes, &bytesRead, pov))
00810 {
00811 cc = (size_t)bytesRead;
00812 }
00813
00814 return cc;
00815 #else
00816 if (offset != -1L)
00817 {
00818 ::off_t offset2 = static_cast< ::off_t>(offset);
00819
00820 if (offset2 != offset)
00821 {
00822 BLOCXX_THROW(FileSystemException, "offset out of range");
00823 }
00824
00825 ::lseek(hdl, offset2, SEEK_SET);
00826 }
00827 return ::read(hdl, bfr, numberOfBytes);
00828 #endif
00829 }
00831 size_t
00832 write(FileHandle hdl, const void* bfr, size_t numberOfBytes,
00833 Int64 offset)
00834 {
00835 if (g_fileSystemMockObject)
00836 {
00837 return g_fileSystemMockObject->write(hdl, bfr, numberOfBytes, offset);
00838 }
00839 #ifdef BLOCXX_WIN32
00840 OVERLAPPED ov = { 0, 0, 0, 0, NULL };
00841 OVERLAPPED *pov = NULL;
00842 if(offset != -1L)
00843 {
00844 ov.Offset = (DWORD) offset;
00845
00846 if (ov.Offset != offset)
00847 {
00848 BLOCXX_THROW(FileSystemException, "offset out of range");
00849 }
00850 pov = &ov;
00851 }
00852
00853 DWORD bytesWritten;
00854 size_t cc = (size_t)-1;
00855 if(::WriteFile(hdl, bfr, (DWORD)numberOfBytes, &bytesWritten, pov))
00856 {
00857 cc = (size_t)bytesWritten;
00858 }
00859 return cc;
00860 #else
00861
00862 if (offset != -1L)
00863 {
00864 ::off_t offset2 = static_cast< ::off_t>(offset);
00865
00866 if (offset2 != offset)
00867 {
00868 BLOCXX_THROW(FileSystemException, "offset out of range");
00869 }
00870 ::lseek(hdl, offset2, SEEK_SET);
00871 }
00872 return ::write(hdl, bfr, numberOfBytes);
00873 #endif
00874 }
00875
00877 Int64
00878 seek(const FileHandle& hdl, Int64 offset, int whence)
00879 {
00880 if (g_fileSystemMockObject)
00881 {
00882 return g_fileSystemMockObject->seek(hdl, offset, whence);
00883 }
00884 #ifdef BLOCXX_WIN32
00885 DWORD moveMethod;
00886 switch(whence)
00887 {
00888 case SEEK_END: moveMethod = FILE_END; break;
00889 case SEEK_CUR: moveMethod = FILE_CURRENT; break;
00890 default: moveMethod = FILE_BEGIN; break;
00891 }
00892
00893 LARGE_INTEGER li;
00894 li.QuadPart = offset;
00895 li.LowPart = SetFilePointer(hdl, li.LowPart, &li.HighPart, moveMethod);
00896
00897 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
00898 {
00899 li.QuadPart = -1;
00900 }
00901
00902 return li.QuadPart;
00903 #else
00904 ::off_t offset2 = static_cast< ::off_t>(offset);
00905
00906 if (offset2 != offset)
00907 {
00908 BLOCXX_THROW(FileSystemException, "offset out of range");
00909 }
00910 return ::lseek(hdl, offset2, whence);
00911 #endif
00912 }
00914 Int64
00915 tell(const FileHandle& hdl)
00916 {
00917 if (g_fileSystemMockObject)
00918 {
00919 return g_fileSystemMockObject->tell(hdl);
00920 }
00921 #ifdef BLOCXX_WIN32
00922 LARGE_INTEGER li;
00923 li.QuadPart = 0;
00924 li.LowPart = SetFilePointer(hdl, li.LowPart, &li.HighPart, FILE_CURRENT);
00925
00926 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
00927 {
00928 li.QuadPart = -1;
00929 }
00930
00931 return li.QuadPart;
00932 #else
00933 return ::lseek(hdl, 0, SEEK_CUR);
00934 #endif
00935 }
00937 UInt64 fileSize(FileHandle fh)
00938 {
00939 if (g_fileSystemMockObject)
00940 {
00941 return g_fileSystemMockObject->fileSize(fh);
00942 }
00943
00944 #ifndef BLOCXX_WIN32
00945
00946 struct stat st;
00947 int rc = ::fstat(fh, &st);
00948 if (rc != 0)
00949 {
00950 BLOCXX_THROW_ERRNO_MSG(FileSystemException, "Could not stat file handle: ");
00951 }
00952 return st.st_size;
00953
00954 #else
00955 LARGE_INTEGER FileSize;
00956 BOOL rc = GetFileSizeEx(fh, &FileSize);
00957 if(!rc)
00958 {
00959 BLOCXX_THROW_ERRNO_MSG(FileSystemException, "Could not GetFileSizeEx() for file handle: ");
00960 }
00961
00962 UInt64 tmp = FileSize.QuadPart;
00963 return tmp;
00964
00965 #endif
00966 }
00968 void
00969 rewind(const FileHandle& hdl)
00970 {
00971 if (g_fileSystemMockObject)
00972 {
00973 return g_fileSystemMockObject->rewind(hdl);
00974 }
00975 #ifdef BLOCXX_WIN32
00976 ::SetFilePointer(hdl, 0L, NULL, FILE_BEGIN);
00977 #else
00978 ::lseek(hdl, 0, SEEK_SET);
00979 #endif
00980 }
00982 int
00983 close(const FileHandle& hdl)
00984 {
00985 if (g_fileSystemMockObject)
00986 {
00987 return g_fileSystemMockObject->close(hdl);
00988 }
00989 #ifdef BLOCXX_WIN32
00990 return (::CloseHandle(hdl)) ? 0 : -1;
00991 #else
00992 return ::close(hdl);
00993 #endif
00994 }
00996 int
00997 flush(FileHandle& hdl)
00998 {
00999 if (g_fileSystemMockObject)
01000 {
01001 return g_fileSystemMockObject->flush(hdl);
01002 }
01003 #ifdef BLOCXX_WIN32
01004 return (::FlushFileBuffers(hdl)) ? 0 : -1;
01005 #else
01006 return ::fsync(hdl);
01007 #endif
01008 }
01010 String getFileContents(const String& filename)
01011 {
01012 if (g_fileSystemMockObject)
01013 {
01014 return g_fileSystemMockObject->getFileContents(filename);
01015 }
01016 std::ifstream in(filename.c_str());
01017 if (!in)
01018 {
01019 BLOCXX_THROW(FileSystemException, Format("Failed to open file %1", filename).c_str());
01020 }
01021 OStringStream ss;
01022 ss << in.rdbuf();
01023 return ss.toString();
01024 }
01025
01027 StringArray getFileLines(const String& filename)
01028 {
01029 if (g_fileSystemMockObject)
01030 {
01031 return g_fileSystemMockObject->getFileLines(filename);
01032 }
01033 return getFileContents(filename).tokenize("\r\n");
01034 }
01035
01037 String readSymbolicLink(const String& path)
01038 {
01039 if (g_fileSystemMockObject)
01040 {
01041 return g_fileSystemMockObject->readSymbolicLink(path);
01042 }
01043 #ifdef BLOCXX_WIN32
01044 return Path::realPath(path);
01045 #else
01046 std::vector<char> buf(MAXPATHLEN + 1);
01047 int rc;
01048 while (true)
01049 {
01050 rc = ::readlink(path.c_str(), &buf[0], buf.size());
01051
01052
01053
01054
01055 if (rc < 0)
01056 {
01057 BLOCXX_THROW_ERRNO_MSG(FileSystemException, path);
01058 }
01059 else if (static_cast<unsigned>(rc) == buf.size())
01060 {
01061 buf.resize(buf.size() * 2);
01062 }
01063 else
01064 {
01065 buf.resize(rc);
01066 buf.push_back('\0');
01067 return String(&buf[0]);
01068 }
01069 }
01070 #endif
01071
01072 return String();
01073 }
01074
01076 namespace Path
01077 {
01078
01080 String realPath(const String& path)
01081 {
01082 if (g_fileSystemMockObject)
01083 {
01084 return g_fileSystemMockObject->realPath(path);
01085 }
01086 #ifdef BLOCXX_WIN32
01087 char c, *bfr, *pname;
01088 const char *pathcstr;
01089 DWORD cc;
01090
01091 pathcstr = path.c_str();
01092 while (*pathcstr == '/' || *pathcstr == '\\')
01093 {
01094 ++pathcstr;
01095 }
01096
01097
01098
01099 if(pathcstr != path.c_str())
01100 {
01101 --pathcstr;
01102 }
01103
01104 cc = GetFullPathName(path.c_str(), 1, &c, &pname);
01105 if(!cc)
01106 {
01107 BLOCXX_THROW(FileSystemException, Format("Can't get full path name for path %s", path).c_str());
01108 }
01109 bfr = new char[cc];
01110 cc = GetFullPathName(path.c_str(), cc, bfr, &pname);
01111 if(!cc)
01112 {
01113 delete [] bfr;
01114 BLOCXX_THROW(FileSystemException, Format("Can't get full path name for path %s", path).c_str());
01115 }
01116 String rstr(bfr);
01117 delete [] bfr;
01118 return rstr;
01119 #else
01120 if (path.startsWith("/"))
01121 {
01122 return security(path, 0).second;
01123 }
01124 else
01125 {
01126 return security(getCurrentWorkingDirectory(), path, 0).second;
01127 }
01128 #endif
01129 }
01130
01132 String dirname(const String& filename)
01133 {
01134 if (g_fileSystemMockObject)
01135 {
01136 return g_fileSystemMockObject->dirname(filename);
01137 }
01138
01139 if (filename.length() == 0)
01140 {
01141 return ".";
01142 }
01143 size_t lastSlash = filename.length() - 1;
01144 while (lastSlash > 0
01145 && filename[lastSlash] == BLOCXX_FILENAME_SEPARATOR_C)
01146 {
01147 --lastSlash;
01148 }
01149
01150 lastSlash = filename.lastIndexOf(BLOCXX_FILENAME_SEPARATOR_C, lastSlash);
01151
01152 if (lastSlash == String::npos)
01153 {
01154 return ".";
01155 }
01156
01157 while (lastSlash > 0 && filename[lastSlash - 1] == BLOCXX_FILENAME_SEPARATOR_C)
01158 {
01159 --lastSlash;
01160 }
01161
01162 if (lastSlash == 0)
01163 {
01164 return BLOCXX_FILENAME_SEPARATOR;
01165 }
01166
01167 return filename.substring(0, lastSlash);
01168 }
01169
01171 String basename(const String& filename)
01172 {
01173 if (g_fileSystemMockObject)
01174 {
01175 return g_fileSystemMockObject->basename(filename);
01176 }
01177 if (filename.length() == 0)
01178 {
01179 return filename;
01180 }
01181 size_t end = filename.length() -1;
01182 while (end > 0
01183 && filename[end] == BLOCXX_FILENAME_SEPARATOR_C)
01184 {
01185 --end;
01186 }
01187 if (end == 0 && filename[0] == BLOCXX_FILENAME_SEPARATOR_C)
01188 {
01189 return BLOCXX_FILENAME_SEPARATOR;
01190 }
01191 if (end == filename.length() -1)
01192 {
01193 end = String::npos;
01194 }
01195 size_t beg = filename.lastIndexOf(BLOCXX_FILENAME_SEPARATOR_C, end);
01196 if (beg == String::npos)
01197 {
01198 beg = 0;
01199 }
01200 else
01201 {
01202 ++beg;
01203 }
01204 size_t len = end == String::npos? end : ++end - beg;
01205 return filename.substring(beg, len);
01206 }
01207
01209 String getCurrentWorkingDirectory()
01210 {
01211 if (g_fileSystemMockObject)
01212 {
01213 return g_fileSystemMockObject->getCurrentWorkingDirectory();
01214 }
01215 std::vector<char> buf(MAXPATHLEN);
01216 char* p;
01217 do
01218 {
01219 p = ::getcwd(&buf[0], buf.size());
01220 if (p != 0)
01221 {
01222 return p;
01223 }
01224 buf.resize(buf.size() * 2);
01225 } while (p == 0 && errno == ERANGE);
01226
01227 BLOCXX_THROW_ERRNO(FileSystemException);
01228 }
01229
01230 }
01231 }
01232 }
01233