blob: 7ec7473a9a31e078b3fdcccfd35fca253fe368bb [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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
30using namespace std;
31
32
33bool 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
79bool 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
86bool 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
100string 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
109bool op_file_readable(string const & file)
110{
111 return op_file_readable(file.c_str());
112}
113
114static 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
120bool 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 */
136static 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
149string 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
172string 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}