• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
copy_file(string const & source,string const & destination)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 
is_directory(string const & dirname)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 
is_files_identical(string const & file1,string const & file2)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 
op_realpath(string const & name)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 
op_file_readable(string const & file)109 bool op_file_readable(string const & file)
110 {
111 	return op_file_readable(file.c_str());
112 }
113 
get_pathname(const char * pathname,void * name_list)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 
create_file_list(list<string> & file_list,string const & base_dir,string const & filter,bool recursive)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  */
erase_trailing_path_separator(string const & path_name)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 
op_dirname(string const & file_name)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 
op_basename(string const & path_name)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