OW_PosixFileSystem.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
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> // for rename
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 // STATIC
00105 int
00106 changeFileOwner(const String& filename,
00107    const UserId& userId)
00108 {
00109 #ifdef OW_WIN32
00110    return 0;   // File ownership on Win32?
00111 #else
00112    return ::chown(filename.c_str(), userId, gid_t(-1));
00113 #endif
00114 }
00116 // STATIC
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 // STATIC
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 // STATIC
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    // Find first directory entry
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    // if we ate some '\' or '/' chars, the back up to
00549    // allow for 1
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    // handle relative paths.
00576    if (workingPath.length() > 0 && workingPath[0] != '/')
00577    {
00578       // result of getCurrentWorkingDirectory is already resolved.
00579       resolvedPath = getCurrentWorkingDirectory();
00580    }
00581 
00582    const char* pathCompBegin(workingPath.c_str());
00583    const char* pathCompEnd(pathCompBegin);
00584    while (*pathCompBegin != '\0')
00585    {
00586       // skip bunches of ////
00587       while (*pathCompBegin == '/')
00588       {
00589          ++pathCompBegin;
00590       }
00591 
00592       // find end of the path component
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          ;// don't add . to the result
00606       }
00607       else if (pathCompEnd - pathCompBegin == 2 && pathCompBegin[0] == '.' && pathCompBegin[1] == '.')
00608       {
00609          // hit .. so remove the last directory from the result
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          // now check the path actually exists
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                // relative link. Remove the link from the resolvedPath and add the linkTarget
00646                OW_ASSERT(resolvedPath.lastIndexOf('/') != String::npos); // should always happen, we just added a / to the string
00647                resolvedPath.erase(resolvedPath.lastIndexOf('/'));
00648 
00649                resolvedPath += '/';
00650                resolvedPath += linkTarget;
00651             }
00652             else
00653             {
00654                // absolute link
00655                resolvedPath = linkTarget;
00656             }
00657 
00658             // now reset and start over on the new path
00659             resolvedPath += pathCompEnd;
00660             workingPath = resolvedPath;
00661             pathCompBegin = pathCompEnd = workingPath.c_str();
00662             resolvedPath.erase();
00663          }
00664 #endif
00665       }
00666 
00667       // keep the loop flowing
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    // skip over trailing slashes
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 } // end namespace Path
00730 } // end namespace FileSystem
00731 } // end namespace OW_NAMESPACE
00732 

Generated on Thu Feb 9 08:48:08 2006 for openwbem by  doxygen 1.4.6