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 #include "../include/PCMFileSystemManager.h"
00030
00031 #include "../include/PCMApplication.h"
00032
00033
00034
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
00050 template <> FileSystemManager * Singleton < FileSystemManager >::mInstance = 0;
00051
00052
00053
00054
00055
00056 const u32 FileSystemManager::MAX_PATH = 1024;
00057 const std::string FileSystemManager::PATH_SEPARATOR = "/";
00058
00059
00060
00061
00062
00063 FileSystemManager::FileSystemManager(const std::string & appDirectory, const std::string & iniFile)
00064
00065
00066
00067
00068
00069
00070
00071 {
00072 mInitialized = false;
00073 mAppDirectory = appDirectory;
00074 mDataDirectory = "(unknown)";
00075 mHomeDirectory = "(unknown)";
00076 mCurrentDirectory = "(unknown)";
00077 mIniFile = iniFile;
00078
00079
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
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
00117 fp.lock();
00118 fclose(fp.getPtr());
00119 fp.unlock();
00120 fp.setNull(true);
00121 }
00122
00123
00124
00125
00126
00127
00128
00129 void FileSystemManager::initialize()
00130 {
00131 Assert(!mInitialized, INVALID_OPERATION_ERROR, "FileSystemManager::initialize()");
00132
00133
00134 _findHomeDirectory();
00135
00136
00137 mCurrentDirectory = Application::getInstance()->getEnvironmentVariable("PWD") + '/';
00138
00139
00140 mAppDirectory = _replaceHomeChar(mAppDirectory);
00141
00142
00143 _createAppDirectory();
00144
00145 mInitialized = true;
00146
00147
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
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
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
00267 guess.push_back("/usr/lib/");
00268 guess.push_back("/usr/local/lib/");
00269 guess.push_back("/lib/");
00270 guess.push_back("./");
00271
00272
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
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
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
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
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
00538
00539
00540
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
00554 std::string relpath = _replaceHomeChar(path);
00555
00556
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
00628 createDirectory(mAppDirectory);
00629 }
00630
00631
00632
00633 }