| /** |
| * @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, '/'); |
| } |