degate 0.1.1
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_prefix;
00236   char *path_real_suffix;
00237   char *path_real_to;
00238   char *path_real_to_suffix;
00239   char *result;
00240   int prefix_len, i, slash_count;
00241   char *string_end;
00242   char path_separator;
00243 #ifdef _WIN32
00244   path_separator = '\\';
00245 #else
00246   path_separator = '/';
00247 #endif
00248 
00249   if (NULL == path || NULL == relative_to)
00250     return NULL;
00251 
00252   path_real = realpath_alloc(path);
00253   if (!path_real)
00254     return NULL;
00255   path_real_to = realpath_alloc(relative_to);
00256   if (!path_real_to)
00257     {
00258       free(path_real);
00259       return NULL;
00260     }
00261 
00262   if (0 == strcmp(path_real, path_real_to))
00263     {
00264       free(path_real);
00265       free(path_real_to);
00266 
00267       //the two directories are equal, the relative path is an empty string
00268       result = (char*)malloc(sizeof(char));
00269       *result = '\0';
00270       return result;
00271     }
00272 
00273   result = NULL;
00274 
00275   //eliminate the common prefix
00276   for (prefix_len = 0;
00277        path_real[prefix_len] != '\0' &&
00278          path_real_to[prefix_len] != '\0' &&
00279          path_real[prefix_len] == path_real_to[prefix_len];
00280        ++prefix_len);
00281 
00282   path_prefix = path_real;
00283   path_real_suffix = path_real + prefix_len;
00284   while ('\0' != *path_real_suffix &&
00285 #ifdef _WIN32
00286          ('/' == *path_real_suffix || '\\' == *path_real_suffix)
00287 #else
00288          ('/' == *path_real_suffix)
00289 #endif
00290          ) { *path_real_suffix++ = '\0'; }
00291 
00292   path_real_to_suffix = path_real_to + prefix_len;
00293   while ('\0' != *path_real_to_suffix &&
00294 #ifdef _WIN32
00295          ('/' == *path_real_to_suffix || '\\' == *path_real_to_suffix)
00296 #else
00297          ('/' == *path_real_to_suffix)
00298 #endif
00299          ) { *path_real_to_suffix++ = '\0'; }
00300 
00301   slash_count = 0;
00302   for (i = 0; '\0' != path_real_to_suffix[i]; ++i)
00303 #ifdef _WIN32
00304     if ('/' == path_real_to_suffix[i] || '\\' == path_real_to_suffix[i])
00305 #else
00306       if ('/' == path_real_to_suffix[i])
00307 #endif
00308         ++slash_count;
00309   if ('\0' != *path_real_to_suffix) ++slash_count;
00310   result = (char*)malloc(sizeof(char) * (4 + 3 * slash_count + strlen(path_real_suffix)));
00311 
00312   string_end = result;
00313   for (i = 0; i < slash_count; ++i)
00314     {
00315       if (i > 0)
00316         *string_end++ = path_separator;
00317       *string_end++ = '.';
00318       *string_end++ = '.';
00319     }
00320   if (0 == slash_count)
00321     *string_end++ = '.';
00322   if ('\0' != *path_real_suffix)
00323     {
00324       *string_end++ = path_separator;
00325       for (i = 0; '\0' != path_real_suffix[i]; ++i)
00326         *string_end++ = path_real_suffix[i];
00327     }
00328   *string_end++ = '\0';
00329 
00330   free(path_real);
00331   free(path_real_to);
00332   return result;
00333 }
00334 
00335 std::string degate::get_relative_path(std::string const& path,
00336                                       std::string const& relative_to) {
00337 
00338   //boost::format fmter("\npath=%1%\nrelative_to=%2%");
00339   //fmter % path % relative_to;
00340   //std::cout << fmter.str() << std::endl;
00341 
00342   char * rel_path = _get_relative_path(path.c_str(), relative_to.c_str());
00343 
00344   std::string ret(rel_path);
00345 
00346   //std::cout << "rel_path=" << ret << std::endl;
00347 
00348   free(rel_path);
00349   return ret;
00350 }
00351 
00352 
00353 
00354 boost::filesystem::path degate::strip_path(boost::filesystem::path const& strip_from,
00355                                            boost::filesystem::path const& strip_what) {
00356 
00357   path::iterator src_path_iter = strip_what.begin();
00358   path::iterator src_path_end = strip_what.end();
00359   path stripped;
00360 
00361   BOOST_FOREACH(path s, strip_from) {
00362     if(src_path_iter != src_path_end && *src_path_iter == s)
00363       ++src_path_iter;
00364     else
00365       stripped /= s;
00366   }
00367 
00368   return stripped;
00369 }