2012-05-10 12:06:41 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* Icinga 2 *
|
2013-09-25 07:43:57 +02:00
|
|
|
* Copyright (C) 2012-2013 Icinga Development Team (http://www.icinga.org/) *
|
2012-05-10 12:06:41 +02:00
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU General Public License *
|
|
|
|
* as published by the Free Software Foundation; either version 2 *
|
|
|
|
* of the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software Foundation *
|
2012-05-11 13:33:57 +02:00
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
2012-05-10 12:06:41 +02:00
|
|
|
******************************************************************************/
|
|
|
|
|
2013-03-16 21:18:53 +01:00
|
|
|
#include "base/utility.h"
|
2013-05-03 11:26:18 +02:00
|
|
|
#include "base/convert.h"
|
2013-03-16 21:18:53 +01:00
|
|
|
#include "base/application.h"
|
|
|
|
#include "base/logger_fwd.h"
|
|
|
|
#include "base/exception.h"
|
2012-05-09 10:15:51 +02:00
|
|
|
#include <mmatch.h>
|
2013-03-15 18:21:29 +01:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/function.hpp>
|
2013-03-16 21:18:53 +01:00
|
|
|
#include <boost/foreach.hpp>
|
2013-09-27 15:30:17 +02:00
|
|
|
#include <boost/algorithm/string/split.hpp>
|
|
|
|
#include <boost/algorithm/string/classification.hpp>
|
2013-03-16 21:18:53 +01:00
|
|
|
|
2013-10-21 09:52:45 +02:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
# include <pthread_np.h>
|
|
|
|
#endif /* __FreeBSD__ */
|
|
|
|
|
2013-11-03 13:45:26 +01:00
|
|
|
#ifndef _MSC_VER
|
2013-03-16 21:18:53 +01:00
|
|
|
# include <cxxabi.h>
|
2013-11-03 13:45:26 +01:00
|
|
|
#endif /* _MSC_VER */
|
2012-04-22 16:45:31 +02:00
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
2013-03-25 18:36:15 +01:00
|
|
|
boost::thread_specific_ptr<String> Utility::m_ThreadName;
|
|
|
|
|
2012-07-11 20:55:46 +02:00
|
|
|
/**
|
2012-09-27 09:38:28 +02:00
|
|
|
* Demangles a symbol name.
|
2012-07-11 20:55:46 +02:00
|
|
|
*
|
2012-09-27 09:38:28 +02:00
|
|
|
* @param sym The symbol name.
|
|
|
|
* @returns A human-readable version of the symbol name.
|
2012-07-11 20:55:46 +02:00
|
|
|
*/
|
2012-09-27 09:38:28 +02:00
|
|
|
String Utility::DemangleSymbolName(const String& sym)
|
2012-07-11 20:55:46 +02:00
|
|
|
{
|
2012-09-27 09:38:28 +02:00
|
|
|
String result = sym;
|
2012-07-11 20:55:46 +02:00
|
|
|
|
2013-11-03 13:45:26 +01:00
|
|
|
#ifndef _MSC_VER
|
2012-07-11 20:55:46 +02:00
|
|
|
int status;
|
2012-09-27 09:38:28 +02:00
|
|
|
char *realname = abi::__cxa_demangle(sym.CStr(), 0, 0, &status);
|
2012-07-11 20:55:46 +02:00
|
|
|
|
|
|
|
if (realname != NULL) {
|
2012-09-27 09:38:28 +02:00
|
|
|
result = String(realname);
|
2012-07-11 20:55:46 +02:00
|
|
|
free(realname);
|
|
|
|
}
|
2013-11-05 20:25:26 +01:00
|
|
|
#else /* _MSC_VER */
|
|
|
|
CHAR output[256];
|
|
|
|
|
|
|
|
if (UnDecorateSymbolName(sym.CStr(), output, sizeof(output), UNDNAME_COMPLETE) > 0)
|
|
|
|
result = output;
|
2013-11-03 13:45:26 +01:00
|
|
|
#endif /* _MSC_VER */
|
2012-07-11 20:55:46 +02:00
|
|
|
|
2012-09-27 09:38:28 +02:00
|
|
|
return result;
|
2012-07-11 20:55:46 +02:00
|
|
|
}
|
|
|
|
|
2012-09-27 09:38:28 +02:00
|
|
|
/**
|
|
|
|
* Returns a human-readable type name of a type_info object.
|
|
|
|
*
|
|
|
|
* @param ti A type_info object.
|
|
|
|
* @returns The type name of the object.
|
|
|
|
*/
|
2013-03-16 21:18:53 +01:00
|
|
|
String Utility::GetTypeName(const std::type_info& ti)
|
2012-09-27 09:38:28 +02:00
|
|
|
{
|
|
|
|
return DemangleSymbolName(ti.name());
|
|
|
|
}
|
2012-07-11 20:55:46 +02:00
|
|
|
|
2012-05-14 19:14:23 +02:00
|
|
|
/**
|
|
|
|
* Performs wildcard pattern matching.
|
|
|
|
*
|
|
|
|
* @param pattern The wildcard pattern.
|
2012-08-02 09:38:08 +02:00
|
|
|
* @param text The String that should be checked.
|
2012-05-14 19:14:23 +02:00
|
|
|
* @returns true if the wildcard pattern matches, false otherwise.
|
|
|
|
*/
|
2013-02-02 09:19:49 +01:00
|
|
|
bool Utility::Match(const String& pattern, const String& text)
|
2012-05-09 10:15:51 +02:00
|
|
|
{
|
2012-08-02 09:38:08 +02:00
|
|
|
return (match(pattern.CStr(), text.CStr()) == 0);
|
2012-05-09 10:15:51 +02:00
|
|
|
}
|
2012-07-08 21:18:35 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the directory component of a path. See dirname(3) for details.
|
|
|
|
*
|
|
|
|
* @param path The full path.
|
|
|
|
* @returns The directory.
|
|
|
|
*/
|
2012-08-02 09:38:08 +02:00
|
|
|
String Utility::DirName(const String& path)
|
2012-07-08 21:18:35 +02:00
|
|
|
{
|
2013-02-09 10:43:11 +01:00
|
|
|
char *dir;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
String dupPath = path;
|
|
|
|
|
|
|
|
/* PathRemoveFileSpec doesn't properly handle forward slashes. */
|
|
|
|
BOOST_FOREACH(char& ch, dupPath) {
|
|
|
|
if (ch == '/')
|
|
|
|
ch = '\\';
|
|
|
|
}
|
|
|
|
|
|
|
|
dir = strdup(dupPath.CStr());
|
|
|
|
#else /* _WIN32 */
|
|
|
|
dir = strdup(path.CStr());
|
|
|
|
#endif /* _WIN32 */
|
2012-07-08 21:18:35 +02:00
|
|
|
|
|
|
|
if (dir == NULL)
|
2013-03-16 21:18:53 +01:00
|
|
|
BOOST_THROW_EXCEPTION(std::bad_alloc());
|
2012-07-08 21:18:35 +02:00
|
|
|
|
2013-02-09 10:43:11 +01:00
|
|
|
String result;
|
|
|
|
|
2012-07-08 21:18:35 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
result = dirname(dir);
|
|
|
|
#else /* _WIN32 */
|
|
|
|
if (!PathRemoveFileSpec(dir)) {
|
|
|
|
free(dir);
|
2013-03-11 14:03:01 +01:00
|
|
|
|
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("PathRemoveFileSpec")
|
|
|
|
<< errinfo_win32_error(GetLastError()));
|
2012-07-08 21:18:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
result = dir;
|
2013-02-02 00:28:00 +01:00
|
|
|
|
|
|
|
if (result.IsEmpty())
|
|
|
|
result = ".";
|
2012-07-08 21:18:35 +02:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
free(dir);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the file component of a path. See basename(3) for details.
|
|
|
|
*
|
|
|
|
* @param path The full path.
|
|
|
|
* @returns The filename.
|
|
|
|
*/
|
2012-08-02 09:38:08 +02:00
|
|
|
String Utility::BaseName(const String& path)
|
2012-07-08 21:18:35 +02:00
|
|
|
{
|
2012-08-02 09:38:08 +02:00
|
|
|
char *dir = strdup(path.CStr());
|
|
|
|
String result;
|
2012-07-08 21:18:35 +02:00
|
|
|
|
|
|
|
if (dir == NULL)
|
2013-03-16 21:18:53 +01:00
|
|
|
BOOST_THROW_EXCEPTION(std::bad_alloc());
|
2012-07-08 21:18:35 +02:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
result = basename(dir);
|
|
|
|
#else /* _WIN32 */
|
|
|
|
result = PathFindFileName(dir);
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
free(dir);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2012-07-24 10:50:53 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Null deleter. Used as a parameter for the shared_ptr constructor.
|
|
|
|
*
|
2012-09-17 13:35:55 +02:00
|
|
|
* @param - The object that should be deleted.
|
2012-07-24 10:50:53 +02:00
|
|
|
*/
|
2012-08-07 21:02:12 +02:00
|
|
|
void Utility::NullDeleter(void *)
|
2012-07-24 10:50:53 +02:00
|
|
|
{
|
|
|
|
/* Nothing to do here. */
|
|
|
|
}
|
2012-07-25 12:59:17 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current UNIX timestamp including fractions of seconds.
|
|
|
|
*
|
|
|
|
* @returns The current time.
|
|
|
|
*/
|
|
|
|
double Utility::GetTime(void)
|
|
|
|
{
|
2012-07-27 16:05:02 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
FILETIME cft;
|
|
|
|
GetSystemTimeAsFileTime(&cft);
|
|
|
|
|
|
|
|
ULARGE_INTEGER ucft;
|
|
|
|
ucft.HighPart = cft.dwHighDateTime;
|
|
|
|
ucft.LowPart = cft.dwLowDateTime;
|
|
|
|
|
|
|
|
SYSTEMTIME est = { 1970, 1, 4, 1, 0, 0, 0, 0};
|
|
|
|
FILETIME eft;
|
|
|
|
SystemTimeToFileTime(&est, &eft);
|
|
|
|
|
|
|
|
ULARGE_INTEGER ueft;
|
|
|
|
ueft.HighPart = eft.dwHighDateTime;
|
|
|
|
ueft.LowPart = eft.dwLowDateTime;
|
|
|
|
|
|
|
|
return ((ucft.QuadPart - ueft.QuadPart) / 10000) / 1000.0;
|
|
|
|
#else /* _WIN32 */
|
2012-07-25 12:59:17 +02:00
|
|
|
struct timeval tv;
|
|
|
|
|
2013-03-11 13:45:08 +01:00
|
|
|
if (gettimeofday(&tv, NULL) < 0) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("gettimeofday")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
2012-07-25 12:59:17 +02:00
|
|
|
|
|
|
|
return tv.tv_sec + tv.tv_usec / 1000000.0;
|
2012-07-27 16:05:02 +02:00
|
|
|
#endif /* _WIN32 */
|
2012-07-25 12:59:17 +02:00
|
|
|
}
|
2012-09-19 13:00:48 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the ID of the current process.
|
|
|
|
*
|
|
|
|
* @returns The PID.
|
|
|
|
*/
|
|
|
|
pid_t Utility::GetPid(void)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
return getpid();
|
|
|
|
#else /* _WIN32 */
|
|
|
|
return GetCurrentProcessId();
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
2012-09-25 15:41:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sleeps for the specified amount of time.
|
|
|
|
*
|
|
|
|
* @param timeout The timeout in seconds.
|
|
|
|
*/
|
|
|
|
void Utility::Sleep(double timeout)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
usleep(timeout * 1000 * 1000);
|
|
|
|
#else /* _WIN32 */
|
2012-09-27 10:05:54 +02:00
|
|
|
::Sleep(timeout * 1000);
|
2012-09-25 15:41:43 +02:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
|
|
|
|
2013-01-17 15:05:34 +01:00
|
|
|
/**
|
2013-03-12 13:45:54 +01:00
|
|
|
* Loads the specified library.
|
2013-01-17 15:05:34 +01:00
|
|
|
*
|
|
|
|
* @param library The name of the library.
|
|
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
|
|
HMODULE
|
|
|
|
#else /* _WIN32 */
|
2013-10-30 11:58:45 +01:00
|
|
|
void *
|
2013-01-17 15:05:34 +01:00
|
|
|
#endif /* _WIN32 */
|
2013-03-12 13:45:54 +01:00
|
|
|
Utility::LoadExtensionLibrary(const String& library)
|
2013-01-17 15:05:34 +01:00
|
|
|
{
|
|
|
|
String path;
|
2013-11-04 07:49:51 +01:00
|
|
|
#if defined(_WIN32)
|
2013-11-03 13:45:26 +01:00
|
|
|
path = library + ".dll";
|
2013-11-04 07:49:51 +01:00
|
|
|
#elif defined(__APPLE__)
|
|
|
|
path = "lib" + library + ".dylib";
|
|
|
|
#else /* __APPLE__ */
|
2013-11-03 13:45:26 +01:00
|
|
|
path = "lib" + library + ".so";
|
2013-01-17 15:05:34 +01:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
2013-03-16 21:18:53 +01:00
|
|
|
Log(LogInformation, "base", "Loading library '" + path + "'");
|
2013-01-17 15:05:34 +01:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
HMODULE hModule = LoadLibrary(path.CStr());
|
|
|
|
|
2013-03-11 14:03:01 +01:00
|
|
|
if (hModule == NULL) {
|
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("LoadLibrary")
|
|
|
|
<< errinfo_win32_error(GetLastError())
|
|
|
|
<< boost::errinfo_file_name(path));
|
2013-03-11 14:03:01 +01:00
|
|
|
}
|
2013-01-17 15:05:34 +01:00
|
|
|
#else /* _WIN32 */
|
2013-10-30 11:58:45 +01:00
|
|
|
void *hModule = dlopen(path.CStr(), RTLD_NOW);
|
2013-01-17 15:05:34 +01:00
|
|
|
|
|
|
|
if (hModule == NULL) {
|
2013-10-30 11:58:45 +01:00
|
|
|
BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror()));
|
2013-01-17 15:05:34 +01:00
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
return hModule;
|
|
|
|
}
|
2013-01-30 09:08:48 +01:00
|
|
|
|
|
|
|
/**
|
2013-05-03 11:26:18 +02:00
|
|
|
* Generates a new unique ID.
|
2013-01-30 09:08:48 +01:00
|
|
|
*
|
2013-05-03 11:26:18 +02:00
|
|
|
* @returns The new unique ID.
|
2013-01-30 09:08:48 +01:00
|
|
|
*/
|
2013-05-03 11:26:18 +02:00
|
|
|
String Utility::NewUniqueID(void)
|
2013-01-30 09:08:48 +01:00
|
|
|
{
|
2013-05-03 11:26:18 +02:00
|
|
|
static boost::mutex mutex;
|
|
|
|
static int next_id = 0;
|
|
|
|
|
|
|
|
/* I'd much rather use UUIDs but RHEL is way too cool to have
|
|
|
|
* a semi-recent version of boost. Yay. */
|
|
|
|
|
|
|
|
String id;
|
|
|
|
|
|
|
|
char buf[128];
|
|
|
|
if (gethostname(buf, sizeof(buf)) == 0)
|
|
|
|
id = String(buf) + "-";
|
|
|
|
|
|
|
|
id += Convert::ToString((long)Utility::GetTime()) + "-";
|
|
|
|
|
|
|
|
{
|
|
|
|
boost::mutex::scoped_lock lock(mutex);
|
|
|
|
id += Convert::ToString(next_id);
|
|
|
|
next_id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
2013-01-30 09:08:48 +01:00
|
|
|
}
|
|
|
|
|
2013-02-02 00:28:00 +01:00
|
|
|
/**
|
|
|
|
* Calls the specified callback for each file matching the path specification.
|
|
|
|
*
|
|
|
|
* @param pathSpec The path specification.
|
2013-11-22 09:03:52 +01:00
|
|
|
* @param callback The callback which is invoked for each matching file.
|
|
|
|
* @param type The file type (a combination of GlobFile and GlobDirectory)
|
2013-02-02 00:28:00 +01:00
|
|
|
*/
|
2013-11-22 09:03:52 +01:00
|
|
|
bool Utility::Glob(const String& pathSpec, const boost::function<void (const String&)>& callback, int type)
|
2013-02-02 00:28:00 +01:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
HANDLE handle;
|
|
|
|
WIN32_FIND_DATA wfd;
|
|
|
|
|
|
|
|
handle = FindFirstFile(pathSpec.CStr(), &wfd);
|
|
|
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
|
|
|
|
|
|
if (errorCode == ERROR_FILE_NOT_FOUND)
|
|
|
|
return false;
|
|
|
|
|
2013-03-11 14:03:01 +01:00
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("FindFirstFile")
|
2013-03-18 22:40:40 +01:00
|
|
|
<< errinfo_win32_error(errorCode)
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_file_name(pathSpec));
|
2013-02-02 00:28:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2013-11-22 09:03:52 +01:00
|
|
|
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(type & GlobDirectory))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(type & GlobFile))
|
|
|
|
continue;
|
|
|
|
|
2013-02-09 10:43:11 +01:00
|
|
|
callback(DirName(pathSpec) + "/" + wfd.cFileName);
|
2013-02-02 00:28:00 +01:00
|
|
|
} while (FindNextFile(handle, &wfd));
|
|
|
|
|
2013-03-11 14:03:01 +01:00
|
|
|
if (!FindClose(handle)) {
|
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("FindClose")
|
2013-03-11 14:03:01 +01:00
|
|
|
<< errinfo_win32_error(GetLastError()));
|
|
|
|
}
|
2013-02-02 00:28:00 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
#else /* _WIN32 */
|
|
|
|
glob_t gr;
|
|
|
|
|
|
|
|
int rc = glob(pathSpec.CStr(), GLOB_ERR | GLOB_NOSORT, NULL, &gr);
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
if (rc == GLOB_NOMATCH)
|
|
|
|
return false;
|
|
|
|
|
2013-03-11 13:45:08 +01:00
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("glob")
|
|
|
|
<< boost::errinfo_errno(errno)
|
|
|
|
<< boost::errinfo_file_name(pathSpec));
|
2013-02-02 00:28:00 +01:00
|
|
|
}
|
|
|
|
|
2013-02-03 01:30:19 +01:00
|
|
|
if (gr.gl_pathc == 0) {
|
|
|
|
globfree(&gr);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-02 00:28:00 +01:00
|
|
|
size_t left;
|
|
|
|
char **gp;
|
|
|
|
for (gp = gr.gl_pathv, left = gr.gl_pathc; left > 0; gp++, left--) {
|
2013-11-22 09:03:52 +01:00
|
|
|
struct stat statbuf;
|
|
|
|
|
2013-11-22 10:41:57 +01:00
|
|
|
if (stat(*gp, &statbuf) < 0)
|
2013-11-29 10:39:48 +01:00
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("stat")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-11-22 09:03:52 +01:00
|
|
|
|
|
|
|
if (!S_ISDIR(statbuf.st_mode) && !S_ISREG(statbuf.st_mode))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (S_ISDIR(statbuf.st_mode) && !(type & GlobDirectory))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!S_ISDIR(statbuf.st_mode) && !(type & GlobFile))
|
|
|
|
continue;
|
|
|
|
|
2013-02-02 00:28:00 +01:00
|
|
|
callback(*gp);
|
|
|
|
}
|
|
|
|
|
|
|
|
globfree(&gr);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
2013-02-06 10:53:28 +01:00
|
|
|
|
2013-11-29 10:39:48 +01:00
|
|
|
/**
|
|
|
|
* Calls the specified callback for each file in the specified directory
|
|
|
|
* or any of its child directories if the file name matches the specified
|
|
|
|
* pattern.
|
|
|
|
*
|
|
|
|
* @param path The path.
|
|
|
|
* @param pattern The pattern.
|
|
|
|
* @param callback The callback which is invoked for each matching file.
|
|
|
|
* @param type The file type (a combination of GlobFile and GlobDirectory)
|
|
|
|
*/
|
2013-12-02 11:11:40 +01:00
|
|
|
bool Utility::GlobRecursive(const String& path, const String& pattern, const boost::function<void (const String&)>& callback, int type)
|
2013-11-29 10:39:48 +01:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
HANDLE handle;
|
|
|
|
WIN32_FIND_DATA wfd;
|
|
|
|
|
|
|
|
String pathSpec = path + "/*";
|
|
|
|
|
|
|
|
handle = FindFirstFile(pathSpec.CStr(), &wfd);
|
|
|
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
|
|
DWORD errorCode = GetLastError();
|
|
|
|
|
|
|
|
if (errorCode == ERROR_FILE_NOT_FOUND)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
|
|
|
<< boost::errinfo_api_function("FindFirstFile")
|
|
|
|
<< errinfo_win32_error(errorCode)
|
|
|
|
<< boost::errinfo_file_name(pathSpec));
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
String cpath = path + "/" + wfd.cFileName;
|
|
|
|
|
|
|
|
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
GlobRecursive(cpath, pattern, callback, type);
|
|
|
|
|
|
|
|
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(type & GlobDirectory))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(type & GlobFile))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!Utility::Match(pattern, wfd.cFileName))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
callback(cpath);
|
|
|
|
} while (FindNextFile(handle, &wfd));
|
|
|
|
|
|
|
|
if (!FindClose(handle)) {
|
|
|
|
BOOST_THROW_EXCEPTION(win32_error()
|
|
|
|
<< boost::errinfo_api_function("FindClose")
|
|
|
|
<< errinfo_win32_error(GetLastError()));
|
|
|
|
}
|
|
|
|
#else /* _WIN32 */
|
|
|
|
DIR *dirp;
|
|
|
|
|
|
|
|
dirp = opendir(path.CStr());
|
|
|
|
|
|
|
|
if (dirp == NULL)
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("opendir")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
|
|
|
|
while (dirp) {
|
|
|
|
dirent ent, *pent;
|
|
|
|
|
|
|
|
if (readdir_r(dirp, &ent, &pent) < 0)
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("readdir_r")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
|
|
|
|
if (!pent)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
String cpath = path + "/" + ent.d_name;
|
|
|
|
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
if (lstat(cpath.CStr(), &statbuf) < 0)
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("lstat")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
|
|
|
|
if (S_ISDIR(statbuf.st_mode))
|
|
|
|
GlobRecursive(cpath, pattern, callback, type);
|
|
|
|
|
|
|
|
if (stat(cpath.CStr(), &statbuf) < 0)
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("stat")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
|
|
|
|
if (!S_ISDIR(statbuf.st_mode) && !S_ISREG(statbuf.st_mode))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (S_ISDIR(statbuf.st_mode) && !(type & GlobDirectory))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!S_ISDIR(statbuf.st_mode) && !(type & GlobFile))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!Utility::Match(pattern, ent.d_name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
callback(cpath);
|
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
2013-12-02 11:11:40 +01:00
|
|
|
|
|
|
|
return true;
|
2013-11-29 10:39:48 +01:00
|
|
|
}
|
|
|
|
|
2013-02-14 10:59:01 +01:00
|
|
|
#ifndef _WIN32
|
2013-02-13 13:03:21 +01:00
|
|
|
void Utility::SetNonBlocking(int fd)
|
|
|
|
{
|
2013-03-11 13:45:08 +01:00
|
|
|
int flags = fcntl(fd, F_GETFL, 0);
|
2013-02-13 13:03:21 +01:00
|
|
|
|
2013-03-11 13:45:08 +01:00
|
|
|
if (flags < 0) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("fcntl")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("fcntl")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
2013-02-13 13:03:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Utility::SetCloExec(int fd)
|
|
|
|
{
|
2013-03-11 13:45:08 +01:00
|
|
|
int flags = fcntl(fd, F_GETFD, 0);
|
2013-02-13 13:03:21 +01:00
|
|
|
|
2013-03-11 13:45:08 +01:00
|
|
|
if (flags < 0) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("fcntl")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("fcntl")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
2013-02-13 13:03:21 +01:00
|
|
|
}
|
2013-02-14 10:59:01 +01:00
|
|
|
#endif /* _WIN32 */
|
2013-02-13 13:03:21 +01:00
|
|
|
|
|
|
|
void Utility::SetNonBlockingSocket(SOCKET s)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
SetNonBlocking(s);
|
|
|
|
#else /* _WIN32 */
|
|
|
|
unsigned long lTrue = 1;
|
|
|
|
ioctlsocket(s, FIONBIO, &lTrue);
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
2013-02-18 14:40:24 +01:00
|
|
|
|
|
|
|
void Utility::QueueAsyncCallback(const boost::function<void (void)>& callback)
|
|
|
|
{
|
2013-03-25 18:36:15 +01:00
|
|
|
Application::GetTP().Post(callback);
|
2013-02-18 14:40:24 +01:00
|
|
|
}
|
2013-02-28 10:27:33 +01:00
|
|
|
|
|
|
|
String Utility::FormatDateTime(const char *format, double ts)
|
|
|
|
{
|
|
|
|
char timestamp[128];
|
2013-09-02 10:53:01 +02:00
|
|
|
time_t tempts = (time_t)ts; /* We don't handle sub-second timestamps here just yet. */
|
2013-02-28 10:27:33 +01:00
|
|
|
tm tmthen;
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
tm *temp = localtime(&tempts);
|
|
|
|
|
2013-03-11 13:45:08 +01:00
|
|
|
if (temp == NULL) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("localtime")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
2013-02-28 10:27:33 +01:00
|
|
|
|
|
|
|
tmthen = *temp;
|
|
|
|
#else /* _MSC_VER */
|
2013-03-11 13:45:08 +01:00
|
|
|
if (localtime_r(&tempts, &tmthen) == NULL) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
2013-03-18 17:04:22 +01:00
|
|
|
<< boost::errinfo_api_function("localtime_r")
|
|
|
|
<< boost::errinfo_errno(errno));
|
2013-03-11 13:45:08 +01:00
|
|
|
}
|
2013-02-28 10:27:33 +01:00
|
|
|
#endif /* _MSC_VER */
|
|
|
|
|
|
|
|
strftime(timestamp, sizeof(timestamp), format, &tmthen);
|
|
|
|
|
|
|
|
return timestamp;
|
|
|
|
}
|
2013-03-22 10:58:47 +01:00
|
|
|
|
|
|
|
String Utility::EscapeShellCmd(const String& s)
|
|
|
|
{
|
|
|
|
String result;
|
2013-08-20 11:06:04 +02:00
|
|
|
size_t prev_quote = String::NPos;
|
2013-03-22 16:05:48 +01:00
|
|
|
int index = -1;
|
2013-03-22 10:58:47 +01:00
|
|
|
|
|
|
|
BOOST_FOREACH(char ch, s) {
|
|
|
|
bool escape = false;
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (ch == '%' || ch == '"' || ch == '\'')
|
|
|
|
escape = true;
|
|
|
|
#else /* _WIN32 */
|
|
|
|
if (ch == '"' || ch == '\'') {
|
|
|
|
/* Find a matching closing quotation character. */
|
|
|
|
if (prev_quote == String::NPos && (prev_quote = s.FindFirstOf(ch, index + 1)) != String::NPos)
|
|
|
|
; /* Empty statement. */
|
|
|
|
else if (prev_quote != String::NPos && s[prev_quote] == ch)
|
|
|
|
prev_quote = String::NPos;
|
|
|
|
else
|
|
|
|
escape = true;
|
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
if (ch == '#' || ch == '&' || ch == ';' || ch == '`' || ch == '|' ||
|
|
|
|
ch == '*' || ch == '?' || ch == '~' || ch == '<' || ch == '>' ||
|
|
|
|
ch == '^' || ch == '(' || ch == ')' || ch == '[' || ch == ']' ||
|
|
|
|
ch == '{' || ch == '}' || ch == '$' || ch == '\\' || ch == '\x0A' ||
|
|
|
|
ch == '\xFF')
|
|
|
|
escape = true;
|
|
|
|
|
|
|
|
if (escape)
|
|
|
|
#ifdef _WIN32
|
2013-11-13 09:08:17 +01:00
|
|
|
result += '^';
|
2013-03-22 10:58:47 +01:00
|
|
|
#else /* _WIN32 */
|
|
|
|
result += '\\';
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
result += ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2013-03-25 18:36:15 +01:00
|
|
|
|
2013-08-30 10:19:32 +02:00
|
|
|
#ifdef _WIN32
|
2013-09-01 06:01:27 +02:00
|
|
|
static void WindowsSetThreadName(const char *name)
|
|
|
|
{
|
2013-08-30 10:19:32 +02:00
|
|
|
THREADNAME_INFO info;
|
|
|
|
info.dwType = 0x1000;
|
2013-09-01 06:01:27 +02:00
|
|
|
info.szName = name;
|
2013-08-30 10:19:32 +02:00
|
|
|
info.dwThreadID = -1;
|
|
|
|
info.dwFlags = 0;
|
|
|
|
|
|
|
|
__try {
|
|
|
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
/* Nothing to do here. */
|
|
|
|
}
|
2013-09-01 06:01:27 +02:00
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
2013-09-03 15:44:31 +02:00
|
|
|
void Utility::SetThreadName(const String& name, bool os)
|
2013-09-01 06:01:27 +02:00
|
|
|
{
|
|
|
|
m_ThreadName.reset(new String(name));
|
|
|
|
|
2013-09-03 15:44:31 +02:00
|
|
|
if (!os)
|
|
|
|
return;
|
|
|
|
|
2013-09-01 06:01:27 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
WindowsSetThreadName(name.CStr());
|
2013-08-30 10:19:32 +02:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
2013-09-08 13:13:37 +02:00
|
|
|
#ifdef HAVE_PTHREAD_SET_NAME_NP
|
|
|
|
pthread_set_name_np(pthread_self(), name.CStr());
|
|
|
|
#endif /* HAVE_PTHREAD_SET_NAME_NP */
|
2013-08-30 10:19:32 +02:00
|
|
|
|
2013-09-08 13:13:37 +02:00
|
|
|
#ifdef HAVE_PTHREAD_SETNAME_NP
|
|
|
|
# ifdef __APPLE__
|
|
|
|
pthread_setname_np(name.CStr());
|
|
|
|
# else /* __APPLE__ */
|
2013-08-30 10:19:32 +02:00
|
|
|
String tname = name.SubStr(0, 15);
|
|
|
|
pthread_setname_np(pthread_self(), tname.CStr());
|
2013-09-08 13:13:37 +02:00
|
|
|
# endif /* __APPLE__ */
|
|
|
|
#endif /* HAVE_PTHREAD_SETNAME_NP */
|
2013-03-25 18:36:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
String Utility::GetThreadName(void)
|
|
|
|
{
|
|
|
|
String *name = m_ThreadName.get();
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
std::ostringstream idbuf;
|
|
|
|
idbuf << boost::this_thread::get_id();
|
|
|
|
return idbuf.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
return *name;
|
|
|
|
}
|
2013-09-12 10:03:48 +02:00
|
|
|
|
|
|
|
unsigned long Utility::SDBM(const String& str)
|
|
|
|
{
|
|
|
|
unsigned long hash = 0;
|
|
|
|
|
|
|
|
BOOST_FOREACH(char c, str) {
|
|
|
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
2013-09-27 15:30:17 +02:00
|
|
|
|
|
|
|
int Utility::CompareVersion(const String& v1, const String& v2)
|
|
|
|
{
|
|
|
|
std::vector<String> tokensv1, tokensv2;
|
|
|
|
boost::algorithm::split(tokensv1, v1, boost::is_any_of("."));
|
|
|
|
boost::algorithm::split(tokensv2, v2, boost::is_any_of("."));
|
|
|
|
|
|
|
|
for (int i = 0; i < tokensv2.size() - tokensv1.size(); i++)
|
|
|
|
tokensv1.push_back("0");
|
|
|
|
|
|
|
|
for (int i = 0; i < tokensv1.size() - tokensv2.size(); i++)
|
|
|
|
tokensv2.push_back("0");
|
|
|
|
|
|
|
|
for (size_t i = 0; i < tokensv1.size(); i++) {
|
|
|
|
if (Convert::ToLong(tokensv2[i]) > Convert::ToLong(tokensv1[i]))
|
|
|
|
return 1;
|
|
|
|
else if (Convert::ToLong(tokensv2[i]) < Convert::ToLong(tokensv1[i]))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2013-10-03 22:10:46 +02:00
|
|
|
|
|
|
|
int Utility::Random(void)
|
|
|
|
{
|
|
|
|
static boost::mutex mtx;
|
|
|
|
boost::mutex::scoped_lock lock(mtx);
|
|
|
|
|
|
|
|
return rand();
|
|
|
|
}
|
2013-11-13 14:56:31 +01:00
|
|
|
|
|
|
|
tm Utility::LocalTime(time_t ts)
|
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
tm *result = localtime(&ts);
|
|
|
|
|
|
|
|
if (temp == NULL) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("localtime")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
return *result;
|
|
|
|
#else /* _MSC_VER */
|
|
|
|
tm result;
|
|
|
|
|
|
|
|
if (localtime_r(&ts, &result) == NULL) {
|
|
|
|
BOOST_THROW_EXCEPTION(posix_error()
|
|
|
|
<< boost::errinfo_api_function("localtime_r")
|
|
|
|
<< boost::errinfo_errno(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
#endif /* _MSC_VER */
|
|
|
|
}
|