/** * @file file_manip.cpp * Useful file management helpers * * @remark Copyright 2002 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <utime.h> #include <limits.h> #include <stdlib.h> #include <cstdio> #include <cerrno> #include <iostream> #include <fstream> #include <vector> #include "op_file.h" #include "file_manip.h" #include "string_manip.h" using namespace std; bool copy_file(string const & source, string const & destination) { int retval; struct stat buf; if (stat(source.c_str(), &buf)) return false; if (!op_file_readable(source)) return false; ifstream in(source.c_str()); if (!in) return false; mode_t mode = buf.st_mode & ~S_IFMT; if (!(mode & S_IWUSR)) mode |= S_IWUSR; int fd = open(destination.c_str(), O_RDWR|O_CREAT, mode); if (fd < 0) return false; close(fd); // ignore error here: a simple user can copy a root.root 744 file // but can't chown the copied file to root. retval = chown(destination.c_str(), buf.st_uid, buf.st_gid); // a scope to ensure out is closed before changing is mtime/atime { ofstream out(destination.c_str(), ios::trunc); if (!out) return false; out << in.rdbuf(); } struct utimbuf utim; utim.actime = buf.st_atime; utim.modtime = buf.st_mtime; if (utime(destination.c_str(), &utim)) return false; return true; } bool is_directory(string const & dirname) { struct stat st; return !stat(dirname.c_str(), &st) && S_ISDIR(st.st_mode); } bool is_files_identical(string const & file1, string const & file2) { struct stat st1; struct stat st2; if (stat(file1.c_str(), &st1) == 0 && stat(file2.c_str(), &st2) == 0) { if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) return true; } return false; } string const op_realpath(string const & name) { static char tmp[PATH_MAX]; if (!realpath(name.c_str(), tmp)) return name; return string(tmp); } bool op_file_readable(string const & file) { return op_file_readable(file.c_str()); } static void get_pathname(const char * pathname, void * name_list) { list<string> * file_list = (list<string> *)name_list; file_list->push_back(pathname); } bool create_file_list(list<string> & file_list, string const & base_dir, string const & filter, bool recursive) { return !get_matching_pathnames(&file_list, get_pathname, base_dir.c_str(), filter.c_str(), recursive ? MATCH_ANY_ENTRY_RECURSION : NO_RECURSION) ? true : false; } /** * @param path_name the path where we remove trailing '/' * * erase all trailing '/' in path_name except if the last '/' is at pos 0 */ static string erase_trailing_path_separator(string const & path_name) { string result(path_name); while (result.length() > 1) { if (result[result.length() - 1] != '/') break; result.erase(result.length() - 1, 1); } return result; } string op_dirname(string const & file_name) { string result = erase_trailing_path_separator(file_name); if (result.find_first_of('/') == string::npos) return "."; // catch result == "/" if (result.length() == 1) return result; size_t pos = result.find_last_of('/'); // "/usr" must return "/" if (pos == 0) pos = 1; result.erase(pos, result.length() - pos); // "////usr" must return "/" return erase_trailing_path_separator(result); } string op_basename(string const & path_name) { string result = erase_trailing_path_separator(path_name); // catch result == "/" if (result.length() == 1) return result; return erase_to_last_of(result, '/'); }