/*++ Function: _wsplitpath See MSDN doc. Notes : This implementation ignores drive letters as they should not be present. If the drive argument is non-NULL, it always returns an empty string. File names in which the only period is at the beginning (like .bashrc, but not .bashrc.bak), the file is treated as having no extension (fname is ".bashrc", ext is "") --*/ void __cdecl _wsplitpath( const wchar_16 *dospath, wchar_16 *drive, wchar_16 *dir, wchar_16 *fname, wchar_16 *ext) { WCHAR path[_MAX_PATH+1]; LPCWSTR slash_ptr = NULL; LPCWSTR period_ptr = NULL; INT size = 0; PERF_ENTRY(_wsplitpath); ENTRY("_wsplitpath (path=%p (%S), drive=%p, dir=%p, fname=%p, ext=%p)\n", dospath?dospath:W16_NULLSTRING, dospath?dospath:W16_NULLSTRING, drive, dir, fname, ext); /* Do performance intensive error checking only in debug builds. NOTE: This function must fail predictably across all platforms. Under Windows this function throw an access violation if NULL was passed in as the value for path. */ #if _DEBUG if ( !dospath ) { ERROR( "path cannot be NULL!\n" ); } #endif if( lstrlenW( dospath ) >= _MAX_PATH ) { ERROR("Path length is > _MAX_PATH (%d)!\n", _MAX_PATH); ON_ERROR; } PAL_wcscpy(path, dospath); FILEDosToUnixPathW(path); /* no drive letters in the PAL */ if( drive != NULL ) { drive[0] = 0; } /* find last path separator char */ slash_ptr = PAL_wcsrchr(path, '/'); if( slash_ptr == NULL ) { TRACE("No path separator in path\n"); slash_ptr = path - 1; } /* find extension separator, if any */ period_ptr = PAL_wcsrchr(path, '.'); /* make sure we only consider periods after the last path separator */ if( period_ptr < slash_ptr ) { period_ptr = NULL; } /* if the only period in the file is a leading period (denoting a hidden file), don't treat what follows as an extension */ if( period_ptr == slash_ptr+1 ) { period_ptr = NULL; } if( period_ptr == NULL ) { TRACE("No extension in path\n"); period_ptr = path + lstrlenW(path); } size = slash_ptr - path + 1; if( dir != NULL ) { INT i; if( (size + 1 ) > _MAX_DIR ) { ERROR("Directory component needs %d characters, _MAX_DIR is %d\n", size+1, _MAX_DIR); ON_ERROR; } memcpy(dir, path, size*sizeof(WCHAR)); dir[size] = 0; /* only allow / separators in returned path */ i = 0; while( dir[ i ] ) { if( dir[ i ] == '\\' ) { dir[i]='/'; } i++; } } size = period_ptr-slash_ptr-1; if( fname != NULL ) { if( (size+1) > _MAX_FNAME ) { ERROR("Filename component needs %d characters, _MAX_FNAME is %d\n", size+1, _MAX_FNAME); ON_ERROR; } memcpy(fname, slash_ptr+1, size*sizeof(WCHAR)); fname[size] = 0; } size = 1 + lstrlenW( period_ptr ); if( ext != NULL ) { if( size > _MAX_EXT ) { ERROR("Extension component needs %d characters, _MAX_EXT is %d\n", size, _MAX_EXT); ON_ERROR; } memcpy(ext, period_ptr, size*sizeof(WCHAR)); ext[size-1] = 0; } TRACE("Path components are '%S' '%S' '%S'\n", dir, fname, ext); done: LOGEXIT("_wsplitpath returns.\n"); PERF_EXIT(_wsplitpath); }
BOOL PALAPI PAL_Random( IN BOOL bStrong, IN OUT LPVOID lpBuffer, IN DWORD dwLength) { int rand_des = -1; BOOL bRet = FALSE; DWORD i; char buf; long num = 0; static BOOL sMissingDevRandom; static BOOL sMissingDevURandom; static BOOL sInitializedMRand; PERF_ENTRY(PAL_Random); ENTRY("PAL_Random(bStrong=%d, lpBuffer=%p, dwLength=%d)\n", bStrong, lpBuffer, dwLength); i = 0; if (bStrong == TRUE && i < dwLength && !sMissingDevRandom) { // request non-blocking access to avoid hangs if the /dev/random is exhausted // or just simply broken if ((rand_des = PAL__open(RANDOM_DEVICE_NAME, O_RDONLY | O_NONBLOCK)) == -1) { if (errno == ENOENT) { sMissingDevRandom = TRUE; } else { ASSERT("PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno)); } // Back off and try /dev/urandom. } else { for( ; i < dwLength; i++) { if (read(rand_des, &buf, 1) < 1) { // the /dev/random pool has been exhausted. Fall back // to /dev/urandom for the remainder of the buffer. break; } *(((BYTE*)lpBuffer) + i) ^= buf; } close(rand_des); } } if (i < dwLength && !sMissingDevURandom) { if ((rand_des = PAL__open(URANDOM_DEVICE_NAME, O_RDONLY)) == -1) { if (errno == ENOENT) { sMissingDevURandom = TRUE; } else { ASSERT("PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno)); } // Back off and try mrand48. } else { for( ; i < dwLength; i++) { if (read(rand_des, &buf, 1) < 1) { // Fall back to srand48 for the remainder of the buffer. break; } *(((BYTE*)lpBuffer) + i) ^= buf; } close(rand_des); } } if (!sInitializedMRand) { srand48(time(NULL)); sInitializedMRand = TRUE; } // always xor srand48 over the whole buffer to get some randomness // in case /dev/random is not really random for(i = 0; i < dwLength; i++) { if (i % sizeof(long) == 0) { num = mrand48(); } *(((BYTE*)lpBuffer) + i) ^= num; num >>= 8; } bRet = TRUE; LOGEXIT("PAL_Random returns %d\n", bRet); PERF_EXIT(PAL_Random); return bRet; }
/*++ Function: pow See MSDN. --*/ PALIMPORT double __cdecl PAL_pow(double x, double y) { double ret; PERF_ENTRY(pow); ENTRY("pow (x=%f, y=%f)\n", x, y); #if !HAVE_COMPATIBLE_POW if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf { if (x == 1.0) { ret = x; } else if (x == -1.0) { ret = 1.0; } else if ((x > -1.0) && (x < 1.0)) { ret = 0.0; } else { ret = PAL_POSINF_DBL; // +Inf } } else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf { if (x == 1.0) { ret = x; } else if (x == -1.0) { ret = 1.0; } else if ((x > -1.0) && (x < 1.0)) { ret = PAL_POSINF_DBL; // +Inf } else { ret = 0.0; } } else if (IS_DBL_NEGZERO(x) && (y == -1.0)) { ret = PAL_NEGINF_DBL; // -Inf } else if ((x == 0.0) && (y < 0.0)) { ret = PAL_POSINF_DBL; // +Inf } else #endif // !HAVE_COMPATIBLE_POW ret = pow(x, y); #if !HAVE_VALID_NEGATIVE_INF_POW if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2))) { ret = PAL_NEGINF_DBL; // -Inf } #endif // !HAVE_VALID_NEGATIVE_INF_POW #if !HAVE_VALID_POSITIVE_INF_POW /* * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0) * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which * is an odd number, so the test ((long long) y % 2 == 0) will always fail for * large y. Since large double numbers are always even (e.g., the representation of * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part * of the representation), this test will always return the wrong result for large y. * * The (ceil(y/2) == floor(y/2)) test is slower, but more robust. */ if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2))) { ret = PAL_POSINF_DBL; // +Inf } #endif // !HAVE_VALID_POSITIVE_INF_POW LOGEXIT("pow returns double %f\n", ret); PERF_EXIT(pow); return ret; }
/* The use of ULONG is by design, to ensure that a 32 bit value is always returned from this function. If "unsigned long" is used instead of ULONG, then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus breaking Windows behavior .*/ ULONG __cdecl PAL_wcstoul( const wchar_16 *nptr, wchar_16 **endptr, int base) { char *s_nptr = 0; char *s_endptr = 0; unsigned long res; int size; DWORD dwLastError = 0; PERF_ENTRY(wcstoul); ENTRY("wcstoul (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING, endptr, base); THREADMarkDiagnostic("PAL_wcstoul -> strtoul"); size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL); if (!size) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL_wcstoulExit; } s_nptr = (char *)PAL_malloc(size); if (!s_nptr) { ERROR("PAL_malloc failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); res = 0; goto PAL_wcstoulExit; } size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL); if (!size) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL_wcstoulExit; } res = strtoul(s_nptr, &s_endptr, base); #ifdef BIT64 if (res > _UI32_MAX) { wchar_16 wc = *nptr; while (PAL_iswspace(wc)) { wc = *nptr++; } /* If the string represents a positive number that is greater than _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno to match Windows behavior. */ if (wc != '-') { res = _UI32_MAX; errno = ERANGE; } } #endif /* only ASCII characters will be accepted by strtol, and those always get mapped to single-byte characters, so the first rejected character will have the same index in the multibyte and widechar strings */ if( endptr ) { size = s_endptr - s_nptr; *endptr = (wchar_16 *)&nptr[size]; } PAL_wcstoulExit: PAL_free(s_nptr); LOGEXIT("wcstoul returning unsigned long %lu\n", res); PERF_EXIT(wcstoul); /* When returning unsigned long res from this function, it will be implicitly cast to ULONG. This handles situations where a string that represents a negative number is passed in to wcstoul. The Windows behavior is analogous to taking the binary equivalent of the negative value and treating it as a positive number. Returning a ULONG from this function, as opposed to native unsigned long, allows us to match this behavior. The explicit case to ULONG below is used to silence any potential warnings due to the implicit casting. */ return (ULONG)res; }
/*++ Function: GetSystemInfo GetSystemInfo The GetSystemInfo function returns information about the current system. Parameters lpSystemInfo [out] Pointer to a SYSTEM_INFO structure that receives the information. Return Values This function does not return a value. Note: fields returned by this function are: dwNumberOfProcessors dwPageSize Others are set to zero. --*/ VOID PALAPI GetSystemInfo( OUT LPSYSTEM_INFO lpSystemInfo) { int nrcpus = 0; #if HAVE_SYSCTL int rc; size_t sz; int mib[2]; #endif // HAVE_SYSCTL long pagesize; PERF_ENTRY(GetSystemInfo); ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo); pagesize = getpagesize(); lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0; lpSystemInfo->wReserved_PAL_Undefined = 0; lpSystemInfo->dwPageSize = pagesize; lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0; #if HAVE_SYSCTL sz = sizeof(nrcpus); mib[0] = CTL_HW; mib[1] = HW_NCPU; rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_NCPU (%d)\n", errno); } #else // HAVE_SYSCONF nrcpus = sysconf(_SC_NPROCESSORS_ONLN); if (nrcpus < 1) { ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno); } #endif TRACE("dwNumberOfProcessors=%d\n", nrcpus); lpSystemInfo->dwNumberOfProcessors = nrcpus; #ifdef VM_MAXUSER_ADDRESS lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS; #elif defined(USERLIMIT) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT; #elif defined(USRSTACK) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK; #else #error The maximum application address is not known on this platform. #endif lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize; lpSystemInfo->dwProcessorType_PAL_Undefined = 0; lpSystemInfo->dwAllocationGranularity = pagesize; lpSystemInfo->wProcessorLevel_PAL_Undefined = 0; lpSystemInfo->wProcessorRevision_PAL_Undefined = 0; LOGEXIT("GetSystemInfo returns VOID\n"); PERF_EXIT(GetSystemInfo); }
/*++ Function: GetFullPathNameA See MSDN doc. --*/ DWORD PALAPI GetFullPathNameA( IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart) { DWORD nReqPathLen, nRet = 0; LPSTR lpUnixPath = NULL; BOOL fullPath = FALSE; PERF_ENTRY(GetFullPathNameA); ENTRY("GetFullPathNameA(lpFileName=%p (%s), nBufferLength=%u, lpBuffer=%p, " "lpFilePart=%p)\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL", nBufferLength, lpBuffer, lpFilePart); if(NULL == lpFileName) { WARN("lpFileName is NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* find out if lpFileName is a partial or full path */ if ('\\' == *lpFileName || '/' == *lpFileName) { fullPath = TRUE; } if(fullPath) { lpUnixPath = strdup( lpFileName ); if(NULL == lpUnixPath) { ERROR("strdup() failed; error is %d (%s)\n", errno, strerror(errno)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; } } else { size_t max_len; /* allocate memory for full non-canonical path */ max_len = strlen(lpFileName)+1; /* 1 for the slash to append */ max_len += MAX_PATH + 1; lpUnixPath = malloc(max_len); if(NULL == lpUnixPath) { ERROR("malloc() failed; error is %d (%s)\n", errno, strerror(errno)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; } /* build full path */ if(!GetCurrentDirectoryA(MAX_PATH + 1, lpUnixPath)) { /* no reason for this to fail now... */ ASSERT("GetCurrentDirectoryA() failed! lasterror is %#xd\n", GetLastError()); SetLastError(ERROR_INTERNAL_ERROR); goto done; } strcat(lpUnixPath,"/"); strcat(lpUnixPath, lpFileName); } /* do conversion to Unix path */ FILEDosToUnixPathA( lpUnixPath ); /* now we can canonicalize this */ FILECanonicalizePath(lpUnixPath); /* at last, we can figure out how long this path is */ nReqPathLen = strlen(lpUnixPath)+1; if(nBufferLength < nReqPathLen) { TRACE("reporting insufficient buffer : minimum is %d, caller " "provided %d\n", nReqPathLen, nBufferLength); nRet = nReqPathLen; goto done; } nRet = nReqPathLen-1; strcpy(lpBuffer, lpUnixPath); /* locate the filename component if caller cares */ if(lpFilePart) { *lpFilePart = strrchr(lpBuffer, '/'); if (*lpFilePart == NULL) { ASSERT("Not able to find '/' in the full path.\n"); SetLastError( ERROR_INTERNAL_ERROR ); nRet = 0; goto done; } else { (*lpFilePart)++; } } done: free (lpUnixPath); LOGEXIT("GetFullPathNameA returns DWORD %u\n", nRet); PERF_EXIT(GetFullPathNameA); return nRet; }
__cdecl _ui64tow( unsigned __int64 value , wchar_16 * string , int radix ) { UINT ReversedIndex = 0; WCHAR ReversedString[ 65 ]; LPWSTR lpString = string; UINT Index = 0; PERF_ENTRY(_ui64tow); ENTRY( "_ui64tow( value=%I64d, string=%p (%S), radix=%d )\n", value, string, string, radix ); if ( !string ) { ERROR( "string has to be a valid pointer.\n" ); LOGEXIT( "_ui64tow returning NULL.\n" ); PERF_EXIT(_ui64tow); return NULL; } if ( radix < 2 || radix > 36 ) { ERROR( "radix has to be between 2 and 36.\n" ); LOGEXIT( "_ui64tow returning NULL.\n" ); PERF_EXIT(_ui64tow); return NULL; } if(0 == value) { ReversedString[0] = '0'; Index++; } else while ( value ) { int temp = value % radix; value /= radix; if ( temp < 10 ) { ReversedString[ Index ] = temp + '0'; Index++; } else { ReversedString[ Index ] = temp - 10 + 'a'; Index++; } } /* Reverse the string. */ ReversedIndex = Index; for ( Index = 0; ReversedIndex > 0; ReversedIndex--, Index++ ) { string[ Index ] = ReversedString[ ReversedIndex - 1 ]; } string[ Index ] = '\0'; LOGEXIT( "_ui64tow returning %p (%S).\n", lpString , lpString ); PERF_EXIT(_ui64tow); return lpString; }
__cdecl PAL_fopen(const char * fileName, const char * mode) { PAL_FILE *f = NULL; LPSTR supported = NULL; LPSTR UnixFileName = NULL; struct stat stat_data; BOOL bTextMode = TRUE; PERF_ENTRY(fopen); ENTRY("fopen ( fileName=%p (%s) mode=%p (%s))\n", fileName, fileName, mode , mode ); _ASSERTE(fileName != NULL); _ASSERTE(mode != NULL); if ( *mode == 'r' || *mode == 'w' || *mode == 'a' ) { supported = MapFileOpenModes( (char*)mode,&bTextMode); if ( !supported ) { goto done; } UnixFileName = PAL__strdup(fileName); if (UnixFileName == NULL ) { ERROR("PAL__strdup() failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; } FILEDosToUnixPathA( UnixFileName ); /*I am not checking for the case where stat fails *as fopen will handle the error more gracefully in case *UnixFileName is invalid*/ if ((stat(UnixFileName, &stat_data) == 0 ) && ((stat_data.st_mode & S_IFMT) == S_IFDIR)) { goto done; } f = (PAL_FILE*)PAL_malloc( sizeof( PAL_FILE ) ); if ( f ) { f->bsdFilePtr = (FILE*)fopen( UnixFileName, supported ); f->PALferrorCode = PAL_FILE_NOERROR; f->bTextMode = bTextMode; if ( !f->bsdFilePtr ) { /* Failed */ PAL_free( f ); f = NULL; } #if UNGETC_NOT_RETURN_EOF else { f->bWriteOnlyMode = WriteOnlyMode(f->bsdFilePtr); } #endif //UNGETC_NOT_RETURN_EOF } else { ERROR( "Unable to allocate memory to the PAL_FILE wrapper\n" ); } } else { ERROR( "The mode flags must start with either an a, w, or r.\n" ); } done: PAL_free( supported ); supported = NULL; PAL_free( UnixFileName ); LOGEXIT( "fopen returns FILE* %p\n", f ); PERF_EXIT(fopen); return f; }
/*++ Function: CreateDirectoryA Note: lpSecurityAttributes always NULL. See MSDN doc. --*/ BOOL PALAPI CreateDirectoryA( IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) { BOOL bRet = FALSE; DWORD dwLastError = 0; PathCharString realPath; char* realPathBuf; LPSTR unixPathName = NULL; int pathLength; int i; const int mode = S_IRWXU | S_IRWXG | S_IRWXO; PERF_ENTRY(CreateDirectoryA); ENTRY("CreateDirectoryA(lpPathName=%p (%s), lpSecurityAttr=%p)\n", lpPathName?lpPathName:"NULL", lpPathName?lpPathName:"NULL", lpSecurityAttributes); if ( lpSecurityAttributes ) { ASSERT("lpSecurityAttributes is not NULL as it should be\n"); dwLastError = ERROR_INVALID_PARAMETER; goto done; } // Windows returns ERROR_PATH_NOT_FOUND when called with NULL. // If we don't have this check, strdup(NULL) segfaults. if (lpPathName == NULL) { ERROR("CreateDirectoryA called with NULL pathname!\n"); dwLastError = ERROR_PATH_NOT_FOUND; goto done; } unixPathName = PAL__strdup(lpPathName); if (unixPathName == NULL ) { ERROR("PAL__strdup() failed\n"); dwLastError = ERROR_NOT_ENOUGH_MEMORY; goto done; } FILEDosToUnixPathA( unixPathName ); // Remove any trailing slashes at the end because mkdir might not // handle them appropriately on all platforms. pathLength = strlen(unixPathName); i = pathLength; while(i > 1) { if(unixPathName[i - 1] =='/') { unixPathName[i - 1]='\0'; i--; } else { break; } } // Get an absolute path. if (unixPathName[0] == '/') { realPathBuf = unixPathName; } else { DWORD len = GetCurrentDirectoryA(realPath); if (len == 0 || !realPath.Reserve(realPath.GetCount() + pathLength + 1 )) { dwLastError = DIRGetLastErrorFromErrno(); WARN("Getcwd failed with errno=%d \n", dwLastError); goto done; } realPath.Append("/", 1); realPath.Append(unixPathName, pathLength); realPathBuf = realPath.OpenStringBuffer(realPath.GetCount()); } // Canonicalize the path so we can determine its length. FILECanonicalizePath(realPathBuf); if ( mkdir(realPathBuf, mode) != 0 ) { TRACE("Creation of directory [%s] was unsuccessful, errno = %d.\n", unixPathName, errno); switch( errno ) { case ENOTDIR: /* FALL THROUGH */ case ENOENT: FILEGetProperNotFoundError( realPathBuf, &dwLastError ); goto done; case EEXIST: dwLastError = ERROR_ALREADY_EXISTS; break; default: dwLastError = ERROR_ACCESS_DENIED; } } else { TRACE("Creation of directory [%s] was successful.\n", unixPathName); bRet = TRUE; } realPath.CloseBuffer(0); //The PathCharString usage is done done: if( dwLastError ) { SetLastError( dwLastError ); } PAL_free( unixPathName ); LOGEXIT("CreateDirectoryA returns BOOL %d\n", bRet); PERF_EXIT(CreateDirectoryA); return bRet; }
/*++ Function: GetSystemInfo GetSystemInfo The GetSystemInfo function returns information about the current system. Parameters lpSystemInfo [out] Pointer to a SYSTEM_INFO structure that receives the information. Return Values This function does not return a value. Note: fields returned by this function are: dwNumberOfProcessors dwPageSize Others are set to zero. --*/ VOID PALAPI GetSystemInfo( OUT LPSYSTEM_INFO lpSystemInfo) { int nrcpus = 0; long pagesize; PERF_ENTRY(GetSystemInfo); ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo); pagesize = getpagesize(); lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0; lpSystemInfo->wReserved_PAL_Undefined = 0; lpSystemInfo->dwPageSize = pagesize; lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0; #if HAVE_SYSCONF #if defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) ) struct pst_dynamic psd; if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) { nrcpus = psd.psd_proc_cnt; } else { ASSERT("pstat_getdynamic failed (%d)\n", errno); } #else // !__hppa__ nrcpus = sysconf(_SC_NPROCESSORS_ONLN); if (nrcpus < 1) { ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno); } #endif // __hppa__ #elif HAVE_SYSCTL int rc; size_t sz; int mib[2]; sz = sizeof(nrcpus); mib[0] = CTL_HW; mib[1] = HW_NCPU; rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_NCPU (%d)\n", errno); } #endif // HAVE_SYSCONF TRACE("dwNumberOfProcessors=%d\n", nrcpus); lpSystemInfo->dwNumberOfProcessors = nrcpus; #ifdef VM_MAXUSER_ADDRESS lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS; #elif defined(__sun__) || defined(_AIX) || defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) ) || defined(__LINUX__) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) -1; #elif defined(USERLIMIT) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT; #elif defined(_WIN64) #if defined(USRSTACK64) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK64; #else // !USRSTACK64 #error How come USRSTACK64 is not defined for 64bit? #endif // USRSTACK64 #elif defined(USRSTACK) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK; #else #error The maximum application address is not known on this platform. #endif lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize; lpSystemInfo->dwProcessorType_PAL_Undefined = 0; lpSystemInfo->dwAllocationGranularity = pagesize; lpSystemInfo->wProcessorLevel_PAL_Undefined = 0; lpSystemInfo->wProcessorRevision_PAL_Undefined = 0; LOGEXIT("GetSystemInfo returns VOID\n"); PERF_EXIT(GetSystemInfo); }
/*++ Function: GlobalMemoryStatusEx GlobalMemoryStatusEx Retrieves information about the system's current usage of both physical and virtual memory. Return Values This function returns a BOOL to indicate its success status. --*/ BOOL PALAPI GlobalMemoryStatusEx( IN OUT LPMEMORYSTATUSEX lpBuffer) { PERF_ENTRY(GlobalMemoryStatusEx); ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer); lpBuffer->dwMemoryLoad = 0; lpBuffer->ullTotalPhys = 0; lpBuffer->ullAvailPhys = 0; lpBuffer->ullTotalPageFile = 0; lpBuffer->ullAvailPageFile = 0; lpBuffer->ullTotalVirtual = 0; lpBuffer->ullAvailVirtual = 0; lpBuffer->ullAvailExtendedVirtual = 0; BOOL fRetVal = FALSE; // Get the physical memory size #if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES int64_t physical_memory; // Get the Physical memory size physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE ); lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory; fRetVal = TRUE; #elif HAVE_SYSCTL int mib[2]; int64_t physical_memory; size_t length; // Get the Physical memory size mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; length = sizeof(INT64); int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0); if (rc != 0) { ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno); } else { lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory; fRetVal = TRUE; } #elif // HAVE_SYSINFO // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that // we can use to fill in the xxxPageFile members. #endif // HAVE_SYSCONF // Get the physical memory in use - from it, we can get the physical memory available. // We do this only when we have the total physical memory available. if (lpBuffer->ullTotalPhys > 0) { #ifndef __APPLE__ lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE); INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys; lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys); #else vm_size_t page_size; mach_port_t mach_port; mach_msg_type_number_t count; vm_statistics_data_t vm_stats; mach_port = mach_host_self(); count = sizeof(vm_stats) / sizeof(natural_t); if (KERN_SUCCESS == host_page_size(mach_port, &page_size)) { if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count)) { lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size; INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) * (INT64)page_size; lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys); } } mach_port_deallocate(mach_task_self(), mach_port); #endif // __APPLE__ } // There is no API to get the total virtual address space size on // Unix, so we use a constant value representing 128TB, which is // the approximate size of total user virtual address space on // the currently supported Unix systems. static const UINT64 _128TB = (1ull << 47); lpBuffer->ullTotalVirtual = _128TB; lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal); PERF_EXIT(GlobalMemoryStatusEx); return fRetVal; }
/*++ Function: OpenEventW Note: dwDesiredAccess is always set to EVENT_ALL_ACCESS See MSDN doc. --*/ HANDLE PALAPI OpenEventW( IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName) { HANDLE hEvent = NULL; SHMPTR shmpEventInfo; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; Event *pEvent; LPCWSTR lpObjectName = NULL; WCHAR MangledObjectName[MAX_PATH]; BOOL nameExists; PERF_ENTRY(OpenEventW); ENTRY("OpenEventW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n", dwDesiredAccess, bInheritHandle, lpName?lpName:W16_NULLSTRING, lpName?lpName:W16_NULLSTRING); SHMLock(); /* validate parameters */ if (dwDesiredAccess != EVENT_ALL_ACCESS) { ASSERT("dwDesiredAccess should be EVENT_ALL_ACCESS\n"); SetLastError(ERROR_INVALID_PARAMETER); goto OpenEventWExit; } if (lpName == NULL) { ASSERT("name is NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto OpenEventWExit; } lpObjectName=lpName; if (!MangleObjectNameW(&lpObjectName, MangledObjectName)) { goto OpenEventWExit; } /* See if the name is already taken. */ shmpEventInfo = SHMFindNamedObjectByName( lpObjectName, SHM_NAMED_EVENTS, &nameExists ); if ( shmpEventInfo == 0 ) { if (nameExists) { SetLastError(ERROR_INVALID_HANDLE); } else { SetLastError(ERROR_INVALID_NAME); } TRACE("Event (name = %S) not found\n", lpName); goto OpenEventWExit; } else { /* build a Event structure */ pEvent = (Event *) malloc(sizeof(Event)); if (pEvent == NULL) { ERROR("Unable to allocate memory\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto OpenEventWExit; } pEvent->objHeader.type = HOBJ_EVENT; pEvent->objHeader.close_handle = CloseEventHandle; pEvent->objHeader.dup_handle = DupEventHandle; pEvent->refCount = 1; pEvent->info = shmpEventInfo; /* get a handle for the event */ hEvent = HMGRGetHandle((HOBJSTRUCT *) pEvent); if (hEvent == INVALID_HANDLE_VALUE) { ERROR("Unable to get a handle from the handle manager\n"); hEvent = NULL; free(pEvent); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto OpenEventWExit; } pEventInfo = SHMPTR_TO_PTR(shmpEventInfo); if (pEventInfo == NULL) { ASSERT("Invalid shared memory pointer\n"); HMGRFreeHandle(hEvent); SetLastError(ERROR_INTERNAL_ERROR); goto OpenEventWExit; } /* increase the refCount in shared memory */ pEventInfo->refCount += 1; TRACE("Event (name=%S) found\n", lpName); } OpenEventWExit: SHMRelease(); LOGEXIT("OpenEventW returns HANDLE %p\n", hEvent); PERF_EXIT(OpenEventW); return hEvent; }
/*++ Function: SetEvent See MSDN doc. --*/ BOOL PALAPI SetEvent( IN HANDLE hEvent) { BOOL bRet = TRUE; Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; SHMPTR pTemp; ThreadWaitingList *pWaitingThread; PERF_ENTRY(SetEvent); ENTRY("SetEvent(hEvent=%p)\n", hEvent); pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT); if(NULL == pEvent) { ERROR("Unable to lock handle %p!\n", hEvent); SetLastError(ERROR_INVALID_HANDLE); LOGEXIT("SetEvent returns BOOL %d\n",FALSE); PERF_EXIT(SetEvent); return FALSE; } SHMLock(); pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info); if (pEventInfo == NULL) { ASSERT("Invalid shared memory pointer\n"); SetLastError(ERROR_INTERNAL_ERROR); bRet = FALSE; goto SetEventExit; } if (!pEventInfo->state) { DWORD *pAwakenState; SHMPTR shmWaitingThread; ThreadWaitingList *prevThread = NULL; pEventInfo->state = TRUE; shmWaitingThread = pEventInfo->waitingThreads; /* wake up waiting threads */ while (shmWaitingThread) { pWaitingThread = SHMPTR_TO_PTR(shmWaitingThread); if (pWaitingThread == NULL) { ASSERT("Invalid shared memory pointer\n"); SetLastError(ERROR_INTERNAL_ERROR); bRet = FALSE; goto SetEventExit; } /* check whether thread is already awake. this can happen if another object already woke up the thread, but the thread hasn't yet had time to remove itself from all waiting lists. */ pAwakenState = SHMPTR_TO_PTR(pWaitingThread->state.shmAwakened); if(!THREADInterlockedAwaken(pAwakenState, FALSE)) { TRACE("thread is already awake, skipping it\n"); prevThread = pWaitingThread; shmWaitingThread = pWaitingThread->ptr.shmNext; continue; } /* remove thread from waiting list */ pTemp = shmWaitingThread; shmWaitingThread = pWaitingThread->ptr.shmNext; if(NULL == prevThread) { pEventInfo->waitingThreads = shmWaitingThread; } else { prevThread->ptr.shmNext = shmWaitingThread; } TRACE("Waking up thread(%#x) Event has been set (%p)\n", pWaitingThread->threadId, hEvent); WakeUpThread(pWaitingThread->threadId, pWaitingThread->processId, pWaitingThread->blockingPipe, WUTC_SIGNALED ); SHMfree(pTemp); /* if the event is auto-reset, we only want to wake up one thread, so break out.*/ if (pEventInfo->manualReset == FALSE) { pEventInfo->state = FALSE; break; } } } SetEventExit: SHMRelease(); HMGRUnlockHandle(hEvent, &pEvent->objHeader); LOGEXIT("SetEvent returns BOOL %d\n", bRet); PERF_EXIT(SetEvent); return bRet; }
/*++ Function: CreateEventW Note: Events could be used for cross-process synchroniztion. Security Attributes could be ignored. lpName could be non NULL. See MSDN doc. --*/ HANDLE PALAPI CreateEventW( IN LPSECURITY_ATTRIBUTES lpEventAttributes, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName) { HANDLE hEvent = NULL; Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; SHMPTR newEvent; DWORD OldLastError; BOOL need_unlock = FALSE; LPCWSTR lpObjectName = NULL; WCHAR MangledObjectName[MAX_PATH]; PERF_ENTRY(CreateEventW); ENTRY("CreateEventW(lpEventAttr=%p, bManualReset=%d, " "bInitialState=%d, lpName=%p (%S)\n", lpEventAttributes, bManualReset, bInitialState, lpName?lpName:W16_NULLSTRING, lpName?lpName:W16_NULLSTRING); /* Validate parameters */ if (lpEventAttributes != NULL) { ASSERT("lpEventAttributes must be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto CreateEventExit; } if (lpName) { lpObjectName=lpName; if (!MangleObjectNameW(&lpObjectName, MangledObjectName)) { goto CreateEventExit; } /* take the shared memory lock to prevent other threads/processes from creating/deleting the object behind our back*/ SHMLock(); need_unlock = TRUE; /* Verify if there's an Event already created with that name */ OldLastError = GetLastError(); /* Try to open the event, using its unmangled name, as OpenEventW will mangle it */ hEvent = OpenEventW(EVENT_ALL_ACCESS, FALSE, lpName); if (hEvent != NULL) { TRACE("Event (%S) already exist.\n", lpName); SetLastError(ERROR_ALREADY_EXISTS); goto CreateEventExit; } if (GetLastError() == ERROR_INVALID_HANDLE) { ERROR("Another kernel object is using that name\n"); SetLastError(ERROR_INVALID_HANDLE); goto CreateEventExit; } SetLastError(OldLastError); } /* Allocate the event object */ pEvent = (Event *) malloc(sizeof(Event)); if (pEvent == NULL) { ERROR("Unable to allocate memory\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto CreateEventExit; } /* Allocate the EventInfo in shared memory, so it can be accessible by other processes */ newEvent = SHMalloc(sizeof(GLOBAL_EVENT_SYSTEM_OBJECT)); if (newEvent == (SHMPTR) NULL) { ERROR("Unable to allocate shared memory\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); free( pEvent ); goto CreateEventExit; } pEvent->objHeader.type = HOBJ_EVENT; pEvent->objHeader.close_handle = CloseEventHandle; pEvent->objHeader.dup_handle = DupEventHandle; pEvent->refCount = 1; pEvent->info = newEvent; pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(newEvent); pEventInfo->refCount = 1; pEventInfo->state = bInitialState; pEventInfo->manualReset = bManualReset; pEventInfo->waitingThreads = (SHMPTR) NULL; pEventInfo->next = (SHMPTR) NULL; pEventInfo->ShmHeader.ObjectType = SHM_NAMED_EVENTS; pEventInfo->ShmHeader.ShmSelf = newEvent; if (lpName) { if ((pEventInfo->ShmHeader.ShmObjectName = SHMWStrDup( lpObjectName )) == 0) { ERROR( "Unable to allocate shared memory!\n " ); SetLastError(ERROR_INTERNAL_ERROR); SHMfree(newEvent); free(pEvent); goto CreateEventExit; } } else { pEventInfo->ShmHeader.ShmObjectName = 0; } hEvent = HMGRGetHandle((HOBJSTRUCT *) pEvent); if (hEvent == INVALID_HANDLE_VALUE) { if (lpName != NULL) { SHMfree(pEventInfo->ShmHeader.ShmObjectName); } SHMfree(newEvent); free(pEvent); ERROR("Unable to get a free handle\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto CreateEventExit; } /* Save the EventInfo into the global link list in shared memory. (Only if it has a name) */ if (lpName) { SHMAddNamedObject(newEvent); } TRACE("Event created (HANDLE=%p)\n", hEvent); CreateEventExit: if(need_unlock) { /* release the lock taken before OpenEventW */ SHMRelease(); } LOGEXIT("CreateEventW returns HANDLE %p\n", hEvent); PERF_EXIT(CreateEventW); return hEvent; }
/*++ Function: GetFullPathNameW See MSDN doc. --*/ DWORD PALAPI GetFullPathNameW( IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart) { LPSTR fileNameA; /* bufferA needs to be able to hold a path that's potentially as large as MAX_PATH WCHARs. */ CHAR bufferA[MAX_PATH * sizeof(WCHAR)]; LPSTR lpFilePartA; int fileNameLength; int srcSize; int length; DWORD nRet = 0; PERF_ENTRY(GetFullPathNameW); ENTRY("GetFullPathNameW(lpFileName=%p (%S), nBufferLength=%u, lpBuffer=%p" ", lpFilePart=%p)\n", lpFileName?lpFileName:W16_NULLSTRING, lpFileName?lpFileName:W16_NULLSTRING, nBufferLength, lpBuffer, lpFilePart); /* Find the number of bytes required to convert lpFileName to ANSI. This may be more than MAX_PATH. We try to handle that case, since it may be less than MAX_PATH WCHARs. */ fileNameLength = WideCharToMultiByte(CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL); if (fileNameLength == 0) { /* Couldn't convert to ANSI. That's odd. */ SetLastError(ERROR_INVALID_PARAMETER); goto done; } else { fileNameA = alloca(fileNameLength); } /* Now convert lpFileName to ANSI. */ srcSize = WideCharToMultiByte (CP_ACP, 0, lpFileName, -1, fileNameA, fileNameLength, NULL, NULL ); if( srcSize == 0 ) { DWORD dwLastError = GetLastError(); if( dwLastError == ERROR_INSUFFICIENT_BUFFER ) { ERROR("lpFileName is larger than MAX_PATH (%d)!\n", MAX_PATH); } else { ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); } SetLastError(ERROR_INVALID_PARAMETER); goto done; } length = GetFullPathNameA(fileNameA, sizeof(bufferA), bufferA, &lpFilePartA); if (length == 0 || length > sizeof(bufferA)) { /* Last error is set by GetFullPathNameA */ nRet = length; goto done; } /* Convert back to Unicode the result */ nRet = MultiByteToWideChar( CP_ACP, 0, bufferA, -1, lpBuffer, nBufferLength ); if (nRet == 0) { if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { /* get the required length */ nRet = MultiByteToWideChar( CP_ACP, 0, bufferA, -1, NULL, 0 ); SetLastError(ERROR_BUFFER_OVERFLOW); } goto done; } /* MultiByteToWideChar counts the trailing NULL, but GetFullPathName does not. */ nRet--; /* now set lpFilePart */ if (lpFilePart != NULL) { *lpFilePart = lpBuffer; *lpFilePart += MultiByteToWideChar( CP_ACP, 0, bufferA, lpFilePartA - bufferA, NULL, 0); } done: LOGEXIT("GetFullPathNameW returns DWORD %u\n", nRet); PERF_EXIT(GetFullPathNameW); return nRet; }
/*++ Function: GetTimeZoneInformation The GetTimeZoneInformation function retrieves the current time-zone parameters. These parameters control the translations between Coordinated Universal Time (UTC) and local time. Parameters lpTimeZoneInformation [out] Pointer to a TIME_ZONE_INFORMATION structure to receive the current time-zone parameters. Return Values If the function succeeds, the return value is one of the following values: TIME_ZONE_ID_UNKNOWN TIME_ZONE_ID_STANDARD TIME_ZONE_ID_DAYLIGHT TIME_ZONE_ID_INVALID --*/ DWORD PALAPI GetTimeZoneInformation( OUT LPTIME_ZONE_INFORMATION lpTimeZoneInformation) { #if HAVE_TIMEZONE_VAR extern long int timezone; #endif // HAVE_TIMEZONE_VAR time_t tt; const char *tzStandardName; const char *tzDaylightName; #if HAVE_LOCALTIME_R struct tm ut; #endif /* HAVE_LOCALTIME_R */ struct tm *utPtr; DWORD retval = TIME_ZONE_ID_INVALID; struct tm dst_date, std_date; PERF_ENTRY(GetTimeZoneInformation); ENTRY("GetTimeZoneInformation (lpTimeZoneInformation=%p)\n", lpTimeZoneInformation); tt = time(NULL); #if HAVE_LOCALTIME_R utPtr = &ut; localtime_r(&tt,&ut); #else /* HAVE_LOCALTIME_R */ utPtr = localtime(&tt); #endif /* HAVE_LOCALTIME_R */ #if HAVE_TZNAME tzStandardName = tzname[0]; tzDaylightName = tzname[1]; #else /* HAVE_TZNAME */ tzStandardName = utPtr->tm_zone; tzDaylightName = ""; #endif /* HAVE_TZNAME */ TRACE("standard timezone name = %s\n", tzStandardName); TRACE("daylight timezone name = %s\n", tzDaylightName); #if HAVE_TM_GMTOFF TRACE("timezone offset = %ld\n", utPtr->tm_gmtoff / 60); #else TRACE("timezone offset = %ld\n", (-timezone + (utPtr->tm_isdst ? 3600 : 0)) / 60); #endif TRACE("daylight savings = %d\n", utPtr->tm_isdst); #if HAVE_TM_GMTOFF lpTimeZoneInformation->Bias = -utPtr->tm_gmtoff / 60; #else lpTimeZoneInformation->Bias = (timezone - (utPtr->tm_isdst ? 3600 : 0)) / 60; #endif /* This may be wrong for some obscure time zones. */ lpTimeZoneInformation->StandardBias = 0; lpTimeZoneInformation->DaylightBias = -60; if (MultiByteToWideChar(CP_ACP, 0, tzStandardName, -1, lpTimeZoneInformation->StandardName, 32) == 0) { ASSERT("failed to convert multibytes to wide chars\n"); goto EXIT; } if (MultiByteToWideChar(CP_ACP, 0, tzDaylightName, -1, lpTimeZoneInformation->DaylightName, 32) == 0) { ASSERT("failed to convert multibytes to wide chars\n"); goto EXIT; } memset(&lpTimeZoneInformation->StandardDate, 0, sizeof(SYSTEMTIME)); memset(&lpTimeZoneInformation->DaylightDate, 0, sizeof(SYSTEMTIME)); if (utPtr->tm_isdst >= 0) { if (!TIMEGetStdDstDates(&dst_date, &std_date)) { goto EXIT; } if ((dst_date.tm_mon == 0) || (std_date.tm_mon == 0)) { retval = TIME_ZONE_ID_STANDARD; goto EXIT; } TRACE("Transition to Standard date: %s\n", asctime(&dst_date)); TRACE("Transition to Daylight date: %s\n", asctime(&std_date)); lpTimeZoneInformation->StandardDate.wDay = TIMEGetWeekDayNumber(std_date); lpTimeZoneInformation->DaylightDate.wDay = TIMEGetWeekDayNumber(dst_date); if(!lpTimeZoneInformation->StandardDate.wDay || !lpTimeZoneInformation->DaylightDate.wDay) { goto EXIT; } lpTimeZoneInformation->StandardDate.wMonth = std_date.tm_mon + 1; lpTimeZoneInformation->DaylightDate.wMonth = dst_date.tm_mon + 1; lpTimeZoneInformation->StandardDate.wDayOfWeek = std_date.tm_wday; lpTimeZoneInformation->DaylightDate.wDayOfWeek = dst_date.tm_wday; lpTimeZoneInformation->StandardDate.wHour = (std_date.tm_hour + 1) % 24; lpTimeZoneInformation->DaylightDate.wHour = (dst_date.tm_hour + 1) % 24; TRACE("StandardDate: mon:%d dofweek:%d hour:%d wday:%d\n", lpTimeZoneInformation->StandardDate.wMonth, lpTimeZoneInformation->StandardDate.wDayOfWeek, lpTimeZoneInformation->StandardDate.wHour, lpTimeZoneInformation->StandardDate.wDay); TRACE("DaylightDate: mon:%d dofweek:%d hour:%d wday:%d\n", lpTimeZoneInformation->DaylightDate.wMonth, lpTimeZoneInformation->DaylightDate.wDayOfWeek, lpTimeZoneInformation->DaylightDate.wHour, lpTimeZoneInformation->DaylightDate.wDay); if (utPtr->tm_isdst) { lpTimeZoneInformation->Bias -= lpTimeZoneInformation->DaylightBias; retval = TIME_ZONE_ID_DAYLIGHT; } else { lpTimeZoneInformation->Bias -= lpTimeZoneInformation->StandardBias; retval = TIME_ZONE_ID_STANDARD; } } else { retval = TIME_ZONE_ID_UNKNOWN; } EXIT: LOGEXIT("GetTimeZoneInformation returns DWORD %u\n", retval); PERF_EXIT(GetTimeZoneInformation); return retval; }
/*++ Function: GetTempPathA See MSDN. Notes: On Windows NT/2000, the temp path is determined by the following steps: 1. The value of the "TMP" environment variable, or if it doesn't exist, 2. The value of the "TEMP" environment variable, or if it doesn't exist, 3. The Windows directory. In this implementation, '/tmp' is used instead of the Windows directory in the final step. Also note that dwPathLen will always be the proper return value, since GetEnvironmentVariable and MultiByteToWideChar will both return the required size of the buffer if they fail, which is what this function should do also. --*/ DWORD PALAPI GetTempPathA( IN DWORD nBufferLength, OUT LPSTR lpBuffer) { DWORD dwPathLen = 0; const char *env_var1 = "TMP"; const char *env_var2 = "TEMP"; // GetTempPath is supposed to include the trailing slash. const char *defaultDir = "/tmp/"; PERF_ENTRY(GetTempPathA); ENTRY("GetTempPathA(nBufferLength=%u, lpBuffer=%p)\n", nBufferLength, lpBuffer); if ( !lpBuffer ) { ERROR( "lpBuffer was not a valid pointer.\n" ) SetLastError( ERROR_INVALID_PARAMETER ); LOGEXIT("GetTempPathA returns DWORD %u\n", dwPathLen); PERF_EXIT(GetTempPathA); return 0; } /* try "TMP" */ dwPathLen = GetEnvironmentVariableA(env_var1, lpBuffer, nBufferLength); if ( dwPathLen > 0 ) { goto done; } /* no luck, try "TEMP" */ dwPathLen = GetEnvironmentVariableA(env_var2, lpBuffer, nBufferLength); if ( dwPathLen > 0 ) { goto done; } /* still no luck, use /tmp */ if ( strlen(defaultDir) < nBufferLength ) { strcpy(lpBuffer, defaultDir); dwPathLen = strlen(defaultDir); } else { /* get the required length */ dwPathLen = strlen(defaultDir) + 1; } done: if ( dwPathLen > nBufferLength ) { ERROR("Buffer is too small, need %d characters\n", dwPathLen); SetLastError( ERROR_INSUFFICIENT_BUFFER ); } LOGEXIT("GetTempPathA returns DWORD %u\n", dwPathLen); PERF_EXIT(GetTempPathA); return dwPathLen; }
/*++ Function: GetSystemTime The GetSystemTime function retrieves the current system date and time. The system time is expressed in Coordinated Universal Time (UTC). Parameters lpSystemTime [out] Pointer to a SYSTEMTIME structure to receive the current system date and time. Return Values This function does not return a value. --*/ VOID PALAPI GetSystemTime( OUT LPSYSTEMTIME lpSystemTime) { time_t tt; #if HAVE_GMTIME_R struct tm ut; #endif /* HAVE_GMTIME_R */ struct tm *utPtr; struct timeval timeval; int timeofday_retval; PERF_ENTRY(GetSystemTime); ENTRY("GetSystemTime (lpSystemTime=%p)\n", lpSystemTime); tt = time(NULL); /* We can't get millisecond resolution from time(), so we get it from gettimeofday() */ timeofday_retval = gettimeofday(&timeval,NULL); #if HAVE_GMTIME_R utPtr = &ut; if (gmtime_r(&tt, utPtr) == NULL) #else /* HAVE_GMTIME_R */ if ((utPtr = gmtime(&tt)) == NULL) #endif /* HAVE_GMTIME_R */ { ASSERT("gmtime() failed; errno is %d (%s)\n", errno, strerror(errno)); goto EXIT; } lpSystemTime->wYear = 1900 + utPtr->tm_year; lpSystemTime->wMonth = utPtr->tm_mon + 1; lpSystemTime->wDayOfWeek = utPtr->tm_wday; lpSystemTime->wDay = utPtr->tm_mday; lpSystemTime->wHour = utPtr->tm_hour; lpSystemTime->wMinute = utPtr->tm_min; lpSystemTime->wSecond = utPtr->tm_sec; if(-1 == timeofday_retval) { ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno)); lpSystemTime->wMilliseconds = 0; } else { int old_seconds; int new_seconds; lpSystemTime->wMilliseconds = timeval.tv_usec/1000; old_seconds = utPtr->tm_sec; new_seconds = timeval.tv_sec%60; /* just in case we reached the next second in the interval between time() and gettimeofday() */ if( old_seconds!=new_seconds ) { TRACE("crossed seconds boundary; setting milliseconds to 999\n"); lpSystemTime->wMilliseconds = 999; } } EXIT: LOGEXIT("GetSystemTime returns void\n"); PERF_EXIT(GetSystemTime); }
/*++ Function : wcstod There is a slight difference between the Windows version of wcstod and the BSD versio of wcstod. Under Windows the string " -1b " returns -1.000000 stop char = 'b' Under BSD the same string returns 0.000000 stop ' ' see msdn doc. --*/ double __cdecl PAL_wcstod( const wchar_16 * nptr, wchar_16 **endptr ) { double RetVal = 0.0; LPSTR lpStringRep = NULL; LPWSTR lpStartOfExpression = (LPWSTR)nptr; LPWSTR lpEndOfExpression = NULL; UINT Length = 0; PERF_ENTRY(wcstod); ENTRY( "wcstod( %p (%S), %p (%S) )\n", nptr, nptr, endptr , endptr ); THREADMarkDiagnostic("PAL_wcstod -> strtod"); if ( !nptr ) { ERROR( "nptr is invalid.\n" ); LOGEXIT( "wcstod returning 0.0\n" ); PERF_EXIT(wcstod); return 0.0; } /* Eat white space. */ while ( PAL_iswspace( *lpStartOfExpression ) ) { lpStartOfExpression++; } /* Get the end of the expression. */ lpEndOfExpression = lpStartOfExpression; while ( *lpEndOfExpression ) { if ( !MISC_CRT_WCSTOD_IsValidCharacter( *lpEndOfExpression ) ) { break; } lpEndOfExpression++; } if ( lpEndOfExpression != lpStartOfExpression ) { Length = lpEndOfExpression - lpStartOfExpression; lpStringRep = (LPSTR)PAL_malloc( Length + 1); if ( lpStringRep ) { if ( WideCharToMultiByte( CP_ACP, 0, lpStartOfExpression, Length, lpStringRep, Length + 1 , NULL, 0 ) != 0 ) { LPSTR ScanStop = NULL; lpStringRep[Length]= 0; RetVal = strtod( lpStringRep, &ScanStop ); /* See if strtod failed. */ if ( RetVal == 0.0 && ScanStop == lpStringRep ) { ASSERT( "An error occured in the conversion.\n" ); lpEndOfExpression = (LPWSTR)nptr; } } else { ASSERT( "Wide char to multibyte conversion failed.\n" ); lpEndOfExpression = (LPWSTR)nptr; } } else { ERROR( "Not enough memory.\n" ); lpEndOfExpression = (LPWSTR)nptr; } } else { ERROR( "Malformed expression.\n" ); lpEndOfExpression = (LPWSTR)nptr; } /* Set the stop scan character. */ if ( endptr != NULL ) { *endptr = lpEndOfExpression; } PAL_free( lpStringRep ); LOGEXIT( "wcstod returning %f.\n", RetVal ); PERF_EXIT(wcstod); return RetVal; }
/*++ Function: RemoveDirectoryW See MSDN doc. --*/ BOOL PALAPI RemoveDirectoryW( IN LPCWSTR lpPathName) { PathCharString mb_dirPathString; int mb_size; DWORD dwLastError = 0; BOOL bRet = FALSE; size_t length; char * mb_dir; PERF_ENTRY(RemoveDirectoryW); ENTRY("RemoveDirectoryW(lpPathName=%p (%S))\n", lpPathName?lpPathName:W16_NULLSTRING, lpPathName?lpPathName:W16_NULLSTRING); if (lpPathName == NULL) { dwLastError = ERROR_PATH_NOT_FOUND; goto done; } length = (PAL_wcslen(lpPathName)+1) * 3; mb_dir = mb_dirPathString.OpenStringBuffer(length); if (NULL == mb_dir) { dwLastError = ERROR_NOT_ENOUGH_MEMORY; goto done; } mb_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, mb_dir, length, NULL, NULL ); mb_dirPathString.CloseBuffer(mb_size); if( mb_size == 0 ) { dwLastError = GetLastError(); if( dwLastError == ERROR_INSUFFICIENT_BUFFER ) { WARN("lpPathName is larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH); dwLastError = ERROR_FILENAME_EXCED_RANGE; } else { ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); dwLastError = ERROR_INTERNAL_ERROR; } goto done; } if ((bRet = RemoveDirectoryHelper (mb_dir, &dwLastError))) { TRACE("Removal of directory [%s] was successful.\n", mb_dir); } done: if( dwLastError ) { SetLastError( dwLastError ); } LOGEXIT("RemoveDirectoryW returns BOOL %d\n", bRet); PERF_EXIT(RemoveDirectoryW); return bRet; }
/* The use of LONG is by design, to ensure that a 32 bit value is always returned from this function. If "long" is used instead of LONG, then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus breaking Windows behavior. */ LONG __cdecl PAL_wcstol( const wchar_16 *nptr, wchar_16 **endptr, int base) { char *s_nptr = 0; char *s_endptr = 0; long res; int size; DWORD dwLastError = 0; PERF_ENTRY(wcstol); ENTRY("wcstol (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING, endptr, base); size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL); if (!size) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL_wcstolExit; } s_nptr = (char *)PAL_malloc(size); if (!s_nptr) { ERROR("PAL_malloc failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); res = 0; goto PAL_wcstolExit; } size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL); if( size==0 ) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL_wcstolExit; } res = strtol(s_nptr, &s_endptr, base); #ifdef BIT64 if (res > _I32_MAX) { res = _I32_MAX; errno = ERANGE; } else if (res < _I32_MIN) { res = _I32_MIN; errno = ERANGE; } #endif /* only ASCII characters will be accepted by strtol, and those always get mapped to single-byte characters, so the first rejected character will have the same index in the multibyte and widechar strings */ if( endptr ) { size = s_endptr - s_nptr; *endptr = (wchar_16 *)&nptr[size]; } PAL_wcstolExit: PAL_free(s_nptr); LOGEXIT("wcstol returning long %ld\n", res); PERF_EXIT(wcstol); /* This explicit cast to LONG is used to silence any potential warnings due to implicitly casting the native long res to LONG when returning. */ return (LONG)res; }
/*++ Function: SetCurrentDirectoryW See MSDN doc. --*/ BOOL PALAPI SetCurrentDirectoryW( IN LPCWSTR lpPathName) { BOOL bRet; DWORD dwLastError = 0; PathCharString dirPathString; int size; size_t length; char * dir; PERF_ENTRY(SetCurrentDirectoryW); ENTRY("SetCurrentDirectoryW(lpPathName=%p (%S))\n", lpPathName?lpPathName:W16_NULLSTRING, lpPathName?lpPathName:W16_NULLSTRING); /*check if the given path is null. If so return FALSE*/ if (lpPathName == NULL ) { ERROR("Invalid path/directory name\n"); dwLastError = ERROR_INVALID_NAME; bRet = FALSE; goto done; } length = (PAL_wcslen(lpPathName)+1) * 3; dir = dirPathString.OpenStringBuffer(length); if (NULL == dir) { dwLastError = ERROR_NOT_ENOUGH_MEMORY; bRet = FALSE; goto done; } size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, dir, length, NULL, NULL ); dirPathString.CloseBuffer(size); if( size == 0 ) { dwLastError = GetLastError(); if( dwLastError == ERROR_INSUFFICIENT_BUFFER ) { WARN("lpPathName is larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH); dwLastError = ERROR_FILENAME_EXCED_RANGE; } else { ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); dwLastError = ERROR_INTERNAL_ERROR; } bRet = FALSE; goto done; } bRet = SetCurrentDirectoryA(dir); done: if( dwLastError ) { SetLastError(dwLastError); } LOGEXIT("SetCurrentDirectoryW returns BOOL %d\n", bRet); PERF_EXIT(SetCurrentDirectoryW); return bRet; }
ULONGLONG __cdecl PAL__wcstoui64( const wchar_16 *nptr, wchar_16 **endptr, int base) { char *s_nptr = 0; char *s_endptr = 0; unsigned long long res; int size; DWORD dwLastError = 0; PERF_ENTRY(wcstoul); ENTRY("_wcstoui64 (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING, endptr, base); THREADMarkDiagnostic("PAL__wcstoui64 -> strtoull"); size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL); if (!size) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL__wcstoui64Exit; } s_nptr = (char *)PAL_malloc(size); if (!s_nptr) { ERROR("PAL_malloc failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); res = 0; goto PAL__wcstoui64Exit; } size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL); if (!size) { dwLastError = GetLastError(); ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError); SetLastError(ERROR_INVALID_PARAMETER); res = 0; goto PAL__wcstoui64Exit; } res = strtoull(s_nptr, &s_endptr, base); /* only ASCII characters will be accepted by strtoull, and those always get mapped to single-byte characters, so the first rejected character will have the same index in the multibyte and widechar strings */ if( endptr ) { size = s_endptr - s_nptr; *endptr = (wchar_16 *)&nptr[size]; } PAL__wcstoui64Exit: PAL_free(s_nptr); LOGEXIT("_wcstoui64 returning unsigned long long %llu\n", res); PERF_EXIT(_wcstoui64); return res; }
/*++ Function: CreateDirectoryA Note: lpSecurityAttributes always NULL. See MSDN doc. --*/ BOOL PALAPI CreateDirectoryA( IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) { BOOL bRet = FALSE; DWORD dwLastError = 0; char *realPath; LPSTR UnixPathName = NULL; int pathLength; int i; const int mode = S_IRWXU | S_IRWXG | S_IRWXO; PERF_ENTRY(CreateDirectoryA); ENTRY("CreateDirectoryA(lpPathName=%p (%s), lpSecurityAttr=%p)\n", lpPathName?lpPathName:"NULL", lpPathName?lpPathName:"NULL", lpSecurityAttributes); if ( lpSecurityAttributes ) { ASSERT("lpSecurityAttributes is not NULL as it should be\n"); dwLastError = ERROR_INVALID_PARAMETER; goto done; } // Windows returns ERROR_PATH_NOT_FOUND when called with NULL. // If we don't have this check, strdup(NULL) segfaults. if (lpPathName == NULL) { ERROR("CreateDirectoryA called with NULL pathname!\n"); dwLastError = ERROR_PATH_NOT_FOUND; goto done; } UnixPathName = PAL__strdup(lpPathName); if (UnixPathName == NULL ) { ERROR("PAL__strdup() failed\n"); dwLastError = ERROR_NOT_ENOUGH_MEMORY; goto done; } FILEDosToUnixPathA( UnixPathName ); // Remove any trailing slashes at the end because mkdir might not // handle them appropriately on all platforms. pathLength = strlen(UnixPathName); i = pathLength; while(i > 1) { if(UnixPathName[i - 1] =='/') { UnixPathName[i - 1]='\0'; i--; } else { break; } } // Check the constraint for the real path length (should be < MAX_LONGPATH). // Get an absolute path. if (UnixPathName[0] == '/') { realPath = UnixPathName; } else { const char *cwd = PAL__getcwd(NULL, MAX_LONGPATH); if (NULL == cwd) { WARN("Getcwd failed with errno=%d [%s]\n", errno, strerror(errno)); dwLastError = DIRGetLastErrorFromErrno(); goto done; } // Copy cwd, '/', path int iLen = strlen(cwd) + 1 + pathLength + 1; realPath = static_cast<char *>(alloca(iLen)); sprintf_s(realPath, iLen, "%s/%s", cwd, UnixPathName); PAL_free((char *)cwd); } // Canonicalize the path so we can determine its length. FILECanonicalizePath(realPath); if (strlen(realPath) >= MAX_LONGPATH) { WARN("UnixPathName is larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH); dwLastError = ERROR_FILENAME_EXCED_RANGE; goto done; } if ( mkdir(realPath, mode) != 0 ) { TRACE("Creation of directory [%s] was unsuccessful, errno = %d.\n", UnixPathName, errno); switch( errno ) { case ENOTDIR: /* FALL THROUGH */ case ENOENT: FILEGetProperNotFoundError( realPath, &dwLastError ); goto done; case EEXIST: dwLastError = ERROR_ALREADY_EXISTS; break; default: dwLastError = ERROR_ACCESS_DENIED; } } else { TRACE("Creation of directory [%s] was successful.\n", UnixPathName); bRet = TRUE; } done: if( dwLastError ) { SetLastError( dwLastError ); } PAL_free( UnixPathName ); LOGEXIT("CreateDirectoryA returns BOOL %d\n", bRet); PERF_EXIT(CreateDirectoryA); return bRet; }
/*++ Function: GetDiskFreeSpaceW See MSDN doc. --*/ PALIMPORT BOOL PALAPI GetDiskFreeSpaceW( LPCWSTR lpDirectoryName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, /* Caller will ignore output value */ LPDWORD lpTotalNumberOfClusters) /* Caller will ignore output value */ { BOOL bRetVal = FALSE; pal_statfs fsInfoBuffer; INT statfsRetVal = 0; DWORD dwLastError = NO_ERROR; CHAR DirNameBuffer[ MAX_LONGPATH ]; PERF_ENTRY(GetDiskFreeSpaceW); ENTRY( "GetDiskFreeSpaceW( lpDirectoryName=%p (%S), lpSectorsPerCluster=%p," "lpBytesPerSector=%p, lpNumberOfFreeClusters=%p, " "lpTotalNumberOfClusters=%p )\n", lpDirectoryName ? lpDirectoryName : W16_NULLSTRING, lpDirectoryName ? lpDirectoryName : W16_NULLSTRING, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters ); /* Sanity checks. */ if ( !lpSectorsPerCluster ) { ERROR( "lpSectorsPerCluster cannot be NULL!\n" ); dwLastError = ERROR_INVALID_PARAMETER; goto exit; } if ( !lpBytesPerSector ) { ERROR( "lpBytesPerSector cannot be NULL!\n" ); dwLastError = ERROR_INVALID_PARAMETER; goto exit; } if ( lpNumberOfFreeClusters || lpTotalNumberOfClusters ) { TRACE("GetDiskFreeSpaceW is ignoring lpNumberOfFreeClusters" " and lpTotalNumberOfClusters\n" ); } if ( lpDirectoryName && PAL_wcslen( lpDirectoryName ) == 0 ) { ERROR( "lpDirectoryName is empty.\n" ); dwLastError = ERROR_INVALID_PARAMETER; goto exit; } /* Fusion uses this API to round file sizes up to their actual size on-disk based on the BytesPerSector * SectorsPerCluster. The intent is to avoid computing the sum of all file sizes in the cache just in bytes and not account for the cluster-sized slop, when determining if the cache is too large or not. */ if ( lpDirectoryName ) { if ( WideCharToMultiByte( CP_ACP, 0, lpDirectoryName, -1, DirNameBuffer,MAX_LONGPATH, 0, 0 ) != 0 ) { FILEDosToUnixPathA( DirNameBuffer ); statfsRetVal = statfs( DirNameBuffer, &fsInfoBuffer ); } else { ASSERT( "Unable to convert the lpDirectoryName to multibyte.\n" ); dwLastError = ERROR_INTERNAL_ERROR; goto exit; } } else { statfsRetVal = statfs( "/", &fsInfoBuffer ); } if ( statfsRetVal == 0 ) { *lpBytesPerSector = fsInfoBuffer.f_bsize; *lpSectorsPerCluster = 1; bRetVal = TRUE; } else { if ( errno == ENOTDIR || errno == ENOENT ) { FILEGetProperNotFoundError( DirNameBuffer, &dwLastError ); goto exit; } dwLastError = FILEGetLastErrorFromErrno(); if ( ERROR_INTERNAL_ERROR == dwLastError ) { ASSERT("statfs() not expected to fail with errno:%d (%s)\n", errno, strerror(errno)); } else { TRACE("statfs() failed, errno:%d (%s)\n", errno, strerror(errno)); } } exit: if ( NO_ERROR != dwLastError ) { SetLastError( dwLastError ); } LOGEXIT( "GetDiskFreeSpace returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" ); PERF_EXIT(GetDiskFreeSpaceW); return bRetVal; }
/*++ Function: SetCurrentDirectoryA See MSDN doc. --*/ BOOL PALAPI SetCurrentDirectoryA( IN LPCSTR lpPathName) { BOOL bRet = FALSE; DWORD dwLastError = 0; int result; LPSTR UnixPathName = NULL; PERF_ENTRY(SetCurrentDirectoryA); ENTRY("SetCurrentDirectoryA(lpPathName=%p (%s))\n", lpPathName?lpPathName:"NULL", lpPathName?lpPathName:"NULL"); /*check if the given path is null. If so return FALSE*/ if (lpPathName == NULL ) { ERROR("Invalid path/directory name\n"); dwLastError = ERROR_INVALID_NAME; goto done; } if (strlen(lpPathName) >= MAX_LONGPATH) { WARN("Path/directory name longer than MAX_LONGPATH characters\n"); dwLastError = ERROR_FILENAME_EXCED_RANGE; goto done; } UnixPathName = PAL__strdup(lpPathName); if (UnixPathName == NULL ) { ERROR("PAL__strdup() failed\n"); dwLastError = ERROR_NOT_ENOUGH_MEMORY; goto done; } FILEDosToUnixPathA( UnixPathName ); TRACE("Attempting to open Unix dir [%s]\n", UnixPathName); result = chdir(UnixPathName); if ( result == 0 ) { bRet = TRUE; } else { if ( errno == ENOTDIR || errno == ENOENT ) { struct stat stat_data; if ( stat( UnixPathName, &stat_data) == 0 && (stat_data.st_mode & S_IFMT) == S_IFREG ) { /* Not a directory, it is a file. */ dwLastError = ERROR_DIRECTORY; } else { FILEGetProperNotFoundError( UnixPathName, &dwLastError ); } TRACE("chdir() failed, path was invalid.\n"); } else { dwLastError = ERROR_ACCESS_DENIED; ERROR("chdir() failed; errno is %d (%s)\n", errno, strerror(errno)); } } done: if( dwLastError ) { SetLastError(dwLastError); } if(UnixPathName != NULL) { PAL_free( UnixPathName ); } LOGEXIT("SetCurrentDirectoryA returns BOOL %d\n", bRet); PERF_EXIT(SetCurrentDirectoryA); return bRet; }
/*++ Function: FormatMessageW See MSDN doc. --*/ DWORD PALAPI FormatMessageW( IN DWORD dwFlags, IN LPCVOID lpSource, IN DWORD dwMessageId, IN DWORD dwLanguageId, OUT LPWSTR lpBuffer, IN DWORD nSize, IN va_list *Arguments) { BOOL bIgnoreInserts = FALSE; BOOL bIsVaList = TRUE; BOOL bIsLocalAlloced = FALSE; LPWSTR lpSourceString = NULL; UINT nCount = 0; LPWSTR lpReturnString = NULL; LPWSTR lpWorkingString = NULL; PERF_ENTRY(FormatMessageW); ENTRY( "FormatMessageW(dwFlags=%#x, lpSource=%p, dwMessageId=%#x, " "dwLanguageId=%#x, lpBuffer=%p, nSize=%u, va_list=%p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); /* Sanity checks. */ if ( dwFlags & FORMAT_MESSAGE_FROM_STRING && !lpSource ) { /* This behavior is different then in Windows. Windows would just crash.*/ ERROR( "lpSource cannot be NULL.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( !(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) && !lpBuffer ) { /* This behavior is different then in Windows. Windows would just crash.*/ ERROR( "lpBuffer cannot be NULL, if " " FORMAT_MESSAGE_ALLOCATE_BUFFER is not specified.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) && ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) ) { ERROR( "These flags cannot co-exist. You can either " "specify FORMAT_MESSAGE_FROM_STRING, or " "FORMAT_MESSAGE_FROM_SYSTEM.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( !( dwFlags & FORMAT_MESSAGE_FROM_STRING ) && ( dwLanguageId != 0 && dwLanguageId != MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) ) ) { ERROR( "Invalid language indentifier.\n" ); SetLastError( ERROR_RESOURCE_LANG_NOT_FOUND ); goto exit; } /* Parameter processing. */ if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) { TRACE( "Allocated %d TCHARs. Don't forget to call LocalFree to " "free the memory when done.\n", nSize ); bIsLocalAlloced = TRUE; } if ( dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS ) { bIgnoreInserts = TRUE; } if ( dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY ) { if ( !Arguments && !bIgnoreInserts ) { ERROR( "The va_list cannot be NULL.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } else { bIsVaList = FALSE; } } if ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) { lpSourceString = (LPWSTR)lpSource; } else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) { lpWorkingString = lpReturnString = FMTMSG_GetMessageString( dwMessageId ); if ( !lpWorkingString ) { ERROR( "Unable to find the message %d.\n", dwMessageId ); SetLastError( ERROR_INTERNAL_ERROR ); nCount = 0; goto exit; } nCount = PAL_wcslen( lpWorkingString ); if ( !bIsLocalAlloced && nCount > nSize ) { ERROR( "Insufficient buffer.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); lpWorkingString = NULL; nCount = 0; goto exit; } if ( !lpWorkingString ) { ERROR( "Invalid error indentifier.\n" ); SetLastError( ERROR_INVALID_ADDRESS ); } goto exit; } else { ERROR( "Unknown flag.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); goto exit; } if ( nSize == 0 && bIsLocalAlloced ) { nSize = 1; } lpWorkingString = LocalAlloc( LMEM_FIXED, nSize * sizeof( WCHAR ) ); if ( !lpWorkingString ) { ERROR( "Unable to allocate memory for the working string.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); goto exit; } /* Process the string. */ lpReturnString = lpWorkingString; while ( *lpSourceString ) { if ( *lpSourceString == '%' && !bIgnoreInserts ) { lpSourceString++; /* Escape sequences. */ if ( *lpSourceString == '0' ) { /* Terminates a message without a newline character. */ *lpWorkingString = '\0'; goto exit; } else if ( PAL_iswdigit( *lpSourceString ) ) { /* Get the insert number. */ WCHAR Number[] = { '\0', '\0', '\0' }; INT Index = 0; Number[ 0 ] = *lpSourceString; lpSourceString++; if ( PAL_iswdigit( *lpSourceString ) ) { Number[ 1 ] = *lpSourceString; lpSourceString++; if ( PAL_iswdigit( *lpSourceString ) ) { ERROR( "Invalid insert indentifier.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } } Index = FMTMSG__watoi( Number ); if ( Index == 0 ) { ERROR( "Invalid insert indentifier.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } if ( *lpSourceString == '!' ) { LPWSTR lpInsertString = NULL; LPWSTR lpPrintfString = NULL; LPWSTR lpStartOfFormattedString = NULL; UINT nPrintfLength = 0; LPWSTR lpFormattedString = NULL; UINT nFormattedLength = 0; if ( !bIsVaList ) { lpInsertString = (LPWSTR)Arguments[ Index - 1 ]; } else { va_list TheArgs = *Arguments; UINT i = 0; for ( ; i < Index; i++ ) { lpInsertString = va_arg( TheArgs, LPWSTR ); } } /* Calculate the length, and extract the printf string.*/ lpSourceString++; { LPWSTR p = PAL_wcschr( lpSourceString, '!' ); if ( NULL == p ) { nPrintfLength = 0; } else { nPrintfLength = p - lpSourceString; } } lpPrintfString = (LPWSTR)malloc( ( nPrintfLength + 1 ) * sizeof( WCHAR ) ); if ( !lpPrintfString ) { ERROR( "Unable to allocate memory.\n" ); SetLastError( ERROR_NOT_ENOUGH_MEMORY ); lpWorkingString = NULL; nCount = 0; goto exit; } PAL_wcsncpy( lpPrintfString, lpSourceString, nPrintfLength ); *( lpPrintfString + nPrintfLength ) = '\0'; lpStartOfFormattedString = lpFormattedString = FMTMSG_ProcessPrintf( *lpPrintfString, lpPrintfString, lpInsertString); if ( !lpFormattedString ) { ERROR( "Unable to process the format string.\n" ); /* Function will set the error code. */ free( lpPrintfString ); lpWorkingString = NULL; goto exit; } nFormattedLength = PAL_wcslen( lpFormattedString ); /* Append the processed printf string into the working string */ while ( *lpFormattedString ) { _CHECKED_ADD_TO_STRING( *lpFormattedString ); lpFormattedString++; } lpSourceString += nPrintfLength + 1; free( lpPrintfString ); free( lpStartOfFormattedString ); lpPrintfString = lpFormattedString = NULL; } else { /* The printf format string defaults to 's'.*/ LPWSTR lpInsert = NULL; if ( !bIsVaList ) { lpInsert = (LPWSTR)Arguments[ Index - 1 ]; } else { va_list TheArgs = *Arguments; UINT i = 0; for ( ; i < Index; i++ ) { lpInsert = va_arg( TheArgs, LPWSTR ); } } while ( *lpInsert ) { _CHECKED_ADD_TO_STRING( *lpInsert ); lpInsert++; } } } /* Format specifiers. */ else if ( *lpSourceString == '%' ) { _CHECKED_ADD_TO_STRING( '%' ); lpSourceString++; } else if ( *lpSourceString == 'n' ) { /* Hard line break. */ _CHECKED_ADD_TO_STRING( '\n' ); lpSourceString++; } else if ( *lpSourceString == '.' ) { _CHECKED_ADD_TO_STRING( '.' ); lpSourceString++; } else if ( *lpSourceString == '!' ) { _CHECKED_ADD_TO_STRING( '!' ); lpSourceString++; } else if ( !*lpSourceString ) { ERROR( "Invalid parameter.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } else /* Append the character. */ { _CHECKED_ADD_TO_STRING( *lpSourceString ); lpSourceString++; } }/* END if ( *lpSourceString == '%' ) */ else { /* In Windows if FormatMessage is called with ignore inserts, then FormatMessage strips %1!s! down to %1, since string is the default. */ if ( bIgnoreInserts && *lpSourceString == '!' && *( lpSourceString + 1 ) == 's' ) { LPWSTR lpLastBang = PAL_wcschr( lpSourceString + 1, '!' ); if ( lpLastBang && ( 2 == lpLastBang - lpSourceString ) ) { lpSourceString = lpLastBang + 1; } else { ERROR( "Mal-formed string\n" ); SetLastError( ERROR_INVALID_PARAMETER ); lpWorkingString = NULL; nCount = 0; goto exit; } } else { /* Append to the string. */ _CHECKED_ADD_TO_STRING( *lpSourceString ); lpSourceString++; } } } /* Terminate the message. */ _CHECKED_ADD_TO_STRING( '\0' ); /* NULL does not count. */ nCount--; exit: /* Function clean-up and exit. */ if ( lpWorkingString ) { if ( bIsLocalAlloced ) { TRACE( "Assigning the buffer to the pointer.\n" ); *((LPVOID*)lpBuffer) = (LPVOID)lpReturnString; } else /* Only delete lpReturnString if the caller has their own buffer.*/ { TRACE( "Copying the string into the buffer.\n" ); PAL_wcsncpy( lpBuffer, lpReturnString, nCount + 1 ); LocalFree( lpReturnString ); } } else /* Error, something occured. */ { if ( lpReturnString ) { LocalFree( lpReturnString ); } } LOGEXIT( "FormatMessageW returns %d.\n", nCount ); PERF_EXIT(FormatMessageW); return nCount; }
/*++ Function: SearchPathW See MSDN doc. PAL-specific notes : -lpPath must be non-NULL; path delimiters are platform-dependent (':' for Unix) -lpFileName must be non-NULL, may be an absolute path -lpExtension must be NULL -lpFilePart (if non-NULL) doesn't need to be used (but we do) --*/ DWORD PALAPI SearchPathW( IN LPCWSTR lpPath, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart ) { DWORD nRet = 0; WCHAR FullPath[MAX_PATH]; LPCWSTR pPathStart; LPCWSTR pPathEnd; size_t PathLength; size_t FileNameLength; DWORD dw; char AnsiPath[MAX_PATH]; WCHAR CanonicalPath[MAX_PATH]; PERF_ENTRY(SearchPathW); ENTRY("SearchPathW(lpPath=%p (%S), lpFileName=%p (%S), lpExtension=%p, " "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n", lpPath, lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); /* validate parameters */ if(NULL == lpPath) { ASSERT("lpPath may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL == lpFileName) { ASSERT("lpFileName may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL != lpExtension) { ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* special case : if file name contains absolute path, don't search the provided path */ if('\\' == lpFileName[0] || '/' == lpFileName[0]) { /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(lpFileName, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { WARN("couldn't canonicalize path <%S>, error is %#x. failing.\n", lpPath, GetLastError()); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; } } else { LPCWSTR pNextPath; pNextPath = lpPath; FileNameLength = PAL_wcslen(lpFileName); while (*pNextPath) { pPathStart = pNextPath; /* get a pointer to the end of the first path in pPathStart */ pPathEnd = PAL_wcschr(pPathStart, ':'); if (!pPathEnd) { pPathEnd = pPathStart + PAL_wcslen(pPathStart); /* we want to break out of the loop after this pass, so let *pNextPath be '\0' */ pNextPath = pPathEnd; } else { /* point to the next component in the path string */ pNextPath = pPathEnd+1; } PathLength = pPathEnd-pPathStart; if (PathLength+FileNameLength+1 >= MAX_PATH) { /* The path+'/'+file length is too long. Skip it. */ WARN("path component %.*S is too long, skipping it\n", (int)PathLength, pPathStart); continue; } else if(0 == PathLength) { /* empty component : there were 2 consecutive ':' */ continue; } /* Construct a pathname by concatenating one path from lpPath, '/' and lpFileName */ memcpy(FullPath, pPathStart, PathLength*sizeof(WCHAR)); FullPath[PathLength] = '/'; PAL_wcscpy(&FullPath[PathLength+1], lpFileName); /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(FullPath, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { /* Call failed - possibly low memory. Skip the path */ WARN("couldn't canonicalize path <%S>, error is %#x. " "skipping it\n", FullPath, GetLastError()); continue; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; break; } } } if (nRet == 0) { /* file not found anywhere; say so. in Windows, this always seems to say FILE_NOT_FOUND, even if path doesn't exist */ SetLastError(ERROR_FILE_NOT_FOUND); } else { /* find out the required buffer size, copy path to buffer if it's large enough */ nRet = PAL_wcslen(CanonicalPath)+1; if(nRet <= nBufferLength) { if(NULL == lpBuffer) { /* Windows merily crashes here, but let's not */ ERROR("caller told us buffer size was %d, but buffer is NULL\n", nBufferLength); SetLastError(ERROR_INVALID_PARAMETER); nRet = 0; goto done; } PAL_wcscpy(lpBuffer, CanonicalPath); /* don't include the null-terminator in the count if buffer was large enough */ nRet--; if(NULL != lpFilePart) { *lpFilePart = PAL_wcsrchr(lpBuffer, '/'); if(NULL == *lpFilePart) { ASSERT("no '/' in full path!\n"); } else { /* point to character after last '/' */ (*lpFilePart)++; } } } } done: LOGEXIT("SearchPathW returns DWORD %u\n", nRet); PERF_EXIT(SearchPathW); return nRet; }
/*++ Function: powf See MSDN. --*/ PALIMPORT float __cdecl PAL_powf(float x, float y) { float ret; PERF_ENTRY(powf); ENTRY("powf (x=%f, y=%f)\n", x, y); #if !HAVE_COMPATIBLE_POW if ((y == PAL_POSINF_FLT) && !isnan(x)) // +Inf { if (x == 1.0f) { ret = x; } else if (x == -1.0f) { ret = 1.0f; } else if ((x > -1.0f) && (x < 1.0f)) { ret = 0.0f; } else { ret = PAL_POSINF_FLT; // +Inf } } else if ((y == PAL_NEGINF_FLT) && !isnan(x)) // -Inf { if (x == 1.0f) { ret = x; } else if (x == -1.0f) { ret = 1.0f; } else if ((x > -1.0f) && (x < 1.0f)) { ret = PAL_POSINF_FLT; // +Inf } else { ret = 0.0f; } } else if (IS_FLT_NEGZERO(x) && (y == -1.0f)) { ret = PAL_NEGINF_FLT; // -Inf } else if ((x == 0.0f) && (y < 0.0f)) { ret = PAL_POSINF_FLT; // +Inf } else #endif // !HAVE_COMPATIBLE_POW ret = powf(x, y); #if !HAVE_VALID_NEGATIVE_INF_POW if ((ret == PAL_POSINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) != floorf(y / 2))) { ret = PAL_NEGINF_FLT; // -Inf } #endif // !HAVE_VALID_NEGATIVE_INF_POW #if !HAVE_VALID_POSITIVE_INF_POW /* * The (ceil(y/2) == floor(y/2)) test is slower, but more robust for platforms where large y * will return the wrong result for ((long) y % 2 == 0). See PAL_pow(double) above for more details. */ if ((ret == PAL_NEGINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) == floorf(y / 2))) { ret = PAL_POSINF_FLT; // +Inf } #endif // !HAVE_VALID_POSITIVE_INF_POW LOGEXIT("powf returns float %f\n", ret); PERF_EXIT(powf); return ret; }
__cdecl _fullpath( char *absPath, const char *relPath, size_t maxLength) { char realpath_buf[PATH_MAX+1]; char path_copy[PATH_MAX+1]; char *retval = NULL; DWORD cPathCopy = sizeof(path_copy)/sizeof(path_copy[0]); size_t min_length; BOOL fBufAllocated = FALSE; PERF_ENTRY(_fullpath); ENTRY("_fullpath (absPath=%p, relPath=%p (%s), maxLength = %lu)\n", absPath, relPath ? relPath:"NULL", relPath ? relPath:"NULL", maxLength); if (strncpy_s(path_copy, sizeof(path_copy), relPath ? relPath : ".", cPathCopy) != SAFECRT_SUCCESS) { TRACE("_fullpath: strncpy_s failed!\n"); goto fullpathExit; } FILEDosToUnixPathA(path_copy); if(NULL == realpath(path_copy, realpath_buf)) { ERROR("realpath() failed; problem path is '%s'. errno is %d (%s)\n", realpath_buf, errno, strerror(errno)); goto fullpathExit; } TRACE("real path is %s\n", realpath_buf); min_length = strlen(realpath_buf)+1; // +1 for the NULL terminator if(NULL == absPath) { absPath = static_cast<char *>( PAL_malloc(_MAX_PATH * sizeof(char))); if (!absPath) { ERROR("PAL_malloc failed with error %d\n", errno); goto fullpathExit; } maxLength = _MAX_PATH; fBufAllocated = TRUE; } if(min_length > maxLength) { ERROR("maxLength is %lu, we need at least %lu\n", maxLength, min_length); if (fBufAllocated) { PAL_free(absPath); fBufAllocated = FALSE; } goto fullpathExit; } strcpy_s(absPath, maxLength, realpath_buf); retval = absPath; fullpathExit: LOGEXIT("_fullpath returns char * %p\n", retval); PERF_EXIT(_fullpath); return retval; }