PCMFileSystemManager.cpp

Go to the documentation of this file.
00001 
00002 //
00003 // This source file is a part of ParCompMark
00004 // Parallel Compositing Benchmark Framework
00005 //
00006 // for latest info see http://parcompmark.sourceforge.net
00007 
00008 //
00009 // Copyright (C) 2006 IT2 ParCompMark Dev. Team
00010 // 
00011 // This program is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License
00013 // as published by the Free Software Foundation; either version 2
00014 // of the License, or (at your option) any later version.
00015 // 
00016 // This program is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 // GNU General Public License for more details.
00020 // 
00021 // You should have received a copy of the GNU General Public License
00022 // along with this program; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00024 
00025 //
00026 // Inner includes
00027 //
00028 
00029 #include "../include/PCMFileSystemManager.h"
00030 
00031 #include "../include/PCMApplication.h"
00032 
00033 //
00034 // Outer includes
00035 //
00036 
00037 #include <dirent.h>
00038 #include <errno.h>
00039 #include <sys/stat.h>
00040 #include <iostream>
00041 #include <fstream>
00042 
00044 extern int errno;
00045 
00046 namespace ParCompMark
00047 {
00048 
00049   // Inherited static attribute initialization
00050   template <> FileSystemManager * Singleton < FileSystemManager >::mInstance = 0;
00051 
00052   //
00053   // Class constants
00054   //
00055 
00056   const u32 FileSystemManager::MAX_PATH = 1024;
00057   const std::string FileSystemManager::PATH_SEPARATOR = "/";
00058 
00059   //
00060   // Constructors & destructor
00061   //
00062 
00063    FileSystemManager::FileSystemManager(const std::string & appDirectory, const std::string & iniFile)
00064         // You have to initialize the following attributes:
00065         // - mInitialized
00066         // - mAppDirectory
00067         // - mDataDirectory
00068         // - mHomeDirectory
00069         // - mCurrentDirectory
00070         // - mIniFile
00071   {
00072         mInitialized = false;
00073         mAppDirectory = appDirectory;
00074         mDataDirectory = "(unknown)";
00075         mHomeDirectory = "(unknown)";
00076         mCurrentDirectory = "(unknown)";
00077         mIniFile = iniFile;
00078 
00079         //if(Logger::getInstance()) Logger::getInstance()->log(Logger::NOTICE, "File system manager has been created.");
00080   }
00081 
00082  /*----------------------------------------------------------------------*/
00083 
00084   FileSystemManager::~FileSystemManager()
00085   {
00086         if(mInitialized)
00087          finalize();
00088 
00089         Logger::getInstance()->log(Logger::NOTICE, "File system manager has been destroyed.");
00090   }
00091 
00092  /*----------------------------------------------------------------------*/
00093 
00094   //
00095   // Class methods
00096   //
00097 
00098   FileSystemManager *FileSystemManager::getInstance()
00099   {
00100         return Singleton < FileSystemManager >::getInstance();
00101   }
00102 
00103  /*----------------------------------------------------------------------*/
00104 
00105   void FileSystemManager::closeFile(FileSystemManager::CppFilePointer & fp)
00106   {
00107         fp.lock();
00108         fp->close();
00109         fp.unlock();
00110   }
00111 
00112  /*----------------------------------------------------------------------*/
00113 
00114   void FileSystemManager::closeFile(FileSystemManager::CFilePointer & fp)
00115   {
00116         // Zero pointer to avoid double-free in Pointer destructor
00117         fp.lock();
00118         fclose(fp.getPtr());
00119         fp.unlock();
00120         fp.setNull(true);
00121   }
00122 
00123  /*----------------------------------------------------------------------*/
00124 
00125   //
00126   // Methods
00127   //
00128 
00129   void FileSystemManager::initialize()
00130   {
00131         Assert(!mInitialized, INVALID_OPERATION_ERROR, "FileSystemManager::initialize()");
00132 
00133         // Find the home directory of the user on the filesystem
00134         _findHomeDirectory();
00135 
00136         // Get full path of current directory
00137         mCurrentDirectory = Application::getInstance()->getEnvironmentVariable("PWD") + '/';
00138 
00139         // Convert application directory
00140         mAppDirectory = _replaceHomeChar(mAppDirectory);
00141 
00142         // Create user-level application directory and ini file
00143         _createAppDirectory();
00144 
00145         mInitialized = true;
00146 
00147         //if(Logger::getInstance()) Logger::getInstance()->log(Logger::DEBUG, "File system manager has been initialized.");
00148   }
00149 
00150  /*----------------------------------------------------------------------*/
00151 
00152   void FileSystemManager::finalize()
00153   {
00154         Assert(mInitialized, INVALID_OPERATION_ERROR, "FileSystemManager::finalize()");
00155 
00156         mInitialized = false;
00157         Logger::getInstance()->log(Logger::DEBUG, "File system manager has been finalized.");
00158   }
00159 
00160  /*----------------------------------------------------------------------*/
00161 
00162   bool FileSystemManager::existsDirectory(const std::string & name) const
00163   {
00164         std::string _name = _replaceHomeChar(name);
00165         return::opendir(_name.c_str()) != 0;
00166   }
00167 
00168  /*----------------------------------------------------------------------*/
00169 
00170   bool FileSystemManager::createDirectory(const std::string & name) const
00171   {
00172         if(existsDirectory(name))
00173          return false;
00174 
00175         std::string _name = _replaceHomeChar(name);
00176 
00177         if(::mkdir(_name.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IRWXO) == -1)
00178         {
00179          switch (errno)
00180          {
00181                 case EACCES:
00182                  Except(FILE_IO_ERROR, "FileSystemManager::createDirectory",
00183                          "Write permission is denied for the parent directory in which the new directory `" + _name +
00184                          "\' is to be added.");
00185                  break;
00186                 case EEXIST:
00187                  // Already exists (something went wrong)
00188                  Logger::getInstance()->log(Logger::WARNING,
00189                                            "Directory `" + _name + "\' already exists (something went wrong).");
00190                  return false;
00191                  break;
00192                 case EMLINK:
00193                  Except(FILE_IO_ERROR, "FileSystemManager::createDirectory",
00194                          "The parent directory has too many links (entries). Unable to create `" + _name + "\'.");
00195                  break;
00196                 case ENOSPC:
00197                  Except(FILE_IO_ERROR, "FileSystemManager::createDirectory",
00198                          "The file system doesn't have enough room to create the new directory `" + _name + "\'.");
00199                  break;
00200                 case EROFS:
00201                  Except(FILE_IO_ERROR, "FileSystemManager::createDirectory",
00202                          "The parent directory of the directory being created is on a read-only file system and cannot be modified. Unable to create `"
00203                          + name + "\'.");
00204                  break;
00205          }
00206         }
00207 
00208         if(Logger::getInstance())
00209          Logger::getInstance()->log(Logger::DEBUG, "Directory `" + _name + "\' has been created.");
00210 
00211         return true;
00212   }
00213 
00214  /*----------------------------------------------------------------------*/
00215 
00216   std::string FileSystemManager::findDataDirectory()const
00217   {
00218         std::string guess[] =
00219         {
00220         "/usr/share/ParCompMark/", "/usr/lib/ParCompMark/", "/usr/local/ParCompMark/",
00221                 "/usr/local/share/ParCompMark/", "./data/", "../data/"};
00222         u32 guessSize = sizeof(guess) / sizeof(guess[0]);
00223 
00224         for(u32 i = 0; i < guessSize; i++)
00225          if(existsDirectory(guess[i]))
00226                 return _translateToAbsolutePath(guess[i]);
00227 
00228         if(existsAppFile(mIniFile))
00229          Except(FILE_IO_ERROR, "FileSystemManager::findDataDirectory()",
00230                  "Application data directory was not found. Please check the application configuration file `" +
00231                  mAppDirectory + mIniFile + "\'");
00232         else
00233          Except(FILE_IO_ERROR, "FileSystemManager::findDataDirectory()",
00234                  "Application data directory was not found. It seems you have to reinstall ParCompMark.");
00235   }
00236 
00237  /*----------------------------------------------------------------------*/
00238 
00239   bool FileSystemManager::existsLibrary(const std::string & library,
00240                                         const std::vector < std::string > &additionalPaths) const
00241   {
00242         try
00243         {
00244          findLibraryPath(library, additionalPaths);
00245         }
00246         catch(Exception & e)
00247         {
00248          return false;
00249         }
00250 
00251         return true;
00252   }
00253 
00254  /*----------------------------------------------------------------------*/
00255 
00256   std::string FileSystemManager::findLibraryPath(const std::string & library,
00257                                                  const std::vector < std::string > &additionalPaths) const
00258   {
00259         std::list < std::string > guess;
00260 
00261         // Append the set paths first
00262         for(std::vector < std::string >::const_iterator i = additionalPaths.begin(); i != additionalPaths.end();
00263          i++)
00264          guess.push_back(*i + (i->substr(i->length() - 1) != "/" ? "/" : ""));
00265 
00266         // Default guesses
00267         guess.push_back("/usr/lib/");
00268         guess.push_back("/usr/local/lib/");
00269         guess.push_back("/lib/");
00270         guess.push_back("./");
00271 
00272         // Check LD_LIBRARY_PATH
00273         if(Application::getInstance()->hasEnvironmentVariable("LD_LIBRARY_PATH"))
00274         {
00275          std::vector < std::string > paths =
00276                 StringConverter::tokenize(Application::getInstance()->getEnvironmentVariable("LD_LIBRARY_PATH"), ":");
00277          for(std::vector < std::string >::iterator i = paths.begin(); i != paths.end(); i++)
00278                 guess.push_back(*i + (i->substr(i->length() - 1) != "/" ? "/" : ""));
00279         }
00280 
00281         for(std::list < std::string >::iterator i = guess.begin(); i != guess.end(); i++)
00282         {
00283          std::cerr << "check " << (*i + library) << std::endl;
00284          if(existsFile(*i + library))
00285                 return _translateToAbsolutePath(*i);
00286         }
00287 
00288         Except(FILE_IO_ERROR, "FileSystemManager::findLibraryPath()",
00289            "Library `" + library +
00290            "' not found on your system (default library directories, LD_LIBRARY_PATH environment variable). Please install this library or move/link to the search path, or add to LD_LIBRARY_PATH.");
00291   }
00292 
00293  /*----------------------------------------------------------------------*/
00294 
00295   std::list < std::string > FileSystemManager::listDirectory(const std::string & directory) const
00296   {
00297         std::list < std::string > files;
00298 
00299         struct dirent buf,
00300          *file;
00301         DIR *dir = opendir(directory.c_str());
00302 
00303         if(!dir)
00304          Except(FILE_IO_ERROR, "FileSystemManager::listDirectory",
00305                  "Unable to open directory `" + directory + "\' for listing");
00306 
00307         // Read files
00308         do
00309         {
00310          readdir_r(dir, &buf, &file);
00311          if(file)
00312                 files.push_back(directory + file->d_name);
00313         } while(file);
00314 
00315         closedir(dir);
00316 
00317         return files;
00318   }
00319 
00320  /*----------------------------------------------------------------------*/
00321 
00322   std::list < std::string > FileSystemManager::listDataDirectory(const std::string & directory) const
00323   {
00324         std::list < std::string > files = listDirectory(mDataDirectory + directory);
00325         for(std::list < std::string >::iterator i = files.begin(); i != files.end(); i++)
00326          (*i) = (*i).substr(mDataDirectory.length());
00327 
00328         return files;
00329   }
00330 
00331  /*----------------------------------------------------------------------*/
00332 
00333   bool FileSystemManager::existsFile(const std::string & name) const
00334   {
00335         std::string _name = _replaceHomeChar(name);
00336         struct stat buf;
00337 
00338         if(stat(_name.c_str(), &buf) == -1)
00339         {
00340          switch (errno)
00341          {
00342                 case ENOTDIR:
00343                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile",
00344                          "A component of the path prefix is not a directory.");
00345                  break;
00346                 case ENAMETOOLONG:
00347                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile",
00348                          "A component of a pathname exceeded {NAME_MAX} characters, or an entire path name exceeded {PATH_MAX} characters.");
00349                  break;
00350                 case ENOENT:
00351                  // The named file does not exist.
00352                  return false;
00353                  break;
00354                 case EACCES:
00355                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile",
00356                          "Search permission is denied for a component of the path prefix.");
00357                  break;
00358                 case ELOOP:
00359                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile",
00360                          "Too many symbolic links were encountered in translating the pathname.");
00361                  break;
00362                 case EFAULT:
00363                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile", "Sb or name points to an invalid address.");
00364                  break;
00365                 case EIO:
00366                  Except(FILE_IO_ERROR, "FileSystemManager::existsFile",
00367                          "An I/O error occurred while reading from or writing to the file system.");
00368                  break;
00369          }
00370         }
00371 
00372         return true;
00373   }
00374 
00375  /*----------------------------------------------------------------------*/
00376 
00377   bool FileSystemManager::existsAppFile(const std::string & name) const
00378   {
00379         return existsFile(mAppDirectory + name);
00380   }
00381 
00382  /*----------------------------------------------------------------------*/
00383 
00384   bool FileSystemManager::existsDataFile(const char *name) const
00385   {
00386         return existsFile(mDataDirectory + std::string(name));
00387   }
00388 
00389  /*----------------------------------------------------------------------*/
00390 
00391   FileSystemManager::CFilePointer FileSystemManager::openFileC(const std::string & name,
00392                                                                  const FileOperation & operation) const
00393   {
00394         Assert(operation != READ || existsFile(name), INVALID_NAME_ERROR, "Application::openFileC()");
00395 
00396         char mode[2] = "r";
00397 
00398         switch (operation)
00399         {
00400          case READ:
00401                 strcpy(mode, "r");
00402                 break;
00403          case WRITE:
00404                 strcpy(mode, "w");
00405                 break;
00406          case APPEND:
00407                 strcpy(mode, "a");
00408                 break;
00409         }
00410 
00411         FILE *fp = fopen(name.c_str(), mode);
00412 
00413         // Operation is not allowed
00414         Assert(fp, INVALID_OPERATION_ERROR, "Application::openFileC()");
00415 
00416         return FileSystemManager::CFilePointer(fp);
00417   }
00418 
00419  /*----------------------------------------------------------------------*/
00420 
00421   FileSystemManager::CFilePointer FileSystemManager::openAppFileC(const std::string & name,
00422                                                                  const FileOperation & operation) const
00423   {
00424         return openFileC(mAppDirectory + name, operation);
00425   }
00426 
00427  /*----------------------------------------------------------------------*/
00428 
00429   FileSystemManager::CFilePointer FileSystemManager::openDataFileC(const std::string & name,
00430                                                                   const FileOperation & operation) const
00431   {
00432         return openFileC(mDataDirectory + name, operation);
00433   }
00434 
00435  /*----------------------------------------------------------------------*/
00436 
00437   FileSystemManager::CppFilePointer FileSystemManager::openFileCpp(const std::string & name,
00438                                                                   const FileOperation & operation) const
00439   {
00440         //Assert(operation != READ || existsFile(name), INVALID_NAME_ERROR, "Application::openFileCpp()");
00441         if(operation == READ && !existsFile(name))
00442          Except(INVALID_NAME_ERROR, "Application::openFileCpp()", "Unable to open `" + name + "' for reading.");
00443 
00444         std::_Ios_Openmode mode = std::ios::in;
00445 
00446         switch (operation)
00447         {
00448          case READ:
00449                 mode = std::ios::in;
00450                 break;
00451          case WRITE:
00452                 mode = std::ios::out;
00453                 break;
00454          case APPEND:
00455                 mode = std::ios::app;
00456                 break;
00457         }
00458 
00459         std::fstream * fstr = new std::fstream(name.c_str(), mode);
00460 
00461         return FileSystemManager::CppFilePointer(fstr);
00462   }
00463 
00464  /*----------------------------------------------------------------------*/
00465 
00466   FileSystemManager::CppFilePointer FileSystemManager::openAppFileCpp(const std::string & name,
00467                                                                         const FileOperation & operation)
00468         const
00469   {
00470         return openFileCpp(mAppDirectory + name, operation);
00471   }
00472 
00473  /*----------------------------------------------------------------------*/
00474 
00475   FileSystemManager::CppFilePointer FileSystemManager::openDataFileCpp(const std::string & name,
00476                                                                          const FileOperation & operation)
00477         const
00478   {
00479         return openFileCpp(mDataDirectory + name, operation);
00480   }
00481 
00482  /*----------------------------------------------------------------------*/
00483 
00484   std::string FileSystemManager::getPathDataFile(const std::string & name) const
00485   {
00486         return mDataDirectory + name;
00487   }
00488 
00489  /*----------------------------------------------------------------------*/
00490 
00491   std::string FileSystemManager::readTextFile(const std::string & name) const
00492   {
00493         CppFilePointer fp(openFileCpp(name, FileSystemManager::READ));
00494 
00495         const u32 lineBufSize = 1024;
00496         char lineBuf[lineBufSize];
00497 
00498         std::ostringstream osstr;
00499 
00500         while(!fp->eof())
00501         {
00502          fp->getline(lineBuf, lineBufSize);
00503          osstr << lineBuf << std::endl;
00504         }
00505 
00506         FileSystemManager::getInstance()->closeFile(fp);
00507         return osstr.str();
00508   }
00509 
00510  /*----------------------------------------------------------------------*/
00511 
00512   std::string FileSystemManager::readAppTextFile(const std::string & name) const
00513   {
00514         return readTextFile(mAppDirectory + name);
00515   }
00516 
00517  /*----------------------------------------------------------------------*/
00518 
00519   std::string FileSystemManager::readDataTextFile(const std::string & name) const
00520   {
00521         return readTextFile(mDataDirectory + name);
00522   }
00523 
00524  /*----------------------------------------------------------------------*/
00525 
00526   void FileSystemManager::_findHomeDirectory()
00527   {
00528         mHomeDirectory = Application::getInstance()->getEnvironmentVariable("HOME") + "/";
00529   }
00530 
00531  /*----------------------------------------------------------------------*/
00532 
00533   std::string FileSystemManager::_replaceHomeChar(const std::string & path) const
00534   {
00535         std::string _path = path;
00536         /*
00537          * int pos = _path.find("~/");
00538          * 
00539          * if(pos != std::string::npos)
00540          * _path.replace(pos, 2, mHomeDirectory);
00541          */
00542         StringConverter::trim(_path);
00543         if(_path.substr(0, 2) == "~/")
00544          _path = mHomeDirectory + _path.substr(2);
00545 
00546         return _path;
00547   }
00548 
00549  /*----------------------------------------------------------------------*/
00550 
00551   std::string FileSystemManager::_translateToAbsolutePath(const std::string & path) const
00552   {
00553         // Create relative path by replacing '~' to home directory
00554         std::string relpath = _replaceHomeChar(path);
00555 
00556         // Jump out if the path is already absolute path
00557         if(relpath.substr(0, 1) == PATH_SEPARATOR)
00558          return relpath;
00559 
00560         bool directory = relpath.substr(relpath.length() - 1) == PATH_SEPARATOR;
00561 
00562         typedef std::queue < char *>QueuePtrChar;
00563         typedef std::stack < char *>StackPtrChar;
00564 
00565         char _abspath[MAX_PATH];
00566 
00567         std::string acTmpCurrDir = mCurrentDirectory;
00568         std::string acTmpRelPath = relpath;
00569 
00570         QueuePtrChar tmpQueueRelPath;
00571         StackPtrChar tmpStackCurrPath;
00572         StackPtrChar tmpStackOutPath;
00573 
00574         char *sTmp = strtok((char *) acTmpRelPath.c_str(), PATH_SEPARATOR.c_str());
00575 
00576         while(sTmp)
00577         {
00578          tmpQueueRelPath.push(sTmp);
00579          sTmp = strtok(0, PATH_SEPARATOR.c_str());
00580         }
00581 
00582         sTmp = strtok((char *) acTmpCurrDir.c_str(), PATH_SEPARATOR.c_str());
00583         while(sTmp)
00584         {
00585          tmpStackCurrPath.push(sTmp);
00586          sTmp = strtok(0, PATH_SEPARATOR.c_str());
00587         }
00588 
00589         while(tmpQueueRelPath.size() > 0)
00590         {
00591          char *pcTmp = tmpQueueRelPath.front();
00592 
00593          if(strcmp(pcTmp, "..") == 0)
00594                 tmpStackCurrPath.pop();
00595          else
00596                 tmpStackCurrPath.push(pcTmp);
00597          tmpQueueRelPath.pop();
00598         }
00599         while(tmpStackCurrPath.size() > 0)
00600         {
00601          tmpStackOutPath.push(tmpStackCurrPath.top());
00602          tmpStackCurrPath.pop();
00603         }
00604 
00605         sTmp = _abspath;
00606 #if defined(__GNUC__)
00607         *sTmp++ = PATH_SEPARATOR.c_str()[0];
00608 #endif
00609         while(tmpStackOutPath.size() > 0)
00610         {
00611          char *pcTmp = tmpStackOutPath.top();
00612 
00613          while(*pcTmp != '\0')
00614                 *sTmp++ = *pcTmp++;
00615          tmpStackOutPath.pop();
00616          *sTmp++ = PATH_SEPARATOR.c_str()[0];
00617         }
00618         *(--sTmp) = '\0';
00619 
00620         return std::string(_abspath) + (directory ? PATH_SEPARATOR : "");
00621   }
00622 
00623  /*----------------------------------------------------------------------*/
00624 
00625   void FileSystemManager::_createAppDirectory()
00626   {
00627         // Creating application directory
00628         createDirectory(mAppDirectory);
00629   }
00630 
00631  /*----------------------------------------------------------------------*/
00632 
00633 }