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