degate  0.1.2
FileSystem.cc
Go to the documentation of this file.
00001 /*
00002 
00003  This file is part of the IC reverse engineering tool degate.
00004 
00005  Copyright 2008, 2009, 2010 by Martin Schobert
00006 
00007  Degate is free software: you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation, either version 3 of the License, or
00010  any later version.
00011 
00012  Degate is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016 
00017  You should have received a copy of the GNU General Public License
00018  along with degate. If not, see <http://www.gnu.org/licenses/>.
00019 
00020 */
00021 
00022 #include <FileSystem.h>
00023 #include <Configuration.h>
00024 #include <degate_exceptions.h>
00025 
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include <unistd.h>
00029 #include <errno.h>
00030 #include <stdlib.h>
00031 #include <dirent.h>
00032 #include <string.h>
00033 #include <limits.h>
00034 
00035 #include <boost/filesystem/operations.hpp>
00036 #include <boost/filesystem/path.hpp>
00037 #include <boost/format.hpp>
00038 #include <boost/foreach.hpp>
00039 #include <iostream>
00040 #include <string>
00041 
00042 using namespace degate;
00043 using namespace boost::filesystem;
00044 
00045 /** @todo Instead of writing own wrapper functions, it would be better to
00046     use the boost filesystem abstraction.
00047 */
00048 
00049 bool degate::is_directory(std::string const & path) {
00050   struct stat stat_buf;
00051   if(stat(path.c_str(), &stat_buf) == 0) {
00052     return S_ISDIR(stat_buf.st_mode) ? true : false;
00053   }
00054   return false;
00055 }
00056 
00057 bool degate::is_file(std::string const & path) {
00058   struct stat stat_buf;
00059   if(stat(path.c_str(), &stat_buf) == 0) {
00060     return S_ISREG(stat_buf.st_mode) ? true : false;
00061   }
00062   return false;
00063 }
00064 
00065 bool degate::is_symlink(std::string const & path) {
00066   struct stat stat_buf;
00067   if(stat(path.c_str(), &stat_buf) == 0) {
00068     return S_ISLNK(stat_buf.st_mode) ? true : false;
00069   }
00070   return false;
00071 }
00072 
00073 bool degate::file_exists(std::string const & path) {
00074   struct stat stat_buf;
00075   return stat(path.c_str(), &stat_buf) == 0 ? true : false;
00076 }
00077 
00078 std::string degate::get_basedir(std::string const & path) {
00079 
00080   std::string resolved_path;
00081 
00082   if(file_exists(path)) {
00083     resolved_path = get_realpath(path);
00084 
00085     if(is_directory(resolved_path)) return resolved_path;
00086     else {
00087       return resolved_path.substr(0, resolved_path.find_last_of('/'));
00088     }
00089   }
00090   else {
00091     // treat it as a file name
00092     size_t last_pos = path.find_last_of('/');
00093     if(last_pos != 0)
00094       return path.substr(0, last_pos);
00095     else return "/";
00096   }
00097 
00098 }
00099 
00100 
00101 std::string degate::get_realpath(std::string const& path) {
00102   char resolved_path[PATH_MAX];
00103   if(realpath(path.c_str(), resolved_path) == NULL) {
00104     boost::format fmter("Error in get_realpath(). Can't get real path for %1%.");
00105     fmter % path;
00106     throw degate::InvalidPathException(fmter.str());
00107   }
00108   else return std::string(resolved_path);
00109 }
00110 
00111 
00112 std::string degate::get_file_suffix(std::string const& path) {
00113   size_t last_occurance = path.rfind(".", path.size());
00114   if(last_occurance < path.size()) {
00115     return path.substr(last_occurance + 1, path.size() - last_occurance);
00116   }
00117   else return std::string();
00118 }
00119 
00120 
00121 void degate::remove_file(std::string const& path) {
00122   if(unlink(path.c_str()) != 0) {
00123     throw degate::FileSystemException(strerror(errno));
00124   }
00125 }
00126 
00127 void degate::remove_directory(std::string const& path) {
00128   boost::filesystem::path p(path);
00129   boost::filesystem::remove_all(path);
00130 }
00131 
00132 void degate::create_directory(std::string const& directory, mode_t mode) {
00133 
00134   if(mkdir(directory.c_str(), mode) != 0) {
00135     throw degate::FileSystemException(strerror(errno));
00136   }
00137 
00138 }
00139 
00140 std::string degate::create_temp_directory() {
00141   return create_temp_directory(generate_temp_file_pattern(get_temp_directory()));
00142 }
00143 
00144 std::string degate::create_temp_directory(std::string const & directory_pattern) {
00145   char template_str[PATH_MAX];
00146   strncpy(template_str, directory_pattern.c_str(), sizeof(template_str));
00147   char * dirname = mkdtemp(template_str);
00148   return std::string(dirname);
00149 }
00150 
00151 
00152 std::string degate::generate_temp_file_pattern(std::string const & basedir) {
00153   return basedir + std::string("/temp.XXXXXXXXXXX");
00154 }
00155 
00156 
00157 std::list<std::string> degate::read_directory(std::string const& path, bool prefix_path) {
00158 
00159   DIR * dir = NULL;
00160   struct dirent * dir_ent = NULL;
00161 
00162   std::string rpth = get_realpath(path);
00163 
00164   if((dir = opendir(rpth.c_str())) == NULL)
00165     throw degate::FileSystemException(strerror(errno));
00166 
00167   std::list<std::string> retlist;
00168 
00169   while((dir_ent = readdir(dir)) != NULL)
00170     if(!(!strcmp(dir_ent->d_name, ".") ||
00171          !strcmp(dir_ent->d_name, "..")))
00172 
00173         retlist.push_back(prefix_path ? join_pathes(path, dir_ent->d_name) : dir_ent->d_name);
00174 
00175   closedir(dir);
00176 
00177   return retlist;
00178 }
00179 
00180 
00181 
00182 std::string degate::join_pathes(std::string const& base_path, std::string const& extension_path) {
00183   return base_path + std::string("/") + extension_path;
00184 }
00185 
00186 
00187 std::string degate::get_filename_from_path(std::string const& path) {
00188   size_t last_occurance = path.rfind("/", path.size());
00189   if(last_occurance < path.size()) {
00190     return path.substr(last_occurance + 1, path.size() - last_occurance);
00191   }
00192   else return path;
00193 }
00194 
00195 std::string degate::get_basename(std::string const& path) {
00196   std::string filename(get_filename_from_path(path));
00197 
00198   size_t last_occurance = filename.rfind(".", filename.size());
00199   if(last_occurance < filename.size())
00200     return filename.substr(0, last_occurance);
00201   else return filename;
00202 }
00203 
00204 
00205 // a copy from qemu
00206 
00207 char *realpath_alloc(const char *path)
00208 {
00209   int buff_len;
00210   char *result;
00211 
00212 #ifdef PATH_MAX
00213   buff_len = PATH_MAX;
00214 #else
00215   buff_len = pathconf(path, _PC_PATH_MAX);
00216   if (buff_len <= 0)
00217     buff_len = 4096;
00218 #endif
00219 
00220   ++buff_len;
00221   result = (char*)malloc(buff_len * sizeof(char));
00222   if (!result)
00223     return NULL;
00224 
00225   if(realpath(path, result) == NULL) {
00226     free(result);
00227     return NULL;
00228   }
00229   else return result;
00230 }
00231 
00232 
00233 char * _get_relative_path(const char * const path, const char * const relative_to) {
00234   char *path_real;
00235   char *path_real_suffix;
00236   char *path_real_to;
00237   char *path_real_to_suffix;
00238   char *result;
00239   int prefix_len, i, slash_count;
00240   char *string_end;
00241   char path_separator;
00242 #ifdef _WIN32
00243   path_separator = '\\';
00244 #else
00245   path_separator = '/';
00246 #endif
00247 
00248   if (NULL == path || NULL == relative_to)
00249     return NULL;
00250 
00251   path_real = realpath_alloc(path);
00252   if (!path_real)
00253     return NULL;
00254   path_real_to = realpath_alloc(relative_to);
00255   if (!path_real_to)
00256     {
00257       free(path_real);
00258       return NULL;
00259     }
00260 
00261   if (0 == strcmp(path_real, path_real_to))
00262     {
00263       free(path_real);
00264       free(path_real_to);
00265 
00266       //the two directories are equal, the relative path is an empty string
00267       result = (char*)malloc(sizeof(char));
00268       *result = '\0';
00269       return result;
00270     }
00271 
00272   result = NULL;
00273 
00274   //eliminate the common prefix
00275   for (prefix_len = 0;
00276        path_real[prefix_len] != '\0' &&
00277          path_real_to[prefix_len] != '\0' &&
00278          path_real[prefix_len] == path_real_to[prefix_len];
00279        ++prefix_len);
00280 
00281   path_real_suffix = path_real + prefix_len;
00282   while ('\0' != *path_real_suffix &&
00283 #ifdef _WIN32
00284          ('/' == *path_real_suffix || '\\' == *path_real_suffix)
00285 #else
00286          ('/' == *path_real_suffix)
00287 #endif
00288          ) { *path_real_suffix++ = '\0'; }
00289 
00290   path_real_to_suffix = path_real_to + prefix_len;
00291   while ('\0' != *path_real_to_suffix &&
00292 #ifdef _WIN32
00293          ('/' == *path_real_to_suffix || '\\' == *path_real_to_suffix)
00294 #else
00295          ('/' == *path_real_to_suffix)
00296 #endif
00297          ) { *path_real_to_suffix++ = '\0'; }
00298 
00299   slash_count = 0;
00300   for (i = 0; '\0' != path_real_to_suffix[i]; ++i)
00301 #ifdef _WIN32
00302     if ('/' == path_real_to_suffix[i] || '\\' == path_real_to_suffix[i])
00303 #else
00304       if ('/' == path_real_to_suffix[i])
00305 #endif
00306         ++slash_count;
00307   if ('\0' != *path_real_to_suffix) ++slash_count;
00308   result = (char*)malloc(sizeof(char) * (4 + 3 * slash_count + strlen(path_real_suffix)));
00309 
00310   string_end = result;
00311   for (i = 0; i < slash_count; ++i)
00312     {
00313       if (i > 0)
00314         *string_end++ = path_separator;
00315       *string_end++ = '.';
00316       *string_end++ = '.';
00317     }
00318   if (0 == slash_count)
00319     *string_end++ = '.';
00320   if ('\0' != *path_real_suffix)
00321     {
00322       *string_end++ = path_separator;
00323       for (i = 0; '\0' != path_real_suffix[i]; ++i)
00324         *string_end++ = path_real_suffix[i];
00325     }
00326   *string_end++ = '\0';
00327 
00328   free(path_real);
00329   free(path_real_to);
00330   return result;
00331 }
00332 
00333 std::string degate::get_relative_path(std::string const& path,
00334                                       std::string const& relative_to) {
00335 
00336   //boost::format fmter("\npath=%1%\nrelative_to=%2%");
00337   //fmter % path % relative_to;
00338   //std::cout << fmter.str() << std::endl;
00339 
00340   char * rel_path = _get_relative_path(path.c_str(), relative_to.c_str());
00341 
00342   std::string ret(rel_path);
00343 
00344   //std::cout << "rel_path=" << ret << std::endl;
00345 
00346   free(rel_path);
00347   return ret;
00348 }
00349 
00350 
00351 
00352 boost::filesystem::path degate::strip_path(boost::filesystem::path const& strip_from,
00353                                            boost::filesystem::path const& strip_what) {
00354 
00355   path::iterator src_path_iter = strip_what.begin();
00356   path::iterator src_path_end = strip_what.end();
00357   path stripped;
00358 
00359   BOOST_FOREACH(path s, strip_from) {
00360     if(src_path_iter != src_path_end && *src_path_iter == s)
00361       ++src_path_iter;
00362     else
00363       stripped /= s;
00364   }
00365 
00366   return stripped;
00367 }