diff options
Diffstat (limited to '')
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h | 659 |
1 files changed, 659 insertions, 0 deletions
diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h new file mode 100644 index 000000000..af2f3d5dc --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h @@ -0,0 +1,659 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_2_ +#define DLIB_DIR_NAV_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + + +#include "dir_nav_kernel_abstract.h" + +#include <string> +#include "../uintn.h" +#include "../algs.h" + +#include <sys/types.h> +#include <dirent.h> +#include <libgen.h> +#include <limits.h> +#include <unistd.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <chrono> + +#if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE) +#define stat64 stat +#endif + +#include <vector> +#include "../stl_checked.h" +#include "../enable_if.h" +#include "../queue.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + CONVENTION + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + !*/ + + friend class directory; + + struct data + { + uint64 file_size; + std::string name; + std::string full_name; + std::chrono::time_point<std::chrono::system_clock> last_modified; + }; + + void init(const std::string& name); + + public: + + struct private_constructor{}; + inline file ( + const std::string& name, + const std::string& full_name, + const uint64 file_size, + const std::chrono::time_point<std::chrono::system_clock>& last_modified, + private_constructor + ) + { + state.file_size = file_size; + state.name = name; + state.full_name = full_name; + state.last_modified = last_modified; + } + + + class file_not_found : public error { + public: file_not_found(const std::string& s): error(s){} + }; + + inline file ( + ) + { + state.file_size = 0; + } + + file ( + const std::string& name + ) { init(name); } + + file ( + const char* name + ) { init(name); } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + inline uint64 size ( + ) const { return state.file_size; } + + inline std::chrono::time_point<std::chrono::system_clock> last_modified ( + ) const { return state.last_modified; } + + operator std::string ( + ) const { return full_name(); } + + bool operator == ( + const file& rhs + ) const; + + bool operator != ( + const file& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const file& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + file& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + + CONVENTION + state.name == name() + state.full_name == full_name() + is_root() == state.name.size() == 0 + + !*/ + + void init(const std::string& name); + + public: + struct private_constructor{}; + inline directory ( + const std::string& name, + const std::string& full_name, + private_constructor + ) + { + state.name = name; + state.full_name = full_name; + } + + struct data + { + std::string name; + std::string full_name; + }; + + class dir_not_found : public error { + public: dir_not_found(const std::string& s):error(s){} + }; + class listing_error : public error { + public: listing_error(const std::string& s):error(s){} + }; + + inline directory ( + ) + { + } + + directory ( + const std::string& name + ) { init(name); } + + directory ( + const char* name + ) { init(name); } + + static char get_separator ( + ); + + template < + typename queue_of_files + > + void get_files ( + queue_of_files& files + ) const; + + template < + typename queue_of_dirs + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + + std::vector<file> get_files ( + ) const + { + std::vector<file> temp_vector; + get_files(temp_vector); + return temp_vector; + } + + std::vector<directory> get_dirs ( + ) const + { + std::vector<directory> temp_vector; + get_dirs(temp_vector); + return temp_vector; + } + + const directory get_parent ( + ) const; + + inline bool is_root ( + ) const { return state.name.size() == 0; } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + operator std::string ( + ) const { return full_name(); } + + bool operator == ( + const directory& rhs + ) const; + + bool operator != ( + const directory& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const directory& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + directory& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data state; + + bool is_root_path ( + const std::string& path + ) const; + /*! + ensures + - returns true if path is a root path. + Note that this function considers root paths that don't + have a trailing separator to also be valid. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + inline std::ostream& operator<< ( + std::ostream& out, + const directory& item + ) { out << (std::string)item; return out; } + + inline std::ostream& operator<< ( + std::ostream& out, + const file& item + ) { out << (std::string)item; return out; } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // templated member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename disable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + using namespace std; + + files.clear(); + if (state.full_name.size() == 0) + throw directory::listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + // get a handle to something we can search with + ffind = opendir(state.full_name.c_str()); + if (ffind == 0) + { + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + } + + uint64 file_size; + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // this might be a broken symbolic link. We can check by calling + // readlink and seeing if it finds anything. + char buf[PATH_MAX]; + ssize_t temp = readlink((path+data->d_name).c_str(),buf,sizeof(buf)); + if (temp == -1) + throw directory::listing_error("Unable to list the contents of " + state.full_name); + else + file_size = static_cast<uint64>(temp); + } + else + { + file_size = static_cast<uint64>(buffer.st_size); + } + auto last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime); +#ifdef _BSD_SOURCE + last_modified += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::nanoseconds(buffer.st_atim.tv_nsec)); +#endif + + if (S_ISDIR(buffer.st_mode) == 0) + { + // this is actually a file + file temp( + data->d_name, + path+data->d_name, + file_size, + last_modified, + file::private_constructor() + ); + files.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + files.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename enable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + queue<file>::kernel_2a temp_files; + directory_helper_get_files(state,temp_files); + + files.clear(); + + // copy the queue of files into the vector + temp_files.reset(); + while (temp_files.move_next()) + { + files.push_back(temp_files.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + void directory:: + get_files ( + queue_of_files& files + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the cygwin version of gcc + directory_helper_get_files(state,files); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename disable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + using namespace std; + + dirs.clear(); + if (state.full_name.size() == 0) + throw directory::listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + // get a handle to something we can search with + ffind = opendir(state.full_name.c_str()); + if (ffind == 0) + { + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + } + + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // just assume this isn't a directory. It is probably a broken + // symbolic link. + continue; + } + + string dtemp(data->d_name); + if (S_ISDIR(buffer.st_mode) && + dtemp != "." && + dtemp != ".." ) + { + // this is a directory so add it to dirs + directory temp(dtemp,path+dtemp, directory::private_constructor()); + dirs.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + dirs.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename enable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + queue<directory>::kernel_2a temp_dirs; + directory_helper_get_dirs(state,temp_dirs); + + dirs.clear(); + + // copy the queue of dirs into the vector + temp_dirs.reset(); + while (temp_dirs.move_next()) + { + dirs.push_back(temp_dirs.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + + template < + typename queue_of_dirs + > + void directory:: + get_dirs ( + queue_of_dirs& dirs + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the cygwin version of gcc + directory_helper_get_dirs(state,dirs); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + directory dir("/"); + roots.enqueue(dir); + } + + template < + typename queue_of_dir + > + typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + std::vector<directory>& roots + ) + { + roots.clear(); + directory dir("/"); + roots.push_back(dir); + } + +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "dir_nav_kernel_2.cpp" +#endif + +#endif // DLIB_DIR_NAV_KERNEl_2_ + |