31 #include "DirectoryUtil.h"
36 #include <sys/types.h>
45 #include "BESForbiddenError.h"
46 #include "BESInternalError.h"
47 #include "TheBESKeys.h"
48 #include "BESNotFoundError.h"
63 DirWrapper(
const string& fullDirPath) :
64 _pDir(0), _fullPath(fullDirPath)
67 _pDir = opendir(fullDirPath.c_str());
91 std::string _fullPath;
95 FileInfo::FileInfo(
const std::string& path,
const std::string& basename,
bool isDir, time_t modTime) :
96 _path(path), _basename(basename), _fullPath(
"")
97 , _isDir(isDir), _modTime(modTime)
103 FileInfo::~FileInfo()
114 FileInfo::basename()
const
119 bool FileInfo::isDir()
const
124 time_t FileInfo::modTime()
const
132 struct tm* pTM = gmtime(&_modTime);
135 strftime(buf, 128,
"%F %T", pTM);
142 if (_fullPath.empty()) {
143 _fullPath = _path +
"/" + _basename;
148 std::string FileInfo::toString()
const
150 return "{FileInfo fullPath=" +
getFullPath() +
" isDir=" + ((isDir()) ? (
"true") : (
"false")) +
" modTime=\""
157 const string DirectoryUtil::_sDebugChannel =
"agg_util";
159 DirectoryUtil::DirectoryUtil() :
160 _rootDir(
"/"), _suffix(
"")
161 , _pRegExp(0), _filteringModTimes(false), _newestModTime(0L)
167 DirectoryUtil::~DirectoryUtil()
188 throw BESForbiddenError(
"can't use rootDir=" + origRootDir +
" since it has a relative path (../)", __FILE__,
193 _rootDir = origRootDir;
214 if (!regexp.empty()) {
215 _pRegExp =
new libdap::Regex(regexp.c_str());
227 _newestModTime = newestModTime;
228 _filteringModTimes =
true;
232 std::vector<FileInfo>* pDirectories)
234 string pathToUse(path);
237 BESDEBUG(_sDebugChannel,
"Attempting to get dir listing for path=\"" << pathToUse <<
"\"" << endl);
240 DirWrapper pDir(pathToUse);
242 throwErrorForOpendirFail(pathToUse);
247 struct dirent* pDirEnt = 0;
248 while ((pDirEnt = readdir(pDir.get())) != 0) {
249 string entryName = pDirEnt->d_name;
251 if (!entryName.empty() && entryName[0] ==
'.') {
256 string pathToEntry = pathToUse +
"/" + entryName;
258 int statResult = stat(pathToEntry.c_str(), &statBuf);
259 if (statResult != 0) {
267 if (pDirectories && S_ISDIR(statBuf.st_mode)) {
268 pDirectories->push_back(
FileInfo(path, entryName,
true, statBuf.st_mtime));
270 else if (pRegularFiles && S_ISREG(statBuf.st_mode)) {
271 FileInfo theFile(path, entryName,
false, statBuf.st_mtime);
273 if (matchesAllFilters(theFile.
getFullPath(), statBuf.st_mtime)) {
274 pRegularFiles->push_back(theFile);
281 std::vector<FileInfo>* pDirectories)
284 string canonicalPath = path;
291 vector<FileInfo> dirs;
300 pDirectories->insert(pDirectories->end(), dirs.begin(), dirs.end());
304 for (vector<FileInfo>::const_iterator it = dirs.begin(); it != dirs.end(); ++it) {
305 string subPath = canonicalPath +
"/" + it->basename();
306 BESDEBUG(_sDebugChannel,
"DirectoryUtil: recursing down to directory subtree=\"" << subPath <<
"\"..." << endl);
319 void DirectoryUtil::throwErrorForOpendirFail(
const string& fullPath)
323 string msg =
"Permission denied for some directory in path=\"" + fullPath +
"\"";
329 string msg =
"A symlink loop was detected in path=\"" + fullPath +
"\"";
335 string msg =
"A name in the path was too long. path=\"" + fullPath +
"\"";
341 string msg =
"Some part of the path was not found. path=\"" + fullPath +
"\"";
347 string msg =
"Some part of the path was not a directory. path=\"" + fullPath +
"\"";
353 string msg =
"Internal Error: Too many files are currently open!";
359 string msg =
"An unknown errno was found after opendir() was called on path=\"" + fullPath +
"\"";
365 bool DirectoryUtil::matchesAllFilters(
const std::string& path, time_t modTime)
const
369 if (!_suffix.empty() && !matchesSuffix(path, _suffix)) {
374 if (matches && _pRegExp) {
376 int numCharsMatching = _pRegExp->match(path.c_str(), path.size(), 0);
377 matches = (numCharsMatching > 0);
380 if (matches && _filteringModTimes) {
381 matches = (modTime < _newestModTime);
389 return (path.find(
"..") != string::npos);
395 string::size_type pos = path.find_last_not_of(
"/");
396 if (pos != string::npos) {
397 path = path.substr(0, pos + 1);
405 string::size_type pos = path.find_first_not_of(
"/");
406 path = path.substr(pos, string::npos);
412 std::ostringstream oss;
414 BESDEBUG(_sDebugChannel, oss.str() << endl);
419 for (vector<FileInfo>::const_iterator it = listing.begin(); it != listing.end(); ++it) {
420 os << it->toString() << endl;
438 bool DirectoryUtil::matchesSuffix(
const std::string& filename,
const std::string& suffix)
441 bool matches = (filename.find(suffix, filename.size() - suffix.size()) != string::npos);
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
error thrown if the resource requested cannot be found
static void check_path(const std::string &path, const std::string &root, bool follow_sym_links)
Check if the specified path is valid.
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
static std::string getBESRootDir()
void setFilterRegExp(const std::string ®exp)
static void removePrecedingSlashes(std::string &path)
static bool hasRelativePath(const std::string &path)
static void printFileInfoList(std::ostream &os, const std::vector< FileInfo > &listing)
void setRootDir(const std::string &rootDir, bool allowRelativePaths=false, bool allowSymLinks=false)
void getListingOfRegularFilesRecursive(const std::string &path, std::vector< FileInfo > &rRegularFiles)
void setFilterSuffix(const std::string &suffix)
static void removeTrailingSlashes(std::string &path)
void getListingForPath(const std::string &path, std::vector< FileInfo > *pRegularFiles, std::vector< FileInfo > *pDirectories)
void getListingForPathRecursive(const std::string &path, std::vector< FileInfo > *pRegularFiles, std::vector< FileInfo > *pDirectories)
void setFilterModTimeOlderThan(time_t newestModTime)
const std::string & getRootDir() const
std::string getModTimeAsString() const
FileInfo(const std::string &path, const std::string &basename, bool isDir, time_t modTime)
const std::string & path() const
const std::string & getFullPath() const
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...