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
00036 #include "OW_config.h"
00037 #include "OW_FileSystem.hpp"
00038 #include "OW_CryptographicRandomNumber.hpp"
00039 #include "OW_Mutex.hpp"
00040 #include "OW_MutexLock.hpp"
00041 #include "OW_File.hpp"
00042 #include "OW_String.hpp"
00043 #include "OW_Array.hpp"
00044 #include "OW_Format.hpp"
00045 #include "OW_ExceptionIds.hpp"
00046 #include "OW_Assertion.hpp"
00047
00048 extern "C"
00049 {
00050 #ifdef OW_WIN32
00051
00052 #include <direct.h>
00053 #include <io.h>
00054 #include <share.h>
00055
00056 #define _ACCESS ::_access
00057 #define R_OK 4
00058 #define F_OK 0
00059 #define W_OK 2
00060 #define _CHDIR _chdir
00061 #define _MKDIR(a,b) _mkdir((a))
00062 #define _RMDIR _rmdir
00063 #define _UNLINK _unlink
00064
00065 #else
00066
00067 #ifdef OW_HAVE_UNISTD_H
00068 #include <unistd.h>
00069 #endif
00070 #ifdef OW_HAVE_DIRENT_H
00071 #include <dirent.h>
00072 #endif
00073
00074 #define _ACCESS ::access
00075 #define _CHDIR chdir
00076 #define _MKDIR(a,b) mkdir((a),(b))
00077 #define _RMDIR rmdir
00078 #define _UNLINK unlink
00079
00080 #ifdef OW_NETWARE
00081 #define MAXSYMLINKS 20
00082 #endif
00083
00084 #endif
00085
00086 #include <sys/stat.h>
00087 #include <sys/types.h>
00088 #include <fcntl.h>
00089 }
00090
00091 #include <cstdio>
00092 #include <fstream>
00093 #include <cerrno>
00094
00095 namespace OW_NAMESPACE
00096 {
00097
00098 OW_DEFINE_EXCEPTION_WITH_ID(FileSystem);
00099
00100 namespace FileSystem
00101 {
00102
00104
00105 int
00106 changeFileOwner(const String& filename,
00107 const UserId& userId)
00108 {
00109 #ifdef OW_WIN32
00110 return 0;
00111 #else
00112 return ::chown(filename.c_str(), userId, gid_t(-1));
00113 #endif
00114 }
00116
00117 File
00118 openFile(const String& path)
00119 {
00120 #ifdef OW_WIN32
00121 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00122 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
00123 FILE_ATTRIBUTE_NORMAL, NULL);
00124
00125 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00126 #else
00127 return File(::open(path.c_str(), O_RDWR));
00128 #endif
00129 }
00131
00132 File
00133 createFile(const String& path)
00134 {
00135 #ifdef OW_WIN32
00136 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00137 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW,
00138 FILE_ATTRIBUTE_NORMAL, NULL);
00139 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00140 #else
00141 int fd = ::open(path.c_str(), O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0660);
00142 if (fd != -1)
00143 {
00144 return File(fd);
00145 }
00146 return File();
00147 #endif
00148
00149 }
00151
00152 File
00153 openOrCreateFile(const String& path)
00154 {
00155 #ifdef OW_WIN32
00156 HANDLE fh = ::CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE,
00157 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
00158 FILE_ATTRIBUTE_NORMAL, NULL);
00159 return (fh != INVALID_HANDLE_VALUE) ? File(fh) : File();
00160 #else
00161 return File(::open(path.c_str(), O_RDWR | O_CREAT, 0660));
00162 #endif
00163 }
00164
00166 bool
00167 exists(const String& path)
00168 {
00169 return _ACCESS(path.c_str(), F_OK) == 0;
00170 }
00171
00173 #ifndef OW_WIN32
00174 bool
00175 isExecutable(const String& path)
00176 {
00177 return _ACCESS(path.c_str(), X_OK) == 0;
00178 }
00179 #endif
00180
00182 bool
00183 canRead(const String& path)
00184 {
00185 return _ACCESS(path.c_str(), R_OK) == 0;
00186 }
00188 bool
00189 canWrite(const String& path)
00190 {
00191 return _ACCESS(path.c_str(), W_OK) == 0;
00192 }
00194 #ifndef OW_WIN32
00195 bool
00196 isLink(const String& path)
00197 {
00198 struct stat st;
00199 if (lstat(path.c_str(), &st) != 0)
00200 {
00201 return false;
00202 }
00203 return S_ISLNK(st.st_mode);
00204 }
00205 #endif
00206
00207 bool
00208 isDirectory(const String& path)
00209 {
00210 #ifdef OW_WIN32
00211 struct _stat st;
00212 if (_stat(path.c_str(), &st) != 0)
00213 {
00214 return false;
00215 }
00216 return ((st.st_mode & _S_IFDIR) != 0);
00217 #else
00218 struct stat st;
00219 if (stat(path.c_str(), &st) != 0)
00220 {
00221 return false;
00222 }
00223 return S_ISDIR(st.st_mode);
00224 #endif
00225 }
00227 bool
00228 changeDirectory(const String& path)
00229 {
00230 return _CHDIR(path.c_str()) == 0;
00231 }
00233 bool
00234 makeDirectory(const String& path, int mode)
00235 {
00236 return _MKDIR(path.c_str(), mode) == 0;
00237 }
00239 bool
00240 getFileSize(const String& path, off_t& size)
00241 {
00242 #ifdef OW_WIN32
00243 struct _stat st;
00244 if (_stat(path.c_str(), &st) != 0)
00245 {
00246 return false;
00247 }
00248 #else
00249 struct stat st;
00250 if (stat(path.c_str(), &st) != 0)
00251 {
00252 return false;
00253 }
00254 #endif
00255 size = st.st_size;
00256 return true;
00257 }
00259 bool
00260 removeDirectory(const String& path)
00261 {
00262 return _RMDIR(path.c_str()) == 0;
00263 }
00265 bool
00266 removeFile(const String& path)
00267 {
00268 return _UNLINK(path.c_str()) == 0;
00269 }
00271 bool
00272 getDirectoryContents(const String& path,
00273 StringArray& dirEntries)
00274 {
00275 static Mutex readdirGuard;
00276 MutexLock lock(readdirGuard);
00277
00278 #ifdef OW_WIN32
00279 struct _finddata_t dentry;
00280 long hFile;
00281 String _path = path;
00282
00283
00284 if (!_path.endsWith(OW_FILENAME_SEPARATOR))
00285 {
00286 _path += OW_FILENAME_SEPARATOR;
00287 }
00288 _path += "*";
00289 if ((hFile = _findfirst( _path.c_str(), &dentry)) == -1L)
00290 {
00291 return false;
00292 }
00293 dirEntries.clear();
00294 while (_findnext(hFile, &dentry) == 0)
00295 {
00296 dirEntries.append(String(dentry.name));
00297 }
00298 _findclose(hFile);
00299 #else
00300 DIR* dp(0);
00301 struct dirent* dentry(0);
00302 if ((dp = opendir(path.c_str())) == NULL)
00303 {
00304 return false;
00305 }
00306 dirEntries.clear();
00307 while ((dentry = readdir(dp)) != NULL)
00308 {
00309 dirEntries.append(String(dentry->d_name));
00310 }
00311 closedir(dp);
00312 #endif
00313 return true;
00314 }
00316 bool
00317 renameFile(const String& oldFileName,
00318 const String& newFileName)
00319 {
00320 return ::rename(oldFileName.c_str(), newFileName.c_str()) == 0;
00321 }
00323 size_t
00324 read(const FileHandle& hdl, void* bfr, size_t numberOfBytes,
00325 off_t offset)
00326 {
00327 #ifdef OW_WIN32
00328 OVERLAPPED ov = { 0, 0, 0, 0, NULL };
00329 OVERLAPPED *pov = NULL;
00330 if(offset != -1L)
00331 {
00332 ov.Offset = (DWORD) offset;
00333 pov = &ov;
00334 }
00335
00336 DWORD bytesRead;
00337 size_t cc = (size_t)-1;
00338 if(::ReadFile(hdl, bfr, (DWORD)numberOfBytes, &bytesRead, pov))
00339 {
00340 cc = (size_t)bytesRead;
00341 }
00342
00343 return cc;
00344 #else
00345 if (offset != -1L)
00346 {
00347 ::lseek(hdl, offset, SEEK_SET);
00348 }
00349 return ::read(hdl, bfr, numberOfBytes);
00350 #endif
00351 }
00353 size_t
00354 write(FileHandle& hdl, const void* bfr, size_t numberOfBytes,
00355 off_t offset)
00356 {
00357 #ifdef OW_WIN32
00358 OVERLAPPED ov = { 0, 0, 0, 0, NULL };
00359 OVERLAPPED *pov = NULL;
00360 if(offset != -1L)
00361 {
00362 ov.Offset = (DWORD) offset;
00363 pov = &ov;
00364 }
00365
00366 DWORD bytesWritten;
00367 size_t cc = (size_t)-1;
00368 if(::WriteFile(hdl, bfr, (DWORD)numberOfBytes, &bytesWritten, pov))
00369 {
00370 cc = (size_t)bytesWritten;
00371 }
00372 return cc;
00373 #else
00374
00375 if (offset != -1L)
00376 {
00377 ::lseek(hdl, offset, SEEK_SET);
00378 }
00379 return ::write(hdl, bfr, numberOfBytes);
00380 #endif
00381 }
00383 off_t
00384 seek(const FileHandle& hdl, off_t offset, int whence)
00385 {
00386 #ifdef OW_WIN32
00387 DWORD moveMethod;
00388 switch(whence)
00389 {
00390 case SEEK_END: moveMethod = FILE_END; break;
00391 case SEEK_CUR: moveMethod = FILE_CURRENT; break;
00392 default: moveMethod = FILE_BEGIN; break;
00393 }
00394 return (off_t) ::SetFilePointer(hdl, (LONG)offset, NULL, moveMethod);
00395 #else
00396 return ::lseek(hdl, offset, whence);
00397 #endif
00398 }
00400 off_t
00401 tell(const FileHandle& hdl)
00402 {
00403 #ifdef OW_WIN32
00404 return (off_t) ::SetFilePointer(hdl, 0L, NULL, FILE_CURRENT);
00405 #else
00406 return ::lseek(hdl, 0, SEEK_CUR);
00407 #endif
00408 }
00410 void
00411 rewind(const FileHandle& hdl)
00412 {
00413 #ifdef OW_WIN32
00414 ::SetFilePointer(hdl, 0L, NULL, FILE_BEGIN);
00415 #else
00416 ::lseek(hdl, 0, SEEK_SET);
00417 #endif
00418 }
00420 int
00421 close(const FileHandle& hdl)
00422 {
00423 #ifdef OW_WIN32
00424 return (::CloseHandle(hdl)) ? 0 : -1;
00425 #else
00426 return ::close(hdl);
00427 #endif
00428 }
00430 int
00431 flush(FileHandle& hdl)
00432 {
00433 #ifdef OW_WIN32
00434 return (::FlushFileBuffers(hdl)) ? 0 : -1;
00435 #else
00436 #ifdef OW_DARWIN
00437 return ::fsync(hdl);
00438 #else
00439 return 0;
00440 #endif
00441 #endif
00442 }
00444 void
00445 initRandomFile(const String& filename)
00446 {
00447 #ifdef OW_WIN32
00448 char bfr[1024];
00449 CryptographicRandomNumber rnum(0, 0xFF);
00450 for (size_t i = 0; i < 1024; ++i)
00451 {
00452 bfr[i] = (char)rnum.getNextNumber();
00453 }
00454 HANDLE fh = ::CreateFile(filename.c_str(), GENERIC_WRITE,
00455 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
00456 FILE_ATTRIBUTE_NORMAL, NULL);
00457 if(fh == INVALID_HANDLE_VALUE)
00458 {
00459 OW_THROW(FileSystemException,
00460 Format("Can't open random file %1 for writing",
00461 filename).c_str());
00462 }
00463 DWORD bytesWritten;
00464 size_t cc = (size_t)-1;
00465 bool success = (::WriteFile(fh, bfr, (DWORD)1024, &bytesWritten, NULL) != 0);
00466 ::CloseHandle(fh);
00467 if(!success || bytesWritten < 1024)
00468 {
00469 OW_THROW(FileSystemException,
00470 Format("Failed writing data to random file %1", filename).c_str());
00471 }
00472 #else
00473 int hdl = ::open(filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0600);
00474 if (hdl == -1)
00475 {
00476 OW_THROW(FileSystemException, Format("Can't open random file %1 for writing", filename).c_str());
00477 }
00478 CryptographicRandomNumber rnum(0, 0xFF);
00479 for (size_t i = 0; i < 1024; ++i)
00480 {
00481 char c = rnum.getNextNumber();
00482 ::write(hdl, &c, 1);
00483 }
00484 ::close(hdl);
00485 #endif
00486 }
00487
00489 String getFileContents(const String& filename)
00490 {
00491 std::ifstream in(filename.c_str());
00492 if (!in)
00493 {
00494 OW_THROW(FileSystemException, Format("Failed to open file %1", filename).c_str());
00495 }
00496 OStringStream ss;
00497 ss << in.rdbuf();
00498 return ss.toString();
00499 }
00500
00502 StringArray getFileLines(const String& filename)
00503 {
00504 return getFileContents(filename).tokenize("\r\n");
00505 }
00506
00508 String readSymbolicLink(const String& path)
00509 {
00510 #ifdef OW_WIN32
00511 return Path::realPath(path);
00512 #else
00513 std::vector<char> buf(MAXPATHLEN);
00514 int rc;
00515 do
00516 {
00517 rc = ::readlink(path.c_str(), &buf[0], buf.size());
00518 if (rc >= 0)
00519 {
00520 buf.resize(rc);
00521 buf.push_back('\0');
00522 return String(&buf[0]);
00523 }
00524 buf.resize(buf.size() * 2);
00525 } while (rc < 0 && errno == ENAMETOOLONG);
00526 OW_THROW_ERRNO(FileSystemException);
00527 #endif
00528 }
00529
00531 namespace Path
00532 {
00533
00535 String realPath(const String& path)
00536 {
00537 #ifdef OW_WIN32
00538 char c, *bfr, *pname;
00539 const char *pathcstr;
00540 DWORD cc;
00541
00542 pathcstr = path.c_str();
00543 while (*pathcstr == '/' || *pathcstr == '\\')
00544 {
00545 ++pathcstr;
00546 }
00547
00548
00549
00550 if(pathcstr != path.c_str())
00551 {
00552 --pathcstr;
00553 }
00554
00555 cc = GetFullPathName(path.c_str(), 1, &c, &pname);
00556 if(!cc)
00557 {
00558 OW_THROW(FileSystemException, Format("Can't get full path name for path %s", path).c_str());
00559 }
00560 bfr = new char[cc];
00561 cc = GetFullPathName(path.c_str(), cc, bfr, &pname);
00562 if(!cc)
00563 {
00564 delete [] bfr;
00565 OW_THROW(FileSystemException, Format("Can't get full path name for path %s", path).c_str());
00566 }
00567 String rstr(bfr);
00568 delete [] bfr;
00569 return rstr;
00570 #else
00571 String workingPath(path);
00572 String resolvedPath;
00573 int numLinks = 0;
00574
00575
00576 if (workingPath.length() > 0 && workingPath[0] != '/')
00577 {
00578
00579 resolvedPath = getCurrentWorkingDirectory();
00580 }
00581
00582 const char* pathCompBegin(workingPath.c_str());
00583 const char* pathCompEnd(pathCompBegin);
00584 while (*pathCompBegin != '\0')
00585 {
00586
00587 while (*pathCompBegin == '/')
00588 {
00589 ++pathCompBegin;
00590 }
00591
00592
00593 pathCompEnd = pathCompBegin;
00594 while (*pathCompEnd != '\0' && *pathCompEnd != '/')
00595 {
00596 ++pathCompEnd;
00597 }
00598
00599 if (pathCompEnd - pathCompBegin == 0)
00600 {
00601 break;
00602 }
00603 else if (pathCompEnd - pathCompBegin == 1 && pathCompBegin[0] == '.')
00604 {
00605 ;
00606 }
00607 else if (pathCompEnd - pathCompBegin == 2 && pathCompBegin[0] == '.' && pathCompBegin[1] == '.')
00608 {
00609
00610 size_t lastSlash = resolvedPath.lastIndexOf('/');
00611 if (lastSlash != String::npos)
00612 {
00613 resolvedPath.erase(lastSlash);
00614 }
00615 }
00616 else
00617 {
00618 resolvedPath += '/';
00619 resolvedPath += String(pathCompBegin, pathCompEnd - pathCompBegin);
00620
00621
00622 struct stat pathStats;
00623 #ifdef OW_NETWARE
00624 if (::stat(resolvedPath.c_str(), &pathStats) < 0)
00625 {
00626 OW_THROW_ERRNO_MSG(FileSystemException, resolvedPath);
00627 }
00628 #else
00629 if (::lstat(resolvedPath.c_str(), &pathStats) < 0)
00630 {
00631 OW_THROW_ERRNO_MSG(FileSystemException, resolvedPath);
00632 }
00633 if (S_ISLNK(pathStats.st_mode))
00634 {
00635 ++numLinks;
00636 if (numLinks > MAXSYMLINKS)
00637 {
00638 errno = ELOOP;
00639 OW_THROW_ERRNO_MSG(FileSystemException, resolvedPath);
00640 }
00641 String linkTarget(readSymbolicLink(resolvedPath));
00642
00643 if (linkTarget.length() > 0 && linkTarget[0] != '/')
00644 {
00645
00646 OW_ASSERT(resolvedPath.lastIndexOf('/') != String::npos);
00647 resolvedPath.erase(resolvedPath.lastIndexOf('/'));
00648
00649 resolvedPath += '/';
00650 resolvedPath += linkTarget;
00651 }
00652 else
00653 {
00654
00655 resolvedPath = linkTarget;
00656 }
00657
00658
00659 resolvedPath += pathCompEnd;
00660 workingPath = resolvedPath;
00661 pathCompBegin = pathCompEnd = workingPath.c_str();
00662 resolvedPath.erase();
00663 }
00664 #endif
00665 }
00666
00667
00668 pathCompBegin = pathCompEnd;
00669 }
00670
00671 if (resolvedPath.empty())
00672 {
00673 resolvedPath = "/";
00674 }
00675
00676 return resolvedPath;
00677 #endif
00678 }
00679
00681 String dirname(const String& filename)
00682 {
00683
00684 size_t lastSlash = filename.length() - 1;
00685 while (lastSlash > 0
00686 && filename[lastSlash] == OW_FILENAME_SEPARATOR_C)
00687 {
00688 --lastSlash;
00689 }
00690
00691 lastSlash = filename.lastIndexOf(OW_FILENAME_SEPARATOR_C, lastSlash);
00692
00693 if (lastSlash == String::npos)
00694 {
00695 return ".";
00696 }
00697
00698 while (lastSlash > 0 && filename[lastSlash - 1] == OW_FILENAME_SEPARATOR_C)
00699 {
00700 --lastSlash;
00701 }
00702
00703 if (lastSlash == 0)
00704 {
00705 return OW_FILENAME_SEPARATOR;
00706 }
00707
00708 return filename.substring(0, lastSlash);
00709 }
00710
00712 String getCurrentWorkingDirectory()
00713 {
00714 std::vector<char> buf(MAXPATHLEN);
00715 char* p;
00716 do
00717 {
00718 p = ::getcwd(&buf[0], buf.size());
00719 if (p != 0)
00720 {
00721 return p;
00722 }
00723 buf.resize(buf.size() * 2);
00724 } while (p == 0 && errno == ERANGE);
00725
00726 OW_THROW_ERRNO(FileSystemException);
00727 }
00728
00729 }
00730 }
00731 }
00732