// -*- Mode: C++ -*- // // Copyright (C) 2013 Red Hat, Inc. // // This file is part of the GNU Application Binary Interface Generic // Analysis and Instrumentation Library (libabigail). This library is // free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 3, or (at your option) any // later version. // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Lesser Public License for more details. // You should have received a copy of the GNU Lesser General Public // License along with this program; see the file COPYING-LGPLV3. If // not, see . ///@file #include #include #include #include #include #include #include #include #include #include "abg-tools-utils.h" using std::string; namespace abigail { namespace tools { using std::ostream; using std::istream; using std::ifstream; using std::string; #define DECLARE_STAT(st) \ struct stat st; \ memset(&st, 0, sizeof(st)) static bool get_stat(const string& path, struct stat* s) {return (stat(path.c_str(), s) == 0);} /// Tests whether \a path exists; bool file_exists(const string& path) { DECLARE_STAT(st); return get_stat(path, &st); } /// Test if path is a path to a regular file. /// /// @param path the path to consider. /// /// @return true iff path is a regular path. bool is_regular_file(const string& path) { DECLARE_STAT(st); if (!get_stat(path, &st)) return false; return !!S_ISREG(st.st_mode); } /// Tests whether #path is a directory. /// /// \return true iff #path is a directory. bool is_dir(const string& path) { DECLARE_STAT(st); if (!get_stat(path, &st)) return false; return !!S_ISDIR(st.st_mode); } /// Return the directory part of a file path. /// /// @param path the file path to consider /// /// @param dirnam the resulting directory part, or "." if the couldn't /// figure out anything better (for now; maybe we should do something /// better than this later ...). /// /// @return true upon successful completion, false otherwise (okay, /// for now it always return true, but that might change in the future). bool dir_name(string const& path, string& dirnam) { if (path.empty()) { dirnam = "."; return true; } char *p = strdup(path.c_str()); char *r = ::dirname(p); dirnam = r; free(p); return true; } /// Return the file name part of a file part. /// /// @param path the file path to consider. /// /// @param file_name the name part of the file to consider. /// ///@return true upon successful completion, false otherwise (okay it ///always return true for now, but that might change in the future). bool base_name(string const &path, string& file_name) { if (path.empty()) { file_name = "."; return true; } char *p = strdup(path.c_str()); char *f = ::basename(p); file_name = f; free(p); return true; } /// Ensures #dir_path is a directory and is created. If #dir_path is /// not created, this function creates it. /// /// \return true if #dir_path is a directory that is already present, /// of if the function has successfuly created it. bool ensure_dir_path_created(const string& dir_path) { struct stat st; memset(&st, 0, sizeof (st)); int stat_result = 0; stat_result = stat(dir_path.c_str(), &st); if (stat_result == 0) { // A file or directory already exists with the same name. if (!S_ISDIR (st.st_mode)) return false; return true; } string cmd; cmd = "mkdir -p " + dir_path; if (system(cmd.c_str())) return false; return true; } /// Ensures that the parent directory of #path is created. /// /// \return true if the parent directory of #path is already present, /// or if this function has successfuly created it. bool ensure_parent_dir_created(const string& path) { bool is_ok = false; if (path.empty()) return is_ok; string parent; if (dir_name(path, parent)) is_ok = ensure_dir_path_created(parent); return is_ok; } /// Check if a given path exists and is readable. /// /// @param path the path to consider. /// /// @param out the out stream to report errors to. /// /// @return true iff path exists and is readable. bool check_file(const string& path, ostream& out) { if (!file_exists(path)) { out << "file " << path << " does not exist\n"; return false; } if (!is_regular_file(path)) { out << path << " is not a regular file\n"; return false; } return true; } /// Guess the type of the content of an input stream. /// /// @param in the input stream to guess the content type for. /// /// @return the type of content guessed. file_type guess_file_type(istream& in) { const unsigned BUF_LEN = 13; const unsigned NB_BYTES_TO_READ = 12; char buf[BUF_LEN]; memset(buf, 0, BUF_LEN); std::streampos initial_pos = in.tellg(); in.read(buf, NB_BYTES_TO_READ); in.seekg(initial_pos); if (in.gcount() < 4 || in.bad()) return FILE_TYPE_UNKNOWN; if (buf[0] == 0x7f && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') return FILE_TYPE_ELF; if (buf[0] == '!' && buf[1] == '<' && buf[2] == 'a' && buf[3] == 'r' && buf[4] == 'c' && buf[5] == 'h' && buf[6] == '>') return FILE_TYPE_AR; if (buf[0] == '<' && buf[1] == 'a' && buf[2] == 'b' && buf[3] == 'i' && buf[4] == '-' && buf[5] == 'i' && buf[6] == 'n' && buf[7] == 's' && buf[8] == 't' && buf[9] == 'r' && buf[10] == ' ') return FILE_TYPE_NATIVE_BI; if (buf[0] == '<' && buf[1] == 'a' && buf[2] == 'b' && buf[3] == 'i' && buf[4] == '-' && buf[5] == 'c' && buf[6] == 'o' && buf[7] == 'r' && buf[8] == 'p' && buf[9] == 'u' && buf[10] == 's' && buf[11] == ' ') return FILE_TYPE_XML_CORPUS; if (buf[0] == 'P' && buf[1] == 'K' && buf[2] == 0x03 && buf[3] == 0x04) return FILE_TYPE_ZIP_CORPUS; return FILE_TYPE_UNKNOWN; } /// Guess the type of the content of an file. /// /// @param file_path the path to the file to consider. /// /// @return the type of content guessed. file_type guess_file_type(const std::string& file_path) { ifstream in(file_path.c_str(), ifstream::binary); file_type r = guess_file_type(in); in.close(); return r; } struct malloced_char_star_deleter { void operator()(char* ptr) {free(ptr);} }; /// Return a copy of the path given in argument, turning it into an /// absolute path by prefixing it with the concatenation of the result /// of get_current_dir_name() and the '/' character. /// /// The result being an shared_ptr to char*, it should manage its /// memory by itself and the user shouldn't need to wory too much for /// that. /// /// @param p the path to turn into an absolute path. /// /// @return a shared pointer to the resulting absolute path. std::tr1::shared_ptr make_path_absolute(const char*p) { using std::tr1::shared_ptr; shared_ptr result; if (p && p[0] != '/') { shared_ptr pwd(get_current_dir_name(), malloced_char_star_deleter()); string s = string(pwd.get()) + "/" + p; result.reset(strdup(s.c_str()), malloced_char_star_deleter()); } else result.reset(strdup(p), malloced_char_star_deleter()); return result; } }//end namespace tools using abigail::ir::function_decl; /// Dump (to the standard error stream) two sequences of strings where /// each string represent one of the functions in the two sequences of /// functions given in argument to this function. /// /// @param a_begin the begin iterator for the first input sequence of /// functions. /// /// @parm a_end the end iterator for the first input sequence of /// functions. /// /// @param b_begin the begin iterator for the second input sequence of /// functions. /// /// @param b_end the end iterator for the second input sequence of functions. void dump_functions_as_string(std::vector::const_iterator a_begin, std::vector::const_iterator a_end, std::vector::const_iterator b_begin, std::vector::const_iterator b_end) {abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);} /// Dump (to the standard error output stream) a pretty representation /// of the signatures of two sequences of functions. /// /// @param a_begin the start iterator of the first input sequence of functions. /// /// @param a_end the end iterator of the first input sequence of functions. /// /// @param b_begin the start iterator of the second input sequence of functions. /// /// @param b_end the end iterator of the second input sequence of functions. void dump_function_names(std::vector::const_iterator a_begin, std::vector::const_iterator a_end, std::vector::const_iterator b_begin, std::vector::const_iterator b_end) { std::vector::const_iterator i; std::ostream& o = std::cerr; for (i = a_begin; i != a_end; ++i) o << (*i)->get_pretty_representation() << "\n"; o << " ->|<- \n"; for (i = b_begin; i != b_end; ++i) o << (*i)->get_pretty_representation() << "\n"; o << "\n"; } /// Compare two functions that are in a vector of functions. /// /// @param an iterator to the beginning of the the sequence of functions. /// /// @param f1_index the index of the first function to compare. /// /// @param f2_inde the index of the second function to compare bool compare_functions(vector::const_iterator base, unsigned f1_index, unsigned f2_index) { function_decl* fn1 = base[f1_index]; function_decl* fn2 = base[f2_index]; return *fn1 == *fn2; } }//end namespace abigail