Home | History | Annotate | Download | only in libutil++
      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