1 /** 2 * @file file_manip.cpp 3 * Useful file management helpers 4 * 5 * @remark Copyright 2002 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Philippe Elie 9 * @author John Levon 10 */ 11 12 #include <unistd.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 #include <utime.h> 16 #include <limits.h> 17 #include <stdlib.h> 18 19 #include <cstdio> 20 #include <cerrno> 21 #include <iostream> 22 #include <fstream> 23 #include <vector> 24 25 #include "op_file.h" 26 27 #include "file_manip.h" 28 #include "string_manip.h" 29 30 using namespace std; 31 32 33 bool copy_file(string const & source, string const & destination) 34 { 35 int retval; 36 struct stat buf; 37 if (stat(source.c_str(), &buf)) 38 return false; 39 40 if (!op_file_readable(source)) 41 return false; 42 43 ifstream in(source.c_str()); 44 if (!in) 45 return false; 46 47 mode_t mode = buf.st_mode & ~S_IFMT; 48 if (!(mode & S_IWUSR)) 49 mode |= S_IWUSR; 50 51 int fd = open(destination.c_str(), O_RDWR|O_CREAT, mode); 52 if (fd < 0) 53 return false; 54 close(fd); 55 56 57 // ignore error here: a simple user can copy a root.root 744 file 58 // but can't chown the copied file to root. 59 retval = chown(destination.c_str(), buf.st_uid, buf.st_gid); 60 61 // a scope to ensure out is closed before changing is mtime/atime 62 { 63 ofstream out(destination.c_str(), ios::trunc); 64 if (!out) 65 return false; 66 out << in.rdbuf(); 67 } 68 69 struct utimbuf utim; 70 utim.actime = buf.st_atime; 71 utim.modtime = buf.st_mtime; 72 if (utime(destination.c_str(), &utim)) 73 return false; 74 75 return true; 76 } 77 78 79 bool is_directory(string const & dirname) 80 { 81 struct stat st; 82 return !stat(dirname.c_str(), &st) && S_ISDIR(st.st_mode); 83 } 84 85 86 bool is_files_identical(string const & file1, string const & file2) 87 { 88 struct stat st1; 89 struct stat st2; 90 91 if (stat(file1.c_str(), &st1) == 0 && stat(file2.c_str(), &st2) == 0) { 92 if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) 93 return true; 94 } 95 96 return false; 97 } 98 99 100 string const op_realpath(string const & name) 101 { 102 static char tmp[PATH_MAX]; 103 if (!realpath(name.c_str(), tmp)) 104 return name; 105 return string(tmp); 106 } 107 108 109 bool op_file_readable(string const & file) 110 { 111 return op_file_readable(file.c_str()); 112 } 113 114 static void get_pathname(const char * pathname, void * name_list) 115 { 116 list<string> * file_list = (list<string> *)name_list; 117 file_list->push_back(pathname); 118 } 119 120 bool create_file_list(list<string> & file_list, string const & base_dir, 121 string const & filter, bool recursive) 122 { 123 return !get_matching_pathnames(&file_list, get_pathname, 124 base_dir.c_str(), filter.c_str(), 125 recursive ? MATCH_ANY_ENTRY_RECURSION : 126 NO_RECURSION) ? true : false; 127 128 } 129 130 131 /** 132 * @param path_name the path where we remove trailing '/' 133 * 134 * erase all trailing '/' in path_name except if the last '/' is at pos 0 135 */ 136 static string erase_trailing_path_separator(string const & path_name) 137 { 138 string result(path_name); 139 140 while (result.length() > 1) { 141 if (result[result.length() - 1] != '/') 142 break; 143 result.erase(result.length() - 1, 1); 144 } 145 146 return result; 147 } 148 149 string op_dirname(string const & file_name) 150 { 151 string result = erase_trailing_path_separator(file_name); 152 if (result.find_first_of('/') == string::npos) 153 return "."; 154 155 // catch result == "/" 156 if (result.length() == 1) 157 return result; 158 159 size_t pos = result.find_last_of('/'); 160 161 // "/usr" must return "/" 162 if (pos == 0) 163 pos = 1; 164 165 result.erase(pos, result.length() - pos); 166 167 // "////usr" must return "/" 168 return erase_trailing_path_separator(result); 169 } 170 171 172 string op_basename(string const & path_name) 173 { 174 string result = erase_trailing_path_separator(path_name); 175 176 // catch result == "/" 177 if (result.length() == 1) 178 return result; 179 180 return erase_to_last_of(result, '/'); 181 } 182