/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #ifndef CPPCMS_IMPL_DIR_H #define CPPCMS_IMPL_DIR_H #if defined(__sun) #define _POSIX_PTHREAD_SEMANTICS #endif #include #ifdef CPPCMS_WIN_NATIVE # include # ifndef NOMINMAX # define NOMINMAX # endif # include #else # include # include # include # include #endif #include #include #include namespace cppcms { namespace impl { class directory : public booster::noncopyable { public: directory(); ~directory(); bool open(std::string const &dir_name); void close(); bool next(); char const *name(); private: #ifdef CPPCMS_WIN_NATIVE HANDLE dir_; _WIN32_FIND_DATAW entry_; std::string utf_name_; #else // POSIX DIR *dir_; #if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__) struct dirent de_; #else #define CPPCMS_DIR_ALLOCATE_DE struct dirent *de_; #endif struct dirent *entry_p_; #endif }; inline directory::~directory() { close(); } #ifdef CPPCMS_WIN_NATIVE inline directory::directory() : dir_(INVALID_HANDLE_VALUE) { } inline void directory::close() { if(dir_!=INVALID_HANDLE_VALUE) { FindClose(dir_); dir_ = INVALID_HANDLE_VALUE; } } inline bool directory::open(std::string const &name) { std::wstring search = booster::locale::conv::utf_to_utf(name.c_str()) +L"/*"; dir_ = FindFirstFileW(search.c_str(),&entry_); if(dir_ == INVALID_HANDLE_VALUE) { if(GetLastError() == ERROR_FILE_NOT_FOUND) return true; else return false; } return true; } inline bool directory::next() { if(dir_ == INVALID_HANDLE_VALUE) return false; utf_name_ = booster::locale::conv::utf_to_utf(entry_.cFileName); if(!FindNextFileW(dir_,&entry_)) { close(); } return true; } inline char const *directory::name() { return utf_name_.c_str(); } #else // POSIX inline directory::directory() : dir_(0), entry_p_(0) { #ifdef CPPCMS_DIR_ALLOCATE_DE de_ = 0; #endif } inline bool directory::open(std::string const &dir_name) { close(); dir_ = opendir(dir_name.c_str()); if(!dir_) return false; #ifdef CPPCMS_DIR_ALLOCATE_DE // // This pathconf/opendir exploit can be used with only file systems // with small file names like fat... So we require // at least 4K so it would be impossible to exploit // this // int name_len = pathconf(dir_name.c_str(),_PC_NAME_MAX); if(name_len < 4096) // -1 or small value name_len = 4096; // guess #ifdef NAME_MAX if(name_len < NAME_MAX) name_len = NAME_MAX; #endif de_ = static_cast(malloc(sizeof(struct dirent) + name_len + 1 - sizeof(de_->d_name))); if(!de_) throw std::bad_alloc(); #endif // alloc de return true; } inline void directory::close() { #ifdef CPPCMS_DIR_ALLOCATE_DE if(de_) { free(de_); de_ = 0; } #endif entry_p_ = 0; if(dir_) { closedir(dir_); dir_=0; } } inline bool directory::next() { assert(dir_); #ifdef CPPCMS_DIR_ALLOCATE_DE struct dirent *d = de_; #else struct dirent *d = &de_; #endif return readdir_r(dir_,d,&entry_p_) == 0 && entry_p_ != 0; } inline char const *directory::name() { assert(entry_p_); return entry_p_->d_name; } #endif // POSIX } // impl } // cppcms #endif