/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ #include #include #include #pragma unmanaged #pragma warning (disable: 4995) // '_snprintf': name was marked as #pragma deprecated DrError DrStringToSignedOrUnsignedInt64(const char *psz, UInt64 *pResult, bool fSigned) { UInt64 v = 0; UInt64 vnew; bool neg = false; bool gotDig = false; int base = 10; while (ISSPACE(*psz)) { psz++; } if (*psz == '+') { psz++; } else if (fSigned && *psz == '-') { neg = true; psz++; } if (*psz == '0' && (*(psz+1) == 'x' ||*(psz+1) == 'X') ) { psz += 2; base = 16; } if (base == 16 && neg == false) { // we allow hex constants to set the sign bit. fSigned = false; } while (*psz != '\0' && !ISSPACE(*psz)) { int dig = -1; if (*psz >= '0' && *psz <= '9') { dig = *psz - '0'; } else if (*psz >= 'a' && *psz <= 'f') { dig = *psz - 'a' + 10; } else if (*psz >= 'A' && *psz <= 'F') { dig = *psz - 'A' + 10; } if (dig < 0 || dig >= base) { return DrError_InvalidParameter; } vnew = v * base + dig; if ((fSigned && (Int64)vnew < 0) || ((vnew - dig)/base != v)) { // overflow return DrError_InvalidParameter; } v = vnew; gotDig = true; psz++; } if (!gotDig) { return DrError_InvalidParameter; } while (ISSPACE(*psz)) { psz++; } if (*psz != '\0') { return DrError_InvalidParameter; } if (neg) { v= (UInt64)(-(Int64)v); } *pResult = v; return DrError_OK; } DrError DrStringToFloat(const char *psz, float *pResult) { double v; DrError err = DrStringToDouble(psz, &v); if (err == DrError_OK) { *pResult = (float)v; } return err; } DrError DrStringToUInt64(const char *psz, UInt64 *pResult) { return DrStringToSignedOrUnsignedInt64(psz, pResult, false); } DrError DrStringToInt64(const char *psz, Int64 *pResult) { return DrStringToSignedOrUnsignedInt64(psz, (UInt64 *)(void *)pResult, true); } DrError DrStringToUInt16(const char *psz, UInt16 *pResult) { UInt64 v; DrError err = DrStringToSignedOrUnsignedInt64(psz, &v, false); if (err != DrError_OK) { return err; } UInt16 v16 = (UInt16)v; if (v != (UInt64)v16) { return DrError_InvalidParameter; } *pResult = v16; return DrError_OK; } DrError DrStringToUInt32(const char *psz, UInt32 *pResult) { UInt64 v; DrError err = DrStringToSignedOrUnsignedInt64(psz, &v, false); if (err != DrError_OK) { return err; } UInt32 v32 = (UInt32)v; if (v != (UInt64)v32) { return DrError_InvalidParameter; } *pResult = v32; return DrError_OK; } DrError DrStringToInt32(const char *psz, Int32 *pResult) { Int64 v; DrError err = DrStringToSignedOrUnsignedInt64(psz, (UInt64 *)(void *)&v, true); if (err != DrError_OK) { return err; } Int32 v32 = (Int32)v; if (v != (Int64)v32) { return DrError_InvalidParameter; } *pResult = v32; return DrError_OK; } DrError DrStringToUInt(const char *psz, unsigned int *pResult) { UInt64 v; DrError err = DrStringToSignedOrUnsignedInt64(psz, &v, false); if (err != DrError_OK) { return err; } unsigned int v32 = (unsigned int)v; if (v != (UInt64)v32) { return DrError_InvalidParameter; } *pResult = v32; return DrError_OK; } DrError DrStringToInt(const char *psz, int *pResult) { Int64 v; DrError err = DrStringToSignedOrUnsignedInt64(psz, (UInt64 *)(void *)&v, true); if (err != DrError_OK) { return err; } int v32 = (int)v; if (v != (Int64)v32) { return DrError_InvalidParameter; } *pResult = v32; return DrError_OK; } DrError DrStringToDouble(const char *psz, double *pResult) { double v = 0; int exponent = 0; bool neg = false; bool gotDig = false; bool gotPoint = false; while (ISSPACE(*psz)) { psz++; } if (*psz == '+') { psz++; } else if (*psz == '-') { neg = true; psz++; } while (*psz != '\0' && !ISSPACE(*psz) && *psz != 'e' && *psz != 'E') { int dig = -1; if (!gotPoint && *psz == '.') { gotPoint = true; psz++; continue; } else if (*psz >= '0' && *psz <= '9') { dig = *psz - '0'; } if (dig < 0 || dig >= 10) { return DrError_InvalidParameter; } v = v * 10.0 + dig; if (gotPoint) { exponent--; } gotDig = true; psz++; } if (!gotDig) { return DrError_InvalidParameter; } if (*psz == 'e' || *psz == 'E') { psz++; Int32 exp2; DrError err = DrStringToInt32(psz, &exp2); if (err != DrError_OK) { return err; } exponent += exp2; } else { while (ISSPACE(*psz)) { psz++; } if (*psz != '\0') { return DrError_InvalidParameter; } } if (exponent != 0) { v = v * pow((double) 10, exponent); } if (neg) { v= -v; } *pResult = v; return DrError_OK; } DrError DrStringToBool(const char *psz, bool *pResult) { bool ret = false; char tmp[16]; size_t length = 0; while (ISSPACE(*psz)) { psz++; } while (length < 15 && *psz != '\0' && !ISSPACE(*psz)) { tmp[length++] = *(psz++); } tmp[length] = '\0'; while (ISSPACE(*psz)) { psz++; } if (*psz != '\0') { return DrError_InvalidParameter; } _strlwr(tmp); length++; if (strncmp(tmp, "true", length) == 0 || strncmp(tmp, "yes", length) == 0 || strncmp(tmp, "on", length) == 0 || strncmp(tmp, "1", length) == 0) { ret = true; } else if ( strncmp(tmp, "false", length) == 0 || strncmp(tmp, "no", length) == 0 || strncmp(tmp, "off", length) == 0 || strncmp(tmp, "0", length) == 0) { ret = false; } else { return DrError_InvalidParameter; } *pResult = ret; return DrError_OK; } DrError DrStringToSizeEx(PCSTR psz, UInt64* result, bool allowNegative) { if ( psz == NULL || result == NULL ) { return DrError_InvalidParameter; } char buf[48]; DrError err = StringCbCopyA( buf, sizeof( buf ), psz ); if ( FAILED( err ) ) { return DrError_InvalidParameter; } UInt32 shift = 0; Size_t len = strlen(psz); if ( len > 2 ) { PCSTR tail = buf + len - 2; if ( _stricmp( tail, "KB" ) == 0 ) { shift = 10; } else if ( _stricmp( tail, "MB" ) == 0 ) { shift = 20; } else if ( _stricmp( tail, "GB" ) == 0 ) { shift = 30; } else if ( _stricmp( tail, "TB" ) == 0 ) { shift = 40; } else if ( _stricmp( tail, "PB" ) == 0 ) { shift = 50; } } if ( shift != 0 ) { buf[len - 2] = 0; } //check if dot is present PSTR dot = strchr( buf, '.' ); if ( dot != NULL ) { // can't have fractions if size specifier is not present if ( shift == 0 ) { return DrError_InvalidParameter; } *dot = 0; } bool negative = false; UInt64 r1; err = DrStringToSignedOrUnsignedInt64( buf, &r1, allowNegative ); if ( err != DrError_OK ) { return err; } if ( allowNegative && ((Int64)r1 < 0ui64) ) { negative = true; r1 = (UInt64)-(Int64)r1; } UInt64 maxVal = allowNegative ? MAX_INT64 : MAX_UINT64; if ( dot != NULL ) { maxVal >>= 4; // reserve space for fraction } maxVal >>= shift; if ( r1 > maxVal ) { return DrError_InvalidParameter; } r1 <<= shift; if ( dot != NULL ) { char buf2[48]; buf2[0] = '0'; buf2[1] = '.'; buf2[2] = 0; err = StringCbCatA( buf2, sizeof(buf2), dot + 1 ); if ( FAILED( err ) ) { return DrError_InvalidParameter; } double rd; err = DrStringToDouble( buf2, &rd ); if ( err != DrError_OK ) { return err; } rd *= 1ui64 << shift; r1 += (UInt64)rd; } if ( negative ) { r1 = (UInt64)-(Int64)r1; } *result = r1; return DrError_OK; } DrError DrStringToSize(PCSTR psz, UInt64* result) { return DrStringToSizeEx( psz, result, false ); } DrError DrStringToIntegerSize(PCSTR psz, Int64* result) { return DrStringToSizeEx( psz, (UInt64*)result, true ); } // // Close session after completing outstanding requests // DrError DryadShutdown(); // // Same as ExitProcess, but flushes logging and stdout/stderr first... // void DrExitProcess(UInt32 exitCode) { // // Close the cluster connection // DrError e = DryadShutdown(); if (e == DrError_OK) { DrLogI("Completed uninitialize dryad"); } else { DrLogE("Couldn't uninitialize dryad"); } // // Flush output logs // fflush(stdout); DrLogging::FlushLog(); // // Exit the current process // ExitProcess((UINT)exitCode); } DrError DrSystemTimeToTimeStamp(const SYSTEMTIME *pSystemTime, DrTimeStamp *pTimeStamp, bool fFromLocalTimeZone) { union { FILETIME ft; DrTimeStamp ts; }; union { FILETIME ft2; DrTimeStamp ts2; }; if (!SystemTimeToFileTime(pSystemTime, &ft)) { return DrGetLastError(); } if (fFromLocalTimeZone && ts != DrTimeStamp_LongAgo && ts != DrTimeStamp_Never) { if (!LocalFileTimeToFileTime(&ft, &ft2)) { return DrGetLastError(); } *pTimeStamp = ts2; } else { *pTimeStamp = ts; } return DrError_OK; } // Returns UTC time DrTimeStamp DrGetCurrentTimeStamp() { union { FILETIME ft; DrTimeStamp ts; }; GetSystemTimeAsFileTime(&ft); return ts; } DrTimeInterval DrGetCurrentLocalTimeZoneBias() { TIME_ZONE_INFORMATION tzi; LONG biasMinutes; DWORD dwRet = GetTimeZoneInformation(&tzi); switch(dwRet) { case TIME_ZONE_ID_UNKNOWN: biasMinutes = tzi.Bias; break; case TIME_ZONE_ID_STANDARD: biasMinutes = tzi.Bias + tzi.StandardBias; break; case TIME_ZONE_ID_DAYLIGHT: biasMinutes = tzi.Bias + tzi.DaylightBias; break; default: LogAssert(dwRet != dwRet); return DrTimeInterval_Zero; } DrTimeInterval bias = DrTimeInterval_Minute * biasMinutes; return bias; } DrError DrGenerateTimeZoneBiasSuffix(DrTimeInterval bias, char *szBuff, size_t nbBuff) { if (bias == DrTimeInterval_Zero) { if (nbBuff < 2) { return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } szBuff[0]= 'Z'; szBuff[1] = '\0'; return DrError_OK; } else { if (nbBuff < 4) { return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } *(szBuff++)= 'L'; nbBuff--; char s = '+'; if (bias < DrTimeInterval_Zero) { s = '-'; bias = -bias; } *(szBuff++)= s; nbBuff--; *szBuff = '\0'; return DrTimeIntervalToString(bias, szBuff, nbBuff); } } __inline DrError DrMultiplyTimeInterval(DrTimeInterval *pValue, Int64 n) { DrTimeInterval v2 = *pValue * n; if (n != 0 && v2 / n != *pValue) { return DrError_InvalidTimeInterval; } *pValue = v2; return DrError_OK; } static DrError DrAddDeltaUnitTimeInterval(DrTimeInterval *pValue, Int64 n, DrTimeInterval units) { DrError err = DrMultiplyTimeInterval(&units, n); if (err != DrError_OK) { return err; } // if the signs of the two addends are the same, we have to check for overflow in the result bool checkSign = ((*pValue >= DrTimeInterval_Zero) == (units >= DrTimeInterval_Zero)); *pValue += units; // if the signs of the two addends were the same, they still should be if (checkSign && (*pValue >= DrTimeInterval_Zero) != (units >= DrTimeInterval_Zero)) { return DrError_InvalidTimeInterval; } return DrError_OK; } // Converts a time interval string to a DrTimeInterval. // If len is -1, it is computed with strlen. // Strings must include units; e.g., "105.42s" or "12d5h10m". DrError DrStringToTimeInterval(const char *pszString, DrTimeInterval *pTimeInterval, int len) { DrError err = DrError_OK; DrTimeInterval val = 0; bool neg = false; char szBuff[32]; if (pszString == NULL) { return DrError_InvalidTimeInterval; } if (pszString[0] == '+') { pszString++; } else if (pszString[0] == '-') { pszString++; neg = true; } if (len < 0) { len = (int)strlen(pszString); } if (len == 0 || *pszString == '\0') { return DrError_InvalidTimeInterval; } if (len == 8 && _strnicmp(pszString, "infinite", 8) == 0) { *pTimeInterval = DrTimeInterval_Infinite; return DrError_OK; } if (len == 16 && _strnicmp(pszString, "negativeinfinite", 16) == 0) { *pTimeInterval = DrTimeInterval_NegativeInfinite; return DrError_OK; } if (len == 1 && pszString[0] == '0') { *pTimeInterval = DrTimeInterval_Zero; return DrError_OK; } int i = 0; while (i < len && pszString[i] != '\0') { UInt64 n = 0; UInt64 frac = 0; int nFrac = 0; int nDig = 0; while (nDig < 31 && i < len && pszString[i] >= '0' && pszString[i] <= '9') { szBuff[nDig++] = pszString[i]; i++; } if (nDig > 0) { szBuff[nDig] = '\0'; err = DrStringToUInt64(szBuff, &n); if (err != DrError_OK || (Int64)n < 0) { return DrError_InvalidTimeInterval; } } if (i < len && pszString[i] == '.') { i++; while (nFrac < 31 && i < len && pszString[i] >= '0' && pszString[i] <= '9') { szBuff[nFrac++] = pszString[i]; i++; } if (nFrac > 0) { szBuff[nFrac] = '\0'; err = DrStringToUInt64(szBuff, &frac); if (err != DrError_OK || (Int64)frac < 0) { return DrError_InvalidTimeInterval; } } } if (nDig == 0 && nFrac == 0) { return DrError_InvalidTimeInterval; } char szUnit[2]; szUnit[0] = ' '; szUnit[1] = ' '; for (int k = 1; k >= 0; --k) { if (i < len && pszString[i] != '\0' && (pszString[i] < '0' || pszString[i] > '9') && pszString[i] != '.') { szUnit[k] = pszString[i++]; if (szUnit[k] >= 'A' && szUnit[k] <= 'Z') { szUnit[k] = szUnit[k] - 'A' + 'a'; } } else { break; } } int tag = (int)*(WORD *)(void *)szUnit; DrTimeInterval units = 0; int fracKeep = 0; // # of fraction digits to keep DrTimeInterval fracunits; switch(tag) { default: return DrError_InvalidTimeInterval; case 'q ': units = DrTimeInterval_Quantum; fracunits = DrTimeInterval_Quantum; fracKeep = 0; break; case 'us': units = DrTimeInterval_Microsecond; fracunits = DrTimeInterval_Quantum; fracKeep = 1; // 10 microseconds per interval break; case 'ms': units = DrTimeInterval_Millisecond; fracunits = DrTimeInterval_Quantum; fracKeep = 4; // 10,000 break; case 's ': units = DrTimeInterval_Second; fracunits = 1; fracKeep = 7; // 10,000,000 break; case 'm ': units = DrTimeInterval_Minute; fracunits = DrTimeInterval_Minute / 100000000; fracKeep = 8; // 600,000,000 break; case 'h ': units = DrTimeInterval_Hour; fracunits = DrTimeInterval_Hour / 1000000000; fracKeep = 9; // 36,000,000,000 break; case 'd ': units = DrTimeInterval_Day; fracunits = DrTimeInterval_Day / 1000000000; fracKeep = 9; // 864,000,000,000 break; case 'w ': units = DrTimeInterval_Week; fracunits = DrTimeInterval_Week / 1000000000; fracKeep = 9; // 6,048,000,000,000 break; case 'y ': units = DrTimeInterval_Year; fracunits = DrTimeInterval_Year / 1000000000; fracKeep = 9; // 314,496,000,000,000 break; } // Normalize the fraction to the correct number of digits while (nFrac > fracKeep) { frac = frac / 10; nFrac--; } while (nFrac < fracKeep) { frac = frac * 10; nFrac++; } // result should be n*units + frac*fracunits err = DrAddDeltaUnitTimeInterval(&val, (Int64)n, units); if (err != DrError_OK) { return err; } err = DrAddDeltaUnitTimeInterval(&val, (Int64)frac, fracunits); if (err != DrError_OK) { return err; } } if (neg) { val = -val; } *pTimeInterval = val; return DrError_OK; } DrError DrTimeStampToString(DrTimeStamp timeStamp, char *pBuffer, int buffLen, DrTimeInterval bias, Int32 nFracDig) { SYSTEMTIME st; if (timeStamp == DrTimeStamp_Never) { if (buffLen < 6) { return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } strncpy(pBuffer, "never", 6); return DrError_OK; } else if (timeStamp == DrTimeStamp_LongAgo) { if (buffLen < 9) { return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); } strncpy(pBuffer, "longago", 9); return DrError_OK; } if (bias == DrTimeInterval_Infinite) { bias = DrGetCurrentLocalTimeZoneBias(); } timeStamp -= bias; DrError err = DrTimeStampToSystemTime(timeStamp, &st, false); if (err != DrError_OK) { return err; } if (nFracDig < 0) { if (st.wMilliseconds == 0) { nFracDig = 0; } else { nFracDig = 3; } } char szFrac[16]; if (nFracDig == 0) { szFrac[0] = '\0'; } else { szFrac[0] = '.'; LogAssert(st.wMilliseconds < 1000); sprintf(szFrac+1, "%03u", st.wMilliseconds); if (nFracDig > 3) { if (nFracDig > 7) { nFracDig = 7; } // Compute quantum ticks in excess of 1ms boundary UInt32 remainder = (UInt32)(timeStamp % 10000); sprintf(szFrac+4, "%04u", remainder); } szFrac[nFracDig+1] = '\0'; } if (bias == DrTimeInterval_Zero) { // No local time bias -- Zulu time _snprintf(pBuffer, (size_t)buffLen, "%04u-%02u-%02uT%02u:%02u:%02u%sZ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, szFrac); } else { // Local time zone bias char szSuffix[k_DrTimeIntervalStringBufferSize+2]; const char *suffix; err = DrGenerateTimeZoneBiasSuffix(bias, szSuffix, ELEMENTCOUNT(szSuffix)); LogAssert(err == DrError_OK); suffix = szSuffix; _snprintf(pBuffer, (size_t)buffLen, "%04u-%02u-%02uT%02u:%02u:%02u%s%s", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, szFrac, suffix); } return DrError_OK; } // Converts a Dryad timeinterval to a human-readable string. // The generated string may be fed back into DrStringToTimeInterval DrError DrTimeIntervalToString(DrTimeInterval timeInterval, char *pBuffer, size_t buffLen) { LogAssert(pBuffer != NULL); LogAssert(buffLen != 0); char tempBuff[k_DrTimeIntervalStringBufferSize]; char *pBuff = pBuffer; if (buffLen < k_DrTimeIntervalStringBufferSize) { // use a temporary buffer if we aren't sure it will fit pBuff = tempBuff; } DrError err = DrError_OK; if (timeInterval == DrTimeInterval_Infinite) { strcpy(pBuff, "infinite"); } else if (timeInterval == DrTimeInterval_NegativeInfinite) { strcpy(pBuff, "negativeinfinite"); } else { bool neg = (timeInterval < DrTimeInterval_Zero); UInt64 v; if (neg) { v = (UInt64)(-timeInterval); } else { v = (UInt64)timeInterval; } UInt32 frac100ns = (UInt32)(v % DrTimeInterval_Second); v = v / DrTimeInterval_Second; UInt32 sec = (UInt32)(v % (UInt32)60); v = v / 60; UInt32 min = (UInt32)(v % (UInt32)60); v = v / 60; UInt32 hr = (UInt32)(v % (UInt32)24); v = v / 24; // v now contains days int i =0; if (neg) { pBuff[i++] = '-'; } int ret = 0; bool fOutput = false; if (v != 0) { ret = _snprintf(pBuff+i, k_DrTimeIntervalStringBufferSize-i-1, "%I64ud", v); LogAssert(ret > 0); i += ret; fOutput = true; } if (hr != 0 || (fOutput && (min != 0 || sec != 0 || frac100ns != 0))) { fOutput = true; ret = _snprintf(pBuff+i, k_DrTimeIntervalStringBufferSize-i-1, "%uh", hr); LogAssert(ret > 0); i += ret; } if (min != 0 || (fOutput && (sec != 0 || frac100ns != 0))) { fOutput = true; ret = _snprintf(pBuff+i, k_DrTimeIntervalStringBufferSize-i-1, "%um", min); LogAssert(ret > 0); i += ret; } if (frac100ns == 0) { // whole number of seconds if (sec != 0 || !fOutput) { fOutput = true; ret = _snprintf(pBuff+i, k_DrTimeIntervalStringBufferSize - i - 1, "%us", sec); LogAssert(ret > 0); i += ret; } } else { // fractional seconds fOutput = true; ret = _snprintf(pBuff+i, k_DrTimeIntervalStringBufferSize - i - 1, "%u.%07u", sec, frac100ns); LogAssert(ret > 0); i += ret; // remove traling "0" characters while (i > 0 && pBuff[i-1] == '0') { --i; } LogAssert((size_t)i+2 < k_DrTimeIntervalStringBufferSize); pBuff[i++] = 's'; pBuff[i] = '\0'; } } if (err == DrError_OK && pBuff == tempBuff) { size_t n = strlen(tempBuff) + 1; if (n <= buffLen) { memcpy(pBuffer, tempBuff, n); } else { err = DrError_StringTooLong; pBuffer[0] = '\0'; } } return err; } DrError DrTimeStampToString(DrTimeStamp timeStamp, char *pBuffer, int buffLen, bool fToLocalTimeZone, Int32 nFracDig) { return DrTimeStampToString(timeStamp, pBuffer, buffLen, fToLocalTimeZone ? DrTimeInterval_Infinite : DrTimeInterval_Zero, nFracDig); } DrError DrStringToTimeStamp(const char *pszTime, DrTimeStamp *pTimeStampOut, DrTimeInterval defaultTimeZoneBias) { // 2006-04-18 13:06:44 // 2006-04-18T13:06:44.mmmL+8h // 2006-04-18T13:06:44.mmm-08:00 // 2006-04-18T13:06:44.mmmZ // 01234567890123456789 // +timeinterval // -timeinterval DrError err = DrError_OK; UInt32 uYear; UInt32 uMonth; UInt32 uDay; UInt32 uHour = 0; UInt32 uMinute = 0; UInt32 uSecond = 0; UInt32 uFrac = 0; UInt32 nFracDigs = 0; DrTimeInterval bias = defaultTimeZoneBias; // If the first character is "+" or "-", it is a relative time interval to the current time if (pszTime != NULL && (pszTime[0] == '-' || pszTime[0] == '+')) { DrTimeInterval ti; err = DrStringToTimeInterval(pszTime, &ti); if (err == DrError_OK) { *pTimeStampOut = DrGetCurrentTimeStamp() + ti; } return err; } // If the string consists entirely of digits, it is a simple decimal encoding of a DrTimeStamp. We optimize for this case: if (pszTime != NULL) { char c1 = *pszTime; // An early detector, numbers that don't start with 1 or 2 (for year) are usually simple numbers if ((c1 >= '0' && c1 < '1') || (c1 >= '3' && c1 <= '9')) { goto trySimple; } // If first 5 chars are numeric, it is probably a simple number for (UInt32 i = 0; i < 5; i++) { if (pszTime[i] == '\0') { break; } else if (pszTime[i] < '0' || pszTime[i] > '9') { goto notSimple; } } trySimple: // might be a simple number err = DrStringToUInt64(pszTime, pTimeStampOut); if (err == DrError_OK) { return err; } // If not a simple number, fall through to try string forms... } notSimple: DrStr32 strTime(pszTime); if (strTime.GetLength() == 7 && strTime == "longago") { *pTimeStampOut = DrTimeStamp_LongAgo; return DrError_OK; } else if (strTime == "never") { *pTimeStampOut = DrTimeStamp_Never; return DrError_OK; } if (strTime.GetLength() < 10 || strTime.GetLength() > 40) { return DrError_InvalidParameter; } char *psz = &(strTime[0]); if (psz[4] != '-') { return DrError_InvalidParameter; } psz[4] = '\0'; err = DrStringToUInt32(psz, &uYear); if (err != DrError_OK) { return err; } if (uYear < 1600 || uYear > 9999) { return DrError_InvalidParameter; } psz += 5; if (psz[2] != '-') { return DrError_InvalidParameter; } psz[2] = '\0'; err = DrStringToUInt32(psz, &uMonth); if (err != DrError_OK) { return err; } if (uMonth < 1 || uMonth > 12) { return DrError_InvalidParameter; } psz += 3; char chNext = psz[2]; psz[2] = '\0'; err = DrStringToUInt32(psz, &uDay); if (err != DrError_OK) { return err; } if (uDay < 1 || uDay > 31) { return DrError_InvalidParameter; } if (chNext == '\0') { psz += 2; } else { psz += 3; } if (chNext == ' ' || chNext == 'T') { // there is HH:MM:SS if (strTime.GetLength() < 19) { return DrError_InvalidParameter; } if (psz[2] != ':') { return DrError_InvalidParameter; } psz[2] = '\0'; err = DrStringToUInt32(psz, &uHour); if (err != DrError_OK) { return err; } if (uHour > 23) { return DrError_InvalidParameter; } psz += 3; if (psz[2] != ':') { return DrError_InvalidParameter; } psz[2] = '\0'; err = DrStringToUInt32(psz, &uMinute); if (err != DrError_OK) { return err; } if (uMinute > 59) { return DrError_InvalidParameter; } psz += 3; chNext = psz[2]; psz[2] = '\0'; err = DrStringToUInt32(psz, &uSecond); if (err != DrError_OK) { return err; } if (uSecond > 59) { return DrError_InvalidParameter; } if (chNext == '\0') { psz += 2; } else { psz += 3; } if (chNext == '.') { // fraction while (*psz >= '0' && *psz <= '9') { nFracDigs++; if (nFracDigs > 9) { return DrError_InvalidParameter; } uFrac = (10 * uFrac) + (UInt32) (*psz - '0'); psz++; } chNext = *psz; if (chNext != '\0') { psz++; } } } if (chNext == 'Z') { bias = 0; } else if (chNext == 'L') { bool fNeg = false; if (*psz == '+' || *psz == '-') { fNeg = (*psz == '-'); psz++; err = DrStringToTimeInterval(psz, &bias); if (err != DrError_OK) { return err; } if (fNeg) { bias = -bias; } psz += strlen(psz); } } //case where time end with [-/+]HH:MM else if (chNext == '+' || chNext == '-') { UInt32 ubiashour = 0; UInt32 ubiasMinute = 0; while(isdigit((int)(*psz))) { ubiashour = ubiashour * 10 + (*psz-'0'); psz++; } if(*psz != ':') { return DrError_InvalidParameter; } psz++; while(isdigit((int)(*psz))) { ubiasMinute= ubiasMinute* 10 + (*psz-'0'); psz++; } bias = ubiashour * DrTimeInterval_Hour + ubiasMinute * DrTimeInterval_Minute; //If timezone is -08:00, we have to add 8 hrs to find utc time. if(chNext == '+') { bias = -bias; } } if (*psz != '\0') { return DrError_InvalidParameter; } SYSTEMTIME st; st.wDayOfWeek = 0; // unknown st.wYear = (WORD) uYear; st.wMonth = (WORD) uMonth; st.wDay = (WORD) uDay; st.wHour = (WORD) uHour; st.wMinute = (WORD) uMinute; st.wSecond = (WORD) uSecond; st.wMilliseconds = 0; // we handle milliseconds ourselves to get better resolution... while (nFracDigs > 7 && uFrac != 0) { uFrac = uFrac / 10; nFracDigs --; } while (nFracDigs < 7 && uFrac != 0) { uFrac = 10 * uFrac; nFracDigs++; } DrTimeStamp ts; err = DrSystemTimeToTimeStamp(&st, &ts, false); if (err != DrError_OK) { return err; } ts += uFrac; ts += bias; *pTimeStampOut = ts; return DrError_OK; } DrError DrStringToTimeStamp(const char *pszTime, DrTimeStamp *pTimeStampOut, bool fDefaultLocalTimeZone) { DrTimeInterval bias; if (fDefaultLocalTimeZone) { bias = DrGetCurrentLocalTimeZoneBias(); } else { bias = 0; } return DrStringToTimeStamp(pszTime, pTimeStampOut, bias); } DrError DrTimeStampToSystemTime(DrTimeStamp timeStamp, SYSTEMTIME *pSystemTime, bool fToLocalTimeZone) { union { FILETIME ft; DrTimeStamp ts; }; if (fToLocalTimeZone && timeStamp != DrTimeStamp_LongAgo && timeStamp != DrTimeStamp_Never) { if (!FileTimeToLocalFileTime((const FILETIME *)(const void *)&timeStamp, &ft)) { return DrGetLastError(); } } else { ts = timeStamp; } if (!FileTimeToSystemTime(&ft, pSystemTime)) { return DrGetLastError(); } return DrError_OK; } // // Get an environment variable // DrError DrGetEnvironmentVariable(const WCHAR *pszVarName, WCHAR ppszValue[]) { DrError err; WCHAR * psz = NULL; DWORD nb2 = 0; // // Get length of environment variable value // DWORD nb = GetEnvironmentVariableW(pszVarName, NULL, 0); if (nb == 0) { err = DrGetLastError(); goto done; } psz = (WCHAR *)malloc(sizeof(WCHAR) * nb); // // Get environment variable value // nb2 = GetEnvironmentVariableW(pszVarName, psz, nb); if (nb2 == 0) { err = DrGetLastError(); goto done; } err = DrError_OK; // Fail if more than MAX_PATH characters if(MAX_PATH <= nb2) { err = DrError_Fail; } done: if (err != DrError_OK || psz == NULL) { // GLE may return wrong results in mixed mode code. If we catch S_OK we need to return a meaningful code instead if (err == S_OK) err = ERROR_ENVVAR_NOT_FOUND; // // If there has been an error, set value to null // and free any allocated resources // if (psz != NULL) { free(psz); } *ppszValue = NULL; } else { LogAssert(psz != NULL); // use length + 1 to get null character ending wcsncpy(ppszValue, psz, nb2+1); free(psz); } return err; } // // Get an environment variable // DrError DrGetEnvironmentVariable(const char *pszVarName, const char **ppszValue) { DrError err; LPWSTR myenvname; LPWSTR psz = NULL; int charLen = lstrlenA(pszVarName); int wcharLen; // // Get length of variable name // wcharLen = ::MultiByteToWideChar(CP_ACP, NULL, pszVarName, charLen, NULL, NULL); if (wcharLen > 0) { // // Get converted variable name // myenvname = ::SysAllocStringLen(0, wcharLen); ::MultiByteToWideChar(CP_ACP, 0, pszVarName, charLen, myenvname, wcharLen); } else { // // If unable to get length, fail // err = DrGetLastError(); goto done; } // // Get length of environment variable value // DWORD nb = GetEnvironmentVariableW(myenvname, NULL, 0); if (nb == 0) { err = DrGetLastError(); goto done; } psz = (LPWSTR )malloc(sizeof(char) * nb); // // Get environment variable value // DWORD nb2 = GetEnvironmentVariableW(myenvname, psz, nb); if (nb2 == 0) { err = DrGetLastError(); goto done; } err = DrError_OK; done: if (err != DrError_OK) { // // If there has been an error, set value to null // and free any allocated resources // if (psz != NULL) { free(psz); } *ppszValue = NULL; } else { LogAssert(psz != NULL); *ppszValue = (char*) psz; } return err; } DrError DrGetSidForUser(LPCWSTR domainUserName, PSID* ppSid) { // Create buffers for SID and domain. If size > default, will retry with new size DWORD bufferSizeSid = 64; DWORD bufferSizeDomain = 64; DWORD newBufferSizeSid = 64; DWORD newBufferSizeDomain = 64; WCHAR* pDomainName = NULL; SID_NAME_USE sidType; // Check SID pointer fo null before using if(ppSid == NULL) { return DrError_Fail; } // Create buffers for the SID and domain name. *ppSid = (PSID) new BYTE[bufferSizeSid]; if (*ppSid == NULL) { return DrError_Fail; } memset(*ppSid, 0, bufferSizeSid); pDomainName = new WCHAR[bufferSizeDomain]; if (pDomainName == NULL) { FreeSid(*ppSid); return DrError_Fail; } memset(pDomainName, 0, bufferSizeDomain*sizeof(WCHAR)); // Try to get SID with default buffer size if (LookupAccountNameW(NULL, domainUserName, *ppSid, &newBufferSizeSid, pDomainName, &newBufferSizeDomain, &sidType)) { delete [] pDomainName; if (IsValidSid(*ppSid) == FALSE) { return DrError_Fail; } return DrError_OK; } // If unable to get account name, check for insufficient buffer DWORD err = GetLastError(); while (err == ERROR_INSUFFICIENT_BUFFER) { if (newBufferSizeSid > bufferSizeSid) { // Free and reallocate buffer for SID FreeSid(*ppSid); *ppSid = (PSID) new BYTE[newBufferSizeSid]; if (*ppSid == NULL) { delete [] pDomainName; return DrError_Fail; } bufferSizeSid = newBufferSizeSid; memset(*ppSid, 0, bufferSizeSid); } if (newBufferSizeDomain > bufferSizeDomain) { // Free and reallocate buffer for domain delete [] pDomainName; pDomainName = new WCHAR[newBufferSizeDomain]; if (pDomainName == NULL) { FreeSid(*ppSid); return DrError_Fail; } bufferSizeDomain = newBufferSizeDomain; memset(pDomainName, 0, bufferSizeDomain*sizeof(WCHAR)); } // Try to get SID with new buffer size if (LookupAccountNameW(NULL, domainUserName, *ppSid, &bufferSizeSid, pDomainName, &bufferSizeDomain, &sidType)) { delete [] pDomainName; if (IsValidSid(*ppSid) == FALSE) { return DrError_Fail; } return DrError_OK; } err = GetLastError(); } // If outside loop, failed to lookup SID return DrError_Fail; } DrError DrGetComputerName(WCHAR ppszValue[]) { WCHAR azureFlag[MAX_PATH+1] = {0}; DrError err = DrGetEnvironmentVariable(L"CCP_ONAZURE", azureFlag); if(err == DrError_OK) { // This process is running on Azure err = DrGetEnvironmentVariable(L"HPC_NODE_NAME", ppszValue); if(err != DrError_OK) { DrLogE( "Error retrieving HPC_NODE_NAME environment variable. Error: %s", DrGetErrorText(err)); return err; } } else { // This process is not running on Azure // swap with current lines for DNS hostname support //DWORD hostLength = DNS_MAX_LABEL_BUFFER_LENGTH; //if (!GetComputerNameExW(ComputerNameDnsHostname, ppszValue, &hostLength)) DWORD hostLength = MAX_COMPUTERNAME_LENGTH + 1; if (!GetComputerName(ppszValue, &hostLength)) { DrLogE( "Error calling GetComputerName. ErrorCode: %u", GetLastError()); return DrError_Fail; } } return DrError_OK; } //JC #if 0 DrError DrGetEnvironmentVariable(const char *pszVarName, /* out */ const char **ppszValue) { // We jump through hoops to use unicode API here and convert to UTF-8 DrError err; WCHAR *psz = NULL; DrWStr256 wstr; DrWStr64 wstrVarName; wstrVarName = pszVarName; DrStr256 str; char *pszRet = NULL; DWORD nb = GetEnvironmentVariableW(wstrVarName.GetString(), NULL, 0); if (nb == 0) { err = DrGetLastError(); goto done; } psz = wstr.GetWritableBuffer(nb); DWORD nb2 = GetEnvironmentVariableW(wstrVarName.GetString(), psz, nb); if (nb2 == 0) { err = DrGetLastError(); goto done; } LogAssert(nb2 < nb); wstr.UpdateLength(nb2); jstr.Set( wstr ); LogAssert(str.GetString() != NULL); pszRet = (char *)malloc(str.GetLength()+1); LogAssert(pszRet != NULL); memcpy(pszRet, str.GetString(), str.GetLength()+1); err = DrError_OK; done: if (err != DrError_OK) { if (pszRet != NULL) { free(pszRet); } *ppszValue = NULL; } else { LogAssert(pszRet != NULL); *ppszValue = pszRet; } return err; } // If pszBaseDir is null, the current working directory is used. If pszRelDir is // fully qualified, pszBaseDir is ignored. DrError DrCanonicalizeFilePath(DrStr& strOut, const char *pszRelDir, const char *pszBaseDir) { DrWStr128 wstrRelDir; DrWStr128 wstrBaseDir; wstrRelDir = pszRelDir; wstrBaseDir = pszBaseDir; if (pszRelDir != NULL && !PathIsRelativeW(wstrRelDir)) { strOut = pszRelDir; return DrError_OK; } if (wstrBaseDir == NULL) { DrStr256 strBase; DrGetCurrentDirectory(strBase); wstrBaseDir = strBase; } WCHAR szBuff1[MAX_PATH]; WCHAR szBuff2[MAX_PATH]; if (wstrRelDir != NULL) { const WCHAR *pszResult = PathCombineW( szBuff1, wstrBaseDir, wstrRelDir); if (pszResult == NULL) { return DrError_InvalidPathname; } BOOL fRet = PathCanonicalizeW(szBuff2, szBuff1); if (!fRet) { return DrError_InvalidPathname; } } else { BOOL fRet = PathCanonicalizeW(szBuff2, wstrBaseDir); if (!fRet) { return DrError_InvalidPathname; } } strOut.Set(szBuff2); return DrError_OK; } #endif