file_manip.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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 <dirent.h>
15#include <fnmatch.h>
16
17#include <cstdio>
18#include <cerrno>
19#include <iostream>
20#include <vector>
21
22#include "op_file.h"
23
24#include "file_manip.h"
25#include "string_manip.h"
26
27using namespace std;
28
29
30bool copy_file(string const & source, string const & destination)
31{
32	struct stat buf;
33	int status = stat(source.c_str(), &buf);
34
35	if (status == 0) {
36		/* FIXME: This code should avoid using system() if possible. */
37		string copy_command("cp -a -f " + source + " " + destination);
38		status = system(copy_command.c_str());
39	}
40	return !status;
41}
42
43
44bool is_directory(string const & dirname)
45{
46	struct stat st;
47	return !stat(dirname.c_str(), &st) && S_ISDIR(st.st_mode);
48}
49
50
51bool is_files_identical(string const & file1, string const & file2)
52{
53	struct stat st1;
54	struct stat st2;
55
56	if (stat(file1.c_str(), &st1) == 0 && stat(file2.c_str(), &st2) == 0) {
57		if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
58			return true;
59	}
60
61	return false;
62}
63
64
65string const op_realpath(string const & name)
66{
67	static char tmp[PATH_MAX];
68	if (!realpath(name.c_str(), tmp))
69		return name;
70	return string(tmp);
71}
72
73
74bool op_file_readable(string const & file)
75{
76	return op_file_readable(file.c_str());
77}
78
79inline static bool is_directory_name(char const * name)
80{
81	return name[0] == '.' &&
82		(name[1] == '\0' ||
83		 (name[1] == '.' && name[2] == '\0'));
84}
85
86
87bool create_file_list(list<string> & file_list, string const & base_dir,
88		      string const & filter, bool recursive)
89{
90	DIR * dir;
91	struct dirent * ent;
92
93	if (!(dir = opendir(base_dir.c_str())))
94		return false;
95
96	while ((ent = readdir(dir)) != 0) {
97		if (!is_directory_name(ent->d_name) &&
98		    fnmatch(filter.c_str(), ent->d_name, 0) != FNM_NOMATCH) {
99			if (recursive) {
100				struct stat stat_buffer;
101				string name = base_dir + '/' + ent->d_name;
102				if (stat(name.c_str(), &stat_buffer) == 0) {
103					if (S_ISDIR(stat_buffer.st_mode) &&
104					    !S_ISLNK(stat_buffer.st_mode)) {
105						// recursive retrieve
106						create_file_list(file_list,
107								 name, filter,
108								 recursive);
109					} else {
110						file_list.push_back(name);
111					}
112				}
113			} else {
114				file_list.push_back(ent->d_name);
115			}
116		}
117	}
118
119	closedir(dir);
120
121	return true;
122}
123
124
125/**
126 * @param path_name the path where we remove trailing '/'
127 *
128 * erase all trailing '/' in path_name except if the last '/' is at pos 0
129 */
130static string erase_trailing_path_separator(string const & path_name)
131{
132	string result(path_name);
133
134	while (result.length() > 1) {
135		if (result[result.length() - 1] != '/')
136			break;
137		result.erase(result.length() - 1, 1);
138	}
139
140	return result;
141}
142
143
144string op_dirname(string const & file_name)
145{
146	string result = erase_trailing_path_separator(file_name);
147	if (result.find_first_of('/') == string::npos)
148		return ".";
149
150	// catch result == "/"
151	if (result.length() == 1)
152		return result;
153
154	size_t pos = result.find_last_of('/');
155
156	// "/usr" must return "/"
157	if (pos == 0)
158		pos = 1;
159
160	result.erase(pos, result.length() - pos);
161
162	// "////usr" must return "/"
163	return erase_trailing_path_separator(result);
164}
165
166
167string op_basename(string const & path_name)
168{
169	string result = erase_trailing_path_separator(path_name);
170
171	// catch result == "/"
172	if (result.length() == 1)
173		return result;
174
175	return erase_to_last_of(result, '/');
176}
177