/*- * Copyright 2006-2007 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #include //--------------------------------------------------------------------------- namespace ksys { //--------------------------------------------------------------------------- bool stackBackTrace = true; //--------------------------------------------------------------------------- utf8::String getBackTrace(/*intptr_t flags,*/intptr_t skipCount,Thread * thread) { #if __GNUG__ thread = thread; utf8::String s; AutoPtr strings(backtrace()); strings.ptr(backtrace_symbols(strings)); for( char ** p = strings; p != NULL && *p != NULL; p++ ){ if( --skipCount < 0 ){ s += *p; s += "\n"; } } return s; #elif !defined(NDEBUG) && (defined(__WIN32__) || defined(__WIN64__)) InterlockedMutex mutex; if( currentFiber() != NULL ){ if( thread == NULL ){ thread = currentThread(); currentFiber()->event_.mutex0_ = &mutex; mutex.acquire(); } else { currentFiber()->event_.mutex0_ = NULL; } currentFiber()->event_.timeout_ = ~uint64_t(0); currentFiber()->event_.data1_ = skipCount; currentFiber()->event_.thread_ = thread; currentFiber()->event_.type_ = etStackBackTrace; currentFiber()->thread()->postRequest(); if( thread != currentThread() ){ currentFiber()->switchFiber(currentFiber()->mainFiber()); } else { mutex.acquire(); mutex.release(); } assert( currentFiber()->event_.type_ == etStackBackTrace ); assert( currentFiber()->event_.errno_ == 0 ); return currentFiber()->event_.string0_; } AsyncEvent event; event.mutex0_ = &mutex; event.data1_ = skipCount; event.tid_ = (uintptr_t) GetCurrentThreadId(); event.type_ = etStackBackTraceZero; event.timeout_ = ~uint64_t(0); mutex.acquire(); Requester::requester().postRequest(&event); mutex.acquire(); mutex.release(); assert( event.type_ == etStackBackTraceZero ); assert( event.errno_ == 0 ); return event.string0_; #else return utf8::String(); #endif } //--------------------------------------------------------------------------- Mutant getProcessPriority() { Mutant m; #if defined(__WIN32__) || defined(__WIN64__) switch( GetPriorityClass(GetCurrentProcess()) ){ case IDLE_PRIORITY_CLASS : m = "IDLE_PRIORITY_CLASS"; break; case BELOW_NORMAL_PRIORITY_CLASS : m = "BELOW_NORMAL_PRIORITY_CLASS"; break; case NORMAL_PRIORITY_CLASS : m = "NORMAL_PRIORITY_CLASS"; break; case ABOVE_NORMAL_PRIORITY_CLASS : m = "ABOVE_NORMAL_PRIORITY_CLASS"; break; case HIGH_PRIORITY_CLASS : m = "HIGH_PRIORITY_CLASS"; break; case REALTIME_PRIORITY_CLASS : m = "REALTIME_PRIORITY_CLASS"; break; default : m = GetPriorityClass(GetCurrentProcess()); } #elif HAVE_GETPRIORITY || HAVE_RTPRIO int32_t err; switch( getpriority(PRIO_PROCESS,0) ){ case -1 : err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); break; case IDLE_PRIORITY_CLASS : m = "IDLE_PRIORITY_CLASS"; break; case BELOW_NORMAL_PRIORITY_CLASS : m = "BELOW_NORMAL_PRIORITY_CLASS"; break; case NORMAL_PRIORITY_CLASS : m = "NORMAL_PRIORITY_CLASS"; break; case ABOVE_NORMAL_PRIORITY_CLASS : m = "ABOVE_NORMAL_PRIORITY_CLASS"; break; case HIGH_PRIORITY_CLASS : m = "HIGH_PRIORITY_CLASS"; break; case REALTIME_PRIORITY_CLASS : m = "REALTIME_PRIORITY_CLASS"; break; default : m = getpriority(PRIO_PROCESS,0); } #endif return m; } //--------------------------------------------------------------------------- void setProcessPriority(const Mutant & m,bool noThrow) { #if defined(__WIN32__) || defined(__WIN64__) int32_t err = 0; BOOL r; try { r = SetPriorityClass(GetCurrentProcess(),m); if( r == 0 ) err = GetLastError(); } catch( ExceptionSP & ){ r = 0; } if( r == 0 && err == 0 ){ utf8::String s(m); if( s.strcasecmp("IDLE_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS); else if( s.strcasecmp("BELOW_NORMAL_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("NORMAL_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("ABOVE_NORMAL_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("HIGH_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); else if( s.strcasecmp("REALTIME_PRIORITY_CLASS") == 0 ) r = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); err = GetLastError(); } if( r == 0 && err != 0 ){ AutoPtr e(newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)); if( noThrow ) e->writeStdError(); else e.ptr(NULL)->throwSP(); } #elif HAVE_SETPRIORITY || HAVE_RTPRIO int32_t err = 0; int r; try { r = setpriority(PRIO_PROCESS,0,m); if( r != 0 ) err = errno; } catch( ExceptionSP & ){ r = -1; } if( r != 0 && err == 0 ){ utf8::String s(m); if( s.strcasecmp("IDLE_PRIORITY_CLASS") == 0 ){ #if HAVE_RTPRIO struct rtprio rtp; rtp.type = RTP_PRIO_IDLE; rtp.prio = 0; r = rtprio(RTP_SET,0,&rtp); #elif HAVE_SETPRIORITY r = setpriority(PRIO_PROCESS,0,IDLE_PRIORITY_CLASS); #endif } else if( s.strcasecmp("BELOW_NORMAL_PRIORITY_CLASS") == 0 ) r = setpriority(PRIO_PROCESS,0,BELOW_NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("NORMAL_PRIORITY_CLASS") == 0 ) r = setpriority(PRIO_PROCESS,0,NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("ABOVE_NORMAL_PRIORITY_CLASS") == 0 ) r = setpriority(PRIO_PROCESS,0,ABOVE_NORMAL_PRIORITY_CLASS); else if( s.strcasecmp("HIGH_PRIORITY_CLASS") == 0 ) r = setpriority(PRIO_PROCESS,0,HIGH_PRIORITY_CLASS); else if( s.strcasecmp("REALTIME_PRIORITY_CLASS") == 0 ){ #if HAVE_RTPRIO struct rtprio rtp; rtp.type = RTP_PRIO_REALTIME; rtp.prio = RTP_PRIO_MAX; r = rtprio(RTP_SET,0,&rtp); #elif HAVE_SETPRIORITY r = setpriority(PRIO_PROCESS,0,REALTIME_PRIORITY_CLASS); #endif } err = errno; } if( r != 0 && err != 0 ){ AutoPtr e(newObjectV1C2(err,__PRETTY_FUNCTION__)); if( noThrow ) e->writeStdError(); else e.ptr(NULL)->throwSP(); } #else if( !noThrow ) newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- utf8::String getEnv(const utf8::String & name,const utf8::String & defValue) { #if defined(__WIN32__) || defined(__WIN64__) DWORD sz; if( isWin9x() ){ AutoPtr b; utf8::AnsiString s(name.getANSIString()); sz = GetEnvironmentVariableA(s,b,0); if( sz != 0 ){ b.alloc(sz); sz = GetEnvironmentVariableA(s,b,sz) + 1; } if( sz == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND ){ int32_t err = GetLastError() + errorOffset; if( defValue.isNull() ) newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); return defValue; } if( sz <= 1 ) return utf8::String(); return b.ptr(); } AutoPtr b; utf8::WideString s(name.getUNICODEString()); sz = GetEnvironmentVariableW(s,b,0); if( sz != 0 ){ b.alloc(sz * sizeof(wchar_t)); sz = GetEnvironmentVariableW(s,b,sz) + 1; } if( sz == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND ){ int32_t err = GetLastError() + errorOffset; if( defValue.isNull() ) newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); return defValue; } if( sz <= 1 ) return utf8::String(); return b.ptr(); #else char * env = getenv(name.getANSIString()); if( env == NULL && errno != 0 ){ int32_t err = errno; if( defValue.isNull() ) newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); return defValue; } return env == NULL ? utf8::String() : env; #endif } //--------------------------------------------------------------------------- void setEnv(const utf8::String & name,const utf8::String & value,bool overwrite) { #if defined(__WIN32__) || defined(__WIN64__) BOOL r; if( isWin9x() ){ r = SetEnvironmentVariableA(name.getANSIString(),value.getANSIString()); } else { r = SetEnvironmentVariableW(name.getUNICODEString(),value.getUNICODEString()); } if( r == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #else if( setenv(name.getANSIString(),value.getANSIString(),overwrite) != 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #endif } //--------------------------------------------------------------------------- void putEnv(const utf8::String & string) { #if defined(__WIN32__) || defined(__WIN64__) utf8::String::Iterator i(string), j(string.strstr("=")); setEnv(utf8::String(i,j),j + 1); #else if( putenv(string.getANSIString()) != 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #endif } //--------------------------------------------------------------------------- void unSetEnv(const utf8::String & name) { #if defined(__WIN32__) || defined(__WIN64__) BOOL r; if( isWin9x() ){ r = SetEnvironmentVariableA(name.getANSIString(),NULL); } else { r = SetEnvironmentVariableW(name.getUNICODEString(),NULL); } if( r == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #else unsetenv(name.getANSIString()); #endif } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- DirectoryChangeNotification::~DirectoryChangeNotification() { stop(); } //--------------------------------------------------------------------------- DirectoryChangeNotification::DirectoryChangeNotification() : #if defined(__WIN32__) || defined(__WIN64__) hFFCNotification_(INVALID_HANDLE_VALUE), hDirectory_(INVALID_HANDLE_VALUE), bufferSize_(0), #endif createPath_(true) { #if !defined(__WIN32__) && !defined(__WIN64__) newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- void DirectoryChangeNotification::monitor(const utf8::String & pathName,uint64_t timeout) { #if defined(__WIN32__) || defined(__WIN64__) assert( (hFFCNotification_ == INVALID_HANDLE_VALUE && hDirectory_ == INVALID_HANDLE_VALUE) || ((hFFCNotification_ != INVALID_HANDLE_VALUE) ^ (hDirectory_ != INVALID_HANDLE_VALUE)) ); if( isWin9x() ){ if( hFFCNotification_ == INVALID_HANDLE_VALUE ){ hFFCNotification_ = FindFirstChangeNotificationA( anyPathName2HostPathName(pathName).getOEMString(), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME ); if( hFFCNotification_ == INVALID_HANDLE_VALUE ){ int32_t err = GetLastError(); if( (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) && createPath_ ){ createDirectory(pathName); return monitor(pathName,timeout); } newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } } else if( FindNextChangeNotification(hFFCNotification_) == 0 ){ int32_t err = GetLastError() + errorOffset; stop(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } } else { if( buffer_ == NULL ){ bufferSize_ = getpagesize() / sizeof(FILE_NOTIFY_INFORMATION); bufferSize_ *= sizeof(FILE_NOTIFY_INFORMATION); buffer_.alloc(bufferSize_); } if( hDirectory_ == INVALID_HANDLE_VALUE ){ hDirectory_ = CreateFileW( anyPathName2HostPathName(pathName).getUNICODEString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL ); if( hDirectory_ == INVALID_HANDLE_VALUE ){ int32_t err = GetLastError(); if( (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) && createPath_ ){ createDirectory(pathName); return monitor(pathName,timeout); } newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } } } Fiber * fiber = currentFiber(); assert( fiber != NULL ); fiber->event_.abort_ = false; fiber->event_.position_ = 0; fiber->event_.directoryChangeNotification_ = this; fiber->event_.timeout_ = timeout; fiber->event_.type_ = etDirectoryChangeNotification; fiber->thread()->postRequest(); fiber->switchFiber(fiber->mainFiber()); assert( fiber->event_.type_ == etDirectoryChangeNotification ); if( fiber->event_.errno_ == ERROR_REQUEST_ABORTED ) stop(); if( fiber->event_.errno_ != 0 && fiber->event_.errno_ != ERROR_NOTIFY_ENUM_DIR ){ newObjectV1C2(fiber->event_.errno_ + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + pathName)->throwSP(); } #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- void DirectoryChangeNotification::stop() { #if defined(__WIN32__) || defined(__WIN64__) if( hFFCNotification_ != INVALID_HANDLE_VALUE ){ FindCloseChangeNotification(hFFCNotification_); hFFCNotification_ = INVALID_HANDLE_VALUE; } if( hDirectory_ != INVALID_HANDLE_VALUE ){ CloseHandle(hDirectory_); hDirectory_ = INVALID_HANDLE_VALUE; } buffer_.free(); bufferSize_ = 0; #endif } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- uint8_t argvPlaceHolder[sizeof(Array)]; #if defined(__WIN32__) || defined(__WIN64__) char pathDelimiter = '\\'; char pathDelimiterStr[2] = "\\"; #else char pathDelimiter = '/'; char pathDelimiterStr[2] = "/"; #endif //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) //--------------------------------------------------------------------------- DWORD mainThreadId; UINT threadFinishMessage; UINT fiberFinishMessage; //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- uintmax_t fibonacci(uintmax_t n) { if( n == 0 ) return 0; uintmax_t prev = 0, curr = 1, next; while( --n > 0 ){ next = curr + prev; prev = curr; curr = next; } return curr; } //--------------------------------------------------------------------------- void createGUID(guid_t & uuid) { #if defined(__WIN32__) || defined(__WIN64__) RPC_STATUS status = UuidCreate((UUID *) &uuid); if( status != RPC_S_OK ){ // if( FAILED(CoCreateGuid(&uuid)) ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #elif HAVE_UUIDGEN if( uuidgen(&uuid,1) != 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #elif HAVE_UUID_CREATE uuid_t * u; uint32_t status; uuid_create(&u,&status); if( status != uuid_s_ok ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } uuid = *u; free(u); #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- guid_t stringToGUID(const char * s) { guid_t uuid; memset(&uuid,0,sizeof(uuid)); #if defined(__WIN32__) || defined(__WIN64__) RPC_STATUS status = UuidFromString((RPC_CSTR) s,&uuid); if( status != RPC_S_OK ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #elif HAVE_UUID_FROM_STRING newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif return uuid; } //--------------------------------------------------------------------------- utf8::String createGUIDAsBase32String() { guid_t uuid; createGUID(uuid); return base32Encode(&uuid,sizeof(uuid)); } //--------------------------------------------------------------------------- utf8::String screenChar(const utf8::String::Iterator & ii) { char b[12]; const char * p; switch( ii.getChar() ){ case '\a' : p = "\\a"; break; case '\b' : p = "\\b"; break; case '\t' : p = "\\t"; break; case '\v' : p = "\\v"; break; case '\f' : p = "\\f"; break; case '\r' : p = "\\r"; break; case '\n' : p = "\\n"; break; case '\\' : p = "\\\\"; break; case ',' : p = "\\,"; break; case ';' : p = "\\;"; break; case '\"' : p = "\\\""; break; case '=' : p = "\\="; break; default : if( ii.isCntrl() || ii.isSpace() ) return "\\0x" + utf8::int2HexStr(ii.getChar(),SIZEOF_WCHAR_T * 2); memset(b,0,sizeof(b)); memcpy(b,ii.c_str(),ii.seqLen()); p = b; } return utf8::plane(p); } //--------------------------------------------------------------------------- /*utf8::String screenString(const utf8::String & s) { utf8::String a; utf8::String::Iterator i(s); while( !i.eof() ){ a += screenChar(i); i.next(); } return a; }*/ //--------------------------------------------------------------------------- static inline void screenChar(const char * seq,uintptr_t & seql,char * b,uintptr_t & l) { uintptr_t c; switch( c = utf8::utf82ucs(seq,seql) ){ case '\a' : if( b != NULL ) memcpy(b,"\\a",2); l = 2; break; case '\b' : if( b != NULL ) memcpy(b,"\\b",2); l = 2; break; case '\t' : if( b != NULL ) memcpy(b,"\\t",2); l = 2; break; case '\v' : if( b != NULL ) memcpy(b,"\\v",2); l = 2; break; case '\f' : if( b != NULL ) memcpy(b,"\\f",2); l = 2; break; case '\r' : if( b != NULL ) memcpy(b,"\\r",2); l = 2; break; case '\n' : if( b != NULL ) memcpy(b,"\\n",2); l = 2; break; case '\\' : if( b != NULL ) memcpy(b,"\\\\",2); l = 2; break; case ',' : if( b != NULL ) memcpy(b,"\\,",2); l = 2; break; case ';' : if( b != NULL ) memcpy(b,"\\;",2); l = 2; break; case '\"' : if( b != NULL ) memcpy(b,"\\\"",2); l = 2; break; case '=' : if( b != NULL ) memcpy(b,"\\=",2); l = 2; break; default : if( (utf8::getC1Type(c) & (C1_CNTRL | C1_SPACE)) != 0 ){ if( b != NULL ) memcpy(b,"\\0x",3); utf8::String s(utf8::int2HexStr(c,SIZEOF_WCHAR_T * 2)); l = s.size(); if( b != NULL ) memcpy(b + 3,s.c_str(),l); l += 3; } else { l = seql; if( b != NULL ) memcpy(b,seq,l); } } } //--------------------------------------------------------------------------- utf8::String screenString(const utf8::String & s) { const char * p; uintptr_t seql, l, len = 0; AutoPtr a; for( p = s.c_str(); *p != '\0'; p += seql, len += l ) screenChar(p,seql,NULL,l); if( len == 0 ) return utf8::String(); a.alloc(len + 1); char * q = a; for( p = s.c_str(); *p != '\0'; p += seql, q += l ) screenChar(p,seql,q,l); a[len] = '\0'; utf8::String::Container * container = newObjectV1V2(0,a.ptr()); a.ptr(NULL); return container; } //--------------------------------------------------------------------------- utf8::String unScreenChar(const utf8::String::Iterator & ii,uintptr_t & screenLen) { utf8::String s; screenLen = 1; switch( ii.getChar() ){ case '0' : if( ii[screenLen].getUpperChar() == 'X' ){ screenLen++; while( screenLen < SIZEOF_WCHAR_T * 2 + 2 && ii[screenLen].isXdigit() ) screenLen++; if( screenLen == SIZEOF_WCHAR_T * 2 + 2 ){ intmax_t a; if( utf8::tryStr2Int(utf8::String(ii + 2,ii + SIZEOF_WCHAR_T * 2 + 2),a,16) ){ char b[5]; b[utf8::ucs2utf8seq(b,(uintptr_t) a)] = '\0'; s = utf8::plane(b); break; } } } else { while( screenLen < SIZEOF_WCHAR_T * 2 + 3 && ii[screenLen].isDigit() ) screenLen++; if( screenLen == SIZEOF_WCHAR_T * 2 + 3 ){ intmax_t a; if( utf8::tryStr2Int(utf8::String(ii + 1,ii + SIZEOF_WCHAR_T * 2 + 3),a,10) ){ char b[5]; b[utf8::ucs2utf8seq(b,(uintptr_t) a)] = '\0'; s = utf8::plane(b); break; } } } screenLen = 1; goto l1; case 'a' : s = "\a"; break; case 'b' : s = "\b"; break; case 't' : s = "\t"; break; case 'v' : s = "\v"; break; case 'f' : s = "\f"; break; case 'r' : s = "\r"; break; case 'n' : s = "\n"; break; case '\\' : s = "\\"; break; default : l1: s = utf8::String(ii,ii + 1); } return s; } //--------------------------------------------------------------------------- static inline void unScreenChar(uintptr_t c,const char * seq,uintptr_t & seql,char * b,uintptr_t & l) { uintptr_t i; switch( c ){ case '0' : if( utf8::utf8c2UpperUCS(seq + seql) == 'X' ){ for( i = 0; i < SIZEOF_WCHAR_T * 2; i++ ){ if( (utf8::getC1Type(utf8::utf82ucs(seq + seql + i + 1)) & (C1_XDIGIT | C1_DIGIT)) == 0 ) break; } if( i == SIZEOF_WCHAR_T * 2 ){ intmax_t a; if( utf8::tryStr2Int(utf8::String(seq + seql + 1,SIZEOF_WCHAR_T * 2),a,16) ){ char buf[6]; buf[l = utf8::ucs2utf8seq(buf,(uintptr_t) a)] = '\0'; if( b != NULL ) memcpy(b,buf,l); seql = SIZEOF_WCHAR_T * 2 + 2; break; } } } goto l1; case 'a' : if( b != NULL ) *b = '\a'; l = 1; break; case 'b' : if( b != NULL ) *b = '\b'; l = 1; break; case 't' : if( b != NULL ) *b = '\t'; l = 1; break; case 'v' : if( b != NULL ) *b = '\v'; l = 1; break; case 'f' : if( b != NULL ) *b = '\f'; l = 1; break; case 'r' : if( b != NULL ) *b = '\r'; l = 1; break; case 'n' : if( b != NULL ) *b = '\n'; l = 1; break; case '\\' : if( b != NULL ) *b = '\\'; l = 1; break; default : l1: if( b != NULL ) memcpy(b,seq,seql); l = seql; } } //--------------------------------------------------------------------------- utf8::String unScreenString(const utf8::String & s) { const char * p; uintptr_t seql, l, len = 0, c; AutoPtr a; for( p = s.c_str(); *p != '\0'; p += seql, len += l ){ c = utf8::utf82ucs(p,seql); l = seql; if( c == '\\' && p[1] != '\0' ){ p += seql; c = utf8::utf82ucs(p,seql); unScreenChar(c,p,seql,NULL,l); } } if( len == 0 ) return utf8::String(); a.alloc(len + 1); char * q = a; for( p = s.c_str(); *p != '\0'; p += seql, q += l ){ c = utf8::utf82ucs(p,seql); l = seql; if( c == '\\' && p[1] != '\0' ){ p += seql; c = utf8::utf82ucs(p,seql); unScreenChar(c,p,seql,q,l); } else { memcpy(q,p,seql); } } a[len] = '\0'; utf8::String::Container * container = newObjectV1V2(0,a.ptr()); a.ptr(NULL); return container; } //--------------------------------------------------------------------------- static intptr_t stringPartByNoHelper(const utf8::String & s,uintptr_t n,const char * delim,utf8::String * pRetValue) { bool inQuotationMarks = false; uintptr_t l, k = 0, c, prev = 0; utf8::String v; utf8::String::Iterator i(s), q(s); if( !i.eos() ) for(;;){ c = i.getChar(); if( inQuotationMarks && c == '\"' && prev != '\\' ){ if( pRetValue != NULL ) v += unScreenString(utf8::String(q,i)); q = i + 1; inQuotationMarks = false; } else if( !inQuotationMarks && c == '\"' ){ q = i + 1; inQuotationMarks = true; } else if( !inQuotationMarks ){ bool eos; const char * d = delim; for(;;){ if( (eos = utf8::utf82ucs(d,l) == c) ){ if( pRetValue != NULL ) v += utf8::String(q,i).trim(); q = i + 1; break; } if( *d == '\0' ) break; d += l; } if( eos ){ if( k == n ) break; k++; v = utf8::String(); } } prev = c; if( i.eos() ) break; i.next(); } if( pRetValue != NULL ) *pRetValue = v; return k; } //--------------------------------------------------------------------------- uintptr_t enumStringParts(const utf8::String & s,const char * delim) { return stringPartByNoHelper(s,~uintptr_t(0),delim,NULL); } //--------------------------------------------------------------------------- utf8::String stringPartByNo(const utf8::String & s,uintptr_t n,const char * delim) { utf8::String v; stringPartByNoHelper(s,n,delim,&v); return v; } //--------------------------------------------------------------------------- intptr_t findStringPart(const utf8::String & s,const utf8::String & part,bool caseSensitive,const char * delim) { intptr_t i; for( i = enumStringParts(s) - 1; i >= 0; i-- ){ if( caseSensitive ){ if( stringPartByNo(s,i,delim).strcmp(part) == 0 ) break; } else { if( stringPartByNo(s,i,delim).strcasecmp(part) == 0 ) break; } } return i; } //--------------------------------------------------------------------------- utf8::String splitString(const utf8::String & s,utf8::String & s0,utf8::String & s1,const utf8::String & separator) { utf8::String::Iterator i(s.strcasestr(separator)); if( i.eos() ) s0 = s; else s0 = utf8::String(s,i); s1 = i + separator.strlen(); return s; } //--------------------------------------------------------------------------- utf8::String formatByteLength(uintmax_t len,uintmax_t all,const char * fmt) { if( len == 0 ) return "-"; uintmax_t q, b, c, t1, t2, t3; const char * suffix = ""; bool suffixes = false, percent = false; while( *fmt != '\0' ) switch( *fmt++ ){ case 'S' : case 's' : suffixes = true; break; case 'P' : case 'p' : percent = true; break; } if( percent ){ q = len * 1000000u / (all != 0 ? all : 1); b = q / 10000u; c = q % 10000u; } else { b = c = 0; } t2 = 1; if( suffixes ){ if( len >= uintmax_t(1024u) * 1024u * 1024u * 1024u ){ t2 = 1024u; t2 *= 1024u * 1024u * 1024u; suffix = "T"; } if( len >= 1024u * 1024u * 1024u ){ t2 = 1024u * 1024u * 1024u; suffix = "G"; } else if( len >= 1024u * 1024u ){ t2 = 1024u * 1024u; suffix = "M"; } else if( len >= 1024u ){ t2 = 1024u; suffix = "K"; } else { suffixes = false; } } t1 = len / t2; t3 = len % t2; if( suffixes ){ t2 = t3 / (t2 / 1024u); if( t2 == 0 ) return utf8::String::print( percent ? "%"PRIuMAX"%s(%"PRIuMAX".%04"PRIuMAX"%%)" : "%"PRIuMAX"%s", t1, suffix, b, c ); return utf8::String::print( percent ? "%"PRIuMAX".%04"PRIuMAX"%s(%"PRIuMAX".%04"PRIuMAX"%%)" : "%"PRIuMAX".%04"PRIuMAX"%s", t1, t2, suffix, b, c ); } return utf8::String::print( percent ? "%"PRIuMAX"(%"PRIuMAX".%04"PRIuMAX"%%)" : "%"PRIuMAX, t1, b, c ); } //------------------------------------------------------------------------------ utf8::String getHostName() { #if HAVE_UNAME struct utsname un; if( uname(&un) != 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #else struct { utf8::String nodename; } un; ksock::APIAutoInitializer ksockAPIAutoInitializer; un.nodename = ksock::SockAddr::gethostname(); #endif return un.nodename; } //------------------------------------------------------------------------------ #if defined(__WIN32__) || defined(__WIN64__) HMODULE getModuleHandleByAddr(void * addr) { MODULEENTRY32 me; HANDLE hSnapshot; HMODULE h = NULL; if( addr == NULL ) addr = (void *) getModuleHandleByAddr; if( (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0)) != INVALID_HANDLE_VALUE ){ me.dwSize = sizeof(me); if( Module32First(hSnapshot,&me) == TRUE ) do { if( (uint8_t *) me.modBaseAddr <= (uint8_t *) addr && (uint8_t *) me.modBaseAddr + me.modBaseSize > (uint8_t *) addr ){ h = me.hModule; break; } } while( Module32Next(hSnapshot,&me) == TRUE ); CloseHandle(hSnapshot); } return h; } #endif //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) utf8::String getModuleFileNameByHandle(HMODULE h) { DWORD a = 1, b; if( isWin9x() ){ AutoPtr moduleFileName; for(;;){ moduleFileName.realloc(a * sizeof(char)); if( (b = GetModuleFileNameA(h,moduleFileName,a)) < a ) break; a <<= 1; } moduleFileName.realloc((b + 1) * sizeof(char)); return moduleFileName.ptr(); } AutoPtr moduleFileName; for(;;){ moduleFileName.realloc(a * sizeof(wchar_t)); if( (b = GetModuleFileNameW(h,moduleFileName,a)) < a ) break; a <<= 1; } moduleFileName.realloc((b + 1) * sizeof(wchar_t)); return moduleFileName.ptr(); } #endif //--------------------------------------------------------------------------- utf8::String getCurrentDir() { #if defined(__WIN32__) || defined(__WIN64__) DWORD a; if( isWin9x() ){ AutoPtr dirName; dirName.realloc((a = GetCurrentDirectoryA(0,NULL)) * sizeof(char)); GetCurrentDirectoryA(a,dirName); return dirName.ptr(); } AutoPtr dirName; dirName.realloc((a = GetCurrentDirectoryW(0,NULL)) * sizeof(wchar_t)); GetCurrentDirectoryW(a,dirName); return dirName.ptr(); #else AutoPtr dirName((char *) kmalloc(MAXPATHLEN + 1 + 1)); if( getcwd(dirName,MAXPATHLEN + 1) == NULL ) strcpy(dirName,"."); strcat(dirName,pathDelimiterStr); return dirName.ptr(); #endif } //--------------------------------------------------------------------------- void changeCurrentDir(const utf8::String & name) { int32_t err = 0; #if defined(__WIN32__) || defined(__WIN64__) BOOL r; if( isWin9x() ){ r = SetCurrentDirectoryA((const char *) anyPathName2HostPathName(name).getANSIString()); } else { r = SetCurrentDirectoryW((const wchar_t *) anyPathName2HostPathName(name).getUNICODEString()); } if( r == 0 ) err = GetLastError(); #else if( chdir((const char *) anyPathName2HostPathName(name).getANSIString()) != 0 ) err = errno; #endif if( err != 0 ) newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } //--------------------------------------------------------------------------- utf8::String getTempPath() { #if defined(__WIN32__) || defined(__WIN64__) DWORD a; if( isWin9x() ){ AutoPtr dirName; dirName.realloc((a = GetTempPathA(0,NULL) + 2) * sizeof(char)); GetTempPathA(a,dirName); if( dirName[strlen(dirName) - 1] != '\\' ) strcat(dirName,"\\"); return dirName.ptr(); } AutoPtr dirName; dirName.realloc((a = GetTempPathW(0,NULL) + 2) * sizeof(wchar_t)); GetTempPathW(a,dirName); if( dirName[lstrlenW(dirName) - 1] != '\\' ) lstrcatW(dirName,L"\\"); return dirName.ptr(); #elif HAVE_PATHS_H return _PATH_TMP; #else #error you system not have paths.h #endif } //--------------------------------------------------------------------------- utf8::String changeFileExt(const utf8::String & fileName,const utf8::String & extension) { utf8::String::Iterator i(fileName); i.last(); while( !i.bos() ){ uintptr_t c = i.getChar(); if( c == '\\' || c == '/' || c == ':' ) break; if( c == '.' ) return utf8::String(utf8::String::Iterator(fileName),i) + extension; i.prev(); } return fileName + extension; } //--------------------------------------------------------------------------- utf8::String getFileExt(const utf8::String & fileName) { utf8::String::Iterator i(fileName); i.last(); while( !i.bos() ){ uintptr_t c = i.getChar(); if( c == '\\' || c == '/' || c == ':' ) break; if( c == '.' ) return utf8::String(i); i.prev(); } return utf8::String(); } //--------------------------------------------------------------------------- utf8::String getExecutableName() { #if defined(__WIN32__) || defined(__WIN64__) HMODULE h = getModuleHandleByAddr(); if( h == NULL ) h = GetModuleHandle(NULL); return getModuleFileNameByHandle(h); #else return argv().count() > 0 ? argv()[0] : utf8::String(); #endif } //--------------------------------------------------------------------------- utf8::String getExecutablePath() { utf8::String name(getExecutableName()); utf8::String::Iterator i(name); i.last(); while( !i.bos() ){ uintptr_t c = i.getChar(); if( c == '\\' || c == '/' ) break; i.prev(); } return utf8::String(utf8::String::Iterator(name),i + 1); } //--------------------------------------------------------------------------- utf8::String excludeTrailingPathDelimiter(const utf8::String & path) { utf8::String s(path); utf8::String::Iterator i(s); i.last(); switch( i.getChar() ){ case '\\' : case '/' : s = s.unique().resize(s.size() - i.seqLen()); default:; } return s; } //--------------------------------------------------------------------------- utf8::String includeTrailingPathDelimiter(const utf8::String & path) { utf8::String s(path); utf8::String::Iterator i(s); i.last(); switch( i.getChar() ){ case '\\' : case '/' : default: char b[2]; b[0] = pathDelimiter; b[1] = '\0'; return s + b; } return s; } //--------------------------------------------------------------------------- bool isPathNameRelative(const utf8::String & pathName) { utf8::String::Iterator i(pathName); uintptr_t c = 0, c2, c3; while( !i.eos() ){ if( !i.isSpace() ){ switch( c2 = i.getChar() ){ case '\\' : case '/' : return false; default: ; } if( c != 0 && c2 == ':' ) return false; if( c == 0 && ((c3 = i.getUpperChar()) < 'A' || c3 > 'Z') ) break; c = i.getChar(); } i.next(); } return true; } //--------------------------------------------------------------------------- utf8::String absolutePathNameFromWorkDir( const utf8::String & workDir, const utf8::String & pathName) { if( isPathNameRelative(pathName) ) return workDir + pathName; return pathName; } //--------------------------------------------------------------------------- bool createDirectory(const utf8::String & name) { // fprintf(stderr,"%s %d %s\n",__FILE__,__LINE__,name.c_str()); if( currentFiber() != NULL ){ currentFiber()->event_.timeout_ = ~uint64_t(0); currentFiber()->event_.string0_ = name; currentFiber()->event_.type_ = etCreateDir; currentFiber()->thread()->postRequest(); currentFiber()->switchFiber(currentFiber()->mainFiber()); assert( currentFiber()->event_.type_ == etCreateDir ); #if defined(__WIN32__) || defined(__WIN64__) if( currentFiber()->event_.errno_ - errorOffset == ERROR_ALREADY_EXISTS ) return false; #else if( currentFiber()->event_.errno_ == EEXIST ) return false; #endif if( currentFiber()->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); return currentFiber()->event_.rval_; } int32_t err = 0; #if defined(__WIN32__) || defined(__WIN64__) if( isWin9x() ){ if( CreateDirectoryA(anyPathName2HostPathName(name).getANSIString(),NULL) == 0 ) err = GetLastError(); } else { if( CreateDirectoryW(anyPathName2HostPathName(name).getUNICODEString(),NULL) == 0 ) err = GetLastError(); } if( err == ERROR_PATH_NOT_FOUND ){ #else mode_t um = umask(0); umask(um); if( mkdir(anyPathName2HostPathName(name).getANSIString(),um | S_IRUSR | S_IWUSR | S_IXUSR) != 0 ) err = errno; // fprintf(stderr,"%s %d err = %d %s\n",__FILE__,__LINE__,err,name.c_str()); if( err == ENOTDIR ){ #endif utf8::String parentDir(getPathFromPathName(name)); if( parentDir.strlen() > 0 ){ if( createDirectory(parentDir) ) return createDirectory(name); err = oserror(); } } #if defined(__WIN32__) || defined(__WIN64__) if( err != 0 && err != ERROR_ALREADY_EXISTS ) #else if( err != 0 && err != EEXIST ) #endif newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); oserror(err); return err == 0; } //--------------------------------------------------------------------------- static int32_t removeDirectoryHelper(const utf8::String & name) { int32_t err = 0; #if defined(__WIN32__) || defined(__WIN64__) if( isWin9x() ){ if( RemoveDirectoryA(anyPathName2HostPathName(name).getANSIString()) == 0 ) err = GetLastError(); } else { if( RemoveDirectoryW(anyPathName2HostPathName(name).getUNICODEString()) == 0 ) err = GetLastError(); } #else if( rmdir(anyPathName2HostPathName(name).getANSIString()) != 0 ) err = errno; #endif oserror(err); return err; } //--------------------------------------------------------------------------- bool removeDirectory(const utf8::String & name,bool recursive,bool noThrow) { Fiber * fiber = currentFiber(); if( fiber != NULL ){ fiber->event_.timeout_ = ~uint64_t(0); fiber->event_.string0_ = name; fiber->event_.recursive_ = recursive; fiber->event_.type_ = etRemoveDir; fiber->thread()->postRequest(); fiber->switchFiber(fiber->mainFiber()); assert( fiber->event_.type_ == etRemoveDir ); #if defined(__WIN32__) || defined(__WIN64__) if( fiber->event_.errno_ - errorOffset == ERROR_PATH_NOT_FOUND || fiber->event_.errno_ - errorOffset == ERROR_FILE_NOT_FOUND ) return false; #else if( fiber->event_.errno_ == ENOTDIR ) return false; #endif if( fiber->event_.errno_ != 0 && !noThrow ) newObjectV1C2(fiber->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); return fiber->event_.rval_ && fiber->event_.errno_ == 0; } int32_t err = removeDirectoryHelper(name); #if defined(__WIN32__) || defined(__WIN64__) if( err == ERROR_DIR_NOT_EMPTY ){ #else if( err == ENOTEMPTY ){ #endif Vector list; getDirList(list,includeTrailingPathDelimiter(name) + "*",utf8::String(),recursive); err = 0; bool rval = true; for( intptr_t i = list.count() - 1; i >= 0; i-- ){ struct Stat st; stat(list[i],st); if( (st.st_mode & S_IFDIR) != 0 && recursive ){ if( !removeDirectory(list[i],true) ){ if( rval ){ err = oserror(); rval = false; } } } else { if( !remove(list[i]) ){ if( rval ){ err = oserror(); rval = false; } } } } if( rval ){ err = removeDirectoryHelper(name); } else { oserror(err); return rval; } } #if defined(__WIN32__) || defined(__WIN64__) if( err == ERROR_PATH_NOT_FOUND || err == ERROR_FILE_NOT_FOUND ) return false; #else if( err == ENOTDIR ) return false; #endif oserror(err); if( err != 0 && !noThrow ) newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); return err == 0; } //--------------------------------------------------------------------------- bool remove(const utf8::String & name,bool noThrow) { Fiber * fiber = currentFiber(); if( fiber != NULL ){ fiber->event_.timeout_ = ~uint64_t(0); fiber->event_.string0_ = name; fiber->event_.type_ = etRemoveFile; fiber->thread()->postRequest(); fiber->switchFiber(fiber->mainFiber()); assert( fiber->event_.type_ == etRemoveFile ); #if defined(__WIN32__) || defined(__WIN64__) if( fiber->event_.errno_ - errorOffset == ERROR_PATH_NOT_FOUND || fiber->event_.errno_ - errorOffset == ERROR_FILE_NOT_FOUND ) return false; #else if( fiber->event_.errno_ == ENOENT ) return false; #endif if( fiber->event_.errno_ != 0 && !noThrow ) newObjectV1C2(fiber->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); return fiber->event_.rval_ && fiber->event_.errno_ == 0; } int32_t err = 0; oserror(0); #if defined(__WIN32__) || defined(__WIN64__) if( isWin9x() ){ if( DeleteFileA(anyPathName2HostPathName(name).getANSIString()) == 0 ) err = GetLastError(); } else { if( DeleteFileW(anyPathName2HostPathName(name).getUNICODEString()) == 0 ) err = GetLastError(); } if( err == ERROR_PATH_NOT_FOUND || err == ERROR_FILE_NOT_FOUND ) return false; #else if( unlink(anyPathName2HostPathName(name).getANSIString()) != 0 ) err = errno; if( err == ENOENT ) return false; #endif if( err != 0 ){ struct Stat st; stat(name,st); if( (st.st_mode & S_IFDIR) != 0 ){ try { if( removeDirectory(name,true) ) return true; err = oserror(); } catch( ExceptionSP & e){ err = e->code() >= errorOffset ? e->code() - errorOffset : e->code(); } } if( !noThrow ) newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); oserror(err); } return err == 0; } //--------------------------------------------------------------------------- #if !defined(__WIN32__) && !defined(__WIN64__) void chModOwn( const utf8::String & pathName, const Mutant & mode,const Mutant & user,const Mutant & group) { int32_t err; union { mode_t m; intmax_t m2; }; m2 = umask(0); umask(m); if( mode.type() == mtInt ){ m2 = mode; } else { utf8::tryStr2Int(mode,m2,8); } if( chmod(anyPathName2HostPathName(pathName).getANSIString(),(mode_t) m2) != 0 ){ err = errno; newObjectV1C2(err,pathName + utf8::String(" ") + __PRETTY_FUNCTION__)->throwSP(); } const struct passwd * u = getpwnam(utf8::String(user).getANSIString()); uid_t userID(u != NULL ? u->pw_uid : (uid_t) user); const struct group * g = getgrnam(utf8::String(group).getANSIString()); gid_t groupID(g != NULL ? g->gr_gid : (gid_t) group); if( chown(anyPathName2HostPathName(pathName).getANSIString(),userID,groupID) != 0 ){ err = errno; newObjectV1C2(err,pathName + utf8::String(" ") + __PRETTY_FUNCTION__)->throwSP(); } } #else void chModOwn(const utf8::String &,const Mutant &,const Mutant &,const Mutant &) { } #endif //--------------------------------------------------------------------------- utf8::String getRootFromPathName(const utf8::String & pathName) { #if defined(__WIN32__) || defined(__WIN64__) uintptr_t offset = pathName.strncmp("\\\\?\\",4) == 0 || pathName.strncmp("//?/",4) == 0 ? 4 : 0; utf8::String s(utf8::String::Iterator(pathName) + offset); if( s.strncmp("\\\\",2) == 0 || s.strncmp("//",2) == 0 ){ // windows network path utf8::String::Iterator i(utf8::String::Iterator(s) + 2); while( !i.bos() ){ uintptr_t c = i.getChar(); if( c == '/' || c == '\\' ){ // windows network server name while( !i.bos() ){ c = i.getChar(); if( c == '/' || c == '\\' ) break; // windows network server resource name i.next(); } return utf8::String(s,i) + pathDelimiterStr; } i.next(); } return utf8::String(s,i) + pathDelimiterStr; } utf8::String::Iterator i(s); while( !i.bos() ){ uintptr_t c = i.getChar(); if( c == '/' || c == '\\' ) break; if( c == ':' ){ return utf8::String(s,i + 1) + pathDelimiterStr; } i.next(); } return getRootFromPathName(getCurrentDir()); #else // FIX ME return pathDelimiterStr; #endif } //--------------------------------------------------------------------------- utf8::String getPathFromPathName(const utf8::String & pathName) { utf8::String::Iterator i(pathName); i.last(); if( (i - 1).getChar() == ':' ) return utf8::String(); while( !i.bos() ){ switch( i.getChar() ){ case ':' : return utf8::String(utf8::String::Iterator(pathName),i + 1); case '\\' : case '/' : return utf8::String(utf8::String::Iterator(pathName),i); default :; } i.prev(); } return "."; } //--------------------------------------------------------------------------- utf8::String getNameFromPathName(const utf8::String & pathName) { utf8::String::Iterator i(pathName); i.last(); while( !i.bos() ){ switch( i.getChar() ){ case '\\' : case '/' : return utf8::String(i + 1,utf8::String::Iterator(pathName).last()); default :; } i.prev(); } return i; } //--------------------------------------------------------------------------- utf8::String anyPathName2HostPathName(const utf8::String & pathName) { if( pathDelimiter == '\\' && !pathName.strstr("/").eos() ) return pathName.replaceAll("/",pathDelimiterStr); if( pathDelimiter == '/' && !pathName.strstr("\\").eos() ) return pathName.replaceAll("\\",pathDelimiterStr); return pathName; } //--------------------------------------------------------------------------- bool nameFitMask(const utf8::String & name,const utf8::String & mask) { uintptr_t c; utf8::String::Iterator ni(name), mi(mask); while( !ni.eos() && !mi.eos() ){ if( (c = mi.getChar()) == '?' ){ ni.next(); mi.next(); } else if( c == '*' ){ mi.next(); if( mi.eos() ){ ni.last(); break; } #if defined(__WIN32__) || defined(__WIN64__) while( ni.getUpperChar() != mi.getUpperChar() ){ ni.next(); if( ni.eos() ) break; } while( ni.getUpperChar() == (c = mi.getUpperChar()) && c != '*' && c != '?' && c != '[' ){ ni.next(); mi.next(); if( ni.eos() ) break; } #else while( !mi.eos() && !ni.eos() && ni.getChar() != mi.getChar() ){ ni.next(); if( ni.eos() ) break; } while( ni.getChar() == (c = mi.getChar()) && c != '*' && c != '?' && c != '[' ){ ni.next(); mi.next(); if( ni.eos() ) break; } #endif } else if( c == '[' ){ // mi.next(); newObjectV1C2(ENOSYS,utf8::String(__PRETTY_FUNCTION__) + " " + utf8::int2Str(__LINE__) + " FIXME")->throwSP(); } else { #if defined(__WIN32__) || defined(__WIN64__) if( ni.getUpperChar() != c ) break; #else if( ni.getChar() != c ) break; #endif ni.next(); mi.next(); } } return ni.eos() && mi.eos(); } //--------------------------------------------------------------------------- bool rename(const utf8::String & oldPathName,const utf8::String & newPathName,bool createPathIfNotExist,bool noThrow) { oserror(0); Fiber * fiber = currentFiber(); if( fiber != NULL ){ fiber->event_.timeout_ = ~uint64_t(0); fiber->event_.string0_ = oldPathName; fiber->event_.string1_ = newPathName; fiber->event_.createIfNotExist_ = createPathIfNotExist; fiber->event_.type_ = etRename; fiber->thread()->postRequest(); fiber->switchFiber(currentFiber()->mainFiber()); assert( fiber->event_.type_ == etRename ); if( fiber->event_.errno_ != 0 && !noThrow ) newObjectV1C2(fiber->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + oldPathName)->throwSP(); oserror(fiber->event_.errno_); } else { #if defined(__WIN32__) || defined(__WIN64__) BOOL r; if( isWin9x() ){ r = MoveFileA( anyPathName2HostPathName(oldPathName).getANSIString(), anyPathName2HostPathName(newPathName).getANSIString() ); } else { r = MoveFileExW( anyPathName2HostPathName(oldPathName).getUNICODEString(), anyPathName2HostPathName(newPathName).getUNICODEString(), MOVEFILE_COPY_ALLOWED ); } if( r == 0 ){ int32_t err = GetLastError(); if( err == ERROR_PATH_NOT_FOUND && createPathIfNotExist ){ createDirectory(getPathFromPathName(newPathName)); return rename(oldPathName,newPathName,false); } #else if( ::rename(anyPathName2HostPathName(oldPathName).getANSIString(),anyPathName2HostPathName(newPathName).getANSIString()) != 0 ){ int32_t err = errno; if( err == ENOTDIR && createPathIfNotExist ){ createDirectory(getPathFromPathName(newPathName)); return rename(oldPathName,newPathName,false); } #endif if( !noThrow ) newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + oldPathName)->throwSP(); oserror(err); } } return oserror() == 0; } //--------------------------------------------------------------------------- void copy(const utf8::String & dstPathName,const utf8::String & srcPathName,uintptr_t bufferSize) { if( currentFiber() != NULL ){ currentFiber()->event_.timeout_ = ~uint64_t(0); currentFiber()->event_.string0_ = dstPathName; currentFiber()->event_.string1_ = srcPathName; currentFiber()->event_.count_ = bufferSize; currentFiber()->event_.type_ = etCopy; currentFiber()->thread()->postRequest(); currentFiber()->switchFiber(currentFiber()->mainFiber()); assert( currentFiber()->event_.type_ == etRename ); if( currentFiber()->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + srcPathName)->throwSP(); } else { if( bufferSize == 0 ) bufferSize = getpagesize(); #if defined(__WIN32__) || defined(__WIN64__) BOOL r; if( isWin9x() ){ r = CopyFileA( anyPathName2HostPathName(srcPathName).getANSIString(), anyPathName2HostPathName(dstPathName).getANSIString(), FALSE ); } else { BOOL bCancel = FALSE; r = CopyFileExW( anyPathName2HostPathName(srcPathName).getUNICODEString(), anyPathName2HostPathName(dstPathName).getUNICODEString(), NULL, NULL, &bCancel, 0 ); } if( r == 0 ){ int32_t err = oserror() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__ + utf8::String(" ") + srcPathName)->throwSP(); } #else AsyncFile dstFile, srcFile; dstFile.fileName(dstPathName).createIfNotExist(true).exclusive(true); srcFile.fileName(srcPathName).readOnly(true); dstFile.open(); srcFile.open(); AutoPtr buffer; buffer.alloc(bufferSize); dstFile.resize(0); for( uint64_t ll, l = srcFile.size(); l > 0; l -= ll ){ ll = bufferSize > l ? l : bufferSize; srcFile.readBuffer(buffer,ll); dstFile.writeBuffer(buffer,ll); } #endif } } //--------------------------------------------------------------------------- void ksleep(uint64_t timeout) { if( currentFiber() != NULL ){ currentFiber()->event_.abort_ = false; currentFiber()->event_.timerStartTime_ = gettimeofday(); currentFiber()->event_.timeout_ = timeout; currentFiber()->event_.type_ = etTimer; currentFiber()->thread()->postRequest(); currentFiber()->switchFiber(currentFiber()->mainFiber()); assert( currentFiber()->event_.type_ == etTimer ); if( currentFiber()->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_ + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } else { #if HAVE_NANOSLEEP struct timespec rqtp; rqtp.tv_sec = timeout / 1000000u; rqtp.tv_nsec = timeout % 1000000u; nanosleep(&rqtp, NULL); #elif defined(__WIN32__) || defined(__WIN64__) Sleep((DWORD) (timeout / 1000u + (timeout < 1000000u))); #elif HAVE_USLEEP usleep(timeout / 1000u); #elif HAVE_SLEEP sleep(timeout / 1000000u); #endif } } //--------------------------------------------------------------------------- static bool getDirListHelper( const utf8::String & name, const utf8::String & mask, const utf8::String & exMask, bool exMaskAsList) { bool add = false; if( nameFitMask(name,mask) ){ if( exMaskAsList ){ add = true; for( intptr_t i = enumStringParts(exMask) - 1; i >= 0; i-- ) if( nameFitMask(name,stringPartByNo(exMask,i)) ){ add = false; break; } } else { add = !nameFitMask(name,exMask); } } return add; } //--------------------------------------------------------------------------- void getDirList( Vector & list, const utf8::String & dirAndMask, const utf8::String & exMask, bool recursive, bool includeDirs, bool exMaskAsList) { Fiber * fiber = currentFiber(); if( fiber != NULL ){ fiber->event_.timeout_ = ~uint64_t(0); fiber->event_.dirList_ = &list; fiber->event_.string0_ = dirAndMask; fiber->event_.string1_ = exMask; fiber->event_.recursive_ = recursive; fiber->event_.includeDirs_ = includeDirs; fiber->event_.exMaskAsList_ = exMaskAsList; fiber->event_.type_ = etDirList; fiber->thread()->postRequest(); fiber->switchFiber(fiber->mainFiber()); assert( fiber->event_.type_ == etDirList ); if( fiber->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); return; } int32_t err; utf8::String path(getPathFromPathName(dirAndMask)); utf8::String mask(getNameFromPathName(dirAndMask)); #if defined(__WIN32__) || defined(__WIN64__) union { WIN32_FIND_DATAA fda; WIN32_FIND_DATAW fdw; }; HANDLE handle; if( isWin9x() ){ handle = FindFirstFileA(anyPathName2HostPathName(path + pathDelimiterStr + "*").getANSIString(),&fda); if( handle == INVALID_HANDLE_VALUE ){ err = GetLastError(); if( err == ERROR_PATH_NOT_FOUND ) return; newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } try { do { if( strcmp(fda.cFileName,".") == 0 || strcmp(fda.cFileName,"..") == 0 ) continue; const char * d_name = fda.cFileName; if( (fda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ){ bool fit = getDirListHelper(d_name,mask,exMask,exMaskAsList); if( includeDirs && fit ) list.add(path + pathDelimiterStr + d_name); if( recursive && fit ) #else DIR * dir = opendir(anyPathName2HostPathName(path).getANSIString()); if( dir == NULL ){ err = errno; if( err == ENOTDIR ) return; newObjectV1C2(err,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); } try { struct dirent * ent; #if HAVE_READDIR_R struct dirent * result, res; ent = &res; for(;;){ if( readdir_r(dir,ent,&result) != 0 ){ err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); } if( result == NULL ) break; #else while( (ent = readdir(dir)) != NULL ){ #endif if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 ) continue; const char * d_name = ent->d_name; #ifdef DT_DIR if( ent->d_type == DT_DIR ){ bool fit = getDirListHelper(d_name,mask,exMask,exMaskAsList); if( includeDirs && fit ) list.add(path + pathDelimiterStr + d_name); if( recursive && fit ) #else struct Stat st; stat(path + pathDelimiterStr + ent->d_name,st); if( (st.st_mode & S_IFDIR) != 0 ){ if( recursive ) #endif #endif getDirList( list, path + pathDelimiterStr + d_name + pathDelimiterStr + mask, exMask, recursive, includeDirs, exMaskAsList ); } else if( getDirListHelper(d_name,mask,exMask,exMaskAsList) ){ list.add(path + pathDelimiterStr + d_name); } #if defined(__WIN32__) || defined(__WIN64__) } while( FindNextFileA(handle,&fda) != 0 ); if( GetLastError() != ERROR_NO_MORE_FILES ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); } } catch( ... ){ FindClose(handle); throw; } FindClose(handle); } else { handle = FindFirstFileW(anyPathName2HostPathName(path + pathDelimiterStr + "*").getUNICODEString(),&fdw); if( handle == INVALID_HANDLE_VALUE ){ err = GetLastError(); if( err == ERROR_PATH_NOT_FOUND ) return; newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); } try { do { if( lstrcmpW(fdw.cFileName,L".") == 0 || lstrcmpW(fdw.cFileName,L"..") == 0 ) continue; if( (fdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ){ bool fit = getDirListHelper(fdw.cFileName,mask,exMask,exMaskAsList); if( includeDirs && fit ) list.add(path + pathDelimiterStr + fdw.cFileName); if( recursive && fit ) getDirList( list, path + pathDelimiterStr + fdw.cFileName + pathDelimiterStr + mask, exMask, recursive, includeDirs, exMaskAsList ); } else if( getDirListHelper(fdw.cFileName,mask,exMask,exMaskAsList) ){ list.add(path + pathDelimiterStr + fdw.cFileName); } } while( FindNextFileW(handle,&fdw) != 0 ); if( GetLastError() != ERROR_NO_MORE_FILES ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__ + utf8::String(" ") + dirAndMask)->throwSP(); } } catch( ... ){ FindClose(handle); throw; } FindClose(handle); } #else } } catch( ... ){ closedir(dir); throw; } closedir(dir); #endif } //--------------------------------------------------------------------------- // переключение раскладки клавиатуры // LoadKeyboardLayout("00000419", KLF_ACTIVATE); //русский //--------------------------------------------------------------------------- void copyStrToClipboard(const utf8::String & s) { #if defined(__WIN32__) || defined(__WIN64__) int32_t err; if( OpenClipboard(NULL) == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( EmptyClipboard() == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( isWin9x() ){ utf8::AnsiString pass(s.getANSIString()); HGLOBAL w = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, (strlen(pass) + 1) * sizeof(char) ); if( w == NULL ){ err = GetLastError() + errorOffset; CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } LPVOID ww = GlobalLock(w); if( ww == NULL ){ err = GetLastError() + errorOffset; CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } memcpy(ww,(const char *) pass,(strlen(pass) + 1) * sizeof(char)); GlobalUnlock(ww); if( SetClipboardData(CF_TEXT,w) == NULL ){ err = GetLastError() + errorOffset; GlobalFree(w); CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } } else { utf8::WideString pass(s.getUNICODEString()); HGLOBAL w = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, (lstrlenW(pass) + 1) * sizeof(wchar_t) ); if( w == NULL ){ err = GetLastError() + errorOffset; CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } LPVOID ww = GlobalLock(w); if( ww == NULL ){ err = GetLastError() + errorOffset; CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } memcpy(ww,(const wchar_t *) pass,(lstrlenW(pass) + 1) * sizeof(wchar_t)); GlobalUnlock(ww); if( SetClipboardData(CF_UNICODETEXT,w) == NULL ){ err = GetLastError() + errorOffset; GlobalFree(w); CloseClipboard(); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } } CloseClipboard(); #endif } //--------------------------------------------------------------------------- pid_t execute(const utf8::String & name,const utf8::String & args,const Array * env,bool wait) { Array a; uintptr_t i, j = enumStringParts(args," \t"); for( i = 0; i < j; i++ ) a.add(stringPartByNo(args,i," \t")); return execute(name,a,env,wait); } //--------------------------------------------------------------------------- pid_t execute(const utf8::String & name,const Array & args,const Array * env,bool wait) { if( currentFiber() != NULL ){ currentFiber()->event_.timeout_ = ~uint64_t(0); currentFiber()->event_.args_ = &args; currentFiber()->event_.env_ = env; currentFiber()->event_.string0_ = name; currentFiber()->event_.wait_ = wait; currentFiber()->event_.type_ = etExec; currentFiber()->thread()->postRequest(); currentFiber()->switchFiber(currentFiber()->mainFiber()); assert( currentFiber()->event_.type_ == etExec ); if( currentFiber()->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_,__PRETTY_FUNCTION__ + utf8::String(" ") + name)->throwSP(); return (pid_t) currentFiber()->event_.data_; } #if defined(__WIN32__) || defined(__WIN64__) BOOL r; uintptr_t i; utf8::String s; for( i = 0; i < args.count(); i++ ){ if( i > 0 ) s += " "; s += args[i]; } MemoryStream e; union { STARTUPINFOA sui; STARTUPINFOW suiW; }; memset(&suiW,0,sizeof(suiW)); PROCESS_INFORMATION pi; memset(&pi,0,sizeof(pi)); if( isWin9x() ){ if( env != NULL ){ for( i = 0; i < env->count(); i++ ){ utf8::AnsiString a((*env)[i].getANSIString()); e.writeBuffer(a,strlen(a) + 1); } e.writeBuffer("",1); } sui.cb = sizeof(sui); r = CreateProcessA( name.getANSIString(), s.getANSIString(), NULL, NULL, FALSE, 0, env != NULL ? e.raw() : NULL, NULL, &sui, &pi ); } else { if( env != NULL ){ for( i = 0; i < env->count(); i++ ){ utf8::WideString a((*env)[i].getUNICODEString()); e.writeBuffer(a,(wcslen(a) + 1) * sizeof(wchar_t)); } e.writeBuffer(L"",sizeof(wchar_t)); } suiW.cb = sizeof(suiW); r = CreateProcessW( name.getUNICODEString(), s.getUNICODEString(), NULL, NULL, FALSE, 0, env != NULL ? e.raw() : NULL, NULL, &suiW, &pi ); } int32_t err; if( r == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( wait ){ DWORD r = WaitForSingleObject(pi.hProcess,INFINITE); if( r == WAIT_FAILED ){ err = GetLastError() + errorOffset; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( r != WAIT_OBJECT_0 ){ CloseHandle(pi.hProcess); CloseHandle(pi.hThread); newObjectV1C2(ERROR_INVALID_DATA,__PRETTY_FUNCTION__)->throwSP(); } DWORD exitCode; if( GetExitCodeProcess(pi.hProcess,&exitCode) == 0 ){ err = GetLastError() + errorOffset; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } pi.dwProcessId = exitCode; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return pi.dwProcessId; #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); return 0; #endif } //--------------------------------------------------------------------------- int32_t waitForProcess(pid_t pid) { if( currentFiber() != NULL ){ currentFiber()->event_.timeout_ = ~uint64_t(0); currentFiber()->event_.pid_ = pid; currentFiber()->event_.type_ = etWaitForProcess; currentFiber()->thread()->postRequest(); currentFiber()->switchFiber(currentFiber()->mainFiber()); assert( currentFiber()->event_.type_ == etWaitForProcess ); if( currentFiber()->event_.errno_ != 0 ) newObjectV1C2(currentFiber()->event_.errno_,__PRETTY_FUNCTION__)->throwSP(); return (int32_t) currentFiber()->event_.data_; } #if defined(__WIN32__) || defined(__WIN64__) int32_t err; HANDLE hProcess = OpenProcess(NULL,FALSE,pid); if( hProcess == NULL ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } DWORD r = WaitForSingleObject(hProcess,INFINITE); if( r == WAIT_FAILED ){ err = GetLastError() + errorOffset; CloseHandle(hProcess); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( r != WAIT_OBJECT_0 ){ CloseHandle(hProcess); newObjectV1C2(ERROR_INVALID_DATA,__PRETTY_FUNCTION__)->throwSP(); } DWORD exitCode; if( GetExitCodeProcess(hProcess,&exitCode) == 0 ){ err = GetLastError() + errorOffset; CloseHandle(hProcess); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } CloseHandle(hProcess); return exitCode; #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); return -1; #endif } //--------------------------------------------------------------------------- static uint64_t processStartTime; int64_t getProcessStartTime(bool toLocalTime) { #if defined(__WIN32__) || defined(__WIN64__) int32_t err = 0; SetLastError(ERROR_SUCCESS); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,GetCurrentProcessId()); union { FILETIME ft; ULARGE_INTEGER sti; } creationTime, exitTime, kernelTime, userTime; creationTime.sti.QuadPart = 0; if( hProcess != NULL ) if( GetProcessTimes(hProcess,&creationTime.ft,&exitTime.ft,&kernelTime.ft,&userTime.ft) != 0 ) if( toLocalTime ) FileTimeToLocalFileTime(&creationTime.ft,&creationTime.ft); err = GetLastError(); if( hProcess != NULL ) CloseHandle(hProcess); if( err != ERROR_SUCCESS ) newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); return (creationTime.sti.QuadPart - UINT64_C(11644473600) * 10000000u) / 10u; #else return toLocalTime ? processStartTime + getgmtoffset() : processStartTime; #endif } //--------------------------------------------------------------------------- intptr_t strToMonth(const utf8::String & month) { if( month.strcasecmp("Jan") == 0 ) return 0; if( month.strcasecmp("Feb") == 0 ) return 1; if( month.strcasecmp("Mar") == 0 ) return 2; if( month.strcasecmp("Apr") == 0 ) return 3; if( month.strcasecmp("Mai") == 0 ) return 4; if( month.strcasecmp("May") == 0 ) return 4; if( month.strcasecmp("Jun") == 0 ) return 5; if( month.strcasecmp("Jul") == 0 ) return 6; if( month.strcasecmp("Aug") == 0 ) return 7; if( month.strcasecmp("Sep") == 0 ) return 8; if( month.strcasecmp("Okt") == 0 ) return 9; if( month.strcasecmp("Oct") == 0 ) return 9; if( month.strcasecmp("Nov") == 0 ) return 10; if( month.strcasecmp("Dez") == 0 ) return 11; if( month.strcasecmp("Dec") == 0 ) return 11; return -1; } //------------------------------------------------------------------------------ utf8::String getTimestamp(const utf8::String & date,const utf8::String & time) { utf8::String::Iterator i(date); return utf8::String(i + 4,i + 4 + 2).replaceAll(" ","0") + "." + utf8::int2Str0(strToMonth(utf8::String(i,i + 3)),2) + "." + utf8::String(i + 7,i + 7 + 4) + " " + time/*.replaceAll(":","")*/ ; } //--------------------------------------------------------------------------- void reverseByteArray(void * array,uintptr_t size) { for( uintptr_t i = size; i > size / 2; i-- ) xchg(((uint8_t *) array) [i - 1],((uint8_t *) array) [size - i]); } //--------------------------------------------------------------------------- void reverseByteArray(void * dst,const void * src,uintptr_t size) { if( dst == src ){ for( uintptr_t i = size; i > size / 2; i-- ) xchg(((uint8_t *) dst) [i - 1],((uint8_t *) dst) [size - i]); } else { for( intptr_t i = size - 1; i >= 0; i-- ) ((uint8_t *) dst) [size - i - 1] = ((const uint8_t *) src) [i]; } } //--------------------------------------------------------------------------- // base64 routines //--------------------------------------------------------------------------- static const char base64Table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; //--------------------------------------------------------------------------- uintptr_t rfcBase64Encode( const uint8_t * inStr, size_t inLen, uint8_t * outStr, size_t outLen) { size_t currOutLen = 0, i = 0; while( i < inLen ){ uint8_t a = inStr[i]; uint8_t b = (i + 1 >= inLen) ? 0 : inStr[i + 1]; uint8_t c = (i + 2 >= inLen) ? 0 : inStr[i + 2]; if( i + 2 < inLen ){ if( currOutLen + 4 <= outLen ){ outStr[currOutLen++] = base64Table[(a >> 2) & 0x3F]; outStr[currOutLen++] = base64Table[((a << 4) & 0x30) + ((b >> 4) & 0xf)]; outStr[currOutLen++] = base64Table[((b << 2) & 0x3c) + ((c >> 6) & 0x3)]; outStr[currOutLen++] = base64Table[c & 0x3F]; } else { currOutLen += 4; } } else if( i + 1 < inLen ){ if( currOutLen + 4 <= outLen ){ outStr[currOutLen++] = base64Table[(a >> 2) & 0x3F]; outStr[currOutLen++] = base64Table[((a << 4) & 0x30) + ((b >> 4) & 0xf)]; outStr[currOutLen++] = base64Table[((b << 2) & 0x3c) + ((c >> 6) & 0x3)]; outStr[currOutLen++] = '='; } else { currOutLen += 4; } } else { if( currOutLen + 4 <= outLen ){ outStr[currOutLen++] = base64Table[(a >> 2) & 0x3F]; outStr[currOutLen++] = base64Table[((a << 4) & 0x30) + ((b >> 4) & 0xf)]; outStr[currOutLen++] = '='; outStr[currOutLen++] = '='; } else { currOutLen += 4; } } i += 3; } if( currOutLen < outLen ) outStr[currOutLen] = '\0'; return currOutLen; } //--------------------------------------------------------------------------- static uint8_t base64DecodeTable[256]; //--------------------------------------------------------------------------- static inline uint8_t base64Encode6(const uint8_t * p,uintptr_t i) { return (uint8_t) (((*(uint16_t *) (p + (i >> 3))) >> (i & 7)) & 63u); } //--------------------------------------------------------------------------- utf8::String base64Encode(const void * p,uintptr_t l) { utf8::String s; if( l > 0 ){ uintptr_t i, k; s.resize(((l << 3) / 6) + ((l << 3) % 6 != 0)); char * sp = s.c_str(); k = (l << 3) - 8; for( i = 0; i < k; i += 6 ){ *sp++ = base64Table[base64Encode6((uint8_t *) p,i)]; } union { uint8_t c[2]; uint32_t c32; }; c32 = *((uint8_t *) p + (i >> 3)); while( i < k + 8 ){ *sp++ = base64Table[base64Encode6(c,i & 7)]; i += 6; } } return s; } //--------------------------------------------------------------------------- uintptr_t base64Decode(const utf8::String & s,void * p,uintptr_t size) { uintptr_t i = 0; utf8::String::Iterator sp(s); size <<= 3; while( !sp.eos() ){ uintptr_t c = sp.getChar(); if( c < 1 || c >= 256 ) newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); c = base64DecodeTable[c]; if( c >= 64 ) newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); if( i < size ){ if( size - i <= 8 ){ *(uint8_t *) ((uint8_t *) p + (i >> 3)) &= (uint8_t) (~(63u << (i & 7))); *(uint8_t *) ((uint8_t *) p + (i >> 3)) |= (uint8_t) (c << (i & 7)); } else { *(uint16_t *) ((uint8_t *) p + (i >> 3)) &= (uint16_t) (~(63u << (i & 7))); *(uint16_t *) ((uint8_t *) p + (i >> 3)) |= (uint16_t) (c << (i & 7)); } } i += 6; sp++; } return i >> 3; } //--------------------------------------------------------------------------- // base32 routines //--------------------------------------------------------------------------- static const char base32Table[32] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5' }; //--------------------------------------------------------------------------- static uint8_t base32DecodeTable[256]; //--------------------------------------------------------------------------- static inline uint8_t base32Encode5(const uint8_t * p,uintptr_t i) { return (uint8_t) (((*(uint16_t *) (p + (i >> 3))) >> (i & 7)) & 31u); } //--------------------------------------------------------------------------- utf8::String base32Encode(const void * p,uintptr_t l) { utf8::String s; if( l > 0 ){ uintptr_t i, k; s.resize(((l << 3) / 5) + ((l << 3) % 5 != 0)); char * sp = s.c_str(); k = (l << 3) - 8; for( i = 0; i < k; i += 5 ){ *sp++ = base32Table[base32Encode5((uint8_t *) p,i)]; } union { uint8_t c[2]; uint32_t c32; }; c32 = *((uint8_t *) p + (i >> 3)); while( i < k + 8 ){ *sp++ = base32Table[base32Encode5(c,i & 7)]; i += 5; } } return s; } //--------------------------------------------------------------------------- uintptr_t base32Decode(const utf8::String & s,void * p,uintptr_t size) { uintptr_t i = 0; utf8::String::Iterator sp(s); size <<= 3; while( !sp.eos() ){ uintptr_t c = sp.getChar(); if( c < 1 || c >= 256 ) newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); c = base32DecodeTable[c]; if( c >= 32 ) newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); if( i < size ){ if( size - i <= 8 ){ *(uint8_t *) ((uint8_t *) p + (i >> 3)) &= (uint8_t) (~(31u << (i & 7))); *(uint8_t *) ((uint8_t *) p + (i >> 3)) |= (uint8_t) (c << (i & 7)); } else { *(uint16_t *) ((uint8_t *) p + (i >> 3)) &= (uint16_t) (~(31u << (i & 7))); *(uint16_t *) ((uint8_t *) p + (i >> 3)) |= (uint16_t) (c << (i & 7)); } } i += 5; sp++; } return i >> 3; } //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) //--------------------------------------------------------------------------- pid_t getpid() { return GetCurrentProcessId(); } //--------------------------------------------------------------------------- uid_t getuid() { /*! * \todo rewrite for windows */ return 0; } //--------------------------------------------------------------------------- gid_t getgid() { /*! * \todo rewrite for windows */ return 0; } //--------------------------------------------------------------------------- #else //--------------------------------------------------------------------------- pid_t getpid() { return ::getpid(); } //--------------------------------------------------------------------------- uid_t getuid() { return ::getuid(); } //--------------------------------------------------------------------------- gid_t getgid() { return ::getgid(); } //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) bool isWow64() { typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle("kernel32"), "IsWow64Process" ); BOOL bIsWow64 = FALSE; if( fnIsWow64Process != NULL && fnIsWow64Process(GetCurrentProcess(),&bIsWow64) == 0 ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } return bIsWow64 == FALSE ? false : true; } #endif //--------------------------------------------------------------------------- #ifndef DOXYGEN_SHOULD_SKIP_THIS //--------------------------------------------------------------------------- utf8::String getMachineUniqueKey() { #if PRIVATE_RELEASE #if defined(__WIN32__) || defined(__WIN64__) #pragma comment(lib,"wbemuuid.lib") utf8::String s; VARIANT vtName; VariantInit(&vtName); VARIANT vtDeviceId; VariantInit(&vtDeviceId); VARIANT vtDescription; VariantInit(&vtDescription); VARIANT vtProcessorId; VariantInit(&vtProcessorId); VARIANT vtMACAddress; VariantInit(&vtMACAddress); VARIANT vtAdapterTypeId; VariantInit(&vtAdapterTypeId); HRESULT CoInit_hres; try { HRESULT hres; // Step 1: -------------------------------------------------- // Initialize COM. ------------------------------------------ CoInit_hres = CoInitializeEx(0,COINIT_MULTITHREADED); if( FAILED(CoInit_hres) ) newObjectV1C2(HRESULT_CODE(CoInit_hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); try { // Step 2: -------------------------------------------------- // Set general COM security levels -------------------------- // Note: If you are using Windows 2000, you need to specify - // the default authentication credentials for a user by using // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ---- // parameter of CoInitializeSecurity ------------------------ if( CoInit_hres == S_OK ){ hres = CoInitializeSecurity( NULL, -1, // COM authentication NULL, // Authentication services NULL, // Reserved RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation NULL, // Authentication info EOAC_NONE, // Additional capabilities NULL // Reserved ); if( FAILED(hres) && hres != RPC_E_TOO_LATE ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } // Step 3: --------------------------------------------------- // Obtain the initial locator to WMI ------------------------- IWbemLocator *pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc ); if( FAILED(hres) ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); try { // Step 4: ----------------------------------------------------- // Connect to WMI through the IWbemLocator::ConnectServer method IWbemServices *pSvc = NULL; // Connect to the root\cimv2 namespace with // the current user and obtain pointer pSvc // to make IWbemServices calls. hres = pLoc->ConnectServer( L"ROOT\\CIMV2", // Object path of WMI namespace NULL, // User name. NULL = current user NULL, // User password. NULL = current 0, // Locale. NULL indicates current NULL, // Security flags. 0, // Authority (e.g. Kerberos) 0, // Context object &pSvc // pointer to IWbemServices proxy ); if( FAILED(hres) ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); try { // Step 5: -------------------------------------------------- // Set security levels on the proxy ------------------------- hres = CoSetProxyBlanket( pSvc, // Indicates the proxy to set RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx NULL, // Server principal name RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx NULL, // client identity EOAC_NONE // proxy capabilities ); if( FAILED(hres) ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); // Step 6: -------------------------------------------------- // Use the IWbemServices pointer to make requests of WMI ---- IEnumWbemClassObject * pEnumerator = NULL; hres = pSvc->ExecQuery( SysAllocString(L"WQL"), SysAllocString(L"SELECT * FROM Win32_Processor"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); if( FAILED(hres) ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); try { // Step 7: ------------------------------------------------- // Get the data from the query in step 6 ------------------- IWbemClassObject * pclsObj; ULONG uReturn = 0; while( pEnumerator != NULL ){ HRESULT hr = pEnumerator->Next(int(WBEM_INFINITE),1,&pclsObj,&uReturn); if( uReturn == 0 ) break; try { hr = pclsObj->Get(L"Name", 0, &vtName, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtName) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtName,&vtName,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } hr = pclsObj->Get(L"DeviceId", 0, &vtDeviceId, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtDeviceId) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtDeviceId,&vtDeviceId,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } hr = pclsObj->Get(L"Description", 0, &vtDescription, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtDescription) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtDescription,&vtDescription,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } hr = pclsObj->Get(L"ProcessorId", 0, &vtProcessorId, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtProcessorId) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtProcessorId,&vtProcessorId,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } if( s.strlen() > 0 ) s += "\n"; s += utf8::String(V_BSTR(&vtDeviceId)) + " " + V_BSTR(&vtName) + " " + V_BSTR(&vtDescription) + " " + V_BSTR(&vtProcessorId) ; } catch( ... ){ pclsObj->Release(); throw; } pclsObj->Release(); } } catch( ... ){ pEnumerator->Release(); throw; } pEnumerator->Release(); hres = pSvc->ExecQuery( SysAllocString(L"WQL"), SysAllocString(L"SELECT * FROM Win32_NetworkAdapter"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); if( FAILED(hres) ) newObjectV1C2(HRESULT_CODE(hres) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); try { // Step 7: ------------------------------------------------- // Get the data from the query in step 6 ------------------- IWbemClassObject * pclsObj; ULONG uReturn = 0; while( pEnumerator != NULL ){ HRESULT hr = pEnumerator->Next(int(WBEM_INFINITE),1,&pclsObj,&uReturn); if( uReturn == 0 ) break; try { hr = pclsObj->Get(L"Name", 0, &vtName, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtName) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtName,&vtName,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } hr = pclsObj->Get(L"AdapterTypeId", 0, &vtAdapterTypeId, 0, 0); if( FAILED(hr) ){ HRESULT hr2 = pclsObj->Get(L"AdapterType", 0, &vtAdapterTypeId, 0, 0); if( FAILED(hr2) ){ hr = hr2; newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } if( V_VT(&vtAdapterTypeId) != VT_NULL ){ if( V_VT(&vtAdapterTypeId) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtAdapterTypeId,&vtAdapterTypeId,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } } } if( V_VT(&vtAdapterTypeId) != VT_NULL ){ if( V_VT(&vtAdapterTypeId) == VT_BSTR ){ if( utf8::String("Ethernet").strncasecmp(V_BSTR(&vtAdapterTypeId),8) == 0 ){ VariantClear(&vtAdapterTypeId); V_VT(&vtAdapterTypeId) = VT_I4; V_I4(&vtAdapterTypeId) = 0; } else { VariantClear(&vtAdapterTypeId); V_VT(&vtAdapterTypeId) = VT_I4; V_I4(&vtAdapterTypeId) = 3; } } if( V_VT(&vtAdapterTypeId) != VT_I4 ){ hr = VariantChangeTypeEx(&vtAdapterTypeId,&vtAdapterTypeId,0,0,VT_I4); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } if( V_I4(&vtAdapterTypeId) >= 0 && V_I4(&vtAdapterTypeId) != 3 ){ hr = pclsObj->Get(L"MACAddress", 0, &vtMACAddress, 0, 0); if( FAILED(hr) ) newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); if( V_VT(&vtMACAddress) != VT_NULL ){ if( V_VT(&vtMACAddress) != VT_BSTR ){ hr = VariantChangeTypeEx(&vtMACAddress,&vtMACAddress,0,0,VT_BSTR); newObjectV1C2(HRESULT_CODE(hr) + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } if( s.strlen() > 0 ) s += "\n"; s += utf8::String(V_BSTR(&vtName)) + " " + V_BSTR(&vtMACAddress); } } } } catch( ... ){ pclsObj->Release(); throw; } pclsObj->Release(); } } catch( ... ){ pEnumerator->Release(); throw; } pEnumerator->Release(); } catch( ... ){ pSvc->Release(); throw; } pSvc->Release(); } catch( ... ){ pLoc->Release(); throw; } pLoc->Release(); } catch( ... ){ if( CoInit_hres == S_OK ) CoUninitialize(); throw; } if( CoInit_hres == S_OK ) CoUninitialize(); } catch( ... ){ VariantClear(&vtProcessorId); VariantClear(&vtDescription); VariantClear(&vtDeviceId); VariantClear(&vtName); VariantClear(&vtMACAddress); throw; } VariantClear(&vtProcessorId); VariantClear(&vtDescription); VariantClear(&vtDeviceId); VariantClear(&vtName); VariantClear(&vtMACAddress); intptr_t size = s.size(), i; union { uint8_t * a; uint16_t * b; uint32_t * c; }; a = (uint8_t *) s.c_str(); for( i = size - 1; i >= 0; i-- ) xchg(a[a[i] % size],a[a[size - i - 1] % size]); b = (uint16_t *) s.c_str(); for( size /= 2, i = size - 1; i >= 0; i-- ) xchg(b[b[i] % size],b[b[size - i - 1] % size]); c = (uint32_t *) s.c_str(); for( size /= 2, i = size - 1; i >= 0; i-- ) xchg(c[c[i] % size],c[c[size - i - 1] % size]); return s; #elif (HAVE_SYS_IOCTL_H && HAVE_SYS_SYSCTL_H && HAVE_NET_IF_H && HAVE_NET_IF_TYPES_H) || HAVE_DO_CPUID utf8::String key; #if HAVE_DO_CPUID u_int regs[4]; do_cpuid(1,regs); u_int cpu_id = regs[0]; // eax // regs[2]; // ecx u_int cpu_feature = regs[3]; // edx if( cpu_feature & CPUID_PSN ){ do_cpuid(3,regs); char cpuSerial[32]; snprintf(cpuSerial, sizeof(cpuSerial), "%04x-%04x-%04x-%04x-%04x-%04x", (cpu_id >> 16), (cpu_id & 0xffff), (regs[3] >> 16), (regs[3] & 0xffff), (regs[2] >> 16), (regs[2] & 0xffff) ); key += cpuSerial; } #endif #if HAVE_SYS_IOCTL_H && HAVE_SYS_SYSCTL_H && HAVE_NET_IF_H && HAVE_NET_IF_TYPES_H int mib[6]; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; /* address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; size_t needed; AutoPtr buf; for(;;){ if( sysctl(mib,6,NULL,&needed,NULL,0) != 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } buf.realloc(needed); if( sysctl(mib,6,buf,&needed,NULL,0) == 0 ) break; if( errno != ENOMEM ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } // Routing table grew, retrying } struct ifreq ifr; struct if_msghdr * ifm, * ifm2 = NULL, * nextifm; struct ifa_msghdr * ifam; struct sockaddr_dl * sdl = NULL, * sdl2 = NULL; const uint8_t * next = buf, * lim = next + needed; while( next < lim ){ ifm = (struct if_msghdr *) next; if( ifm->ifm_type == RTM_IFINFO ){ if( ifm->ifm_data.ifi_datalen == 0 ) ifm->ifm_data.ifi_datalen = sizeof(struct if_data); sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) - sizeof(struct if_data) + ifm->ifm_data.ifi_datalen); } // else { // newObjectV1C2(EINVAL,__PRETTY_FUNCTION__ + utf8::String(" out of sync parsing NET_RT_IFLIST"))->throwSP(); // } // if( ifm->ifm_flags & IFF_UP ); // if( sdl->sdl_type == IFT_ETHER ); if( ifm->ifm_type == RTM_IFINFO && (ifm->ifm_flags & IFF_LOOPBACK) == 0 && sdl->sdl_type == IFT_ETHER ){ if( ifm2 == NULL ) ifm2 = ifm; if( sdl2 == NULL ) sdl2 = sdl; char name[IFNAMSIZ]; memcpy(name,sdl->sdl_data,sizeof(name) < sdl->sdl_nlen ? sizeof(name)-1 : sdl->sdl_nlen); name[sizeof(name) < sdl->sdl_nlen ? sizeof(name)-1 : sdl->sdl_nlen] = '\0'; ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name,name,sizeof(ifr.ifr_name)); ksock::APIAutoInitializer ksockAPIAutoInitializer; int s = socket(ifr.ifr_addr.sa_family,SOCK_DGRAM,0); if( s == INVALID_SOCKET ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( ioctl(s,SIOCGIFCAP,(caddr_t) &ifr) != 0 ){ int32_t err = errno; close(s); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } try { struct rt_addrinfo info; info.rti_info[RTAX_IFA] = (struct sockaddr *) sdl; if( sdl != NULL && sdl->sdl_alen > 0 ){ if( sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ETHER_ADDR_LEN ){ #if HAVE_NET_ETHERNET_H #ifndef NDEBUG fprintf(stderr,"name %s, ether %s\n",name,ether_ntoa((const struct ether_addr *)LLADDR(sdl))); #endif key += ether_ntoa((const struct ether_addr *)LLADDR(sdl)); #else #endif } else { int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; #if HAVE_NET_IF_DL_H #ifndef NDEBUG fprintf(stderr,"name %s, lladdr %s\n",name,link_ntoa(sdl) + n); #endif key += link_ntoa(sdl) + n; #else #endif } } } catch( ExceptionSP & ){ close(s); throw; } close(s); } next += ifm->ifm_msglen; ifam = NULL; while( next < lim ){ nextifm = (struct if_msghdr *) next; if( nextifm->ifm_type != RTM_NEWADDR ) break; if( ifam == NULL ) ifam = (struct ifa_msghdr *) nextifm; next += nextifm->ifm_msglen; } } #endif #ifndef NDEBUG fprintf(stderr,"machine key: %s\n",(const char *) key.getOEMString()); #endif return key; #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); return utf8::String(); #endif #else return utf8::String(); #endif } //--------------------------------------------------------------------------- utf8::String getMachineCleanUniqueKey() { utf8::String key(getMachineUniqueKey()); return base64Encode(key.c_str(),key.size()); } //--------------------------------------------------------------------------- static uint8_t machineCryptKey[sizeof(SHA256_CTX) + 1]; //--------------------------------------------------------------------------- utf8::String getMachineCryptedUniqueKey(const utf8::String & text,const utf8::String & info,SHA256Cryptor * decryptor) { SHA256Cryptor crypt; SHA256Cryptor & cryptor = decryptor != NULL ? *decryptor : crypt; cryptor.threshold(~(uintptr_t) 0); cryptor.init(text.c_str(),text.size()); if( machineCryptKey[sizeof(SHA256_CTX)] == 0 ){ memcpy(machineCryptKey,cryptor.sha256(),cryptor.size()); machineCryptKey[sizeof(SHA256_CTX)] = 1; } SHA256 sha; sha.make(cryptor.sha256(),cryptor.size()); utf8::String key(base64Encode(sha.sha256(),sha.size())); AutoPtr info2; uintptr_t size = info.size(); info2.alloc(size + sizeof(uint32_t) + sizeof(uint32_t)); uint32_t checksum = crc32(0,NULL,0); checksum = crc32(checksum,info.c_str(),size); *(uint32_t *)(info2.ptr() + size) = checksum; cryptor.crypt(info2,info.c_str(),size); cryptor.crypt(info2.ptr() + size,sizeof(uint32_t)); checksum = crc32(0,NULL,0); checksum = crc32(checksum,info2,size + sizeof(uint32_t)); *(uint32_t *)(info2.ptr() + size + sizeof(uint32_t)) = checksum; cryptor.init(text.c_str(),text.size()); return key + base64Encode(info2,size + sizeof(uint32_t) + sizeof(uint32_t)); } //--------------------------------------------------------------------------- #if PRIVATE_RELEASE //--------------------------------------------------------------------------- bool checkMachineBinding(const utf8::String & key,bool abortProgram) { struct tm lt = time2tm(getlocaltimeofday()); if( lt.tm_year < 2008 - 1900 || (lt.tm_year == 2008 - 1900 && lt.tm_mon < 7) ) return false; bool pirate = true, mkey = true, expire = true; try { SHA256Cryptor decryptor; if( machineUniqueCryptedKey().strlen() == 0 ){ machineUniqueCryptedKey() = getMachineCryptedUniqueKey(getMachineCleanUniqueKey(),utf8::String(),&decryptor); } else { memcpy(decryptor.sha256(),machineCryptKey,decryptor.size()); } pirate = mkey = machineUniqueCryptedKey().left(43).strcmp(key.left(43)) != 0; if( key.strlen() > 43 ){ // check expiration date utf8::String info(key.right(key.size() - 43)); AutoPtr info1; uintptr_t size, size2; info1.alloc(size = base64Decode(info,NULL,0)); if( size > sizeof(uint32_t) * 2 ){ base64Decode(info,info1,size); size2 = size - sizeof(uint32_t) - sizeof(uint32_t); uint32_t checksum = crc32(0,NULL,0); checksum = crc32(checksum,info1,size - sizeof(uint32_t)); pirate = *(uint32_t *)(info1.ptr() + size - sizeof(uint32_t)) != checksum || pirate; utf8::String info2; info2.resize(size2); decryptor.crypt(info1,size - sizeof(uint32_t)); memcpy(info2.c_str(),info1,size2); checksum = crc32(0,NULL,0); checksum = crc32(checksum,info1,size2); pirate = *(uint32_t *)(info1.ptr() + size2) != checksum || pirate; // now this is expiration date text from keymaker command line as plain text in info2 uint64_t ld = gettimeofday(); uint64_t ed = timeFromTimeString(info2,false); pirate = (expire = ed > 0 && ld > ed) && pirate; } else { pirate = true; } } else { pirate = true; } } catch( ... ){ pirate = true; } if( pirate ){ if( abortProgram ){ if( !mkey && expire ){ // stdErr.debug(9,utf8::String::Stream() << "Expiration date reached. Aborted...\n"); stdErr.debug(9,utf8::String::Stream() << "nonsystem error 1253. Aborted...\n"); } else { // stdErr.debug(9,utf8::String::Stream() << "Pirate copy detected. Aborted...\n"); stdErr.debug(9,utf8::String::Stream() << "nonsystem error 4298. Aborted...\n"); } exit(EINVAL); } // newObjectV1C2(EINVAL,"Pirate copy detected")->throwSP(); newObjectV1C2(EINVAL,"nonsystem error 1726")->throwSP(); } return pirate; } //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- uint8_t machineUniqueCryptedKeyHolder[sizeof(utf8::String)]; //--------------------------------------------------------------------------- #endif /* DOXYGEN_SHOULD_SKIP_THIS */ //--------------------------------------------------------------------------- void readProtectedMemory(const void * memory,void * data,uintptr_t count) { #if defined(__WIN32__) || defined(__WIN64__) SIZE_T rb; BOOL r = ReadProcessMemory( GetCurrentProcess(), memory, data, count, &rb ); if( r == 0 || rb != count ){ int32_t err = GetLastError(); if( rb != count ) err = ERROR_INVALID_DATA; newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- void writeProtectedMemory(void * memory,const void * data,uintptr_t count) { #if defined(__WIN32__) || defined(__WIN64__) DWORD old; BOOL r = VirtualProtect( memory, count, PAGE_EXECUTE_READWRITE, &old ); if( r == 0 ){ int32_t err = GetLastError(); newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } SIZE_T w; r = WriteProcessMemory( GetCurrentProcess(), memory, data, count, &w ); if( r == 0 || w != count ){ int32_t err = GetLastError(); VirtualProtect(memory,count,old,&old); if( w != count ) err = ERROR_INVALID_DATA; newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } VirtualProtect(memory,count,old,&old); #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); #endif } //--------------------------------------------------------------------------- void * findProcImportedEntryAddress(const utf8::String & dllName,const utf8::String & importedDllName,const utf8::String & funcName,bool noThrow) { #if defined(__WIN32__) || defined(__WIN64__) union { HMODULE hModule; uintptr_t basePointer; }; if( isWin9x() ){ hModule = GetModuleHandleA(dllName.getANSIString()); } else { hModule = GetModuleHandleW(dllName.getUNICODEString()); } if( hModule == NULL ){ if( noThrow ) return NULL; int32_t err = GetLastError(); newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } ULONG size; PVOID importTableOffset = ImageDirectoryEntryToData(hModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size); if( importTableOffset == NULL ){ if( noThrow ) return NULL; int32_t err = GetLastError(); newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } uintptr_t rva = uintptr_t(importTableOffset) - basePointer; for(;;){ uintptr_t dllNameOffset = *(uintptr_t *)(rva + 12 + basePointer); if( dllNameOffset == 0 ){ if( noThrow ) return NULL; newObjectV1C2(ERROR_INVALID_DATA + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } if( utf8::String((const char *)(basePointer + dllNameOffset)).strcasecmp(importedDllName) != 0 ){ rva += 20; continue; } uintptr_t funcNamesOffset = *(uintptr_t *)(rva + basePointer), nFuncName = 0; for(;;){ uintptr_t funcNameOffset = *(uintptr_t *)(funcNamesOffset + basePointer); if( funcNameOffset == 0 ){ if( noThrow ) return NULL; newObjectV1C2(ERROR_INVALID_DATA + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } nFuncName++; utf8::String name((const char *)(basePointer + funcNameOffset) + 2); if( name.strcmp(funcName) != 0 ){ funcNamesOffset += sizeof(uintptr_t); nFuncName++; continue; } uintptr_t funcAddrsOffset = *(uintptr_t *)(rva + 16 + basePointer), nFuncAddr = 0; for(;;){ uintptr_t funcAddrOffset = *(uintptr_t *)(funcAddrsOffset + basePointer); if( funcAddrOffset == 0 ){ if( noThrow ) return NULL; newObjectV1C2(ERROR_INVALID_DATA + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } nFuncAddr++; if( nFuncAddr != nFuncName ){ funcAddrsOffset += sizeof(uintptr_t); nFuncAddr++; continue; } return (void *) (funcAddrsOffset + basePointer); } } } #else newObjectV1C2(ENOSYS,__PRETTY_FUNCTION__)->throwSP(); return NULL; #endif } //--------------------------------------------------------------------------- bool isDaemonCommandLineOption() { utf8::String opt("--daemon"); for( uintptr_t i = 1; i < argv().count(); i++ ) if( argv()[i].strcmp(opt) == 0 ) return true; return false; } //--------------------------------------------------------------------------- void daemonize() { #if !defined(__WIN32__) && !defined(__WIN64__) struct sigaction osa, sa; pid_t newgrp; int oerrno; int osa_ok; // A SIGHUP may be thrown when the parent exits below. sigemptyset(&sa.sa_mask); sa.sa_handler = SIG_IGN; sa.sa_flags = 0; osa_ok = sigaction(SIGHUP,&sa,&osa); if( osa_ok != 0 ){ perror(NULL); abort(); } switch( fork() ){ case -1 : perror(NULL); abort(); case 0 : break; default : exit(0); } newgrp = setsid(); oerrno = errno; sigaction(SIGHUP,&osa,NULL); if( newgrp == -1 ){ errno = oerrno; perror(NULL); abort(); } #endif } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// // System initialization and finalization /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- void initializeArguments(int argc,char ** argv) { ksys::argv().resize(argc); while( --argc >= 0 ) ksys::argv()[argc] = argv[argc]; } //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { switch( dwCtrlType ){ default : case CTRL_C_EVENT : case CTRL_BREAK_EVENT : case CTRL_CLOSE_EVENT : case CTRL_LOGOFF_EVENT : case CTRL_SHUTDOWN_EVENT : while( PostThreadMessage(mainThreadId,WM_QUIT,0,0) == 0 ) ksleep1(); } return TRUE; } #elif HAVE_SIGNAL_H static uint8_t signalsCountersSemPlaceHolder[sizeof(Semaphore)]; static inline Semaphore & signalsCountersSem() { return *reinterpret_cast(signalsCountersSemPlaceHolder); } void waitForSignalsSemaphore() { signalsCountersSem().wait(); } volatile uilock_t signalsCounters[_SIG_MAXSIG]; static void sigHandler(int sig,siginfo_t * siginfo,ucontext_t * uap) { interlockedIncrement(signalsCounters[sig - 1],1); signalsCountersSem().post(); } #endif //--------------------------------------------------------------------------- void initialize(int argc,char ** argv) { // runtime checks for system or compiler incompatibilities assert( sizeof(char) == 1 ); if( sizeof(char) != 1 ){ fprintf(stderr,"sizeof(char) != 1\n"); abort(); } assert( (unsigned int) false == 0 ); if( (unsigned int) false != 0 ){ fprintf(stderr,"(unsigned int) false != 0\n"); abort(); } assert( (unsigned int) !1 == 0 ); if( (unsigned int) !1 != 0 ){ fprintf(stderr,"(unsigned int) !1 != 0\n"); abort(); } assert( (unsigned int) !0 == 1 ); if( (unsigned int) !0 != 1 ){ fprintf(stderr,"(unsigned int) !0 != 1\n"); abort(); } #if HAVE__TZSET _tzset(); #elif HAVE_TZSET tzset(); #endif #if defined(__WIN32__) || defined(__WIN64__) // force the system to create the message queue for main thread (if not already created) MSG msg; SetLastError(0); PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE); if( GetLastError() != 0 ){ perror(NULL); abort(); } mainThreadId = GetCurrentThreadId(); threadFinishMessage = RegisterWindowMessageA("F07E92E6-81C9-441D-98D6-4D9802D81956"); fiberFinishMessage = RegisterWindowMessageA("A08C6FDA-1417-43C5-A17D-D146500B5886"); SetProcessShutdownParameters(0x400,SHUTDOWN_NORETRY); SetConsoleCtrlHandler(consoleCtrlHandler,TRUE); #else if( processStartTime == 0 ) processStartTime = gettimeofday(); #if HAVE_SIGNAL_H new (signalsCountersSemPlaceHolder) Semaphore; sigset_t ss; if( sigemptyset(&ss) != 0 || sigaddset(&ss,SIGSYS) != 0 || sigprocmask(SIG_BLOCK,&ss,NULL) != 0 ){ perror(NULL); abort(); } struct sigaction act;//, oact; memset(&act,0,sizeof(act)); act.sa_flags = SA_SIGINFO; act.sa_handler = (void (*)(int)) sigHandler; if( sigaction(SIGHUP,&act,NULL) != 0 || sigaction(SIGINT,&act,NULL) != 0 || sigaction(SIGQUIT,&act,NULL) != 0 || sigaction(SIGTERM,&act,NULL) != 0 || sigaction(SIGXCPU,&act,NULL) != 0 || sigaction(SIGXFSZ,&act,NULL) != 0 ){ perror(NULL); abort(); } #endif #endif Object::initialize(); LZO1X::initialize(); //--------------------------------------------------------------------------- { intptr_t i; memset(base64DecodeTable,~0u,sizeof(base64DecodeTable)); for( i = sizeof(base64Table) / sizeof(base64Table[0]) - 1; i >= 0; i-- ) base64DecodeTable[uintptr_t(base64Table[i])] = (uint8_t) i; memset(base32DecodeTable,~0u,sizeof(base32DecodeTable)); for( i = sizeof(base32Table) / sizeof(base32Table[0]) - 1; i >= 0; i-- ) base32DecodeTable[uintptr_t(base32Table[i])] = (uint8_t) i; } //--------------------------------------------------------------------------- InterlockedMutex::initialize(); MemoryManager::initialize(); Thread::initialize(); MemoryStream::initialize(); Mutant::initialize(); utf8::String::initialize(); new (argvPlaceHolder) Array; initializeArguments(argc,argv); strErrorInitialize(); Fiber::initialize(); BaseThread::initialize(); AsyncFile::initialize(); LogFile::initialize(); Config::initialize(); #ifdef NETMAIL_ENABLE_PROFILER TProfiler::initialize(); #endif ksock::api.initialize(); try { utf8::String cwd(getCurrentDir()); utf8::String::Iterator i(cwd); while( !i.eos() ){ uintptr_t c = i.getChar(); if( c == '\\' || c == '/' ){ pathDelimiter = char(c); pathDelimiterStr[0] = char(c); pathDelimiterStr[1] = '\0'; break; } i.next(); } } catch( ... ){ } new (machineUniqueCryptedKeyHolder) utf8::String(); #if HAVE_CLOCK_GETRES // struct timespec ts; // clock_getres(CLOCK_REALTIME,&ts); // fprintf(stderr,"timer resolution: %ld %ld\n",ts.tv_sec,ts.tv_nsec); // uint64_t t2 = gettimeofday(), t3 = 0; // while( gettimeofday() - t2 < 2000000u ){ // clock_gettime(CLOCK_REALTIME,&ts); // if( t3 < (uint64_t) ts.tv_nsec ) t3 = ts.tv_nsec; // } // fprintf(stderr,"max tv_nsec: %"PRIu64"\n",t3); // Semaphore sem; // uint64_t t0 = gettimeofday(), t1 = t0; // sem.timedWait(1000000u); // t0 = gettimeofday() - t0; // struct timespec ts0, ts1; // clock_gettime(CLOCK_REALTIME,&ts0); // ksleep(1000000u); // clock_gettime(CLOCK_REALTIME,&ts1); // fprintf(stderr,"sem_timedwait: %"PRIu64", start %ld %ld, stop %ld %ld, tod %"PRIu64"\n",t0,ts0.tv_sec,ts0.tv_nsec,ts1.tv_sec,ts1.tv_nsec,t1 / 1000000u); // fprintf(stderr,"stop - start %ld %ld\n",ts1.tv_sec - ts1.tv_sec,ts1.tv_nsec - ts0.tv_nsec); #endif } //--------------------------------------------------------------------------- void cleanup() { stdErr.close(); machineUniqueCryptedKey().~String(); ksock::api.cleanup(); #ifdef NETMAIL_ENABLE_PROFILER TProfiler::cleanup(); #endif Config::cleanup(); LogFile::cleanup(); AsyncFile::cleanup(); BaseThread::cleanup(); Fiber::cleanup(); strErrorCleanup(); argv().~Array(); utf8::String::cleanup(); Mutant::cleanup(); MemoryStream::cleanup(); Thread::cleanup(); MemoryManager::cleanup(); InterlockedMutex::cleanup(); Object::cleanup(); #if defined(__WIN32__) || defined(__WIN64__) SetConsoleCtrlHandler(consoleCtrlHandler,FALSE); #elif HAVE_SIGNAL_H signalsCountersSem().~Semaphore(); #endif } //--------------------------------------------------------------------------- } // namespace ksys //--------------------------------------------------------------------------- intptr_t memncmp(const void * m1,const void * m2,uintptr_t n) { intptr_t c = 0; while( n-- > 0 ){ c = intptr_t(*(const uint8_t *) m1) - intptr_t(*(const uint8_t *) m2); if( c != 0 ) break; m1 = (const uint8_t *) m1 + 1; m2 = (const uint8_t *) m2 + 1; } return c; } //--------------------------------------------------------------------------- intptr_t memncmp(const void * m1,uintptr_t n1,const void * m2,uintptr_t n2) { intptr_t c = n1 - n2; for(;;){ if( c != 0 || n1 == 0 ) break; c = intptr_t(*(const uint8_t *) m1) - intptr_t(*(const uint8_t *) m2); m1 = (const uint8_t *) m1 + 1; m2 = (const uint8_t *) m2 + 1; n1--; } return c; } //---------------------------------------------------------------------------