182 lines
3.6 KiB
C++
182 lines
3.6 KiB
C++
/**
|
|
* @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, '/');
|
|
}
|