1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
/*
copyright 20016-2017 Paul Dreik (earlier Paul Sundvall)
Distributed under GPL v 2.0 or later, at your option.
See LICENSE for further details.
*/
#include "config.h"
// std
#include <cerrno>
#include <cstring>
#include <iostream>
#include <string>
// os
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// project
#include "Dirlist.hh"
#include "RdfindDebug.hh" //debug macros
static const int maxdepth = 50;
int
Dirlist::walk(const std::string& dir, const int recursionlevel)
{
RDDEBUG("Now in walk with dir=" << dir.c_str() << " and recursionlevel="
<< recursionlevel << std::endl);
if (recursionlevel >= maxdepth) {
std::cerr << "recursion limit exceeded\n";
return -1;
}
// open the directory
DIR* dirp = opendir(dir.c_str());
if (dirp == NULL) {
// failed to open directory
RDDEBUG("failed to open directory" << std::endl);
// this can be due to rights, or some other error.
handlepossiblefile(dir, recursionlevel);
return 1; // its a file (or something else)
}
// we opened the directory. let us read the content.
RDDEBUG("opened directory" << std::endl);
struct dirent* dp = NULL;
while (NULL != (dp = readdir(dirp))) {
// is the directory . or ..?
if (0 == strcmp(".", dp->d_name) || 0 == strcmp("..", dp->d_name)) {
continue;
}
// investigate what kind of file it is, dont follow any
// symlinks when doing this (lstat instead of stat).
struct stat info;
const int statval =
lstat((dir + "/" + std::string(dp->d_name)).c_str(), &info);
if (statval != 0) {
// failed to do stat
continue;
}
// investigate what kind of item it was.
bool dowalk = false;
if (S_ISLNK(info.st_mode)) {
// symlink
if (m_followsymlinks) {
(*m_callback)(dir, std::string(dp->d_name), recursionlevel);
}
if (m_followsymlinks) {
dowalk = true;
}
} else if (S_ISDIR(info.st_mode)) {
// directory
dowalk = true;
} else if (S_ISREG(info.st_mode)) {
// regular file
(*m_callback)(dir, std::string(dp->d_name), recursionlevel);
}
// try to open directory
if (dowalk) {
walk(dir + "/" + dp->d_name, recursionlevel + 1);
}
} // while
// close the directory
(void)closedir(dirp);
return 2; // its a directory
}
// splits inputstring into path and filename. if no / character is found,
// empty string is returned as path and filename is set to inputstring.
int
splitfilename(std::string& path,
std::string& filename,
const std::string& inputstring)
{
const auto pos = inputstring.rfind('/');
if (pos == std::string::npos) {
path = "";
filename = inputstring;
return -1;
}
path = inputstring.substr(0, pos + 1);
filename = inputstring.substr(pos + 1, std::string::npos);
return 0;
}
// this function is called for files that were believed to be directories,
// or failed re
int
Dirlist::handlepossiblefile(const std::string& possiblefile, int recursionlevel)
{
struct stat info;
RDDEBUG("Now in handlepossiblefile with name "
<< possiblefile.c_str() << " and recursionlevel " << recursionlevel
<< std::endl);
// split filename into path and filename
std::string path, filename;
splitfilename(path, filename, possiblefile);
RDDEBUG("split filename is path=" << path.c_str() << " filename="
<< filename.c_str() << std::endl);
// investigate what kind of file it is, dont follow symlink
int statval = 0;
do {
statval = lstat(possiblefile.c_str(), &info);
} while (statval < 0 && errno == EINTR);
if (statval < 0) {
// probably file does not exist, or trouble with rights.
RDDEBUG("got negative statval " << statval << std::endl);
//(*m_report_failed_on_stat)(path, filename, recursionlevel);
return -1;
} else {
RDDEBUG("got positive statval " << statval << std::endl);
}
if (S_ISLNK(info.st_mode)) {
RDDEBUG("found symlink" << std::endl);
if (m_followsymlinks) {
(*m_callback)(path, filename, recursionlevel);
}
return 0;
} else {
RDDEBUG("not a symlink" << std::endl);
}
if (S_ISDIR(info.st_mode)) {
std::cerr << "Dirlist.cc::handlepossiblefile: This should never happen. "
"FIXME! details on the next row:\n";
std::cerr << "possiblefile=\"" << possiblefile << "\"\n";
// this should never happen, because this function is only to be called
// for items that can not be opened with opendir.
// maybe it happens if someone else is changing the file while we
// are reading it?
return -2;
} else {
RDDEBUG("not a dir\n");
}
if (S_ISREG(info.st_mode)) {
RDDEBUG("it is a regular file" << std::endl);
(*m_callback)(path, filename, recursionlevel);
return 0;
} else {
RDDEBUG("not a regular file" << std::endl);
}
std::cout
<< "Dirlist.cc::handlepossiblefile(): found something else than a dir or "
"a regular file."
<< std::endl;
return -1;
}
|