From 413b2afa17df6d303dc28899f68eb055588557b2 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 10 Oct 2022 22:26:37 -0700 Subject: [PATCH] Revert "Reduce CoreCLR PAL (#76832)" This reverts commit f745eb9faee1bd67886bf7f7b684821424aa014d. --- .../dlls/mscordac/mscordac_unixexports.src | 3 + src/coreclr/ilasm/main.cpp | 12 +- src/coreclr/inc/clrconfigvalues.h | 2 +- src/coreclr/inc/holder.h | 8 + src/coreclr/inc/longfilepathwrappers.h | 8 + src/coreclr/inc/winwrap.h | 7 + src/coreclr/pal/inc/pal.h | 89 ++- src/coreclr/pal/inc/palprivate.h | 24 + src/coreclr/pal/src/cruntime/filecrt.cpp | 97 +++ src/coreclr/pal/src/file/directory.cpp | 94 +++ src/coreclr/pal/src/file/file.cpp | 482 +++++++++++++++ src/coreclr/pal/src/include/pal/cs.hpp | 4 + src/coreclr/pal/src/include/pal/file.hpp | 6 + src/coreclr/pal/src/include/pal/palinternal.h | 5 +- src/coreclr/pal/src/map/map.cpp | 44 ++ src/coreclr/pal/src/misc/environ.cpp | 32 + src/coreclr/pal/src/sync/cs.cpp | 148 +++++ src/coreclr/pal/src/thread/thread.cpp | 69 +++ src/coreclr/pal/tests/palsuite/CMakeLists.txt | 29 + .../c_runtime/_fdopen/test1/test1.cpp | 111 ++++ .../c_runtime/_putenv/test1/test1.cpp | 97 +++ .../c_runtime/_putenv/test2/test2.cpp | 75 +++ .../c_runtime/_putenv/test3/test3.cpp | 101 +++ .../c_runtime/_putenv/test4/test4.cpp | 74 +++ .../palsuite/c_runtime/fclose/test1/test1.cpp | 78 +++ .../palsuite/c_runtime/fclose/test2/test2.cpp | 76 +++ .../palsuite/c_runtime/getenv/test1/test1.cpp | 77 +++ .../palsuite/c_runtime/getenv/test2/test2.cpp | 100 +++ .../palsuite/c_runtime/getenv/test3/test3.cpp | 74 +++ .../pal/tests/palsuite/common/palsuite.cpp | 16 - .../pal/tests/palsuite/common/palsuite.h | 12 +- .../pal/tests/palsuite/compilableTests.txt | 32 + .../file_io/CopyFileA/test1/CopyFileA.cpp | 2 +- .../file_io/CopyFileA/test3/test3.cpp | 16 +- .../file_io/CopyFileA/test4/test4.cpp | 6 +- .../file_io/DeleteFileA/test1/DeleteFileA.cpp | 181 ++++++ .../file_io/DeleteFileW/test1/DeleteFileW.cpp | 163 +++++ .../FindNextFileA/test1/FindNextFileA.cpp | 4 +- .../test1/GetCurrentDirectoryA.cpp | 97 +++ .../test1/GetCurrentDirectoryW.cpp | 105 ++++ .../file_io/GetFileSize/test1/GetFileSize.cpp | 44 ++ .../GetFileSizeEx/test1/GetFileSizeEx.cpp | 54 ++ .../MoveFileExA/test1/ExpectedResults.txt | 1 + .../file_io/MoveFileExA/test1/MoveFileExA.cpp | 364 +++++++++++ .../MoveFileExW/test1/ExpectedResults.txt | 1 + .../file_io/MoveFileExW/test1/MoveFileExW.cpp | 430 +++++++++++++ .../SetEndOfFile/test1/SetEndOfFile.cpp | 84 +++ .../SetEndOfFile/test2/SetEndOfFile.cpp | 151 +++++ .../SetEndOfFile/test3/SetEndOfFile.cpp | 108 ++++ .../SetEndOfFile/test4/setendoffile.cpp | 137 +++++ .../file_io/SetEndOfFile/test5/test5.cpp | 182 ++++++ .../SetFilePointer/test2/SetFilePointer.cpp | 42 ++ .../SetFilePointer/test4/SetFilePointer.cpp | 26 + .../SetFilePointer/test5/SetFilePointer.cpp | 53 ++ .../SetFilePointer/test6/SetFilePointer.cpp | 40 ++ .../SetFilePointer/test7/SetFilePointer.cpp | 53 +- .../file_io/WriteFile/test2/WriteFile.cpp | 2 +- .../file_io/errorpathnotfound/test1/test1.cpp | 12 +- .../MapViewOfFile/test1/MapViewOfFile.cpp | 2 +- .../MapViewOfFile/test5/mapviewoffile.cpp | 41 ++ .../test1/OpenFileMappingW.cpp | 154 +++++ .../test2/OpenFileMappingW.cpp | 216 +++++++ .../test3/OpenFileMappingW.cpp | 209 +++++++ .../miscellaneous/CreatePipe/test1/test1.cpp | 112 ++++ .../pal/tests/palsuite/paltestlist.txt | 24 + .../palsuite/paltestlist_to_be_reviewed.txt | 5 + .../CreateProcessW/test1/childProcess.cpp | 8 +- .../CreateProcessW/test1/parentProcess.cpp | 8 +- .../CriticalSectionFunctions/test3/test3.cpp | 374 ++++++++++++ .../DuplicateHandle/test11/test11.cpp | 17 +- .../threading/DuplicateHandle/test5/test5.cpp | 144 +++++ .../threading/DuplicateHandle/test6/test6.cpp | 145 +++++ .../threading/ExitThread/test2/test2.cpp | 9 +- .../GetExitCodeProcess/test1/test1.cpp | 9 +- .../threading/GetThreadTimes/test1/test1.cpp | 102 ++++ .../threading/OpenProcess/test1/test1.cpp | 17 +- src/coreclr/tools/superpmi/mcs/verbmerge.cpp | 5 +- .../superpmi/superpmi-shared/logging.cpp | 7 +- .../superpmi/superpmi/parallelsuperpmi.cpp | 12 +- src/coreclr/utilcode/fstream.cpp | 41 ++ src/coreclr/utilcode/longfilepathwrappers.cpp | 83 +++ src/coreclr/vm/synch.cpp | 575 ++++++++++++++++++ src/coreclr/vm/synch.h | 171 ++++++ 83 files changed, 6819 insertions(+), 115 deletions(-) create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test1/test1.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test2/test2.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test3/test3.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test4/test4.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/fclose/test1/test1.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/fclose/test2/test2.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/getenv/test1/test1.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/getenv/test2/test2.cpp create mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/getenv/test3/test3.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt create mode 100644 src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt create mode 100644 src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.cpp create mode 100644 src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.cpp create mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.cpp create mode 100644 src/coreclr/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.cpp create mode 100644 src/coreclr/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.cpp create mode 100644 src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.cpp create mode 100644 src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.cpp create mode 100644 src/coreclr/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.cpp diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index 410e411d86400..f9f082ebf3a90 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -99,6 +99,7 @@ nativeStringResourceTable_mscorrc #CloseHandle #DebugBreak #DeleteCriticalSection +#DeleteFileW #DuplicateHandle #EnterCriticalSection #FindClose @@ -111,6 +112,7 @@ nativeStringResourceTable_mscorrc #FreeLibrary #FileTimeToSystemTime #GetACP +#GetCurrentDirectoryW #GetCurrentProcess #GetCurrentProcessId #GetCurrentThreadId @@ -139,6 +141,7 @@ nativeStringResourceTable_mscorrc #LoadLibraryExW #MapViewOfFile #MapViewOfFileEx +#MoveFileExW #MultiByteToWideChar #OpenProcess #OutputDebugStringW diff --git a/src/coreclr/ilasm/main.cpp b/src/coreclr/ilasm/main.cpp index 39bf5f11b5d22..c2feb91e474b9 100644 --- a/src/coreclr/ilasm/main.cpp +++ b/src/coreclr/ilasm/main.cpp @@ -846,16 +846,8 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) *pc = W('.'); } wcscpy_s(pc+1,4,W("PDB")); - -#ifdef TARGET_WINDOWS - _wremove(wzOutputFilename); -#else - MAKE_UTF8PTR_FROMWIDE_NOTHROW(szOutputFilename, wzOutputFilename); - if (szOutputFilename != NULL) - { - remove(szOutputFilename); - } -#endif +#undef DeleteFileW + DeleteFileW(wzOutputFilename); } if (exitval == 0) { diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 81cd74e76250a..faf9ee9726852 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -529,7 +529,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadPool_DisableStarvationDetection, W("Thre RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadPool_DebugBreakOnWorkerStarvation, W("ThreadPool_DebugBreakOnWorkerStarvation"), 0, "Breaks into the debugger if the ThreadPool detects work queue starvation") RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadPool_EnableWorkerTracking, W("ThreadPool_EnableWorkerTracking"), 0, "Enables extra expensive tracking of how many workers threads are working simultaneously") #ifdef TARGET_ARM64 -// Spinning scheme is currently different on ARM64 +// Spinning scheme is currently different on ARM64, see CLRLifoSemaphore::Wait(DWORD, UINT32, UINT32) RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadPool_UnfairSemaphoreSpinLimit, W("ThreadPool_UnfairSemaphoreSpinLimit"), 0x32, "Maximum number of spins per processor a thread pool worker thread performs before waiting for work") #else // !TARGET_ARM64 RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadPool_UnfairSemaphoreSpinLimit, W("ThreadPool_UnfairSemaphoreSpinLimit"), 0x46, "Maximum number of spins a thread pool worker thread performs before waiting for work") diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index 4aa8a0b8fba4f..a02ca9ea955d3 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -1144,6 +1144,14 @@ typedef Wrapper, VoidFindClose, (UINT_PTR) -1> FindHan typedef Wrapper MapViewHolder; +#ifdef WszDeleteFile +// Deletes a file with the specified path. Do not use if you care about failures +// deleting the file, as failures are ignored by VoidDeleteFile. +FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); } +typedef Wrapper, VoidDeleteFile, NULL> DeleteFileHolder; +#endif // WszDeleteFile + + //----------------------------------------------------------------------------- // Misc holders //----------------------------------------------------------------------------- diff --git a/src/coreclr/inc/longfilepathwrappers.h b/src/coreclr/inc/longfilepathwrappers.h index 5a77cb102a57a..3bcac98d5979d 100644 --- a/src/coreclr/inc/longfilepathwrappers.h +++ b/src/coreclr/inc/longfilepathwrappers.h @@ -34,6 +34,10 @@ GetFileAttributesExWrapper( _In_ GET_FILEEX_INFO_LEVELS fInfoLevelId, _Out_writes_bytes_(sizeof(WIN32_FILE_ATTRIBUTE_DATA)) LPVOID lpFileInformation ); +BOOL +DeleteFileWrapper( + _In_ LPCWSTR lpFileName + ); #ifndef HOST_UNIX BOOL @@ -62,6 +66,10 @@ DWORD WINAPI GetTempPathWrapper( SString& lpBuffer ); +DWORD WINAPI GetCurrentDirectoryWrapper( + SString& lpBuffer + ); + DWORD GetModuleFileNameWrapper( _In_opt_ HMODULE hModule, diff --git a/src/coreclr/inc/winwrap.h b/src/coreclr/inc/winwrap.h index 7152d550288ce..ea700cf15abf5 100644 --- a/src/coreclr/inc/winwrap.h +++ b/src/coreclr/inc/winwrap.h @@ -71,6 +71,7 @@ #undef OpenSemaphore #undef CreateWaitableTimer #undef CreateFileMapping +#undef OpenFileMapping #undef LoadLibrary #undef LoadLibraryEx #undef GetModuleFileName @@ -91,16 +92,19 @@ #undef GetSystemDirectory #undef GetTempPath #undef GetTempFileName +#undef GetCurrentDirectory #undef GetFullPathName #undef CreateFile #undef GetFileAttributes #undef GetFileAttributesEx +#undef DeleteFile #undef FindFirstFileEx #undef FindFirstFile #undef FindNextFile #undef CopyFile #undef CopyFileEx #undef MoveFile +#undef MoveFileEx #undef CreateHardLink #undef CreateNamedPipe #undef WaitNamedPipe @@ -139,6 +143,7 @@ #define WszOpenEvent OpenEventW #define WszCreateWaitableTimer CreateWaitableTimerW #define WszCreateFileMapping CreateFileMappingW +#define WszOpenFileMapping OpenFileMappingW #define WszGetModuleHandle GetModuleHandleW #define WszGetModuleHandleEx GetModuleHandleExW #define WszGetCommandLine GetCommandLineW @@ -196,11 +201,13 @@ #define WszCreateFile CreateFileWrapper #define WszGetFileAttributes GetFileAttributesWrapper #define WszGetFileAttributesEx GetFileAttributesExWrapper +#define WszDeleteFile DeleteFileWrapper //Can not use extended syntax #define WszGetFullPathName GetFullPathNameW //Long Files will not work on these till redstone +#define WszGetCurrentDirectory GetCurrentDirectoryWrapper #define WszGetTempPath GetTempPathWrapper //APIS which have a buffer as an out parameter diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index a7ee0c8c20264..d5a60d766d3d3 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -672,6 +672,35 @@ CopyFileW( #define CopyFile CopyFileA #endif +PALIMPORT +BOOL +PALAPI +DeleteFileW( + IN LPCWSTR lpFileName); + +#ifdef UNICODE +#define DeleteFile DeleteFileW +#else +#define DeleteFile DeleteFileA +#endif + +#define MOVEFILE_REPLACE_EXISTING 0x00000001 +#define MOVEFILE_COPY_ALLOWED 0x00000002 + +PALIMPORT +BOOL +PALAPI +MoveFileExW( + IN LPCWSTR lpExistingFileName, + IN LPCWSTR lpNewFileName, + IN DWORD dwFlags); + +#ifdef UNICODE +#define MoveFileEx MoveFileExW +#else +#define MoveFileEx MoveFileExA +#endif + typedef struct _WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; @@ -828,6 +857,12 @@ PALAPI GetStdHandle( IN DWORD nStdHandle); +PALIMPORT +BOOL +PALAPI +SetEndOfFile( + IN HANDLE hFile); + PALIMPORT DWORD PALAPI @@ -953,6 +988,19 @@ GetTempPathA( #define GetTempPath GetTempPathA #endif +PALIMPORT +DWORD +PALAPI +GetCurrentDirectoryW( + IN DWORD nBufferLength, + OUT LPWSTR lpBuffer); + +#ifdef UNICODE +#define GetCurrentDirectory GetCurrentDirectoryW +#else +#define GetCurrentDirectory GetCurrentDirectoryA +#endif + PALIMPORT HANDLE PALAPI @@ -1075,6 +1123,11 @@ DWORD PALAPI GetCurrentProcessId(); +PALIMPORT +DWORD +PALAPI +GetCurrentSessionId(); + PALIMPORT HANDLE PALAPI @@ -2548,6 +2601,16 @@ SetThreadPriority( IN HANDLE hThread, IN int nPriority); +PALIMPORT +BOOL +PALAPI +GetThreadTimes( + IN HANDLE hThread, + OUT LPFILETIME lpCreationTime, + OUT LPFILETIME lpExitTime, + OUT LPFILETIME lpKernelTime, + OUT LPFILETIME lpUserTime); + PALIMPORT HRESULT PALAPI @@ -2670,7 +2733,9 @@ typedef struct _CRITICAL_SECTION { PALIMPORT VOID PALAPI EnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); PALIMPORT VOID PALAPI LeaveCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); PALIMPORT VOID PALAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection); +PALIMPORT BOOL PALAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags); PALIMPORT VOID PALAPI DeleteCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); +PALIMPORT BOOL PALAPI TryEnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); #define SEM_FAILCRITICALERRORS 0x0001 #define SEM_NOOPENFILEERRORBOX 0x8000 @@ -2725,6 +2790,16 @@ CreateFileMappingW( #define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS #define FILE_MAP_COPY SECTION_QUERY +PALIMPORT +HANDLE +PALAPI +OpenFileMappingW( + IN DWORD dwDesiredAccess, + IN BOOL bInheritHandle, + IN LPCWSTR lpName); + +#define OpenFileMapping OpenFileMappingW + typedef INT_PTR (PALAPI_NOEXPORT *FARPROC)(); PALIMPORT @@ -3914,6 +3989,16 @@ PALAPI GetSystemInfo( OUT LPSYSTEM_INFO lpSystemInfo); +PALIMPORT +BOOL +PALAPI +CreatePipe( + OUT PHANDLE hReadPipe, + OUT PHANDLE hWritePipe, + IN LPSECURITY_ATTRIBUTES lpPipeAttributes, + IN DWORD nSize + ); + // // NUMA related APIs // @@ -4132,7 +4217,6 @@ PALIMPORT int __cdecl iswspace(wint_t); PALIMPORT int __cdecl iswxdigit(wint_t); PALIMPORT wint_t __cdecl towupper(wint_t); PALIMPORT wint_t __cdecl towlower(wint_t); -PALIMPORT int remove(const char*); #endif // PAL_STDCPP_COMPAT /* _TRUNCATE */ @@ -4404,6 +4488,8 @@ PALIMPORT int __cdecl PAL_ferror(PAL_FILE *); PALIMPORT PAL_FILE * __cdecl PAL_fopen(const char *, const char *); PALIMPORT int __cdecl PAL_setvbuf(PAL_FILE *stream, char *, int, size_t); +PALIMPORT int __cdecl _getw(PAL_FILE *); +PALIMPORT int __cdecl _putw(int, PAL_FILE *); PALIMPORT PAL_FILE * __cdecl _fdopen(int, const char *); PALIMPORT PAL_FILE * __cdecl _wfopen(const WCHAR *, const WCHAR *); @@ -4443,6 +4529,7 @@ PALIMPORT DLLEXPORT int * __cdecl PAL_errno(int caller); #endif // PAL_STDCPP_COMPAT PALIMPORT DLLEXPORT char * __cdecl getenv(const char *); +PALIMPORT DLLEXPORT int __cdecl _putenv(const char *); #define ERANGE 34 diff --git a/src/coreclr/pal/inc/palprivate.h b/src/coreclr/pal/inc/palprivate.h index 1801f014443b3..49e302df32d7a 100644 --- a/src/coreclr/pal/inc/palprivate.h +++ b/src/coreclr/pal/inc/palprivate.h @@ -35,6 +35,14 @@ PALAPI DeleteFileA( IN LPCSTR lpFileName); +PALIMPORT +BOOL +PALAPI +MoveFileExA( + IN LPCSTR lpExistingFileName, + IN LPCSTR lpNewFileName, + IN DWORD dwFlags); + PALIMPORT BOOL PALAPI @@ -108,6 +116,13 @@ GetTempPathA( IN DWORD nBufferLength, OUT LPSTR lpBuffer); +PALIMPORT +DWORD +PALAPI +GetCurrentDirectoryA( + IN DWORD nBufferLength, + OUT LPSTR lpBuffer); + PALIMPORT BOOL PALAPI @@ -178,6 +193,15 @@ CompareFileTime( IN CONST FILETIME *lpFileTime1, IN CONST FILETIME *lpFileTime2); +/* These are from the file in windows. + They are needed for _open_osfhandle.*/ +#define _O_RDONLY 0x0000 +#define _O_APPEND 0x0008 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 + +PALIMPORT int __cdecl _open_osfhandle(INT_PTR, int); + #ifdef __cplusplus } #endif diff --git a/src/coreclr/pal/src/cruntime/filecrt.cpp b/src/coreclr/pal/src/cruntime/filecrt.cpp index 5d2fe0e5d999f..4c5363402df5f 100644 --- a/src/coreclr/pal/src/cruntime/filecrt.cpp +++ b/src/coreclr/pal/src/cruntime/filecrt.cpp @@ -34,6 +34,103 @@ using namespace CorUnix; SET_DEFAULT_DEBUG_CHANNEL(CRT); +/*++ +Function: + _open_osfhandle + +See MSDN doc. +--*/ +int +__cdecl +_open_osfhandle( INT_PTR osfhandle, int flags ) +{ + PAL_ERROR palError = NO_ERROR; + CPalThread *pthrCurrent = NULL; + IPalObject *pobjFile = NULL; + CFileProcessLocalData *pLocalData = NULL; + IDataLock *pDataLock = NULL; + INT nRetVal = -1; + INT openFlags = 0; + + PERF_ENTRY(_open_osfhandle); + ENTRY( "_open_osfhandle (osfhandle=%#x, flags=%#x)\n", osfhandle, flags ); + + pthrCurrent = InternalGetCurrentThread(); + + if (flags != _O_RDONLY) + { + ASSERT("flag(%#x) not supported\n", flags); + goto EXIT; + } + + openFlags |= O_RDONLY; + + palError = g_pObjectManager->ReferenceObjectByHandle( + pthrCurrent, + reinterpret_cast(osfhandle), + &aotFile, + &pobjFile + ); + + if (NO_ERROR != palError) + { + ERROR("Error dereferencing file handle\n"); + goto EXIT; + } + + palError = pobjFile->GetProcessLocalData( + pthrCurrent, + ReadLock, + &pDataLock, + reinterpret_cast(&pLocalData) + ); + + if (NO_ERROR == palError) + { + if (NULL != pLocalData->unix_filename) + { + nRetVal = InternalOpen(pLocalData->unix_filename, openFlags); + } + else /* the only file object with no unix_filename is a pipe */ + { + /* check if the file pipe descriptor is for read or write */ + if (pLocalData->open_flags == O_WRONLY) + { + ERROR( "Couldn't open a write pipe on read mode\n"); + goto EXIT; + } + + nRetVal = pLocalData->unix_fd; + } + + if ( nRetVal == -1 ) + { + ERROR( "Error: %s.\n", strerror( errno ) ); + } + } + else + { + ASSERT("Unable to access file data"); + } + +EXIT: + + if (NULL != pDataLock) + { + pDataLock->ReleaseLock(pthrCurrent, FALSE); + } + + if (NULL != pobjFile) + { + pobjFile->ReleaseReference(pthrCurrent); + } + + LOGEXIT( "_open_osfhandle return nRetVal:%d\n", nRetVal); + PERF_EXIT(_open_osfhandle); + return nRetVal; +} + + /*++ Function: PAL_fflush diff --git a/src/coreclr/pal/src/file/directory.cpp b/src/coreclr/pal/src/file/directory.cpp index a19e517932dd1..d8279bccbe95d 100644 --- a/src/coreclr/pal/src/file/directory.cpp +++ b/src/coreclr/pal/src/file/directory.cpp @@ -295,6 +295,100 @@ GetCurrentDirectoryA(PathCharString& lpBuffer) return dwDirLen; } +/*++ +Function: + GetCurrentDirectoryA + +See MSDN doc. +--*/ +DWORD +PALAPI +GetCurrentDirectoryA( + IN DWORD nBufferLength, + OUT LPSTR lpBuffer) +{ + + PathCharString lpBufferString; + DWORD dwDirLen = GetCurrentDirectoryA(lpBufferString); + + /* if the supplied buffer isn't long enough, return the required + length, including room for the NULL terminator */ + if ( nBufferLength <= dwDirLen ) + { + ++dwDirLen; /* include space for the NULL */ + } + else + { + strcpy_s( lpBuffer, nBufferLength, lpBufferString ); + } + + return dwDirLen; +} + +/*++ +Function: + GetCurrentDirectoryW + +See MSDN doc. +--*/ +DWORD +PALAPI +GetCurrentDirectoryW( + IN DWORD nBufferLength, + OUT LPWSTR lpBuffer) +{ + DWORD dwWideLen = 0; + DWORD dwLastError = ERROR_BAD_PATHNAME; + int dir_len; + PathCharString current_dir; + + PERF_ENTRY(GetCurrentDirectoryW); + ENTRY("GetCurrentDirectoryW(nBufferLength=%u, lpBuffer=%p)\n", + nBufferLength, lpBuffer); + + + dir_len = GetCurrentDirectoryA(current_dir); + + if( dir_len == 0) + { + dwLastError = DIRGetLastErrorFromErrno(); + goto done; + } + + dwWideLen = MultiByteToWideChar( CP_ACP, 0, + current_dir, dir_len, + NULL, 0 ); + + /* if the supplied buffer isn't long enough, return the required + length, including room for the NULL terminator */ + if ( nBufferLength > dwWideLen ) + { + if(!MultiByteToWideChar( CP_ACP, 0, current_dir, dir_len + 1, + lpBuffer, nBufferLength )) + { + ASSERT("MultiByteToWideChar failure!\n"); + dwWideLen = 0; + dwLastError = ERROR_INTERNAL_ERROR; + } + } + else + { + ++dwWideLen; /* include the space for the NULL */ + } + +done: + + if ( dwLastError ) + { + SetLastError(dwLastError); + } + + LOGEXIT("GetCurrentDirectoryW returns DWORD %u\n", dwWideLen); + PERF_EXIT(GetCurrentDirectoryW); + return dwWideLen; +} + + /*++ Function: SetCurrentDirectoryW diff --git a/src/coreclr/pal/src/file/file.cpp b/src/coreclr/pal/src/file/file.cpp index e6e13bbc21360..c0630974b1669 100644 --- a/src/coreclr/pal/src/file/file.cpp +++ b/src/coreclr/pal/src/file/file.cpp @@ -1068,6 +1068,314 @@ DeleteFileA( return bRet; } +/*++ +Function: + DeleteFileW + +See MSDN doc. +--*/ +BOOL +PALAPI +DeleteFileW( + IN LPCWSTR lpFileName) +{ + CPalThread *pThread; + int size; + PathCharString namePS; + char * name; + int length = 0; + BOOL bRet = FALSE; + + PERF_ENTRY(DeleteFileW); + ENTRY("DeleteFileW(lpFileName=%p (%S))\n", + lpFileName?lpFileName:W16_NULLSTRING, + lpFileName?lpFileName:W16_NULLSTRING); + + pThread = InternalGetCurrentThread(); + + if (lpFileName != NULL) + { + length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor; + } + + name = namePS.OpenStringBuffer(length); + if (NULL == name) + { + pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + + size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length, + NULL, NULL ); + + if( size == 0 ) + { + namePS.CloseBuffer(0); + DWORD dwLastError = GetLastError(); + ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); + pThread->SetLastError(ERROR_INTERNAL_ERROR); + bRet = FALSE; + goto done; + } + + namePS.CloseBuffer(size - 1); + bRet = DeleteFileA( name ); + +done: + LOGEXIT("DeleteFileW returns BOOL %d\n", bRet); + PERF_EXIT(DeleteFileW); + return bRet; +} + + +/*++ +Function: + MoveFileExA + +See MSDN doc. +--*/ +BOOL +PALAPI +MoveFileExA( + IN LPCSTR lpExistingFileName, + IN LPCSTR lpNewFileName, + IN DWORD dwFlags) +{ + CPalThread *pThread; + int result; + PathCharString source; + PathCharString dest; + BOOL bRet = TRUE; + DWORD dwLastError = 0; + + PERF_ENTRY(MoveFileExA); + ENTRY("MoveFileExA(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), " + "dwFlags=%#x)\n", + lpExistingFileName?lpExistingFileName:"NULL", + lpExistingFileName?lpExistingFileName:"NULL", + lpNewFileName?lpNewFileName:"NULL", + lpNewFileName?lpNewFileName:"NULL", dwFlags); + + pThread = InternalGetCurrentThread(); + /* only two flags are accepted */ + if ( dwFlags & ~(MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) ) + { + ASSERT( "dwFlags is invalid\n" ); + dwLastError = ERROR_INVALID_PARAMETER; + goto done; + } + + + if( !source.Set(lpExistingFileName, strlen(lpExistingFileName))) + { + dwLastError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + FILEDosToUnixPathA( source ); + + if( !dest.Set(lpNewFileName, strlen(lpNewFileName))) + { + dwLastError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + FILEDosToUnixPathA( dest ); + + if ( !(dwFlags & MOVEFILE_REPLACE_EXISTING) ) + { +#if HAVE_CASE_SENSITIVE_FILESYSTEM + if ( strcmp(source, dest) != 0 ) +#else // HAVE_CASE_SENSITIVE_FILESYSTEM + if ( strcasecmp(source, dest) != 0 ) +#endif // HAVE_CASE_SENSITIVE_FILESYSTEM + { + // Let things proceed normally if source and + // dest are the same. + if ( access(dest, F_OK) == 0 ) + { + dwLastError = ERROR_ALREADY_EXISTS; + goto done; + } + } + } + + result = rename( source, dest ); + if ((result < 0) && (dwFlags & MOVEFILE_REPLACE_EXISTING) && + ((errno == ENOTDIR) || (errno == EEXIST))) + { + bRet = DeleteFileA( lpNewFileName ); + + if ( bRet ) + { + result = rename( source, dest ); + } + else + { + dwLastError = GetLastError(); + } + } + + if ( result < 0 ) + { + switch( errno ) + { + case EXDEV: /* we tried to link across devices */ + + if ( dwFlags & MOVEFILE_COPY_ALLOWED ) + { + BOOL bFailIfExists = !(dwFlags & MOVEFILE_REPLACE_EXISTING); + + /* if CopyFile fails here, so should MoveFailEx */ + bRet = CopyFileA( lpExistingFileName, + lpNewFileName, + bFailIfExists ); + /* CopyFile should set the appropriate error */ + if ( !bRet ) + { + dwLastError = GetLastError(); + } + else + { + if (!DeleteFileA(lpExistingFileName)) + { + ERROR("Failed to delete the source file\n"); + dwLastError = GetLastError(); + + /* Delete the destination file if we're unable to delete + the source file */ + if (!DeleteFileA(lpNewFileName)) + { + ERROR("Failed to delete the destination file\n"); + } + } + } + } + else + { + dwLastError = ERROR_ACCESS_DENIED; + } + break; + case EINVAL: // tried to rename "." or ".." + dwLastError = ERROR_SHARING_VIOLATION; + break; + case ENOENT: + { + struct stat buf; + if (lstat(source, &buf) == -1) + { + FILEGetProperNotFoundError(source, &dwLastError); + } + else + { + dwLastError = ERROR_PATH_NOT_FOUND; + } + } + break; + default: + dwLastError = FILEGetLastErrorFromErrno(); + break; + } + } + +done: + if ( dwLastError ) + { + pThread->SetLastError( dwLastError ); + bRet = FALSE; + } + + LOGEXIT( "MoveFileExA returns BOOL %d\n", bRet ); + PERF_EXIT(MoveFileExA); + return bRet; +} + +/*++ +Function: + MoveFileExW + +See MSDN doc. +--*/ +BOOL +PALAPI +MoveFileExW( + IN LPCWSTR lpExistingFileName, + IN LPCWSTR lpNewFileName, + IN DWORD dwFlags) +{ + CPalThread *pThread; + PathCharString sourcePS; + PathCharString destPS; + char * source; + char * dest; + int length = 0; + int src_size,dest_size; + BOOL bRet = FALSE; + + PERF_ENTRY(MoveFileExW); + ENTRY("MoveFileExW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), dwFlags=%#x)\n", + lpExistingFileName?lpExistingFileName:W16_NULLSTRING, + lpExistingFileName?lpExistingFileName:W16_NULLSTRING, + lpNewFileName?lpNewFileName:W16_NULLSTRING, + lpNewFileName?lpNewFileName:W16_NULLSTRING, dwFlags); + + pThread = InternalGetCurrentThread(); + + if (lpExistingFileName != NULL) + { + length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor; + } + + source = sourcePS.OpenStringBuffer(length); + if (NULL == source) + { + pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length, + NULL, NULL ); + if( src_size == 0 ) + { + sourcePS.CloseBuffer(0); + DWORD dwLastError = GetLastError(); + ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); + pThread->SetLastError(ERROR_INTERNAL_ERROR); + goto done; + } + + sourcePS.CloseBuffer(src_size - 1); + length = 0; + if (lpNewFileName != NULL) + { + length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor; + } + + dest = destPS.OpenStringBuffer(length); + if (NULL == dest) + { + pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length, + NULL, NULL ); + + if( dest_size == 0 ) + { + destPS.CloseBuffer(0); + DWORD dwLastError = GetLastError(); + ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); + pThread->SetLastError(ERROR_INTERNAL_ERROR); + goto done; + } + + destPS.CloseBuffer(dest_size - 1); + bRet = MoveFileExA(source,dest,dwFlags); + +done: + LOGEXIT("MoveFileExW returns BOOL %d\n", bRet); + PERF_EXIT(MoveFileExW); + return bRet; +} /*++ Function: @@ -1944,6 +2252,179 @@ GetStdHandle( return hRet; } +PAL_ERROR +CorUnix::InternalSetEndOfFile( + CPalThread *pThread, + HANDLE hFile + ) +{ + PAL_ERROR palError = 0; + IPalObject *pFileObject = NULL; + CFileProcessLocalData *pLocalData = NULL; + IDataLock *pLocalDataLock = NULL; + + off_t curr = 0; + + if (INVALID_HANDLE_VALUE == hFile) + { + ERROR( "Invalid file handle\n" ); + palError = ERROR_INVALID_HANDLE; + goto InternalSetEndOfFileExit; + } + + palError = g_pObjectManager->ReferenceObjectByHandle( + pThread, + hFile, + &aotFile, + &pFileObject + ); + + if (NO_ERROR != palError) + { + goto InternalSetEndOfFileExit; + } + + palError = pFileObject->GetProcessLocalData( + pThread, + ReadLock, + &pLocalDataLock, + reinterpret_cast(&pLocalData) + ); + + if (NO_ERROR != palError) + { + goto InternalSetEndOfFileExit; + } + + if (pLocalData->open_flags_deviceaccessonly == TRUE) + { + ERROR("File open for device access only\n"); + palError = ERROR_ACCESS_DENIED; + goto InternalSetEndOfFileExit; + } + + curr = lseek(pLocalData->unix_fd, 0, SEEK_CUR); + + TRACE("current file pointer offset is %u\n", curr); + if ( curr < 0 ) + { + ERROR("lseek returned %ld\n", curr); + palError = FILEGetLastErrorFromErrno(); + goto InternalSetEndOfFileExit; + } + +#if SIZEOF_OFF_T > 4 +#if !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT + // ftruncate will return the wrong value for some large lengths. + // We'll short-circuit the process and simply return failure for + // the set of values that covers those cases, all of which would + // have failed anyway on any standard-sized hard drive. + if (curr >= 0xFFFFFFFF000ULL) + { + ERROR("Skipping ftruncate because the offset is too large\n"); + palError = ERROR_INVALID_PARAMETER; + goto InternalSetEndOfFileExit; + } +#endif // !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT +#endif // SIZEOF_OFF_T + +#if HAS_FTRUNCATE_LENGTH_ISSUE + // Perform an additional check to make sure that there's likely to be enough free space to satisfy the + // request. Do this because it's been observed on Mac OSX that ftruncate can return failure but still + // extend the file to consume the remainder of free space. + // + struct statfs sFileSystemStats; + off_t cbFreeSpace; + if (fstatfs(pLocalData->unix_fd, &sFileSystemStats) != 0) + { + ERROR("fstatfs failed\n"); + palError = FILEGetLastErrorFromErrno(); + goto InternalSetEndOfFileExit; + } + + // Free space is free blocks times the size of each block in bytes. + cbFreeSpace = (off_t)sFileSystemStats.f_bavail * (off_t)sFileSystemStats.f_bsize; + + if (curr > cbFreeSpace) + { + ERROR("Not enough disk space for ftruncate\n"); + palError = ERROR_DISK_FULL; + goto InternalSetEndOfFileExit; + } +#endif // HAS_FTRUNCATE_LENGTH_ISSUE + + if ( ftruncate(pLocalData->unix_fd, curr) != 0 ) + { + ERROR("ftruncate failed\n"); + if ( errno == EACCES ) + { + ERROR("file may not be writable\n"); + } + palError = FILEGetLastErrorFromErrno(); + goto InternalSetEndOfFileExit; + } + + +InternalSetEndOfFileExit: + + // Windows starts returning ERROR_INVALID_PARAMETER at an arbitrary file size (~16TB). The file system + // underneath us may be able to support larger and it would be a shame to prevent that. As a compromise, + // if the operation fails and the file size was above the Windows limit map ERROR_DISK_FULL to + // ERROR_INVALID_PARAMETER. + // curr has been checked to be positive after getting the value from lseek. The following cast is put to + // suppress the compilation warning. + if (palError == ERROR_DISK_FULL && (static_cast(curr) > 0x00000fffffff0000ULL ) ) + palError = ERROR_INVALID_PARAMETER; + + if (NULL != pLocalDataLock) + { + pLocalDataLock->ReleaseLock(pThread, FALSE); + } + + if (NULL != pFileObject) + { + pFileObject->ReleaseReference(pThread); + } + + return palError; +} + + + +/*++ +Function: + SetEndOfFile + +See MSDN doc. +--*/ +BOOL +PALAPI +SetEndOfFile( + IN HANDLE hFile) +{ + PAL_ERROR palError = NO_ERROR; + CPalThread *pThread;; + + PERF_ENTRY(SetEndOfFile); + ENTRY("SetEndOfFile(hFile=%p)\n", hFile); + + pThread = InternalGetCurrentThread(); + + palError = InternalSetEndOfFile( + pThread, + hFile + ); + + if (NO_ERROR != palError) + { + pThread->SetLastError(palError); + } + + LOGEXIT("SetEndOfFile returns BOOL %d\n", NO_ERROR == palError); + PERF_EXIT(SetEndOfFile); + return NO_ERROR == palError; +} + // // We need to break out the actual mechanics of setting the file pointer // on the unix FD for InternalReadFile and InternalWriteFile, as they @@ -3165,6 +3646,7 @@ CopyFileA( return bGood; } + PAL_ERROR CorUnix::InternalCreatePipe( CPalThread *pThread, diff --git a/src/coreclr/pal/src/include/pal/cs.hpp b/src/coreclr/pal/src/include/pal/cs.hpp index cb374ffa1ec0f..5fc1d2e3253ce 100644 --- a/src/coreclr/pal/src/include/pal/cs.hpp +++ b/src/coreclr/pal/src/include/pal/cs.hpp @@ -38,6 +38,10 @@ namespace CorUnix CRITICAL_SECTION *pcs ); + bool InternalTryEnterCriticalSection( + CPalThread * pThread, + PCRITICAL_SECTION pCriticalSection); + #ifdef _DEBUG void PALCS_ReportStatisticalData(void); void PALCS_DumpCSList(); diff --git a/src/coreclr/pal/src/include/pal/file.hpp b/src/coreclr/pal/src/include/pal/file.hpp index e45607d0bc1dd..f35d769d5c3d2 100644 --- a/src/coreclr/pal/src/include/pal/file.hpp +++ b/src/coreclr/pal/src/include/pal/file.hpp @@ -76,6 +76,12 @@ namespace CorUnix LPOVERLAPPED lpOverlapped ); + PAL_ERROR + InternalSetEndOfFile( + CPalThread *pThread, + HANDLE hFile + ); + PAL_ERROR InternalGetFileSize( CPalThread *pThread, diff --git a/src/coreclr/pal/src/include/pal/palinternal.h b/src/coreclr/pal/src/include/pal/palinternal.h index 89923bf5248e3..b5d81aedbfd17 100644 --- a/src/coreclr/pal/src/include/pal/palinternal.h +++ b/src/coreclr/pal/src/include/pal/palinternal.h @@ -231,7 +231,6 @@ function_name() to call the system's implementation #define tanf DUMMY_tanf #define tanhf DUMMY_tanhf #define truncf DUMMY_truncf -#define remove DUMMY_remove /* RAND_MAX needed to be renamed to avoid duplicate definition when including stdlib.h header files. PAL_RAND_MAX should have the same value as RAND_MAX @@ -495,7 +494,7 @@ function_name() to call the system's implementation #undef getenv #undef open #undef glob -#undef remove + #undef ptrdiff_t #undef intptr_t #undef uintptr_t @@ -726,6 +725,4 @@ const char StackOverflowMessage[] = "Stack overflow.\n"; #define FALLTHROUGH #endif -DWORD PALAPI GetCurrentSessionId(); - #endif /* _PAL_INTERNAL_H_ */ diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp index bf26cbed4a067..b723d771b20b0 100644 --- a/src/coreclr/pal/src/map/map.cpp +++ b/src/coreclr/pal/src/map/map.cpp @@ -741,6 +741,50 @@ CorUnix::InternalCreateFileMapping( return palError; } +/*++ +Function: + OpenFileMappingW + +See MSDN doc. +--*/ +HANDLE +PALAPI +OpenFileMappingW( + IN DWORD dwDesiredAccess, + IN BOOL bInheritHandle, + IN LPCWSTR lpName) +{ + HANDLE hFileMapping = NULL; + PAL_ERROR palError = NO_ERROR; + CPalThread *pThread = NULL; + + PERF_ENTRY(OpenFileMappingW); + ENTRY("OpenFileMappingW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S)\n", + dwDesiredAccess, bInheritHandle, lpName?lpName:W16_NULLSTRING, lpName?lpName:W16_NULLSTRING); + + pThread = InternalGetCurrentThread(); + + /* validate parameters */ + if (lpName == nullptr) + { + ERROR("name is NULL\n"); + palError = ERROR_INVALID_PARAMETER; + } + else + { + ASSERT("lpName: Cross-process named objects are not supported in PAL"); + palError = ERROR_NOT_SUPPORTED; + } + + if (NO_ERROR != palError) + { + pThread->SetLastError(palError); + } + LOGEXIT("OpenFileMappingW returning %p.\n", hFileMapping); + PERF_EXIT(OpenFileMappingW); + return hFileMapping; +} + /*++ Function: MapViewOfFile diff --git a/src/coreclr/pal/src/misc/environ.cpp b/src/coreclr/pal/src/misc/environ.cpp index 44bf50128afd9..a31d6b177760b 100644 --- a/src/coreclr/pal/src/misc/environ.cpp +++ b/src/coreclr/pal/src/misc/environ.cpp @@ -981,6 +981,38 @@ EnvironInitialize(void) /*++ +Function : _putenv. + +See MSDN for more details. + +Note: The BSD implementation can cause + memory leaks. See man pages for more details. +--*/ +int +__cdecl +_putenv( const char * envstring ) +{ + int ret = -1; + + PERF_ENTRY(_putenv); + ENTRY( "_putenv( %p (%s) )\n", envstring ? envstring : "NULL", envstring ? envstring : "NULL") ; + + if (envstring != nullptr) + { + ret = EnvironPutenv(envstring, TRUE) ? 0 : -1; + } + else + { + ERROR( "_putenv() called with NULL envstring!\n"); + } + + LOGEXIT( "_putenv returning %d\n", ret); + PERF_EXIT(_putenv); + return ret; +} + +/*++ + Function : PAL_getenv See MSDN for more details. diff --git a/src/coreclr/pal/src/sync/cs.cpp b/src/coreclr/pal/src/sync/cs.cpp index d04b2c13bb68a..7593f6f5566ff 100644 --- a/src/coreclr/pal/src/sync/cs.cpp +++ b/src/coreclr/pal/src/sync/cs.cpp @@ -213,6 +213,25 @@ void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) PERF_EXIT(InitializeCriticalSection); } +/*++ +Function: + InitializeCriticalSectionEx - Flags is ignored. + +See MSDN doc. +--*/ +BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) +{ + PERF_ENTRY(InitializeCriticalSection); + ENTRY("InitializeCriticalSectionEx(lpCriticalSection=%p, dwSpinCount=%d, Flags=%d)\n", + lpCriticalSection, dwSpinCount, Flags); + + InternalInitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount, false); + + LOGEXIT("InitializeCriticalSectionEx returns TRUE\n"); + PERF_EXIT(InitializeCriticalSection); + return true; +} + /*++ Function: InitializeCriticalSectionAndSpinCount @@ -272,6 +291,28 @@ void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) PERF_EXIT(EnterCriticalSection); } +/*++ +Function: + TryEnterCriticalSection + +See MSDN doc. +--*/ +BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + PERF_ENTRY(TryEnterCriticalSection); + ENTRY("TryEnterCriticalSection(lpCriticalSection=%p)\n", lpCriticalSection); + + CPalThread * pThread = InternalGetCurrentThread(); + + bool fRet = InternalTryEnterCriticalSection(pThread, + lpCriticalSection); + + LOGEXIT("TryEnterCriticalSection returns bool %d\n", (int)fRet); + PERF_EXIT(TryEnterCriticalSection); + + return (BOOL)fRet; +} + /*++ Function: LeaveCriticalSection @@ -941,6 +982,68 @@ namespace CorUnix return; } + /*++ + Function: + CorUnix::InternalTryEnterCriticalSection + + Tries to acquire a CS. It returns true on success, false if the CS is + locked by another thread + --*/ + bool InternalTryEnterCriticalSection( + CPalThread * pThread, + PCRITICAL_SECTION pCriticalSection) + { + PAL_CRITICAL_SECTION * pPalCriticalSection = + reinterpret_cast(pCriticalSection); + + LONG lNewVal; + SIZE_T threadId; + bool fRet = true; + + _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState); + + threadId = ObtainCurrentThreadId(pThread); + + lNewVal = InterlockedCompareExchange (&pPalCriticalSection->LockCount, + (LONG)PALCS_LOCK_BIT, + (LONG)PALCS_LOCK_INIT); + if (lNewVal == PALCS_LOCK_INIT) + { + // CS successfully acquired: setting ownership data + pPalCriticalSection->OwningThread = threadId; + pPalCriticalSection->RecursionCount = 1; +#ifdef _DEBUG + if (NULL != pPalCriticalSection->DebugInfo) + { + pPalCriticalSection->DebugInfo->lAcquireCount += 1; + pPalCriticalSection->DebugInfo->lEnterCount += 1; + } +#endif // _DEBUG + + goto ITECS_exit; + } + + // check if the current thread already owns the criticalSection + if ((lNewVal & PALCS_LOCK_BIT) && + (pPalCriticalSection->OwningThread == threadId)) + { + pPalCriticalSection->RecursionCount += 1; +#ifdef _DEBUG + if (NULL != pPalCriticalSection->DebugInfo) + { + pPalCriticalSection->DebugInfo->lEnterCount += 1; + } +#endif // _DEBUG + + goto ITECS_exit; + } + + // Failed to acquire the CS + fRet = false; + + ITECS_exit: + return fRet; + } #endif // MUTEX_BASED_CSS /*++ @@ -1454,5 +1557,50 @@ namespace CorUnix _ASSERTE(0 == iRet); } + /*++ + Function: + CorUnix::InternalTryEnterCriticalSection + + Tries to acquire a CS. It returns true on success, false if the CS is + locked by another thread + --*/ +#ifdef MUTEX_BASED_CSS + bool InternalTryEnterCriticalSection( + CPalThread * pThread, + PCRITICAL_SECTION pCriticalSection) +#else // MUTEX_BASED_CSS + bool MTX_InternalTryEnterCriticalSection( + CPalThread * pThread, + PCRITICAL_SECTION pCriticalSection) +#endif // MUTEX_BASED_CSS + { + PAL_CRITICAL_SECTION * pPalCriticalSection = + reinterpret_cast(pCriticalSection); + bool fRet; + SIZE_T threadId; + + _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState); + + threadId = ObtainCurrentThreadId(pThread); + + /* check if the current thread already owns the criticalSection */ + if (pPalCriticalSection->OwningThread == threadId) + { + pPalCriticalSection->RecursionCount += 1; + fRet = true; + goto ITECS_exit; + } + + fRet = (0 == pthread_mutex_trylock(&pPalCriticalSection->csndNativeData.mutex)); + + if (fRet) + { + pPalCriticalSection->OwningThread = threadId; + pPalCriticalSection->RecursionCount = 1; + } + + ITECS_exit: + return fRet; + } #endif // MUTEX_BASED_CSS || _DEBUG } diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index 6d614b7e37ed5..0d84a5a876585 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -1484,6 +1484,75 @@ CorUnix::GetThreadTimesInternal( return retval; } +/*++ +Function: + GetThreadTimes + +See MSDN doc. +--*/ +BOOL +PALAPI +GetThreadTimes( + IN HANDLE hThread, + OUT LPFILETIME lpCreationTime, + OUT LPFILETIME lpExitTime, + OUT LPFILETIME lpKernelTime, + OUT LPFILETIME lpUserTime) +{ + PERF_ENTRY(GetThreadTimes); + ENTRY("GetThreadTimes(hThread=%p, lpExitTime=%p, lpKernelTime=%p," + "lpUserTime=%p)\n", + hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime ); + + FILETIME KernelTime, UserTime; + + BOOL retval = GetThreadTimesInternal(hThread, &KernelTime, &UserTime); + + /* Not sure if this still needs to be here */ + /* + TRACE ("thread_info User: %ld sec,%ld microsec. Kernel: %ld sec,%ld" + " microsec\n", + resUsage.user_time.seconds, resUsage.user_time.microseconds, + resUsage.system_time.seconds, resUsage.system_time.microseconds); + */ + + __int64 calcTime; + if (lpUserTime) + { + /* Produce the time in 100s of ns */ + calcTime = ((ULONG64)UserTime.dwHighDateTime << 32); + calcTime += (ULONG64)UserTime.dwLowDateTime; + calcTime /= 100; + lpUserTime->dwLowDateTime = (DWORD)calcTime; + lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32); + } + if (lpKernelTime) + { + /* Produce the time in 100s of ns */ + calcTime = ((ULONG64)KernelTime.dwHighDateTime << 32); + calcTime += (ULONG64)KernelTime.dwLowDateTime; + calcTime /= 100; + lpKernelTime->dwLowDateTime = (DWORD)calcTime; + lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32); + } + //Set CreationTime and Exit time to zero for now - maybe change this later? + if (lpCreationTime) + { + lpCreationTime->dwLowDateTime = 0; + lpCreationTime->dwHighDateTime = 0; + } + + if (lpExitTime) + { + lpExitTime->dwLowDateTime = 0; + lpExitTime->dwHighDateTime = 0; + } + + LOGEXIT("GetThreadTimes returns BOOL %d\n", retval); + PERF_EXIT(GetThreadTimes); + return (retval); +} + HRESULT PALAPI SetThreadDescription( diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index de1636c900272..2e3142d4107c4 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -98,6 +98,8 @@ add_executable_clr(paltests c_runtime/expf/test1/test1.cpp c_runtime/fabs/test1/test1.cpp c_runtime/fabsf/test1/test1.cpp + c_runtime/fclose/test1/test1.cpp + c_runtime/fclose/test2/test2.cpp c_runtime/ferror/test1/test1.cpp c_runtime/ferror/test2/test2.cpp c_runtime/fflush/test1/test1.cpp @@ -145,6 +147,9 @@ add_executable_clr(paltests c_runtime/fseek/test1/test1.cpp c_runtime/ftell/test1/ftell.cpp c_runtime/fwrite/test1/test1.cpp + c_runtime/getenv/test1/test1.cpp + c_runtime/getenv/test2/test2.cpp + c_runtime/getenv/test3/test3.cpp c_runtime/ilogb/test1/test1.cpp c_runtime/ilogbf/test1/test1.cpp c_runtime/isalnum/test1/test1.cpp @@ -377,6 +382,7 @@ add_executable_clr(paltests c_runtime/wcstoul/test5/test5.cpp c_runtime/wcstoul/test6/test6.cpp c_runtime/_alloca/test1/test1.cpp + c_runtime/_fdopen/test1/test1.cpp c_runtime/_finite/test1/test1.cpp c_runtime/_finitef/test1/test1.cpp #c_runtime/_gcvt/test1/_gcvt.cpp @@ -384,6 +390,10 @@ add_executable_clr(paltests c_runtime/_isnan/test1/test1.cpp c_runtime/_isnanf/test1/test1.cpp c_runtime/_itow/test1/test1.cpp + c_runtime/_putenv/test1/test1.cpp + c_runtime/_putenv/test2/test2.cpp + c_runtime/_putenv/test3/test3.cpp + c_runtime/_putenv/test4/test4.cpp c_runtime/_rotl/test1/test1.cpp c_runtime/_rotr/test1/test1.cpp c_runtime/_snprintf_s/test1/test1.cpp @@ -534,6 +544,9 @@ add_executable_clr(paltests filemapping_memmgt/MapViewOfFile/test4/mapviewoffile.cpp filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.cpp filemapping_memmgt/MapViewOfFile/test6/mapviewoffile.cpp + filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.cpp + filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.cpp + filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.cpp filemapping_memmgt/ProbeMemory/ProbeMemory_neg1/ProbeMemory_neg.cpp filemapping_memmgt/ProbeMemory/test1/ProbeMemory.cpp filemapping_memmgt/UnmapViewOfFile/test1/UnmapViewOfFile.cpp @@ -579,6 +592,8 @@ add_executable_clr(paltests file_io/CopyFileW/test3/test3.cpp file_io/CreateFileA/test1/CreateFileA.cpp file_io/CreateFileW/test1/CreateFileW.cpp + file_io/DeleteFileA/test1/DeleteFileA.cpp + file_io/DeleteFileW/test1/DeleteFileW.cpp file_io/errorpathnotfound/test1/test1.cpp file_io/errorpathnotfound/test2/test2.cpp file_io/FILECanonicalizePath/FILECanonicalizePath.cpp @@ -591,6 +606,8 @@ add_executable_clr(paltests file_io/FindNextFileW/test2/findnextfilew.cpp file_io/FlushFileBuffers/test1/FlushFileBuffers.cpp file_io/GetConsoleOutputCP/test1/GetConsoleOutputCP.cpp + file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.cpp + file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.cpp file_io/GetFileAttributesA/test1/GetFileAttributesA.cpp file_io/GetFileAttributesExW/test1/test1.cpp file_io/GetFileAttributesExW/test2/test2.cpp @@ -617,11 +634,18 @@ add_executable_clr(paltests file_io/GetTempFileNameW/test3/gettempfilenamew.cpp file_io/gettemppatha/test1/gettemppatha.cpp file_io/GetTempPathW/test1/GetTempPathW.cpp + file_io/MoveFileExA/test1/MoveFileExA.cpp + file_io/MoveFileExW/test1/MoveFileExW.cpp file_io/ReadFile/test1/ReadFile.cpp file_io/ReadFile/test2/ReadFile.cpp file_io/ReadFile/test3/ReadFile.cpp file_io/ReadFile/test4/readfile.cpp file_io/SearchPathW/test1/SearchPathW.cpp + file_io/SetEndOfFile/test1/SetEndOfFile.cpp + file_io/SetEndOfFile/test2/SetEndOfFile.cpp + file_io/SetEndOfFile/test3/SetEndOfFile.cpp + file_io/SetEndOfFile/test4/setendoffile.cpp + file_io/SetEndOfFile/test5/test5.cpp file_io/SetFilePointer/test1/SetFilePointer.cpp file_io/SetFilePointer/test2/SetFilePointer.cpp file_io/SetFilePointer/test3/SetFilePointer.cpp @@ -664,6 +688,7 @@ add_executable_clr(paltests miscellaneous/CGroup/test1/test.cpp miscellaneous/CloseHandle/test1/test.cpp miscellaneous/CloseHandle/test2/test.cpp + miscellaneous/CreatePipe/test1/test1.cpp miscellaneous/FlushInstructionCache/test1/test1.cpp miscellaneous/FormatMessageW/test1/test.cpp miscellaneous/FormatMessageW/test2/test.cpp @@ -753,6 +778,7 @@ add_executable_clr(paltests threading/CreateThread/test3/test3.cpp threading/CriticalSectionFunctions/test1/InitializeCriticalSection.cpp threading/CriticalSectionFunctions/test2/test2.cpp + threading/CriticalSectionFunctions/test3/test3.cpp threading/CriticalSectionFunctions/test4/test4.cpp threading/CriticalSectionFunctions/test5/test5.cpp threading/CriticalSectionFunctions/test6/test6.cpp @@ -766,6 +792,8 @@ add_executable_clr(paltests threading/DuplicateHandle/test2/test2.cpp threading/DuplicateHandle/test3/test3.cpp threading/DuplicateHandle/test4/test4.cpp + threading/DuplicateHandle/test5/test5.cpp + threading/DuplicateHandle/test6/test6.cpp threading/DuplicateHandle/test7/test7.cpp threading/DuplicateHandle/test8/test8.cpp # threading/DuplicateHandle/test9/test9.cpp @@ -782,6 +810,7 @@ add_executable_clr(paltests threading/GetCurrentThreadId/test1/threadId.cpp threading/GetExitCodeProcess/test1/childProcess.cpp threading/GetExitCodeProcess/test1/test1.cpp + threading/GetThreadTimes/test1/test1.cpp threading/NamedMutex/test1/namedmutex.cpp threading/NamedMutex/test1/nopal.cpp threading/OpenEventW/test1/test1.cpp diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.cpp new file mode 100644 index 0000000000000..9cff3b731d878 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.cpp @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test1.c (fdopen) +** +** Purpose: Tests the PAL implementation of the fdopen function. +** This will test fdopen in r (read) mode. This test +** creates and opens a test pipe, to write and read +** from. fdopen requires a file handle(int), therefore +** _open_osfhandle is used to get that handle. +** _open_osfhandle is only used with CreatePipe. The +** test will write and read from the pipe comparing +** the results. +** +** See /tests/palsuite/README.txt for more information. +** +** +**===================================================================*/ + +#include + +#define cTestString "one fish, two fish, read fish, blue fish." + +PALTEST(c_runtime__fdopen_test1_paltest_fdopen_test1, "c_runtime/_fdopen/test1/paltest_fdopen_test1") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + BOOL bRetVal = FALSE; + int iFiledes = 0; + DWORD dwBytesWritten; + char buffer[45]; + FILE *fp; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, // read handle + &hWritePipe, // write handle + &lpPipeAttributes, // security attributes + 0); // pipe size + + if (bRetVal == FALSE) + { + Fail("ERROR: unable to create pipe"); + } + + /*Write to the write pipe handle*/ + bRetVal = WriteFile(hWritePipe, // handle to file + cTestString, // data buffer + (DWORD)strlen(cTestString), // number of bytes to write + &dwBytesWritten, // number of bytes written + NULL); // overlapped buffer + + if (bRetVal == FALSE) + { + Fail("ERROR: unable to write to pipe write handle " + "hWritePipe=0x%lx", hWritePipe); + } + + /*Get a file descriptor for the read pipe handle*/ + iFiledes = _open_osfhandle((long)hReadPipe, _O_RDONLY); + + if (iFiledes == -1) + { + Fail("ERROR: _open_osfhandle failed to open " + " hReadPipe=0x%lx", hReadPipe); + } + + /*Open read pipe handle in read mode*/ + fp = _fdopen(iFiledes, "r"); + + if (fp == NULL) + { + Fail("ERROR: unable to fdopen file descriptor" + " iFiledes=%d", iFiledes); + } + + /*Read from the read pipe handle*/ + if((fread(buffer, sizeof(char), strlen(cTestString), fp)) == 0) + { + Fail("ERROR: Unable to read from file stream fp=0x%lx\n", fp); + } + + /*Compare what was read with what was written.*/ + if ((memcmp(cTestString, buffer, strlen(cTestString))) != 0) + { + Fail("ERROR: read \"%s\" expected \"%s\" \n", buffer, cTestString); + } + + /*Close the file handle*/ + if (_close(iFiledes) != 0) + { + Fail("ERROR: Unable to close file handle iFiledes=%d\n", iFiledes); + } + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test1/test1.cpp new file mode 100644 index 0000000000000..a7ebbe4fa6189 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test1/test1.cpp @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Create an environment variable with _putenv and then use getenv +** to check it. Check that we get the expected errors with invalid input. +** +** +**===================================================================*/ + +#include + +struct TestElement +{ + char _putenvString[1024]; /* argument string sent to putenv */ + char varName[1024]; /* variable component of argument string */ + char varValue[1024]; /* value component of argument string */ + BOOL bValidString; /* valid argument string identifier */ +}; + +PALTEST(c_runtime__putenv_test1_paltest_putenv_test1, "c_runtime/_putenv/test1/paltest_putenv_test1") +{ + struct TestElement TestCases[] = + { + {"PalTestingEnvironmentVariable=A value", "PalTestingEnvironmentVariable", + "A value", TRUE}, + {"AnotherVariable=", "AnotherVariable", "", TRUE}, + {"YetAnotherVariable", "", "", FALSE}, + {"=ADifferentVariable", "", "ADifferentVariable", FALSE}, + {"", "", "", FALSE} + + }; + + int i; + char *variableValue; + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + for (i = 0; i < (sizeof(TestCases)/sizeof(struct TestElement)) ; i++) + { + if((_putenv(TestCases[i]._putenvString) == -1) && + ( TestCases[i].bValidString == TRUE)) + { + Fail("ERROR: _putenv failed to set an environment " + "variable with a valid format.\n Call was" + "_putenv(%s)\n", TestCases[i]._putenvString); + } + /* + * For valid _putenvString values, check to see the variable was set + */ + if (TestCases[i].bValidString == TRUE) + { + variableValue = getenv(TestCases[i].varName); + + if (variableValue == NULL) + { + if (*TestCases[i].varValue != '\0') + { + Fail("ERROR: getenv(%s) call returned NULL.\nThe call " + "should have returned \"%s\"\n", TestCases[i].varName + , TestCases[i].varValue); + } + } + else if ( strcmp(variableValue, TestCases[i].varValue) != 0) + { + Fail("ERROR: _putenv(%s)\nshould have set the variable " + "%s\n to \"%s\".\nA subsequent call to getenv(%s)\n" + "returned \"%s\" instead.\n", TestCases[i]._putenvString + , TestCases[i].varName, TestCases[i].varValue + , TestCases[i].varName, variableValue); + } + } + else + /* + * Check to see that putenv fails for malformed _putenvString values + */ + { + variableValue = getenv(TestCases[i].varName); + + if (variableValue != NULL) + { + Fail("ERROR: getenv(%s) call should have returned NULL.\n" + "Instead it returned \"%s\".\n", TestCases[i].varName + , TestCases[i].varValue); + } + } + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test2/test2.cpp new file mode 100644 index 0000000000000..ee84e375c2e2e --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test2/test2.cpp @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test2.c +** +** Purpose: Create an environment variable with _putenv and then use getenv +** to check it. This test resets an environment variable. +** +** +**===================================================================*/ + +#include + +const char *_putenvString0 = "AnUnusualVariable=AnUnusualValue"; +const char *_putenvString1 = "AnUnusualVariable="; +const char *variable = "AnUnusualVariable"; +const char *value = "AnUnusualValue"; + +PALTEST(c_runtime__putenv_test2_paltest_putenv_test2, "c_runtime/_putenv/test2/paltest_putenv_test2") +{ + + char *variableValue; + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + if(_putenv(_putenvString0) == -1) + { + Fail("ERROR: _putenv failed to set an environment " + "variable with a valid format.\n Call was" + "_putenv(%s)\n", _putenvString0); + } + + variableValue = getenv(variable); + + if (variableValue == NULL) + { + Fail("ERROR: getenv(%s) call returned NULL\nThe call " + "should have returned '%s'\n", variable, value); + } + else + { + if ( strcmp(variableValue, value) != 0 ) + { + Fail("ERROR: _putenv(%s)\nshould have set the variable " + "'%s'\n to '%s'.\nA subsequent call to getenv(%s)\n" + "returned '%s' instead.\n", _putenvString0, + variable, value, variable, variableValue); + } + else + { + if(_putenv(_putenvString1) == -1) + { + Fail("ERROR: _putenv failed to set an environment " + "variable with a valid format.\n Call was" + "_putenv(%s)\n", _putenvString1); + } + + variableValue = getenv(variable); + + if (variableValue != NULL) + { + Fail("ERROR: getenv(%s) call did not return NULL.\nThe call " + "returned '%s'.\n", variable, value); + } + } + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test3/test3.cpp new file mode 100644 index 0000000000000..ab1397193ce3e --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test3/test3.cpp @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test3.c +** +** Purpose: Create environment variables that differ only in Case, and +** verify that the BSD operating system treats the variables +** differently. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime__putenv_test3_paltest_putenv_test3, "c_runtime/_putenv/test3/paltest_putenv_test3") +{ +#if WIN32 + + return PASS; + +#else + + const char* FirstVariable = "PalTestingEnvironmentVariable=The value"; + const char* SecondVariable = "PALTESTINGEnvironmentVariable=Different value"; + const char* FirstVarName = "PalTestingEnvironmentVariable"; + const char* FirstVarValue = "The value"; + char* result; + + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Use _putenv to set an environment variable. This ensures that the + variable we're testing on is always present. + */ + + if(_putenv(FirstVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + + /* Call getenv -- ensure it doesn't return NULL and the string it returns + is the value we set above. Also make sure that each environment variable, + differing only by case, returns it's own value. + */ + + result = getenv(FirstVarName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, FirstVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + FirstVarValue, + result); + } + + /* Set the second environment variable, which only differs in Case */ + if(_putenv(SecondVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + /* Verify that the environment variables + */ + + result = getenv(FirstVarName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, FirstVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + FirstVarValue, + result); + } + + PAL_Terminate(); + return PASS; + +#endif +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test4/test4.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test4/test4.cpp new file mode 100644 index 0000000000000..4e438fb347630 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/_putenv/test4/test4.cpp @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test4.c +** +** Purpose: Create an environment variable and try to retrieve +** it using the same name but with different case. This +** is to show that the Win32 representation of _putenv +** is case insensitive. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime__putenv_test4_paltest_putenv_test4, "c_runtime/_putenv/test4/paltest_putenv_test4") +{ +#if WIN32 + + const char* FirstVariable = "PalTestingEnvironmentVariable=The value"; + const char* ModifiedName = "PALTESTINGEnvironmentVariable"; + const char* FirstVarValue = "The value"; + char* result; + + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Use _putenv to set an environment variable. This ensures that the + variable we're testing on is always present. + */ + + if(_putenv(FirstVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + + /* Call getenv -- ensure it doesn't return NULL and the string it returns + is the value we set above. Also make sure that each environment variable, + differing only by case, doesn't affect the return value. + */ + + result = getenv(ModifiedName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, FirstVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + FirstVarValue, + result); + } + + + PAL_Terminate(); + return PASS; + +#else + return PASS; + +#endif +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test1/test1.cpp new file mode 100644 index 0000000000000..fe615787c7248 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test1/test1.cpp @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test1.c (fclose) +** +** Purpose: Tests the PAL implementation of the fclose function. +** This test will use fdopen to create a file stream, +** that will be used to test fclose. fclose will also +** be passed a closed file handle to make sure it handle +** it accordingly. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime_fclose_test1_paltest_fclose_test1, "c_runtime/fclose/test1/paltest_fclose_test1") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + BOOL bRetVal = FALSE; + int iFiledes = 0; + FILE *fp; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, // read handle + &hWritePipe, // write handle + &lpPipeAttributes,// security attributes + 0); // pipe size + + if (bRetVal == FALSE) + { + Fail("ERROR: Unable to create pipe; returned error code %ld" + , GetLastError()); + } + + /*Get a file descriptor for the read pipe handle*/ + iFiledes = _open_osfhandle((long)hReadPipe,_O_RDONLY); + + if (iFiledes == -1) + { + Fail("ERROR: _open_osfhandle failed to open " + " hReadPipe=0x%lx", hReadPipe); + } + + /*Open read pipe handle in read mode*/ + fp = _fdopen(iFiledes, "r"); + + if (fp == NULL) + { + Fail("ERROR: unable to fdopen file descriptor" + " iFiledes=%d", iFiledes); + } + + /*Attempt to close the file stream*/ + if (fclose(fp) != 0) + { + Fail("ERROR: Unable to fclose file stream fp=0x%lx\n",fp); + } + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test2/test2.cpp new file mode 100644 index 0000000000000..d27349a2448d9 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/fclose/test2/test2.cpp @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test2.c (fclose) +** +** Purpose: Tests the PAL implementation of the fclose function. +** fclose will be passed a closed file handle to make +** sure it handles it accordingly. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime_fclose_test2_paltest_fclose_test2, "c_runtime/fclose/test2/paltest_fclose_test2") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + BOOL bRetVal = FALSE; + int iFiledes = 0; + FILE *fp; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, /* read handle */ + &hWritePipe, /* write handle */ + &lpPipeAttributes,/* security attributes */ + 0); /* pipe size */ + + if (bRetVal == FALSE) + { + Fail("ERROR: Unable to create pipe; returned error code %ld" + , GetLastError()); + } + + /*Get a file descriptor for the read pipe handle*/ + iFiledes = _open_osfhandle((long)hReadPipe,_O_RDONLY); + + if (iFiledes == -1) + { + Fail("ERROR: _open_osfhandle failed to open " + " hReadPipe=0x%lx", hReadPipe); + } + + /*Open read pipe handle in read mode*/ + fp = _fdopen(iFiledes, "r"); + + if (fp == NULL) + { + Fail("ERROR: unable to fdopen file descriptor" + " iFiledes=%d", iFiledes); + } + + /*Attempt to close the file stream*/ + if (fclose(fp) != 0) + { + Fail("ERROR: Unable to fclose file stream fp=0x%lx\n", fp); + } + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test1/test1.cpp new file mode 100644 index 0000000000000..0842b82f46d3d --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test1/test1.cpp @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Create an environment variable and then use getenv to get +** a pointer to it. Check that the pointer is valid and that the string +** is what we expected. Also check that searching for a non-existent +** variable will cause getenv to return NULL. Also check that function +** passes when the parameter has it's casing changed (e.g upper case) +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime_getenv_test1_paltest_getenv_test1, "c_runtime/getenv/test1/paltest_getenv_test1") +{ + + const char* SetVariable = "PalTestingEnvironmentVariable=The value"; + const char* VariableName = "PalTestingEnvironmentVariable"; + const char* VariableValue = "The value"; + char* result; + + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Use _putenv to set an environment variable. This ensures that the + variable we're testing on is always present. + */ + + if(_putenv(SetVariable) == -1) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + /* Call getenv -- ensure it doesn't return NULL and the string it returns + is the value we set above. + */ + + result = getenv(VariableName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, VariableValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + VariableValue, + result); + } + + /* Try calling getenv on an environment variable which doesn't + exist. + */ + result = getenv("SomeEnvironmentVariableThatReallyDoesNotExist"); + + if(result != NULL) + { + Fail("ERROR: Called getenv on an environment variable which " + "doesn't exist and it returned '%s' instead of NULL.\n",result); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test2/test2.cpp new file mode 100644 index 0000000000000..6ddea26d003a4 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test2/test2.cpp @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test2.c +** +** Purpose: Create environment variables that differ only in Case, and +** verify that the BSD operating system treats the variables +** differently. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime_getenv_test2_paltest_getenv_test2, "c_runtime/getenv/test2/paltest_getenv_test2") +{ +#if WIN32 + + return PASS; + +#else + + const char* FirstVariable = "PalTestingEnvironmentVariable=The value"; + const char* SecondVariable = "PALTESTINGEnvironmentVariable=Different value"; + const char* FirstVarName = "PalTestingEnvironmentVariable"; + const char* SecondVarName = "PALTESTINGEnvironmentVariable"; + const char* FirstVarValue = "The value"; + const char* SecondVarValue = "Different value"; + char* result; + + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Use _putenv to set the environment variables. This ensures that the + variables we're testing with are always present. + */ + if(_putenv(FirstVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + if(_putenv(SecondVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + + /* Call getenv -- ensure it doesn't return NULL and the string it returns + is the value we set above. Also make sure that each environment variable, + differing only by case, returns it's own value. + */ + + result = getenv(FirstVarName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, FirstVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + FirstVarValue, + result); + } + + + result = getenv(SecondVarName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, SecondVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + SecondVarValue, + result); + } + + + PAL_Terminate(); + return PASS; + +#endif +} diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test3/test3.cpp new file mode 100644 index 0000000000000..5274fbd9f9e2f --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/c_runtime/getenv/test3/test3.cpp @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test3.c +** +** Purpose: Create an environment variable and try to retrieve +** it using the same name but with different case. This +** is to show that the Win32 representation of getenv +** is case insensitive. +** +** +**===================================================================*/ + +#include + +PALTEST(c_runtime_getenv_test3_paltest_getenv_test3, "c_runtime/getenv/test3/paltest_getenv_test3") +{ +#if WIN32 + + const char* FirstVariable = "PalTestingEnvironmentVariable=The value"; + const char* ModifiedName = "PALTESTINGEnvironmentVariable"; + const char* FirstVarValue = "The value"; + char* result; + + + if (0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Use _putenv to set an environment variable. This ensures that the + variable we're testing on is always present. + */ + + if(_putenv(FirstVariable) != 0) + { + Fail("ERROR: _putenv failed to set an environment variable that " + "getenv will be using for testing.\n"); + } + + + /* Call getenv -- ensure it doesn't return NULL and the string it returns + is the value we set above. Also make sure that each environment variable, + differing only by case, doesn't affect the return value. + */ + + result = getenv(ModifiedName); + if(result == NULL) + { + Fail("ERROR: The result of getenv on a valid Environment Variable " + "was NULL, which indicates the environment variable was not " + "found.\n"); + } + + if(strcmp(result, FirstVarValue) != 0) + { + Fail("ERROR: The value obtained by getenv() was not equal to the " + "correct value of the environment variable. The correct " + "value is '%s' and the function returned '%s'.\n", + FirstVarValue, + result); + } + + + PAL_Terminate(); + return PASS; + +#else + return PASS; + +#endif +} diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.cpp b/src/coreclr/pal/tests/palsuite/common/palsuite.cpp index 5e02d5e709fca..94c0ef8a94063 100644 --- a/src/coreclr/pal/tests/palsuite/common/palsuite.cpp +++ b/src/coreclr/pal/tests/palsuite/common/palsuite.cpp @@ -208,19 +208,3 @@ mkAbsoluteFilenameA ( return (sizeAPN); } - -BOOL -DeleteFileW( - IN LPCWSTR lpFileName) -{ - _ASSERTE(lpFileName != NULL); - - CHAR mbFileName[ _MAX_PATH ]; - - if (WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, mbFileName, sizeof(mbFileName), NULL, NULL ) != 0 ) - { - return remove(mbFileName) == 0; - } - - return FALSE; -} \ No newline at end of file diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.h b/src/coreclr/pal/tests/palsuite/common/palsuite.h index ae612690e5ef8..57a56772065be 100644 --- a/src/coreclr/pal/tests/palsuite/common/palsuite.h +++ b/src/coreclr/pal/tests/palsuite/common/palsuite.h @@ -217,15 +217,7 @@ mkAbsoluteFilenameA ( DWORD dwFileLength, LPSTR absPathName ); -BOOL -CreatePipe( - OUT PHANDLE hReadPipe, - OUT PHANDLE hWritePipe, - IN LPSECURITY_ATTRIBUTES lpPipeAttributes, - IN DWORD nSize); +#endif + -BOOL -DeleteFileW( - IN LPCWSTR lpFileName); -#endif diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index fa0207d74e4c6..63ce856529287 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -33,6 +33,8 @@ c_runtime/exp/test1/paltest_exp_test1 c_runtime/expf/test1/paltest_expf_test1 c_runtime/fabs/test1/paltest_fabs_test1 c_runtime/fabsf/test1/paltest_fabsf_test1 +c_runtime/fclose/test1/paltest_fclose_test1 +c_runtime/fclose/test2/paltest_fclose_test2 c_runtime/ferror/test1/paltest_ferror_test1 c_runtime/ferror/test2/paltest_ferror_test2 c_runtime/fflush/test1/paltest_fflush_test1 @@ -80,6 +82,9 @@ c_runtime/free/test1/paltest_free_test1 c_runtime/fseek/test1/paltest_fseek_test1 c_runtime/ftell/test1/paltest_ftell_test1 c_runtime/fwrite/test1/paltest_fwrite_test1 +c_runtime/getenv/test1/paltest_getenv_test1 +c_runtime/getenv/test2/paltest_getenv_test2 +c_runtime/getenv/test3/paltest_getenv_test3 c_runtime/ilogb/test1/paltest_ilogb_test1 c_runtime/ilogbf/test1/paltest_ilogbf_test1 c_runtime/isalnum/test1/paltest_isalnum_test1 @@ -310,11 +315,16 @@ c_runtime/wcstoul/test4/paltest_wcstoul_test4 c_runtime/wcstoul/test5/paltest_wcstoul_test5 c_runtime/wcstoul/test6/paltest_wcstoul_test6 c_runtime/_alloca/test1/paltest_alloca_test1 +c_runtime/_fdopen/test1/paltest_fdopen_test1 c_runtime/_finite/test1/paltest_finite_test1 c_runtime/_finitef/test1/paltest_finitef_test1 c_runtime/_isnan/test1/paltest_isnan_test1 c_runtime/_isnanf/test1/paltest_isnanf_test1 c_runtime/_itow/test1/paltest_itow_test1 +c_runtime/_putenv/test1/paltest_putenv_test1 +c_runtime/_putenv/test2/paltest_putenv_test2 +c_runtime/_putenv/test3/paltest_putenv_test3 +c_runtime/_putenv/test4/paltest_putenv_test4 c_runtime/_rotl/test1/paltest_rotl_test1 c_runtime/_rotr/test1/paltest_rotr_test1 c_runtime/_snprintf_s/test1/paltest_snprintf_test1 @@ -440,6 +450,12 @@ filemapping_memmgt/MapViewOfFile/test3/paltest_mapviewoffile_test3 filemapping_memmgt/MapViewOfFile/test4/paltest_mapviewoffile_test4 filemapping_memmgt/MapViewOfFile/test5/paltest_mapviewoffile_test5 filemapping_memmgt/MapViewOfFile/test6/paltest_mapviewoffile_test6 +filemapping_memmgt/OpenFileMappingA/test1/paltest_openfilemappinga_test1 +filemapping_memmgt/OpenFileMappingA/test2/paltest_openfilemappinga_test2 +filemapping_memmgt/OpenFileMappingA/test3/paltest_openfilemappinga_test3 +filemapping_memmgt/OpenFileMappingW/test1/paltest_openfilemappingw_test1 +filemapping_memmgt/OpenFileMappingW/test2/paltest_openfilemappingw_test2 +filemapping_memmgt/OpenFileMappingW/test3/paltest_openfilemappingw_test3 filemapping_memmgt/ProbeMemory/ProbeMemory_neg1/paltest_probememory_probememory_neg1 filemapping_memmgt/ProbeMemory/test1/paltest_probememory_test1 filemapping_memmgt/UnmapViewOfFile/test1/paltest_unmapviewoffile_test1 @@ -485,6 +501,8 @@ file_io/CopyFileW/test2/paltest_copyfilew_test2 file_io/CopyFileW/test3/paltest_copyfilew_test3 file_io/CreateFileA/test1/paltest_createfilea_test1 file_io/CreateFileW/test1/paltest_createfilew_test1 +file_io/DeleteFileA/test1/paltest_deletefilea_test1 +file_io/DeleteFileW/test1/paltest_deletefilew_test1 file_io/errorpathnotfound/test1/paltest_errorpathnotfound_test1 file_io/errorpathnotfound/test2/paltest_errorpathnotfound_test2 file_io/FILECanonicalizePath/paltest_filecanonicalizepath_test1 @@ -497,6 +515,8 @@ file_io/FindNextFileW/test1/paltest_findnextfilew_test1 file_io/FindNextFileW/test2/paltest_findnextfilew_test2 file_io/FlushFileBuffers/test1/paltest_flushfilebuffers_test1 file_io/GetConsoleOutputCP/test1/paltest_getconsoleoutputcp_test1 +file_io/GetCurrentDirectoryA/test1/paltest_getcurrentdirectorya_test1 +file_io/GetCurrentDirectoryW/test1/paltest_getcurrentdirectoryw_test1 file_io/GetFileAttributesA/test1/paltest_getfileattributesa_test1 file_io/GetFileAttributesExW/test1/paltest_getfileattributesexw_test1 file_io/GetFileAttributesExW/test2/paltest_getfileattributesexw_test2 @@ -523,11 +543,18 @@ file_io/GetTempFileNameW/test2/paltest_gettempfilenamew_test2 file_io/GetTempFileNameW/test3/paltest_gettempfilenamew_test3 file_io/gettemppatha/test1/paltest_gettemppatha_test1 file_io/GetTempPathW/test1/paltest_gettemppathw_test1 +file_io/MoveFileExA/test1/paltest_movefileexa_test1 +file_io/MoveFileExW/test1/paltest_movefileexw_test1 file_io/ReadFile/test1/paltest_readfile_test1 file_io/ReadFile/test2/paltest_readfile_test2 file_io/ReadFile/test3/paltest_readfile_test3 file_io/ReadFile/test4/paltest_readfile_test4 file_io/SearchPathW/test1/paltest_searchpathw_test1 +file_io/SetEndOfFile/test1/paltest_setendoffile_test1 +file_io/SetEndOfFile/test2/paltest_setendoffile_test2 +file_io/SetEndOfFile/test3/paltest_setendoffile_test3 +file_io/SetEndOfFile/test4/paltest_setendoffile_test4 +file_io/SetEndOfFile/test5/paltest_setendoffile_test5 file_io/SetFilePointer/test1/paltest_setfilepointer_test1 file_io/SetFilePointer/test2/paltest_setfilepointer_test2 file_io/SetFilePointer/test3/paltest_setfilepointer_test3 @@ -562,6 +589,7 @@ locale_info/WideCharToMultiByte/test5/paltest_widechartomultibyte_test5 miscellaneous/CGroup/test1/paltest_cgroup_test1 miscellaneous/CloseHandle/test1/paltest_closehandle_test1 miscellaneous/CloseHandle/test2/paltest_closehandle_test2 +miscellaneous/CreatePipe/test1/paltest_createpipe_test1 miscellaneous/FlushInstructionCache/test1/paltest_flushinstructioncache_test1 miscellaneous/FormatMessageW/test1/paltest_formatmessagew_test1 miscellaneous/FormatMessageW/test2/paltest_formatmessagew_test2 @@ -643,6 +671,7 @@ threading/CreateThread/test2/paltest_createthread_test2 threading/CreateThread/test3/paltest_createthread_test3 threading/CriticalSectionFunctions/test1/paltest_criticalsectionfunctions_test1 threading/CriticalSectionFunctions/test2/paltest_criticalsectionfunctions_test2 +threading/CriticalSectionFunctions/test3/paltest_criticalsectionfunctions_test3 threading/CriticalSectionFunctions/test4/paltest_criticalsectionfunctions_test4 threading/CriticalSectionFunctions/test5/paltest_criticalsectionfunctions_test5 threading/CriticalSectionFunctions/test6/paltest_criticalsectionfunctions_test6 @@ -655,6 +684,8 @@ threading/DuplicateHandle/test12/paltest_duplicatehandle_test12 threading/DuplicateHandle/test2/paltest_duplicatehandle_test2 threading/DuplicateHandle/test3/paltest_duplicatehandle_test3 threading/DuplicateHandle/test4/paltest_duplicatehandle_test4 +threading/DuplicateHandle/test5/paltest_duplicatehandle_test5 +threading/DuplicateHandle/test6/paltest_duplicatehandle_test6 threading/DuplicateHandle/test7/paltest_duplicatehandle_test7 threading/DuplicateHandle/test8/paltest_duplicatehandle_test8 threading/DuplicateHandle/test9/paltest_duplicatehandle_test9 @@ -669,6 +700,7 @@ threading/GetCurrentThread/test1/paltest_getcurrentthread_test1 threading/GetCurrentThread/test2/paltest_getcurrentthread_test2 threading/GetCurrentThreadId/test1/paltest_getcurrentthreadid_test1 threading/GetExitCodeProcess/test1/paltest_getexitcodeprocess_test1 +threading/GetThreadTimes/test1/paltest_getthreadtimes_test1 threading/NamedMutex/test1/paltest_namedmutex_test1 threading/OpenEventW/test1/paltest_openeventw_test1 threading/OpenEventW/test2/paltest_openeventw_test2 diff --git a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.cpp b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.cpp index 486c4dcbd6c65..f6e7d11e0fd6d 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.cpp @@ -149,7 +149,7 @@ PALTEST(file_io_CopyFileA_test1_paltest_copyfilea_test1, "file_io/CopyFileA/test } } /* delete file file but don't worry if it fails */ - remove(szDstNonExistent); + DeleteFileA(szDstNonExistent); } int exitCode = bSuccess ? PASS : FAIL; diff --git a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test3/test3.cpp index 33d3c541c5e98..37f7601986e90 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test3/test3.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test3/test3.cpp @@ -111,11 +111,11 @@ PALTEST(file_io_CopyFileA_test3_paltest_copyfilea_test3, "file_io/CopyFileA/test } /* delete the newly copied file */ - int st = remove(szDest); - if(st != 0) + bRc = DeleteFile(szDest); + if(!bRc) { - Fail("CopyFileA: remove failed to delete the" - "file correctly with error,%u.\n",errno); + Fail("CopyFileA: DeleteFile failed to delete the" + "file correctly with error,%u.\n",GetLastError()); } /* set the attributes of the source file to normal again */ @@ -127,11 +127,11 @@ PALTEST(file_io_CopyFileA_test3_paltest_copyfilea_test3, "file_io/CopyFileA/test } /* delete the original file */ - st = remove(szSrcExisting); - if(st != 0) + bRc = DeleteFile(szSrcExisting); + if(!bRc) { - Fail("CopyFileA: remove failed to delete the" - "file correctly with error,%u.\n",errno); + Fail("CopyFileA: DeleteFile failed to delete the" + "file correctly with error,%u.\n",GetLastError()); } PAL_Terminate(); diff --git a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/test4.cpp b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/test4.cpp index 9eaecf2702c0b..39cf310c8b8ab 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/test4.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/test4.cpp @@ -164,11 +164,11 @@ PALTEST(file_io_CopyFileA_test4_paltest_copyfilea_test4, "file_io/CopyFileA/test } /* Remove the temporary file */ - int st = remove(szDest); - if(st != 0) + bRc = DeleteFile(szDest); + if(!bRc) { Fail("CopyFileA: Could not remove copied file with error %u\n", - errno); + GetLastError()); } PAL_Terminate(); diff --git a/src/coreclr/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp b/src/coreclr/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp new file mode 100644 index 0000000000000..e87baa03bc683 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: DeleteFileA.c +** +** Purpose: Tests the PAL implementation of the DeleteFileA function. +** +** +**===================================================================*/ + +// delete an existing file +// delete a non-existent file +// delete an open file +// delete files using wild cards +// delete a hidden file +// delete a file without proper permissions +// + +#define PAL_STDCPP_COMPAT +#include +#undef PAL_STDCPP_COMPAT + +#include +#include + + +PALTEST(file_io_DeleteFileA_test1_paltest_deletefilea_test1, "file_io/DeleteFileA/test1/paltest_deletefilea_test1") +{ + FILE *tempFile = NULL; + BOOL bRc = FALSE; + + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + // + // create a test file + // + tempFile = fopen("testFile01.txt", "w"); + if (tempFile == NULL) + { + Fail ("DeleteFileA: ERROR: Couldn't create \"DeleteFileA's" + " testFile01.txt\"\n"); + } + + fprintf(tempFile, "DeleteFileA test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's" + " testFile01.txt\"\n"); + } + + // + // delete a symlink to an existing file + // + if (symlink("testFile01.txt", "testFile01_symlink") != 0) + { + Fail("DeleteFileA: ERROR: Failed to create a symlink to testFile01.txt.\n"); + } + + bRc = DeleteFileA("testFile01_symlink"); + if (bRc != TRUE) + { + Fail ("DeleteFileA: ERROR: Couldn't delete symlink!\n Error is %d\n", GetLastError()); + } + + struct stat statBuffer; + if (lstat("testFile01.txt", &statBuffer) != 0) + { + Fail("DeleteFileA: ERROR: Deleting a symlink deleted the file it was pointing to.\n"); + } + + if (lstat("testFile01_symlink", &statBuffer) == 0) + { + Fail("DeleteFileA: ERROR: Failed to delete a symlink.\n"); + } + + // + // deleting an existing file + // + bRc = DeleteFileA("testFile01.txt"); + if (bRc != TRUE) + { + Fail ("DeleteFileA: ERROR: Couldn't delete DeleteFileA's" + " \"testFile01.txt\"\n" + " Error is %d\n", GetLastError()); + } + + + // + // deleting a non-existent file : should fail + // + + bRc = DeleteFileA("testFile02.txt"); + if (bRc != FALSE) + { + Fail ("DeleteFileA: ERROR: Was able to delete the non-existent" + " file \"testFile02.txt\"\n"); + } + + + + + // + // deleting an open file + // + tempFile = fopen("testFile03.txt", "w"); + if (tempFile == NULL) + { + Fail("DeleteFileA: ERROR: Couldn't create \"DeleteFileA's" + " testFile03.txt\"\n"); + } + + fprintf(tempFile, "DeleteFileA test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's" + " testFile03.txt\"\n"); + } + + bRc = DeleteFileA("testFile03.txt"); + if (bRc != TRUE) + { + Fail("DeleteFileA: ERROR: Couldn't delete DeleteFileA's" + " \"testFile03.txt\"\n" + " Error is %d\n", GetLastError()); + } + bRc = DeleteFileA("testFile03.txt"); + + + + + // + // delete using wild cards + // + + // create the test file + tempFile = fopen("testFile04.txt", "w"); + if (tempFile == NULL) + { + Fail("DeleteFileA: ERROR: Couldn't create DeleteFileA's" + " \"testFile04.txt\"\n"); + } + fprintf(tempFile, "DeleteFileA test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's" + " testFile04.txt\"\n"); + } + + // delete using '?' + bRc = DeleteFileA("testFile0?.txt"); + if (bRc == TRUE) + { + Fail("DeleteFileA: ERROR: Was able to delete using the" + " \'?\' wildcard\n"); + } + + // delete using '*' + bRc = DeleteFileA("testFile*.txt"); + if (bRc == TRUE) + { + Fail("DeleteFileA: ERROR: Was able to delete using the" + " \'*\' wildcard\n"); + } + + bRc = DeleteFileA("testFile04.txt"); + if (bRc != TRUE) + { + Fail ("DeleteFileA: ERROR: Couldn't delete DeleteFileA's" + " \"testFile04.txt\"\n" + " Error is %d\n", GetLastError()); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.cpp b/src/coreclr/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.cpp new file mode 100644 index 0000000000000..f7643a0b49f3d --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.cpp @@ -0,0 +1,163 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: DeleteFileW.c +** +** Purpose: Tests the PAL implementation of the DeleteFileW function. +** +** +**===================================================================*/ + +// delete an existing file +// delete a non-existent file +// delete an open file +// delete files using wild cards +// delete a hidden file +// delete a file without proper permissions +// + + +#include + + +PALTEST(file_io_DeleteFileW_test1_paltest_deletefilew_test1, "file_io/DeleteFileW/test1/paltest_deletefilew_test1") +{ + FILE *tempFile = NULL; + BOOL bRc = FALSE; + WCHAR* pTemp = NULL; + + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + // + // deleting an existing file + // + tempFile = fopen("testFile01.tmp", "w"); + if (tempFile == NULL) + { + Fail ("DeleteFileW: ERROR: Couldn't create \"DeleteFileW's" + " testFile01.tmp\"\n"); + } + + fprintf(tempFile, "DeleteFileW test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's" + " testFile01.tmp\"\n"); + } + + pTemp = convert("testFile01.tmp"); + bRc = DeleteFileW(pTemp); + free(pTemp); + if (bRc != TRUE) + { + Fail ("DeleteFileW: ERROR: Couldn't delete DeleteFileW's" + " \"testFile01.tmp\"\n" + " Error is %d\n", GetLastError()); + } + + + // + // deleting a non-existent file : should fail + // + + pTemp = convert("testFile02.tmp"); + bRc = DeleteFileW(pTemp); + free(pTemp); + if (bRc != FALSE) + { + Fail ("DeleteFileW: ERROR: Was able to delete the non-existent" + " file \"testFile02.tmp\"\n"); + } + + + + + // + // deleting an open file + // + tempFile = fopen("testFile03.tmp", "w"); + if (tempFile == NULL) + { + Fail("DeleteFileW: ERROR: Couldn't create \"DeleteFileW's" + " testFile03.tmp\"\n"); + } + + fprintf(tempFile, "DeleteFileW test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's" + " testFile03.tmp\"\n"); + } + + pTemp = convert("testFile03.tmp"); + bRc = DeleteFileW(pTemp); + if (bRc != TRUE) + { + Fail("DeleteFileW: ERROR: Couldn't delete DeleteFileW's" + " \"testFile03.tmp\"\n" + " Error is %d\n", GetLastError()); + free(pTemp); + } + bRc = DeleteFileW(pTemp); + free(pTemp); + + + + + // + // delete using wild cards + // + + // create the test file + tempFile = fopen("testFile04.tmp", "w"); + if (tempFile == NULL) + { + Fail("DeleteFileW: ERROR: Couldn't create DeleteFileW's" + " \"testFile04.tmp\"\n"); + } + fprintf(tempFile, "DeleteFileW test file.\n"); + if (fclose(tempFile) != 0) + { + Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's" + " testFile04.tmp\"\n"); + } + + // delete using '?' + pTemp = convert("testFile0?.tmp"); + bRc = DeleteFileW(pTemp); + free(pTemp); + if (bRc == TRUE) + { + Fail("DeleteFileW: ERROR: Was able to delete using the" + " \'?\' wildcard\n"); + } + + // delete using '*' + pTemp = convert("testFile*.tmp"); + bRc = DeleteFileW(pTemp); + free(pTemp); + if (bRc == TRUE) + { + Fail("DeleteFileW: ERROR: Was able to delete using the" + " \'*\' wildcard\n"); + } + + pTemp = convert("testFile04.tmp"); + bRc = DeleteFileW(pTemp); + free(pTemp); + if (bRc != TRUE) + { + Fail ("DeleteFileW: ERROR: Couldn't delete DeleteFileW's" + " \"testFile04.tmp\"\n" + " Error is %d\n", GetLastError()); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.cpp b/src/coreclr/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.cpp index ab5c184d13a19..dd7981efaabc3 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.cpp @@ -33,8 +33,8 @@ void removeAll_FindNextFileA_test1() wTempPtr = convert((LPSTR)szDirName_02); RemoveDirectoryW(wTempPtr); free (wTempPtr); - remove(szFindName); - remove(szFindName_02); + DeleteFile(szFindName); + DeleteFile(szFindName_02); } diff --git a/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.cpp b/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.cpp new file mode 100644 index 0000000000000..e5411c0aad8fc --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.cpp @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: GetCurrentDirectoryA.c (test 1) +** +** Purpose: Tests the PAL implementation of the GetCurrentDirectoryA function. +** +** +**===================================================================*/ + +#include + + + +PALTEST(file_io_GetCurrentDirectoryA_test1_paltest_getcurrentdirectorya_test1, "file_io/GetCurrentDirectoryA/test1/paltest_getcurrentdirectorya_test1") +{ + const char* szFileName = "blah"; + + DWORD dwRc = 0; + DWORD dwRc2 = 0; + char szReturnedPath[_MAX_PATH+1]; + char szCurrentDir[_MAX_PATH+1]; + LPSTR pPathPtr; + size_t nCount = 0; + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + // use GetFullPathName to to get the current path by stripping + // the file name off the end + memset(szReturnedPath, 0, sizeof(char)*(_MAX_PATH+1)); + dwRc = GetFullPathNameA(szFileName, _MAX_PATH, szReturnedPath, &pPathPtr); + if (dwRc == 0) + { + // GetFullPathName failed + Fail("GetCurrentDirectoryA: ERROR -> GetFullPathNameA failed " + "with error code: %ld.\n", GetLastError()); + } + else if(dwRc > _MAX_PATH) + { + Fail("GetCurrentDirectoryA: ERROR -> The path name GetFullPathNameA " + "returned is longer than _MAX_PATH characters.\n"); + } + + + // strip the file name from the full path to get the current path + nCount = strlen(szReturnedPath) - strlen(szFileName) - 1; + memset(szCurrentDir, 0, sizeof(char)*(_MAX_PATH+1)); + strncpy(szCurrentDir, szReturnedPath, nCount); + + // compare the results of GetCurrentDirectoryA with the above + memset(szReturnedPath, 0, sizeof(char)*(_MAX_PATH+1)); + dwRc = GetCurrentDirectoryA((sizeof(char)*(_MAX_PATH+1)), szReturnedPath); + if (dwRc == 0) + { + Fail("GetCurrentDirectoryA: ERROR -> GetCurrentDirectoryA failed " + "with error code: %ld.\n", GetLastError()); + } + else if(dwRc > _MAX_PATH) + { + Fail("GetCurrentDirectoryA: ERROR -> The path name " + "returned is longer than _MAX_PATH characters.\n"); + } + + + /* test case the passed buffer size is not big enough + * function should return the size required + 1 a terminating null character + */ + + /* good buffer size */ + dwRc = GetCurrentDirectoryA((sizeof(CHAR)*(_MAX_PATH+1)), szReturnedPath); + + /* small buffer (0 size)*/ + dwRc2 = GetCurrentDirectoryA(0, szReturnedPath); + if (dwRc2 != (dwRc+1) ) + { + Fail("GetCurrentDirectoryA: ERROR -> failed to give the correct " + "return value when passed a buffer not big enough. " + "Expected %u while result is %u \n",(dwRc+1),dwRc2); + + } + + if (strcmp(szReturnedPath, szCurrentDir) != 0) + { + Fail("GetCurrentDirectoryA: ERROR -> The computed and returned " + "directories do not compare.\n"); + } + + + PAL_Terminate(); + return PASS; +} + diff --git a/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.cpp b/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.cpp new file mode 100644 index 0000000000000..f25ff41d6cc9d --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.cpp @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: GetCurrentDirectoryW.c (test 1) +** +** Purpose: Tests the PAL implementation of the GetCurrentDirectoryW function. +** +** +**===================================================================*/ + +#include + + +PALTEST(file_io_GetCurrentDirectoryW_test1_paltest_getcurrentdirectoryw_test1, "file_io/GetCurrentDirectoryW/test1/paltest_getcurrentdirectoryw_test1") +{ + DWORD dwRc = 0; + DWORD dwRc2 = 0; + WCHAR szwReturnedPath[_MAX_PATH+1]; + WCHAR szwCurrentDir[_MAX_PATH+1]; + WCHAR szwFileName[_MAX_PATH] = {'b','l','a','h','\0'}; + LPWSTR pPathPtr; + size_t nCount = 0; + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + /* use GetFullPathName to to get the current path by stripping + * the file name off the end */ + memset(szwReturnedPath, 0, sizeof(WCHAR)*(_MAX_PATH+1)); + dwRc = GetFullPathNameW(szwFileName, _MAX_PATH, szwReturnedPath, &pPathPtr); + if (dwRc == 0) + { + /* GetFullPathName failed */ + Fail("GetCurrentDirectoryW: ERROR -> GetFullPathNameW failed " + "with error code: %ld.\n", GetLastError()); + } + else if(dwRc >_MAX_PATH) + { + Fail("GetCurrentDirectoryW: ERROR -> The path name GetFullPathNameW " + "returned is longer than _MAX_PATH characters.\n"); + } + + /* strip the file name from the full path to get the current path */ + nCount = wcslen(szwReturnedPath) - wcslen(szwFileName) - 1; + memset(szwCurrentDir, 0, sizeof(WCHAR)*(_MAX_PATH+1)); + memcpy(szwCurrentDir, szwReturnedPath, nCount*sizeof(WCHAR)); + + /* compare the results of GetCurrentDirectoryW with the above */ + memset(szwReturnedPath, 0, sizeof(WCHAR)*(_MAX_PATH+1)); + dwRc = GetCurrentDirectoryW((sizeof(WCHAR)*(_MAX_PATH+1)), szwReturnedPath); + if (dwRc == 0) + { + Fail("GetCurrentDirectoryW: ERROR -> GetCurrentDirectoryW failed " + "with error code: %ld.\n", GetLastError()); + } + else if(dwRc >_MAX_PATH) + { + Fail("GetCurrentDirectoryW: ERROR -> The path name " + "returned is longer than _MAX_PATH characters.\n"); + } + + /* check to see whether the length of the returned string is equal to + * the DWORD returned by GetCurrentDirectoryW. + */ + if(wcslen(szwReturnedPath) != dwRc) + { + Fail("GetCurrentDirectoryW: ERROR -> The Length of the path name " + "returned \"%u\" is not equal to the return value of the " + "function \"%u\".\n" , wcslen(szwReturnedPath), dwRc); + } + + + + /* test case the passed buffer size is not big enough + * function should return the size required + 1 for a terminating null character + */ + + /* good buffer size */ + dwRc = GetCurrentDirectoryW((sizeof(WCHAR)*(_MAX_PATH+1)), szwReturnedPath); + + /* small buffer (0 size)*/ + dwRc2 = GetCurrentDirectoryW(0, szwReturnedPath); + if (dwRc2 != (dwRc+1) ) + { + Fail("GetCurrentDirectoryW: ERROR -> failed to give the correct " + "return value when passed a buffer not big enough. " + "Expected %u while result is %u ",(dwRc+1),dwRc2); + + } + + if (wcsncmp(szwReturnedPath, szwCurrentDir, wcslen(szwReturnedPath)) != 0) + { + Fail("GetCurrentDirectoryW: ERROR -> The computed and returned " + "directories do not compare.\n"); + } + + + PAL_Terminate(); + return PASS; +} + diff --git a/src/coreclr/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.cpp b/src/coreclr/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.cpp index aab5c9405e101..4a58e113a9315 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.cpp @@ -28,6 +28,40 @@ void CleanUp_GetFileSize_test1(HANDLE hFile) } } +void CheckFileSize_GetFileSize_test1(HANDLE hFile, DWORD dwOffset, DWORD dwHighOrder) +{ + DWORD dwRc = 0; + DWORD dwReturnedHighOrder = 0; + DWORD dwReturnedOffset = 0; + + dwRc = SetFilePointer(hFile, dwOffset, (PLONG)&dwHighOrder, FILE_BEGIN); + if (dwRc == INVALID_SET_FILE_POINTER) + { + Trace("GetFileSize: ERROR -> Call to SetFilePointer failed with %ld.\n", + GetLastError()); + CleanUp_GetFileSize_test1(hFile); + Fail(""); + } + else + { + if (!SetEndOfFile(hFile)) + { + Trace("GetFileSize: ERROR -> Call to SetEndOfFile failed with %ld.\n", + GetLastError()); + CleanUp_GetFileSize_test1(hFile); + Fail(""); + } + dwReturnedOffset = GetFileSize(hFile, &dwReturnedHighOrder); + if ((dwReturnedOffset != dwOffset) || + (dwReturnedHighOrder != dwHighOrder)) + { + CleanUp_GetFileSize_test1(hFile); + Fail("GetFileSize: ERROR -> File sizes do not match up.\n"); + } + } +} + + PALTEST(file_io_GetFileSize_test1_paltest_getfilesize_test1, "file_io/GetFileSize/test1/paltest_getfilesize_test1") { HANDLE hFile = NULL; @@ -91,6 +125,16 @@ PALTEST(file_io_GetFileSize_test1_paltest_getfilesize_test1, "file_io/GetFileSiz szTextFile); } + /* give the file a size */ + CheckFileSize_GetFileSize_test1(hFile, 256, 0); + + /* make the file large using the high order option */ + CheckFileSize_GetFileSize_test1(hFile, 256, 1); + + + /* set the file size to zero */ + CheckFileSize_GetFileSize_test1(hFile, 0, 0); + /* test if file size changes by writing to it. */ /* get file size */ dwRc = GetFileSize(hFile, NULL); diff --git a/src/coreclr/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.cpp b/src/coreclr/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.cpp index b8aef40157c4e..1268fad42001e 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.cpp @@ -30,6 +30,50 @@ void CleanUp_GetFileSizeEx_test1(HANDLE hFile) } } +void CheckFileSize_GetFileSizeEx_test1(HANDLE hFile, DWORD dwOffset, DWORD dwHighOrder) +{ + DWORD dwRc = 0; + DWORD dwError = 0; + LARGE_INTEGER qwFileSize; + + dwRc = SetFilePointer(hFile, dwOffset, (PLONG)&dwHighOrder, FILE_BEGIN); + if (dwRc == INVALID_SET_FILE_POINTER) + { + Trace("GetFileSizeEx: ERROR -> Call to SetFilePointer failed with %ld.\n", + GetLastError()); + CleanUp_GetFileSizeEx_test1(hFile); + Fail(""); + } + else + { + if (!SetEndOfFile(hFile)) + { + dwError = GetLastError(); + CleanUp_GetFileSizeEx_test1(hFile); + if (dwError == 112) + { + Fail("GetFileSizeEx: ERROR -> SetEndOfFile failed due to lack of " + "disk space\n"); + } + else + { + Fail("GetFileSizeEx: ERROR -> SetEndOfFile call failed " + "with error %ld\n", dwError); + } + } + else + { + GetFileSizeEx(hFile, &qwFileSize); + if ((qwFileSize.u.LowPart != dwOffset) || + (qwFileSize.u.HighPart != dwHighOrder)) + { + CleanUp_GetFileSizeEx_test1(hFile); + Fail("GetFileSizeEx: ERROR -> File sizes do not match up.\n"); + } + } + } +} + PALTEST(file_io_GetFileSizeEx_test1_paltest_getfilesizeex_test1, "file_io/GetFileSizeEx/test1/paltest_getfilesizeex_test1") { HANDLE hFile = NULL; @@ -81,6 +125,16 @@ PALTEST(file_io_GetFileSizeEx_test1_paltest_getfilesizeex_test1, "file_io/GetFil szTextFile); } + /* give the file a size */ + CheckFileSize_GetFileSizeEx_test1(hFile, 256, 0); + + /* make the file large using the high order option */ + CheckFileSize_GetFileSizeEx_test1(hFile, 256, 1); + + + /* set the file size to zero */ + CheckFileSize_GetFileSizeEx_test1(hFile, 0, 0); + /* test if file size changes by writing to it. */ /* get file size */ GetFileSizeEx(hFile, &qwFileSize); diff --git a/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt new file mode 100644 index 0000000000000..684b8a536fcf7 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt @@ -0,0 +1 @@ +01110011000000000111001100000000 diff --git a/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.cpp b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.cpp new file mode 100644 index 0000000000000..ff99b864eded3 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.cpp @@ -0,0 +1,364 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: MoveFileExA.c +** +** Purpose: Tests the PAL implementation of the MoveFileExA function. +** +** +**===================================================================*/ + +#include + + +LPSTR lpSource_MoveFileExA_test1[4] = { + "src_existing.tmp", + "src_non-existent.tmp", + "src_dir_existing", + "src_dir_non-existent" + }; +LPSTR lpDestination_MoveFileExA_test1[4]={ + "dst_existing.tmp", + "dst_non-existent.tmp", + "dst_dir_existing", + "dst_dir_non-existent" + }; + +LPSTR lpFiles_MoveFileExA_test1[14] ={ + "src_dir_existing\\test01.tmp", + "src_dir_existing\\test02.tmp", + "dst_dir_existing\\test01.tmp", + "dst_dir_existing\\test02.tmp", + "src_dir_non-existent\\test01.tmp", + "src_dir_non-existent\\test02.tmp", + "dst_existing.tmp\\test01.tmp", + "dst_existing.tmp\\test02.tmp", + "dst_non-existent.tmp\\test01.tmp", + "dst_non-existent.tmp\\test02.tmp", + "dst_dir_existing\\test01.tmp", + "dst_dir_existing\\test02.tmp", + "dst_dir_non-existent\\test01.tmp", + "dst_dir_non-existent\\test02.tmp" + }; + +DWORD dwFlag_MoveFileExA_test1[2] = {MOVEFILE_COPY_ALLOWED, MOVEFILE_REPLACE_EXISTING}; + + + + +int createExisting_MoveFileExA_test1(void) +{ + HANDLE tempFile = NULL; + HANDLE tempFile2 = NULL; + + /* create the src_existing file and dst_existing file */ + tempFile = CreateFileA(lpSource_MoveFileExA_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileA(lpDestination_MoveFileExA_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR[%ul]: couldn't create %S or %S\n", GetLastError(), lpSource_MoveFileExA_test1[0], + lpDestination_MoveFileExA_test1[0]); + return FAIL; + } + + /* create the src_dir_existing and dst_dir_existing directory and files */ + CreateDirectoryA(lpSource_MoveFileExA_test1[2], NULL); + + tempFile = CreateFileA(lpFiles_MoveFileExA_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileA(lpFiles_MoveFileExA_test1[1], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR[%ul]: couldn't create src_dir_existing\\test01.tmp\n", GetLastError()); + return FAIL; + } + + CreateDirectoryA(lpDestination_MoveFileExA_test1[2], NULL); + tempFile = CreateFileA(lpFiles_MoveFileExA_test1[2], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileA(lpFiles_MoveFileExA_test1[3], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR[%ul]: couldn't create dst_dir_existing\\test01.tmp\n" , GetLastError()); + return FAIL; + } + return PASS; + +} + +void removeDirectoryHelper_MoveFileExA_test1(LPSTR dir, int location) +{ + DWORD dwAtt = GetFileAttributesA(dir); + + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + LPWSTR dirW = convert(dir); + if(!RemoveDirectoryW(dirW)) + { + DWORD dwError = GetLastError(); + free(dirW); + Fail("ERROR: Failed to remove Directory [%s], Error Code [%d], location [%d]\n", dir, dwError, location); + } + + free(dirW); + } +} + +void removeFileHelper_MoveFileExA_test1(LPSTR pfile, int location) +{ + FILE *fp; + fp = fopen( pfile, "r"); + + if (fp != NULL) + { + if(fclose(fp)) + { + Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location); + } + + if(!DeleteFileA(pfile)) + { + Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location); + } + } + +} + +void removeAll_MoveFileExA_test1(void) +{ + DWORD dwAtt; + /* get rid of destination dirs and files */ + removeFileHelper_MoveFileExA_test1(lpSource_MoveFileExA_test1[0], 11); + removeFileHelper_MoveFileExA_test1(lpSource_MoveFileExA_test1[1], 12); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[0], 13); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[1], 14); + + removeDirectoryHelper_MoveFileExA_test1(lpSource_MoveFileExA_test1[2], 101); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[4], 15); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[5], 16); + removeDirectoryHelper_MoveFileExA_test1(lpSource_MoveFileExA_test1[3], 102); + + /* get rid of destination dirs and files */ + dwAtt = GetFileAttributesA(lpDestination_MoveFileExA_test1[0]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[6], 18); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[7], 19); + removeDirectoryHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[0], 103); + } + else + { + removeFileHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[0], 17); + } + + dwAtt = GetFileAttributesA(lpDestination_MoveFileExA_test1[1]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[8], 21); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[9], 22); + removeDirectoryHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[1], 104); + } + else + { + removeFileHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[1], 19); + } + + dwAtt = GetFileAttributesA(lpDestination_MoveFileExA_test1[2]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[10], 24); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[11], 25); + removeDirectoryHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[2], 105); + } + else + { + removeFileHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[2], 23); + } + + dwAtt = GetFileAttributesA(lpDestination_MoveFileExA_test1[3]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[12], 26); + removeFileHelper_MoveFileExA_test1(lpFiles_MoveFileExA_test1[13], 27); + removeDirectoryHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[3], 106); + } + else + { + removeFileHelper_MoveFileExA_test1(lpDestination_MoveFileExA_test1[3], 107); + } + +} + +PALTEST(file_io_MoveFileExA_test1_paltest_movefileexa_test1, "file_io/MoveFileExA/test1/paltest_movefileexa_test1") +{ + BOOL bRc = TRUE; + char results[40]; + FILE* resultsFile = NULL; + int i, j, k, nCounter = 0; + int res = FAIL; + char tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'}; + char tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'}; + HANDLE hFile; + DWORD result; + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + /* read in the expected results to compare with actual results */ + memset (results, 0, 34); + resultsFile = fopen("expectedresults.txt", "r"); + if (resultsFile == NULL) + { + Trace("MoveFileExA ERROR: Unable to open \"expectedresults.txt\"\n"); + goto EXIT; + } + + fgets(results, 34, resultsFile); + fclose(resultsFile); + + nCounter = 0; + + + /* clean the slate */ + removeAll_MoveFileExA_test1(); + if (createExisting_MoveFileExA_test1() != PASS) + { + goto EXIT; + } + + /* lpSource_MoveFileExA_test1 loop */ + for (i = 0; i < 4; i++) + { + /* lpDestination_MoveFileExA_test1 loop */ + for (j = 0; j < 4; j++) + { + /* dwFlag_MoveFileExA_test1 loop */ + for (k = 0; k < 2; k++) + { + + /* move the file to the new location */ + bRc = MoveFileExA(lpSource_MoveFileExA_test1[i], lpDestination_MoveFileExA_test1[j], dwFlag_MoveFileExA_test1[k]); + + if (!( + ((bRc == TRUE) && (results[nCounter] == '1')) + || + ((bRc == FALSE ) && (results[nCounter] == '0')) ) + ) + { + Trace("MoveFileExA(%s, %s, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c LastError[%d]Flag[%d]FAILED\n", + lpSource_MoveFileExA_test1[i], lpDestination_MoveFileExA_test1[j], + k == 1 ? + "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter], GetLastError(), bRc); + goto EXIT; + } + + /* undo the last move */ + removeAll_MoveFileExA_test1(); + if (createExisting_MoveFileExA_test1() != PASS) + { + goto EXIT; + } + nCounter++; + } + } + } + + /* create the temp source file */ + hFile = CreateFileA(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + + if( hFile == INVALID_HANDLE_VALUE ) + { + Trace("MoveFileExA: CreateFile failed to " + "create the file correctly.\n"); + goto EXIT; + } + + bRc = CloseHandle(hFile); + if(!bRc) + { + Trace("MoveFileExA: CloseHandle failed to close the " + "handle correctly. yo %u\n",GetLastError()); + goto EXIT; + } + + /* set the file attributes to be readonly */ + bRc = SetFileAttributesA(tempSource, FILE_ATTRIBUTE_READONLY); + if(!bRc) + { + Trace("MoveFileExA: SetFileAttributes failed to set file " + "attributes correctly. ERROR:%u\n",GetLastError()); + goto EXIT; + } + + /* move the file to the new location */ + bRc = MoveFileExA(tempSource, tempDest, MOVEFILE_COPY_ALLOWED ); + if(!bRc) + { + Trace("MoveFileExA(%S, %S, %s): GetFileAttributes " + "failed to get the file's attributes.\n", + tempSource, tempDest, "MOVEFILE_COPY_ALLOWED"); + goto EXIT; + } + + /* check that the newly moved file has the same file attributes + as the original */ + result = GetFileAttributesA(tempDest); + if(result == 0) + { + Trace("MoveFileExA: GetFileAttributes failed to get " + "the file's attributes.\n"); + goto EXIT; + } + + if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY) + { + Trace("MoveFileExA: GetFileAttributes failed to get " + "the correct file attributes.\n"); + goto EXIT; + } + + /* set the file attributes back to normal, to be deleted */ + bRc = SetFileAttributesA(tempDest, FILE_ATTRIBUTE_NORMAL); + if(!bRc) + { + Trace("MoveFileExA: SetFileAttributes " + "failed to set file attributes correctly.\n"); + goto EXIT; + } + + /* delete the newly moved file */ + bRc = DeleteFileA(tempDest); + if(!bRc) + { + Trace("MoveFileExA: DeleteFileA failed to delete the" + "file correctly.\n"); + goto EXIT; + } + + res = PASS; + +EXIT: + removeAll_MoveFileExA_test1(); + + PAL_TerminateEx(res); + return res; +} + diff --git a/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt new file mode 100644 index 0000000000000..684b8a536fcf7 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt @@ -0,0 +1 @@ +01110011000000000111001100000000 diff --git a/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.cpp b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.cpp new file mode 100644 index 0000000000000..0144858733b89 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.cpp @@ -0,0 +1,430 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: MoveFileExW.c +** +** Purpose: Tests the PAL implementation of the MoveFileExW function. +** +** +**===================================================================*/ + +#include + + +LPWSTR lpSource_MoveFileExW_test1[4]; +LPWSTR lpDestination_MoveFileExW_test1[4]; +LPWSTR lpFiles_MoveFileExW_test1[14]; + +DWORD dwFlag_MoveFileExW_test1[2] = {MOVEFILE_COPY_ALLOWED, MOVEFILE_REPLACE_EXISTING}; + + + +int createExisting_MoveFileExW_test1(void) +{ + HANDLE tempFile = NULL; + HANDLE tempFile2 = NULL; + + /* create the src_existing file and dst_existing file */ + tempFile = CreateFileW(lpSource_MoveFileExW_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileW(lpDestination_MoveFileExW_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR: couldn't create %S or %S\n", lpSource_MoveFileExW_test1[0], + lpDestination_MoveFileExW_test1[0]); + return FAIL; + } + + /* create the src_dir_existing and dst_dir_existing directory and files */ + CreateDirectoryW(lpSource_MoveFileExW_test1[2], NULL); + + tempFile = CreateFileW(lpFiles_MoveFileExW_test1[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileW(lpFiles_MoveFileExW_test1[1], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR: couldn't create src_dir_existing\\test01.tmp\n"); + return FAIL; + } + + CreateDirectoryW(lpDestination_MoveFileExW_test1[2], NULL); + tempFile = CreateFileW(lpFiles_MoveFileExW_test1[2], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + tempFile2 = CreateFileW(lpFiles_MoveFileExW_test1[3], GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + CloseHandle(tempFile2); + CloseHandle(tempFile); + + if ((tempFile == NULL) || (tempFile2 == NULL)) + { + Trace("ERROR: couldn't create dst_dir_existing\\test01.tmp\n"); + return FAIL; + } + return PASS; +} + +void removeDirectoryHelper_MoveFileExW_test1(LPWSTR dir, int location) +{ + DWORD dwAtt = GetFileAttributesW(dir); +// Trace(" Value of location[%d], and directorye [%S]\n", location, dir); + + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + if(!RemoveDirectoryW(dir)) + { + Fail("ERROR: Failed to remove Directory [%S], Error Code [%d], location [%d]\n", dir, GetLastError(), location); + } + } +} + +void removeFileHelper_MoveFileExW_test1(LPWSTR wfile, int location) +{ + FILE *fp; + char * pfile = convertC(wfile); + +// Trace(" Value of location[%d], and file [%s]\n", location, pfile); + fp = fopen( pfile, "r"); + + if (fp != NULL) + { + if(fclose(fp)) + { + Fail("ERROR: Failed to close the file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location); + } + + if(!DeleteFileW(wfile)) + { + Fail("ERROR: Failed to delete file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location); + } + else + { + // Trace("Success: deleted file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location); + } + } + + free(pfile); +} + +void removeAll_MoveFileExW_test1(void) +{ + DWORD dwAtt; + /* get rid of destination dirs and files */ + removeFileHelper_MoveFileExW_test1(lpSource_MoveFileExW_test1[0], 11); +// lpSource_MoveFileExW_test1[0] = convert("src_existing.tmp"); + + removeFileHelper_MoveFileExW_test1(lpSource_MoveFileExW_test1[1], 12); + //lpSource_MoveFileExW_test1[1] = convert("src_non-existent.tmp"); + + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[0], 13); +// lpFiles_MoveFileExW_test1[0] = convert("src_dir_existing\\test01.tmp"); + + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[1], 14); +// lpFiles_MoveFileExW_test1[1] = convert("src_dir_existing\\test02.tmp"); + + removeDirectoryHelper_MoveFileExW_test1(lpSource_MoveFileExW_test1[2], 101); +// lpSource_MoveFileExW_test1[2] = convert("src_dir_existing"); + + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[4], 15); +// lpFiles_MoveFileExW_test1[4] = convert("src_dir_non-existent\\test01.tmp"); + + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[5], 16); +// lpFiles_MoveFileExW_test1[5] = convert("src_dir_non-existent\\test02.tmp"); + + removeDirectoryHelper_MoveFileExW_test1(lpSource_MoveFileExW_test1[3], 102); +// lpSource_MoveFileExW_test1[3] = convert("src_dir_non-existent"); + + /* get rid of destination dirs and files */ + dwAtt = GetFileAttributesW(lpDestination_MoveFileExW_test1[0]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[6], 18); + // lpFiles_MoveFileExW_test1[6] = convert("dst_existing.tmp\\test01.tmp"); + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[7], 19); + // lpFiles_MoveFileExW_test1[7] = convert("dst_existing.tmp\\test02.tmp"); + removeDirectoryHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[0], 103); + // lpDestination_MoveFileExW_test1[0] = convert("dst_existing.tmp"); + + } + else + { + removeFileHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[0], 17); + // lpDestination_MoveFileExW_test1[0] = convert("dst_existing.tmp"); + } + + dwAtt = GetFileAttributesW(lpDestination_MoveFileExW_test1[1]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[8], 21); + // lpFiles_MoveFileExW_test1[8] = convert("dst_non-existent.tmp\\test01.tmp"); + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[9], 22); + // lpFiles_MoveFileExW_test1[9] = convert("dst_non-existent.tmp\\test02.tmp"); + removeDirectoryHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[1], 104); + // lpDestination_MoveFileExW_test1[1] = convert("dst_non-existent.tmp"); + + } + else + { + removeFileHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[1], 19); + //lpDestination_MoveFileExW_test1[1] = convert("dst_non-existent.tmp"); + } + + dwAtt = GetFileAttributesW(lpDestination_MoveFileExW_test1[2]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[10], 24); + // lpFiles_MoveFileExW_test1[10] = convert("dst_dir_existing\\test01.tmp"); + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[11], 25); + // lpFiles_MoveFileExW_test1[11] = convert("dst_dir_existing\\test02.tmp"); + removeDirectoryHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[2], 105); + // lpDestination_MoveFileExW_test1[2] = convert("dst_dir_existing"); + + } + else + { + removeFileHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[2], 23); + // lpDestination_MoveFileExW_test1[2] = convert("dst_dir_existing"); + + } + + dwAtt = GetFileAttributesW(lpDestination_MoveFileExW_test1[3]); + if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) ) + { + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[12], 26); + // lpFiles_MoveFileExW_test1[12] = convert("dst_dir_non-existent\\test01.tmp"); + removeFileHelper_MoveFileExW_test1(lpFiles_MoveFileExW_test1[13], 27); + // lpFiles_MoveFileExW_test1[13] = convert("dst_dir_non-existent\\test02.tmp"); + removeDirectoryHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[3], 106); + // lpDestination_MoveFileExW_test1[3] = convert("dst_dir_non-existent"); + + } + else + { + removeFileHelper_MoveFileExW_test1(lpDestination_MoveFileExW_test1[3], 107); + // lpDestination_MoveFileExW_test1[3] = convert("dst_dir_non-existent"); + + } + +} + +PALTEST(file_io_MoveFileExW_test1_paltest_movefileexw_test1, "file_io/MoveFileExW/test1/paltest_movefileexw_test1") +{ + BOOL bRc = TRUE; + char results[40]; + FILE* resultsFile = NULL; + int i, j, k, nCounter = 0; + int res = FAIL; + WCHAR tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'}; + WCHAR tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'}; + HANDLE hFile; + DWORD result; + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + lpSource_MoveFileExW_test1[0] = convert("src_existing.tmp"); + lpSource_MoveFileExW_test1[1] = convert("src_non-existent.tmp"); + lpSource_MoveFileExW_test1[2] = convert("src_dir_existing"); + lpSource_MoveFileExW_test1[3] = convert("src_dir_non-existent"); + + lpDestination_MoveFileExW_test1[0] = convert("dst_existing.tmp"); + lpDestination_MoveFileExW_test1[1] = convert("dst_non-existent.tmp"); + lpDestination_MoveFileExW_test1[2] = convert("dst_dir_existing"); + lpDestination_MoveFileExW_test1[3] = convert("dst_dir_non-existent"); + + lpFiles_MoveFileExW_test1[0] = convert("src_dir_existing\\test01.tmp"); + lpFiles_MoveFileExW_test1[1] = convert("src_dir_existing\\test02.tmp"); + lpFiles_MoveFileExW_test1[2] = convert("dst_dir_existing\\test01.tmp"); + lpFiles_MoveFileExW_test1[3] = convert("dst_dir_existing\\test02.tmp"); + lpFiles_MoveFileExW_test1[4] = convert("src_dir_non-existent\\test01.tmp"); + lpFiles_MoveFileExW_test1[5] = convert("src_dir_non-existent\\test02.tmp"); + + lpFiles_MoveFileExW_test1[6] = convert("dst_existing.tmp\\test01.tmp"); + lpFiles_MoveFileExW_test1[7] = convert("dst_existing.tmp\\test02.tmp"); + + lpFiles_MoveFileExW_test1[8] = convert("dst_non-existent.tmp\\test01.tmp"); + lpFiles_MoveFileExW_test1[9] = convert("dst_non-existent.tmp\\test02.tmp"); + + lpFiles_MoveFileExW_test1[10] = convert("dst_dir_existing\\test01.tmp"); + lpFiles_MoveFileExW_test1[11] = convert("dst_dir_existing\\test02.tmp"); + + lpFiles_MoveFileExW_test1[12] = convert("dst_dir_non-existent\\test01.tmp"); + lpFiles_MoveFileExW_test1[13] = convert("dst_dir_non-existent\\test02.tmp"); + + /* read in the expected results to compare with actual results */ + memset (results, 0, 34); + resultsFile = fopen("expectedresults.txt", "r"); + if (resultsFile == NULL) + { + Trace("MoveFileExW ERROR: Unable to open \"expectedresults.txt\"\n"); + goto EXIT; + } + + fgets(results, 34, resultsFile); + fclose(resultsFile); + +// Trace("Value of results[%]=%s\n", i, results); + for( i = 0; i < 32; i++) + { + Trace("Value of results[%d]=%c\n", i, results[i]); + } + nCounter = 0; + + + /* clean the slate */ + removeAll_MoveFileExW_test1(); + if (createExisting_MoveFileExW_test1() != PASS) + { + goto EXIT; + } + + /* lpSource_MoveFileExW_test1 loop */ + for (i = 0; i < 4; i++) + { + /* lpDestination_MoveFileExW_test1 loop */ + for (j = 0; j < 4; j++) + { + /* dwFlag_MoveFileExW_test1 loop */ + for (k = 0; k < 2; k++) + { + + //if(nCounter == 22) + //{ + //exit(1); + //} + /* move the file to the new location */ + bRc = MoveFileExW(lpSource_MoveFileExW_test1[i], lpDestination_MoveFileExW_test1[j], dwFlag_MoveFileExW_test1[k]); + + if (!( + ((bRc == TRUE) && (results[nCounter] == '1')) + || + ((bRc == FALSE ) && (results[nCounter] == '0')) ) + ) + { + Trace("MoveFileExW(%S, %S, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c LastError[%d]Flag[%d]FAILED\n", + lpSource_MoveFileExW_test1[i], lpDestination_MoveFileExW_test1[j], + k == 1 ? + "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter], GetLastError(), bRc); + goto EXIT; + } + + //Trace("MoveFileExW(%S, %S, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c \n", + // lpSource_MoveFileExW_test1[i], lpDestination_MoveFileExW_test1[j], + // k == 1 ? + // "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter]); + + + /* undo the last move */ + removeAll_MoveFileExW_test1(); + if (createExisting_MoveFileExW_test1() != PASS) + { + goto EXIT; + } + //Trace("Counter [%d] over \n", nCounter); + nCounter++; + } + } + } + + /* create the temp source file */ + hFile = CreateFileW(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + + if( hFile == INVALID_HANDLE_VALUE ) + { + Trace("MoveFileExW: CreateFile failed to " + "create the file correctly.\n"); + goto EXIT; + } + + bRc = CloseHandle(hFile); + if(!bRc) + { + Trace("MoveFileExW: CloseHandle failed to close the " + "handle correctly. yo %u\n",GetLastError()); + goto EXIT; + } + + /* set the file attributes to be readonly */ + bRc = SetFileAttributesW(tempSource, FILE_ATTRIBUTE_READONLY); + if(!bRc) + { + Trace("MoveFileExW: SetFileAttributes failed to set file " + "attributes correctly. ERROR:%u\n",GetLastError()); + goto EXIT; + } + + /* move the file to the new location */ + bRc = MoveFileExW(tempSource, tempDest, MOVEFILE_COPY_ALLOWED ); + if(!bRc) + { + Trace("MoveFileExW(%S, %S, %s): GetFileAttributes " + "failed to get the file's attributes.\n", + tempSource, tempDest, "MOVEFILE_COPY_ALLOWED"); + goto EXIT; + } + + /* check that the newly moved file has the same file attributes + as the original */ + result = GetFileAttributesW(tempDest); + if(result == 0) + { + Trace("MoveFileExW: GetFileAttributes failed to get " + "the file's attributes.\n"); + goto EXIT; + } + + if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY) + { + Trace("MoveFileExW: GetFileAttributes failed to get " + "the correct file attributes.\n"); + goto EXIT; + } + + /* set the file attributes back to normal, to be deleted */ + bRc = SetFileAttributesW(tempDest, FILE_ATTRIBUTE_NORMAL); + if(!bRc) + { + Trace("MoveFileExW: SetFileAttributes " + "failed to set file attributes correctly.\n"); + goto EXIT; + } + + /* delete the newly moved file */ + bRc = DeleteFileW(tempDest); + if(!bRc) + { + Trace("MoveFileExW: DeleteFileW failed to delete the" + "file correctly.\n"); + goto EXIT; + } + + res = PASS; + +EXIT: + removeAll_MoveFileExW_test1(); + for (i=0; i<4; i++) + { + free(lpSource_MoveFileExW_test1[i]); + free(lpDestination_MoveFileExW_test1[i]); + } + for (i=0; i<14; i++) + { + free(lpFiles_MoveFileExW_test1[i]); + } + + PAL_TerminateEx(res); + return res; +} + diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.cpp new file mode 100644 index 0000000000000..56bcbcfce69a7 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.cpp @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: SetEndOfFile.c (test 1) +** +** Purpose: Tests the PAL implementation of the SetEndOfFile function. +** This test will attempt to operate on a NULL file handle and +** also test truncating a file not opened with GENERIC_WRITE +** +** Assumes successful: +** SetEndOfFile +** CreateFile +** CloseHandle +** + +** +**===================================================================*/ + +#include + + + + +PALTEST(file_io_SetEndOfFile_test1_paltest_setendoffile_test1, "file_io/SetEndOfFile/test1/paltest_setendoffile_test1") +{ + HANDLE hFile = NULL; + BOOL bRc = FALSE; + + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + bRc = SetEndOfFile(NULL); + if (bRc == TRUE) + { + Fail("SetEndOfFile: ERROR -> Operation succeeded on a NULL file " + "handle\n"); + } + + /* create a test file */ + hFile = CreateFile(szTextFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n", + szTextFile); + } + + bRc = SetEndOfFile(hFile); + if (bRc == TRUE) + { + Trace("SetEndOfFile: ERROR -> Operation succeeded on read-only" + " file.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.cpp new file mode 100644 index 0000000000000..b3b5372ec640a --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.cpp @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: SetEndOfFile.c (test 2) +** +** Purpose: Tests the PAL implementation of the SetEndOfFile function. +** This test will attempt to truncate a file +** +** +**===================================================================*/ + +#include + + +#define szStringTest "The quick fox jumped over the lazy dog's back." + +PALTEST(file_io_SetEndOfFile_test2_paltest_setendoffile_test2, "file_io/SetEndOfFile/test2/paltest_setendoffile_test2") +{ + HANDLE hFile = NULL; + DWORD dwByteCount = 0; + DWORD dwBytesWritten; + BOOL bRc = FALSE; + char szBuffer[100]; + DWORD dwBytesRead = 0; + FILE *pFile = NULL; + + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + // create a test file + hFile = CreateFile(szTextFile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n", + szTextFile); + } + + bRc = WriteFile(hFile, szStringTest, 20, &dwBytesWritten, NULL); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Uable to write to \"%s\".\n", + szTextFile); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + + // open the test file + hFile = CreateFile(szTextFile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("SetEndOfFile: ERROR -> Unable to open file \"%s\".\n", + szTextFile); + } + + // read a bit of the file to move the file pointer + dwByteCount = 10; + bRc = ReadFile(hFile, szBuffer, dwByteCount, &dwBytesRead, NULL); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Uable to read from \"%s\".\n", + szTextFile); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = SetEndOfFile(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Uable to set end of file.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + + // open and read the test file + pFile = fopen(szTextFile, "r"); + if (pFile == NULL) + { + Fail("SetEndOfFile: ERROR -> fopen was unable to open file \"%s\".\n", + szTextFile); + } + + // since we truncated the file at 10 characters, + // try reading 20 just to be safe + memset(szBuffer, 0, 100); + fgets(szBuffer, 20, pFile); + fclose(pFile); + if (strlen(szBuffer) != dwByteCount) + { + Fail("SetEndOfFile: ERROR -> file apparently not truncated at " + "correct position.\n"); + } + if (strncmp(szBuffer, szStringTest, dwByteCount) != 0) + { + Fail("SetEndOfFile: ERROR -> truncated file contents doesn't " + "compare with what should be there\n"); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.cpp new file mode 100644 index 0000000000000..3d30a6a39ac6b --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.cpp @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: SetEndOfFile.c (test 3) +** +** Purpose: Tests the PAL implementation of the SetEndOfFile function. +** This test will attempt to expand a file. Assumes successful +** SetFilePointer and GetFileSize tests. +** +** +**===================================================================*/ + +#include + + + + + +PALTEST(file_io_SetEndOfFile_test3_paltest_setendoffile_test3, "file_io/SetEndOfFile/test3/paltest_setendoffile_test3") +{ + HANDLE hFile = NULL; + DWORD dwByteCount = 0; + DWORD dwOffset = 25; + DWORD dwRc = 0; + BOOL bRc = FALSE; + + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + /* create a test file */ + hFile = CreateFile(szTextFile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n", + szTextFile); + } + + /* move the file pointer */ + /* assumes a successful SetFilePointer test */ + dwRc = SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN); + if (dwRc == INVALID_SET_FILE_POINTER) + { + Trace("SetEndOfFile: ERROR -> Call to SetFilePointer failed\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = SetEndOfFile(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Uable to set end of file.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + + /* call GetFileSize to verify pointer position */ + /* assumes a successful GetFileSize test */ + + dwByteCount = GetFileSize(hFile, NULL); + if (dwByteCount != dwOffset) + { + Trace("SetEndOfFile: ERROR -> file apparently not expanded to the" + " correct size.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n", + szTextFile); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.cpp new file mode 100644 index 0000000000000..f4da80135d243 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.cpp @@ -0,0 +1,137 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: setendoffile.c (test 4) +** +** Purpose: Tests the PAL implementation of the SetEndOfFile function. +** Verify that the file pointer is the same before +** and after a SetEndOfFile using SetFilePointer with +** FILE_BEGIN, FILE_CURRENT and FILE_END +** +** +**===================================================================*/ + +#include + + +#define szStringTest "The quick fox jumped over the lazy dog's back." +#define szTextFile "test.tmp" + +static void Cleanup(HANDLE hFile) +{ + if (!CloseHandle(hFile)) + { + Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\". ", + "GetLastError returned %u.\n", + szTextFile, + GetLastError()); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetEndOfFile: ERROR -> Unable to delete file \"%s\". ", + "GetLastError returned %u.\n", + szTextFile, + GetLastError()); + } +} + +static void DoTest(HANDLE hFile, DWORD dwOffset, DWORD dwMethod) +{ + DWORD dwFP1 = 0; + DWORD dwFP2 = 0; + DWORD dwError; + + /* set the pointer*/ + dwFP1 = SetFilePointer(hFile, dwOffset, NULL, dwMethod); + if ((dwFP1 == INVALID_SET_FILE_POINTER) && + ((dwError = GetLastError()) != ERROR_SUCCESS)) + { + Trace("SetEndOfFile: ERROR -> Unable to set the pointer to the " + "end of the file. GetLastError returned %u.\n", + dwError); + Cleanup(hFile); + Fail(""); + } + + /* set EOF */ + if (!SetEndOfFile(hFile)) + { + Trace("SetEndOfFile: ERROR -> Unable to set end of file. " + "GetLastError returned %u.\n", + GetLastError()); + Cleanup(hFile); + Fail(""); + } + + /* get current file pointer pointer */ + dwFP2 = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if ((dwFP1 == INVALID_SET_FILE_POINTER) && + ((dwError = GetLastError()) != ERROR_SUCCESS)) + { + Trace("SetEndOfFile: ERROR -> Unable to set the pointer to the " + "end of the file. GetLastError returned %u.\n", + dwError); + Cleanup(hFile); + Fail(""); + } + + /* are they the same? */ + if (dwFP1 != dwFP2) + { + Trace("SetEndOfFile: ERROR -> File pointer before (%u) the " + "SetEndOfFile call was different than after (%u).\n", + dwFP1, + dwFP2); + Cleanup(hFile); + Fail(""); + } +} + +PALTEST(file_io_SetEndOfFile_test4_paltest_setendoffile_test4, "file_io/SetEndOfFile/test4/paltest_setendoffile_test4") +{ + HANDLE hFile = NULL; + DWORD dwBytesWritten; + + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + /* create a test file */ + hFile = CreateFile(szTextFile, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\". " + "GetLastError returned %u.\n", + szTextFile, + GetLastError()); + } + + if (!WriteFile(hFile, szStringTest, strlen(szStringTest), &dwBytesWritten, NULL)) + { + Trace("SetEndOfFile: ERROR -> Unable to write to \"%s\". ", + "GetLastError returned %u.\n", + szTextFile, + GetLastError()); + Cleanup(hFile); + Fail(""); + } + + DoTest(hFile, -2, FILE_END); /* test the end */ + DoTest(hFile, -10, FILE_CURRENT); /* test the middle-ish */ + DoTest(hFile, 0, FILE_BEGIN); /* test the start */ + + Cleanup(hFile); + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.cpp new file mode 100644 index 0000000000000..8af9bccc7988b --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.cpp @@ -0,0 +1,182 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test5.c +** +** Purpose: Tests the PAL implementation of the SetEndOfFile function. +** Test attempts to read the number of characters up to +** the EOF pointer, which was specified. +** +** +**===================================================================*/ + +#include + +PALTEST(file_io_SetEndOfFile_test5_paltest_setendoffile_test5, "file_io/SetEndOfFile/test5/paltest_setendoffile_test5") +{ + HANDLE hFile = NULL; + DWORD dwBytesWritten; + DWORD retCode; + BOOL bRc = FALSE; + char szBuffer[256]; + DWORD dwBytesRead = 0; + char testFile[] = "testfile.tmp"; + char testString[] = "watch what happens"; + LONG shiftAmount = 10; + + /* Initialize the PAL. + */ + if (0 != PAL_Initialize(argc,argv)) + { + return FAIL; + } + + /* Initialize the buffer. + */ + memset(szBuffer, 0, 256); + + /* Create a file to test with. + */ + hFile = CreateFile(testFile, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_WRITE|FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + Fail("ERROR:%u: Unable to create file \"%s\".\n", + GetLastError(), + testFile); + } + + /* Write to the File handle. + */ + bRc = WriteFile(hFile, + testString, + strlen(testString), + &dwBytesWritten, + NULL); + + if (bRc == FALSE) + { + Trace("ERROR:%u: Unable to write to file handle " + "hFile=0x%lx\n", + GetLastError(), + hFile); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + /* Set the file pointer to shiftAmount bytes from the front of the file + */ + retCode = SetFilePointer(hFile, shiftAmount, NULL, FILE_BEGIN); + if(retCode == INVALID_SET_FILE_POINTER) + { + Trace("ERROR:%u: Unable to set the file pointer to %d\n", + GetLastError(), + shiftAmount); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + /* set the end of file pointer to 'shiftAmount' */ + bRc = SetEndOfFile(hFile); + if (bRc == FALSE) + { + Trace("ERROR:%u: Unable to set file pointer of file handle 0x%lx.\n", + GetLastError(), + hFile); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + /* Set the file pointer to 10 bytes from the front of the file + */ + retCode = SetFilePointer(hFile, (LONG)NULL, NULL, FILE_BEGIN); + if(retCode == INVALID_SET_FILE_POINTER) + { + Trace("ERROR:%u: Unable to set the file pointer to %d\n", + GetLastError(), + FILE_BEGIN); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + /* Attempt to read the entire string, 'testString' from a file + * that has it's end of pointer set at shiftAmount; + */ + bRc = ReadFile(hFile, + szBuffer, + strlen(testString), + &dwBytesRead, + NULL); + + if (bRc == FALSE) + { + Trace("ERROR:%u: Unable to read from file handle 0x%lx.\n", + GetLastError(), + hFile); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + /* Confirm the number of bytes read with that requested. + */ + if (dwBytesRead != shiftAmount) + { + Trace("ERROR: The number of bytes read \"%d\" is not equal to the " + "number that should have been written \"%d\".\n", + dwBytesRead, + shiftAmount); + if (!CloseHandle(hFile)) + { + Fail("ERROR:%u%: Unable to close handle 0x%lx.\n", + GetLastError(), + hFile); + } + Fail(""); + } + + bRc = CloseHandle(hFile); + if(!bRc) + { + Fail("ERROR:%u CloseHandle failed to close the handle\n", + GetLastError()); + } + + /* Terminate the PAL. + */ + PAL_Terminate(); + return PASS; +} + diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.cpp index cc2cc6dc82f6c..1167f229c4c68 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.cpp @@ -288,6 +288,48 @@ PALTEST(file_io_SetFilePointer_test2_paltest_setfilepointer_test2, "file_io/SetF PAL_TerminateEx(FAIL); return FAIL; } + else + { + /* verify */ + bRc = SetEndOfFile(hFile); + if (bRc != TRUE) + { + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + if (GetFileSize(hFile, NULL) != strlen(szText)+20) + { + Trace("SetFilePointer: ERROR -> Failed to move pointer past" + " EOF.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + } + + bRc = CloseHandle(hFile); if (bRc != TRUE) diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.cpp index 4695d7ecba86a..9294886be11da 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.cpp @@ -165,6 +165,32 @@ PALTEST(file_io_SetFilePointer_test4_paltest_setfilepointer_test4, "file_io/SetF PAL_TerminateEx(FAIL); return FAIL; } + else + { + /* verify results */ + bRc = SetEndOfFile(hFile); + if ((dwRc = GetFileSize(hFile, NULL)) != strlen(szText)+20) + { + Trace("SetFilePointer: ERROR -> Asked to move back 20 bytes past" + " theend of the file. GetFileSize returned %ld whereas it " + "should have been %d.\n", + dwRc, + strlen(szText)+20); + if (CloseHandle(hFile) != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + } + /* * move the pointer backwards to before the start of the file and verify diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.cpp index 71680a60e064e..d2f8911b4b586 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.cpp @@ -102,6 +102,59 @@ PALTEST(file_io_SetFilePointer_test5_paltest_setfilepointer_test5, "file_io/SetF PAL_TerminateEx(FAIL); return FAIL; } + else + { + /* verify */ + bRc = SetEndOfFile(hFile); + if (bRc != TRUE) + { + dwError = GetLastError(); + if (dwError == 112) + { + Trace("SetFilePointer: ERROR -> SetEndOfFile failed due to " + "lack of disk space\n"); + } + else + { + Trace("SetFilePointer: ERROR -> SetEndOfFile call failed with " + "error %ld\n", dwError); + } + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + + dwReturnedOffset = GetFileSize(hFile, &dwReturnedHighWord); + if ((dwOffset != dwReturnedOffset) || + (dwHighWord != dwReturnedHighWord)) + { + Trace("SetFilePointer: ERROR -> Failed to move pointer past" + " EOF.\n"); + bRc = CloseHandle(hFile); + if (bRc != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + } bRc = CloseHandle(hFile); if (bRc != TRUE) diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.cpp index f128133c4344d..69fe23373fdaf 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.cpp @@ -98,6 +98,46 @@ PALTEST(file_io_SetFilePointer_test6_paltest_setfilepointer_test6, "file_io/SetF PAL_TerminateEx(FAIL); return FAIL; } + else + { + /* verify results */ + if (SetEndOfFile(hFile) != TRUE) + { + Trace("SetFilePointer: ERROR -> Call to SetEndOfFile failed with " + "error code: %d\n", GetLastError()); + if (CloseHandle(hFile) != TRUE) + { + Trace("SetFilePointer: ERROR -> Unable to close file" + " \"%s\".\n", szTextFile); + } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + dwReturnedOffset = GetFileSize(hFile, (DWORD*)&dwReturnedHighOrder); + if ((dwReturnedOffset != dwOffset) || + (dwReturnedHighOrder != dwHighOrder)) + { + Trace("SetFilePointer: ERROR -> Asked to move far past the " + "current file pointer. " + "low order sent: %ld low order returned: %ld " + "high order sent: %ld high order returned: %ld", + dwOffset, dwReturnedOffset, + dwHighOrder, dwReturnedHighOrder); + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file" + " \"%s\".\n", szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; + } + } + /* * move the pointer backwards in the file and verify diff --git a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.cpp b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.cpp index 64796bc54fdbb..3230a215f73df 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.cpp @@ -101,39 +101,48 @@ PALTEST(file_io_SetFilePointer_test7_paltest_setfilepointer_test7, "file_io/SetF } else { - /* verify results */ - dwReturnedHighOrder = 0; - dwReturnedOffset = SetFilePointer(hFile, 0, &dwReturnedHighOrder, FILE_CURRENT); - if ((dwReturnedOffset != dwOffset) || (dwReturnedHighOrder != dwHighOrder)) + /* verify results */ + if (SetEndOfFile(hFile) != TRUE) + { + Trace("SetFilePointer: ERROR -> Call to SetEndOfFile failed with " + "error code: %d\n", + GetLastError()); + if (CloseHandle(hFile) != TRUE) { - Trace("SetFilePointer: ERROR -> Asked to move far past the " - "end of the file. low order sent: %ld low order returned: %ld " - "high order sent: %ld high order returned: %ld", - dwOffset, dwReturnedOffset, - dwHighOrder, dwReturnedHighOrder); - if (!DeleteFileA(szTextFile)) - { - Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n", - szTextFile); - } - PAL_TerminateEx(FAIL); - return FAIL; + Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n", + szTextFile); } + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n", + szTextFile); + } + PAL_TerminateEx(FAIL); + return FAIL; } - - DWORD bytesWritten = 0; - char ch = ' '; - if (!WriteFile(hFile, &ch, 1, &bytesWritten, NULL)) + dwReturnedOffset = GetFileSize(hFile, (DWORD*)&dwReturnedHighOrder); + if ((dwReturnedOffset != dwOffset) || (dwReturnedHighOrder != dwHighOrder)) { - Trace("WriteFile: ERROR\n"); + Trace("SetFilePointer: ERROR -> Asked to move far past the " + "end of the file. low order sent: %ld low order returned: %ld " + "high order sent: %ld high order returned: %ld", + dwOffset, dwReturnedOffset, + dwHighOrder, dwReturnedHighOrder); + if (!DeleteFileA(szTextFile)) + { + Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n", + szTextFile); + } PAL_TerminateEx(FAIL); return FAIL; + } } + /* * move the pointer backwards in the file and verify */ - dwOffset = -1; + dwOffset = 0; dwHighOrder = -1; dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_END); if (dwRc != 10) diff --git a/src/coreclr/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.cpp b/src/coreclr/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.cpp index f228f9c6a69dd..463e6744b443a 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.cpp @@ -28,7 +28,7 @@ BOOL writeTest_WriteFile_test2(DWORD dwByteCount, DWORD dwBytesWrittenResult, BO BOOL bRc = FALSE; /* create the test file */ - remove(szWritableFile); + DeleteFile(szWritableFile); hFile = CreateFile(szWritableFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); diff --git a/src/coreclr/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.cpp index 1b805708ee75c..fa624a352e7df 100644 --- a/src/coreclr/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.cpp @@ -312,13 +312,13 @@ PALTEST(file_io_errorpathnotfound_test1_paltest_errorpathnotfound_test1, "file_i } - if(!remove(sBadFileName)) + if(!DeleteFile(sBadFileName)) { - Trace("CreateFileA: Call to remove failed with ErrorCode " + Trace("CreateFileA: Call to DeleteFile failed with ErrorCode " - "[%u]\n", errno); + "[%u]\n", GetLastError()); } @@ -390,13 +390,13 @@ PALTEST(file_io_errorpathnotfound_test1_paltest_errorpathnotfound_test1, "file_i } - if(!remove(sBadFilePath)) + if(!DeleteFile(sBadFilePath)) { - Trace("CreateFileA: Call to remove Failed with ErrorCode " + Trace("CreateFileA: Call to DeleteFile Failed with ErrorCode " - "[%u]\n", errno); + "[%u]\n", GetLastError()); } diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp index 9790197dbdf3c..0c25bdbc46d9e 100644 --- a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp +++ b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp @@ -235,7 +235,7 @@ PALTEST(filemapping_memmgt_MapViewOfFile_test1_paltest_mapviewoffile_test1, "fil VirtualFree( buf, 0, MEM_RELEASE ); - remove(lpFilePath); + DeleteFile(lpFilePath); PAL_Terminate(); return PASS; diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.cpp index 0f42512a66f02..a2c221f159e15 100644 --- a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.cpp +++ b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.cpp @@ -80,8 +80,49 @@ PALTEST(filemapping_memmgt_MapViewOfFile_test5_paltest_mapviewoffile_test5, "fil Fail(""); } + /* Setup SECURITY_ATTRIBUTES structure for CreatePipe. + */ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /* Create a Pipe. + */ + bRetVal = CreatePipe(&hReadPipe, /* read handle*/ + &hWritePipe, /* write handle */ + &lpPipeAttributes,/* security attributes*/ + 0); /* pipe size*/ + if (bRetVal == FALSE) + { + Fail("ERROR: %ld :Unable to create pipe\n", + GetLastError()); + } + + /* Attempt creating a MapViewOfFile with a Pipe Handle. + */ + lpMapViewAddress = MapViewOfFile( + hReadPipe, + FILE_MAP_WRITE, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + MAPPINGSIZE); /* number of bytes for map */ + + if((NULL != lpMapViewAddress) && + (GetLastError() != ERROR_INVALID_HANDLE)) + { + Trace("ERROR:%u: Able to create a MapViewOfFile with " + "hFileMapping=0x%lx.\n", + GetLastError()); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + UnmapViewOfFile(lpMapViewAddress); + Fail(""); + } + /* Clean-up and Terminate the PAL. */ + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); PAL_Terminate(); return PASS; } diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.cpp new file mode 100644 index 0000000000000..a7ba76aa7b1c4 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.cpp @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================= +** +** Source: openfilemappingw.c (test 1) +** +** Purpose: Positive test the OpenFileMapping API. +** Call OpenFileMapping to open a named file-mapping +** object with FILE_MAP_ALL_ACCESS access +** +** +**============================================================*/ + +#define UNICODE +#include + +PALTEST(filemapping_memmgt_OpenFileMappingW_test1_paltest_openfilemappingw_test1, "filemapping_memmgt/OpenFileMappingW/test1/paltest_openfilemappingw_test1") +{ + + HANDLE lpMapViewAddress; + char buf[] = "this is a test"; + char ch[1024]; + + HANDLE FileMappingHandle; + HANDLE OpenFileMappingHandle; + const int LOWORDERSIZE = 1024; + int RetVal = PASS; + WCHAR wpMappingFileObject[] = {'m','y','O','b','j','e','c','t','\0'}; + + /* Initialize the PAL environment. + */ + if(0 != PAL_Initialize(argc, argv)) + { + return FAIL; + } + + /* Create a unnamed file-mapping object with file handle FileHandle. + */ + FileMappingHandle = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, /* Not inherited*/ + PAGE_READWRITE, /* Read and write*/ + 0, /* High-order size*/ + LOWORDERSIZE, /* Low-order size*/ + wpMappingFileObject);/* Named object*/ + + + if(NULL == FileMappingHandle) + { + Fail("\nFailed to call CreateFileMapping to create a " + "mapping object!\n"); + } + if(GetLastError() == ERROR_ALREADY_EXISTS) + { + Trace("\nFile mapping object already exists!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Open a named file-mapping object with FILE_MAP_ALL_ACCESS access. + */ + OpenFileMappingHandle = OpenFileMapping( + FILE_MAP_ALL_ACCESS, + FALSE, + wpMappingFileObject); + + if(NULL == OpenFileMappingHandle) + { + Trace("\nFailed to Call OpenFileMapping API!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Test the opened map view. + */ + lpMapViewAddress = MapViewOfFile( + OpenFileMappingHandle, + FILE_MAP_ALL_ACCESS, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + LOWORDERSIZE); /* number of bytes for map */ + + if(NULL == lpMapViewAddress) + { + Trace("ERROR:%u: Failed to call MapViewOfFile " + "API to map a view of file!\n", + GetLastError()); + RetVal = FAIL; + goto CleanUpTwo; + } + + /* Write to the Map View. + */ + memcpy(lpMapViewAddress, buf, strlen(buf)); + + /* Read from the Map View. + */ + memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE); + + /* Compare what was written to the Map View, + * to what was read. + */ + if (memcmp(ch, buf, strlen(buf))!= 0) + { + Trace("ERROR: MapViewOfFile not equal to file contents " + "retrieved \"%s\", expected \"%s\".\n", + ch, buf); + RetVal = FAIL; + goto CleanUpThree; + } + +CleanUpThree: + + /* Unmap the view of file. + */ + if ( UnmapViewOfFile(lpMapViewAddress) == FALSE ) + { + Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n", + GetLastError(), + lpMapViewAddress); + RetVal = FAIL; + } + +CleanUpTwo: + + /* Close Handle to opend file mapping. + */ + if ( CloseHandle(OpenFileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + OpenFileMappingHandle); + RetVal = FAIL; + } + +CleanUpOne: + + /* Close Handle to create file mapping. + */ + if ( CloseHandle(FileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + FileMappingHandle); + RetVal = FAIL; + } + + /* Terminate the PAL. + */ + PAL_TerminateEx(RetVal); + return RetVal; +} + diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.cpp new file mode 100644 index 0000000000000..c1d43ab16f99f --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.cpp @@ -0,0 +1,216 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================= +** +** Source: openfilemappingw.c (test 2) +** +** Purpose: Positive test the OpenFileMapping API. +** Call OpenFileMapping to open a named file-mapping +** object with FILE_MAP_WRITE access +** +** +**============================================================*/ +#define UNICODE +#include + +PALTEST(filemapping_memmgt_OpenFileMappingW_test2_paltest_openfilemappingw_test2, "filemapping_memmgt/OpenFileMappingW/test2/paltest_openfilemappingw_test2") +{ + HANDLE FileMappingHandle; + HANDLE OpenFileMappingHandle; + HANDLE lpMapViewAddress; + HANDLE OpenFileMappingHandle2; + HANDLE lpMapViewAddress2; + const int LOWORDERSIZE = 1024; + WCHAR MapObject[] = {'m','y','O','b','j','e','c','t','\0'}; + char buf[] = "this is a test"; + char ch[1024]; + int RetVal = PASS; + + + /* Initialize the PAL environment. + */ + if(0 != PAL_Initialize(argc, argv)) + { + return FAIL; + } + + /* Create a named file-mapping object with file handle FileHandle. + */ + FileMappingHandle = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, /* not inherited */ + PAGE_READWRITE, /* read and wite */ + 0, /* high-order size */ + LOWORDERSIZE, /* low-order size */ + MapObject); /* named object */ + + if(NULL == FileMappingHandle) + { + Fail("\nFailed to call CreateFileMapping to " + "create a mapping object!\n"); + } + if(GetLastError() == ERROR_ALREADY_EXISTS) + { + Trace("\nFile mapping object already exists!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Open a named file-mapping object with FILE_MAP_WRITE access. + */ + OpenFileMappingHandle = OpenFileMapping( + FILE_MAP_WRITE, + FALSE, + MapObject); + + if(NULL == OpenFileMappingHandle) + { + Trace("\nFailed to Call OpenFileMappingW API!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Open a named file-mapping object with + * FILE_MAP_ALL_ACCESS access, to verify + * the FILE_MAP_WRITE access map. + */ + OpenFileMappingHandle2 = OpenFileMapping( + FILE_MAP_ALL_ACCESS, + FALSE, + MapObject); + + if(NULL == OpenFileMappingHandle2) + { + Trace("\nFailed to Call OpenFileMappingW API!\n"); + RetVal = FAIL; + goto CleanUpTwo; + } + + /* Create map view of the open mapping that has + * FILE_MAP_WRITE access. + */ + lpMapViewAddress = MapViewOfFile( + OpenFileMappingHandle, + FILE_MAP_WRITE, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + LOWORDERSIZE); /* number of bytes for map */ + + if(NULL == lpMapViewAddress) + { + Trace("ERROR:%u: Failed to call MapViewOfFile " + "API to map a view of file!\n", + GetLastError()); + RetVal = FAIL; + goto CleanUpThree; + } + + /* Create map view of the open mapping that has + * FILE_MAP_ALL_ACCESS access. + */ + + lpMapViewAddress2 = MapViewOfFile( + OpenFileMappingHandle2, + FILE_MAP_ALL_ACCESS, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + LOWORDERSIZE); /* number of bytes for map */ + + if(NULL == lpMapViewAddress2) + { + Trace("ERROR:%u: Failed to call MapViewOfFile " + "API to map a view of file!\n", + GetLastError()); + RetVal = FAIL; + goto CleanUpFour; + } + + /* Write to the Map View. + */ + memcpy(lpMapViewAddress, buf, strlen(buf)); + + /* Read from the Map View. + */ + memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE); + + /* Compare what was written to the Map View, + * to what was read. + */ + if (memcmp(ch, buf, strlen(buf))!= 0) + { + + Trace("ERROR: MapViewOfFile not equal to file contents " + "retrieved \"%s\", expected \"%s\".\n", + ch, buf); + RetVal = FAIL; + goto CleanUpFive; + } + + +CleanUpFive: + + /* Unmap the view of file. + */ + if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE ) + { + Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n", + GetLastError(), + lpMapViewAddress2); + RetVal = FAIL; + } + +CleanUpFour: + + /* Unmap the view of file. + */ + if ( UnmapViewOfFile(lpMapViewAddress) == FALSE ) + { + Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n", + GetLastError(), + lpMapViewAddress); + RetVal = FAIL; + } + +CleanUpThree: + + /* Close Handle to opened file mapping. + */ + if ( CloseHandle(OpenFileMappingHandle2) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + OpenFileMappingHandle2); + RetVal = FAIL; + } + +CleanUpTwo: + + /* Close Handle to opened file mapping. + */ + if ( CloseHandle(OpenFileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + OpenFileMappingHandle); + RetVal = FAIL; + } + +CleanUpOne: + + /* Close Handle to create file mapping. + */ + if ( CloseHandle(FileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + FileMappingHandle); + RetVal = FAIL; + } + + /* Terminate the PAL. + */ + PAL_TerminateEx(RetVal); + return RetVal; +} + diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.cpp new file mode 100644 index 0000000000000..ebffd6f2baf34 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.cpp @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================= +** +** Source: openfilemappingw.c (test 3) +** +** Purpose: Positive test the OpenFileMappingW API. +** Call OpenFileMappingW to open a named file-mapping +** object with FILE_MAP_READ access +** +** +**============================================================*/ +#define UNICODE +#include + +PALTEST(filemapping_memmgt_OpenFileMappingW_test3_paltest_openfilemappingw_test3, "filemapping_memmgt/OpenFileMappingW/test3/paltest_openfilemappingw_test3") +{ + char buf[] = "this is a test"; + char ch[1024]; + HANDLE FileMappingHandle; + HANDLE OpenFileMappingHandle; + HANDLE OpenFileMappingHandle2; + HANDLE lpMapViewAddress; + HANDLE lpMapViewAddress2; + const int LOWORDERSIZE = 1024; + int RetVal = PASS; + WCHAR wpMappingFileObject[] = {'m','y','O','b','j','e','c','t','\0'}; + + + /* Initialize the PAL environment. + */ + if(0 != PAL_Initialize(argc, argv)) + { + return FAIL; + } + + /* Create a unnamed file-mapping object with file handle FileHandle. + */ + FileMappingHandle = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, /* not inherited */ + PAGE_READWRITE, /* read and wite */ + 0, /* high-order size */ + LOWORDERSIZE, /* must be non-zero */ + wpMappingFileObject);/* named object */ + + if(NULL == FileMappingHandle) + { + Fail("\nFailed to call CreateFileMapping to create mapping object!\n"); + } + if(GetLastError() == ERROR_ALREADY_EXISTS) + { + Trace("\nFile mapping object already exists!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Open a named file-mapping object with FILE_MAP_ALL_ACCESS access. + */ + OpenFileMappingHandle = OpenFileMapping( + FILE_MAP_READ, + FALSE, + wpMappingFileObject); + + if(NULL == OpenFileMappingHandle) + { + Trace("\nFailed to Call OpenFileMapping API!\n"); + RetVal = FAIL; + goto CleanUpOne; + } + + /* Open a file mapping with FILE_MAP_ALL_ACCESS access, + * to verify the FILE_MAP_READ. + */ + OpenFileMappingHandle2 = OpenFileMapping( + FILE_MAP_ALL_ACCESS, + FALSE, + wpMappingFileObject); + + if(NULL == OpenFileMappingHandle2) + { + Trace("\nFailed to Call OpenFileMapping API!\n"); + RetVal = FAIL; + goto CleanUpTwo; + } + + /* Test the opened map view. + */ + lpMapViewAddress = MapViewOfFile( + OpenFileMappingHandle, + FILE_MAP_READ, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + LOWORDERSIZE); /* number of bytes for map */ + + if(NULL == lpMapViewAddress) + { + Trace("ERROR:%u: Failed to call MapViewOfFile " + "API to map a view of file!\n", + GetLastError()); + RetVal = FAIL; + goto CleanUpThree; + } + + /* Open a map view with FILE_MAP_ALL_ACCESS to verify, + * the FILE_MAP_READ view. + */ + lpMapViewAddress2 = MapViewOfFile( + OpenFileMappingHandle2, + FILE_MAP_ALL_ACCESS, /* access code */ + 0, /* high order offset */ + 0, /* low order offset */ + LOWORDERSIZE); /* number of bytes for map */ + + if(NULL == lpMapViewAddress2) + { + Trace("2ERROR:%u: Failed to call MapViewOfFile " + "API to map a view of file!\n", + GetLastError()); + RetVal = FAIL; + goto CleanUpFour; + } + + /* Write to the Map View. + */ + memcpy(lpMapViewAddress2, buf, strlen(buf)); + /* Read from the Map View. + */ + memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE); + + /* Compare what was written to the Map View, + * to what was read. + */ + if (memcmp(ch, buf, strlen(buf))!= 0) + { + Trace("ERROR: MapViewOfFile not equal to file contents " + "retrieved \"%s\", expected \"%s\".\n", + ch, + buf); + RetVal = FAIL; + goto CleanUpFive; + } + +CleanUpFive: + + /* Unmap the view of file. + */ + if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE ) + { + Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n", + GetLastError(), + lpMapViewAddress2); + RetVal = FAIL; + } + +CleanUpFour: + + /* Unmap the view of file. + */ + if ( UnmapViewOfFile(lpMapViewAddress) == FALSE ) + { + Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n", + GetLastError(), + lpMapViewAddress); + RetVal = FAIL; + } + +CleanUpThree: + + /* Close Handle to opened file mapping. + */ + if ( CloseHandle(OpenFileMappingHandle2) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + OpenFileMappingHandle2); + RetVal = FAIL; + } + +CleanUpTwo: + + /* Close Handle to opened file mapping. + */ + if ( CloseHandle(OpenFileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + OpenFileMappingHandle); + RetVal = FAIL; + } + +CleanUpOne: + + /* Close Handle to create file mapping. + */ + if ( CloseHandle(FileMappingHandle) == 0 ) + { + Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n", + GetLastError(), + FileMappingHandle); + RetVal = FAIL; + } + + /* Terminate the PAL. + */ + PAL_TerminateEx(RetVal); + return RetVal; +} diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.cpp new file mode 100644 index 0000000000000..2aa0d42d69fba --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.cpp @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test1.c (CreatePipe) +** +** Purpose: Tests the PAL implementation of the CreatePipe function. +** This test will create two pipes, a read and a write. Once +** the pipes have been created, they will be tested by writing +** and then reading, then comparing the results. +** +** Depends: WriteFile +** ReadFile +** memcmp +** CloseHandle +** +** +**===================================================================*/ + +#include + +#define cTestString "one fish, two fish, read fish, blue fish." + +PALTEST(miscellaneous_CreatePipe_test1_paltest_createpipe_test1, "miscellaneous/CreatePipe/test1/paltest_createpipe_test1") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + BOOL bRetVal = FALSE; + DWORD dwBytesWritten; + DWORD dwBytesRead; + char buffer[256]; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, /* read handle*/ + &hWritePipe, /* write handle */ + &lpPipeAttributes, /* security attributes*/ + 0); /* pipe size*/ + if (bRetVal == FALSE) + { + Fail("ERROR: %ld :Unable to create pipe\n", GetLastError()); + } + + /*Write to the write pipe handle*/ + bRetVal = WriteFile(hWritePipe, /* handle to write pipe*/ + cTestString, /* buffer to write*/ + strlen(cTestString),/* number of bytes to write*/ + &dwBytesWritten, /* number of bytes written*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Fail("ERROR: %ld :unable to write to write pipe handle " + "hWritePipe=0x%lx\n", GetLastError(), hWritePipe); + } + + /*Read, 256 bytes, more bytes then actually written. + This will give allow us to use the value that ReadFile + returns for comparison.*/ + bRetVal = ReadFile(hReadPipe, /* handle to read pipe*/ + buffer, /* buffer to write to*/ + 256, /* number of bytes to read*/ + &dwBytesRead, /* number of bytes read*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Fail("ERROR: %ld : unable read hWritePipe=0x%lx\n", + GetLastError(), hWritePipe); + } + + /*Compare what was read with what was written.*/ + if ((memcmp(cTestString, buffer, dwBytesRead)) != 0) + { + Fail("ERROR: read \"%s\" expected \"%s\" \n", buffer, cTestString); + } + + /*Compare values returned from WriteFile and ReadFile.*/ + if (dwBytesWritten != dwBytesRead) + { + Fail("ERROR: WriteFile wrote \"%d\", but ReadFile read \"%d\"," + " these should be the same\n", buffer, cTestString); + } + + /*Close write pipe handle*/ + if (CloseHandle(hWritePipe) == 0) + { + Fail("ERROR: %ld : Unable to close write pipe handle " + "hWritePipe=0x%lx\n",GetLastError(), hWritePipe); + } + + /*Close Read pipe handle*/ + if (CloseHandle(hReadPipe) == 0) + { + Fail("ERROR: %ld : Unable to close read pipe handle " + "hReadPipe=0x%lx\n", GetLastError(), hReadPipe); + } + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/paltestlist.txt b/src/coreclr/pal/tests/palsuite/paltestlist.txt index a88cb7ae43561..3a653a8c129b9 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist.txt @@ -32,6 +32,8 @@ c_runtime/exp/test1/paltest_exp_test1 c_runtime/expf/test1/paltest_expf_test1 c_runtime/fabs/test1/paltest_fabs_test1 c_runtime/fabsf/test1/paltest_fabsf_test1 +c_runtime/fclose/test1/paltest_fclose_test1 +c_runtime/fclose/test2/paltest_fclose_test2 c_runtime/fflush/test1/paltest_fflush_test1 c_runtime/fgets/test1/paltest_fgets_test1 c_runtime/fgets/test2/paltest_fgets_test2 @@ -72,6 +74,9 @@ c_runtime/fputs/test1/paltest_fputs_test1 c_runtime/free/test1/paltest_free_test1 c_runtime/fseek/test1/paltest_fseek_test1 c_runtime/fwrite/test1/paltest_fwrite_test1 +c_runtime/getenv/test1/paltest_getenv_test1 +c_runtime/getenv/test2/paltest_getenv_test2 +c_runtime/getenv/test3/paltest_getenv_test3 c_runtime/ilogb/test1/paltest_ilogb_test1 c_runtime/ilogbf/test1/paltest_ilogbf_test1 c_runtime/isalnum/test1/paltest_isalnum_test1 @@ -298,11 +303,16 @@ c_runtime/wcstoul/test4/paltest_wcstoul_test4 c_runtime/wcstoul/test5/paltest_wcstoul_test5 c_runtime/wcstoul/test6/paltest_wcstoul_test6 c_runtime/_alloca/test1/paltest_alloca_test1 +c_runtime/_fdopen/test1/paltest_fdopen_test1 c_runtime/_finite/test1/paltest_finite_test1 c_runtime/_finitef/test1/paltest_finitef_test1 c_runtime/_isnan/test1/paltest_isnan_test1 c_runtime/_isnanf/test1/paltest_isnanf_test1 c_runtime/_itow/test1/paltest_itow_test1 +c_runtime/_putenv/test1/paltest_putenv_test1 +c_runtime/_putenv/test2/paltest_putenv_test2 +c_runtime/_putenv/test3/paltest_putenv_test3 +c_runtime/_putenv/test4/paltest_putenv_test4 c_runtime/_rotl/test1/paltest_rotl_test1 c_runtime/_rotr/test1/paltest_rotr_test1 c_runtime/_snprintf_s/test1/paltest_snprintf_test1 @@ -447,6 +457,8 @@ file_io/CopyFileA/test3/paltest_copyfilea_test3 file_io/CopyFileA/test4/paltest_copyfilea_test4 file_io/CopyFileW/test2/paltest_copyfilew_test2 file_io/CopyFileW/test3/paltest_copyfilew_test3 +file_io/DeleteFileA/test1/paltest_deletefilea_test1 +file_io/DeleteFileW/test1/paltest_deletefilew_test1 file_io/errorpathnotfound/test2/paltest_errorpathnotfound_test2 file_io/FILECanonicalizePath/paltest_filecanonicalizepath_test1 file_io/FindClose/test1/paltest_findclose_test1 @@ -458,6 +470,8 @@ file_io/FindNextFileW/test1/paltest_findnextfilew_test1 file_io/FindNextFileW/test2/paltest_findnextfilew_test2 file_io/FlushFileBuffers/test1/paltest_flushfilebuffers_test1 file_io/GetConsoleOutputCP/test1/paltest_getconsoleoutputcp_test1 +file_io/GetCurrentDirectoryA/test1/paltest_getcurrentdirectorya_test1 +file_io/GetCurrentDirectoryW/test1/paltest_getcurrentdirectoryw_test1 file_io/GetFileAttributesA/test1/paltest_getfileattributesa_test1 file_io/GetFileAttributesExW/test2/paltest_getfileattributesexw_test2 file_io/GetFileAttributesW/test1/paltest_getfileattributesw_test1 @@ -482,6 +496,11 @@ file_io/ReadFile/test2/paltest_readfile_test2 file_io/ReadFile/test3/paltest_readfile_test3 file_io/ReadFile/test4/paltest_readfile_test4 file_io/SearchPathW/test1/paltest_searchpathw_test1 +file_io/SetEndOfFile/test1/paltest_setendoffile_test1 +file_io/SetEndOfFile/test2/paltest_setendoffile_test2 +file_io/SetEndOfFile/test3/paltest_setendoffile_test3 +file_io/SetEndOfFile/test4/paltest_setendoffile_test4 +file_io/SetEndOfFile/test5/paltest_setendoffile_test5 file_io/SetFilePointer/test1/paltest_setfilepointer_test1 file_io/SetFilePointer/test2/paltest_setfilepointer_test2 file_io/SetFilePointer/test3/paltest_setfilepointer_test3 @@ -510,6 +529,7 @@ locale_info/WideCharToMultiByte/test3/paltest_widechartomultibyte_test3 locale_info/WideCharToMultiByte/test5/paltest_widechartomultibyte_test5 miscellaneous/CloseHandle/test1/paltest_closehandle_test1 miscellaneous/CloseHandle/test2/paltest_closehandle_test2 +miscellaneous/CreatePipe/test1/paltest_createpipe_test1 miscellaneous/FlushInstructionCache/test1/paltest_flushinstructioncache_test1 miscellaneous/FormatMessageW/test1/paltest_formatmessagew_test1 miscellaneous/FormatMessageW/test2/paltest_formatmessagew_test2 @@ -577,12 +597,15 @@ threading/CreateThread/test1/paltest_createthread_test1 threading/CreateThread/test3/paltest_createthread_test3 threading/CriticalSectionFunctions/test1/paltest_criticalsectionfunctions_test1 threading/CriticalSectionFunctions/test2/paltest_criticalsectionfunctions_test2 +threading/CriticalSectionFunctions/test3/paltest_criticalsectionfunctions_test3 threading/CriticalSectionFunctions/test4/paltest_criticalsectionfunctions_test4 threading/CriticalSectionFunctions/test7/paltest_criticalsectionfunctions_test7 threading/CriticalSectionFunctions/test8/paltest_criticalsectionfunctions_test8 threading/DuplicateHandle/test10/paltest_duplicatehandle_test10 threading/DuplicateHandle/test2/paltest_duplicatehandle_test2 threading/DuplicateHandle/test4/paltest_duplicatehandle_test4 +threading/DuplicateHandle/test5/paltest_duplicatehandle_test5 +threading/DuplicateHandle/test6/paltest_duplicatehandle_test6 threading/DuplicateHandle/test7/paltest_duplicatehandle_test7 threading/DuplicateHandle/test8/paltest_duplicatehandle_test8 threading/ExitProcess/test1/paltest_exitprocess_test1 @@ -592,6 +615,7 @@ threading/ExitThread/test1/paltest_exitthread_test1 threading/GetCurrentProcessId/test1/paltest_getcurrentprocessid_test1 threading/GetCurrentThread/test1/paltest_getcurrentthread_test1 threading/GetCurrentThread/test2/paltest_getcurrentthread_test2 +threading/GetThreadTimes/test1/paltest_getthreadtimes_test1 threading/NamedMutex/test1/paltest_namedmutex_test1 threading/QueryThreadCycleTime/test1/paltest_querythreadcycletime_test1 threading/QueueUserAPC/test2/paltest_queueuserapc_test2 diff --git a/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt b/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt index 490f9fb4ad9e8..b488ac96134f9 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt @@ -60,6 +60,9 @@ filemapping_memmgt/GetModuleFileNameA/test1/paltest_getmodulefilenamea_test1 filemapping_memmgt/GetModuleFileNameW/test1/paltest_getmodulefilenamew_test1 filemapping_memmgt/GetProcAddress/test1/paltest_getprocaddress_test1 filemapping_memmgt/GetProcAddress/test2/paltest_getprocaddress_test2 +filemapping_memmgt/OpenFileMappingW/test1/paltest_openfilemappingw_test1 +filemapping_memmgt/OpenFileMappingW/test2/paltest_openfilemappingw_test2 +filemapping_memmgt/OpenFileMappingW/test3/paltest_openfilemappingw_test3 filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/paltest_readprocessmemory_readprocessmemory_neg1 filemapping_memmgt/ReadProcessMemory/test1/paltest_readprocessmemory_test1 filemapping_memmgt/ReadProcessMemory/test2/paltest_readprocessmemory_test2 @@ -75,6 +78,8 @@ file_io/GetTempFileNameW/test1/paltest_gettempfilenamew_test1 file_io/GetTempFileNameW/test2/paltest_gettempfilenamew_test2 file_io/gettemppatha/test1/paltest_gettemppatha_test1 file_io/GetTempPathW/test1/paltest_gettemppathw_test1 +file_io/MoveFileExA/test1/paltest_movefileexa_test1 +file_io/MoveFileExW/test1/paltest_movefileexw_test1 file_io/ReadFile/test1/paltest_readfile_test1 file_io/WriteFile/test2/paltest_writefile_test2 loader/LoadLibraryA/test1/paltest_loadlibrarya_test1 diff --git a/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.cpp b/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.cpp index dc059cf7e69f0..a10dd00799225 100644 --- a/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.cpp @@ -9,7 +9,7 @@ ** launches a child process, and examines a file written by the child. ** This code is the child code. ** -** Dependencies: GetTempPath +** Dependencies: GetCurrentDirectory ** MultiByteToWideChar ** wcslen ** strlen @@ -49,12 +49,12 @@ PALTEST(threading_CreateProcessW_test1_paltest_createprocessw_test1_child, "thre return ( FAIL ); } - dwDirLength = GetTempPath(_MAX_PATH, szDirNameW); + dwDirLength = GetCurrentDirectory( _MAX_PATH, szDirNameW ); if (0 == dwDirLength) { - Fail ("GetTempPath call failed. Could not get " - "temp directory\n. Exiting.\n"); + Fail ("GetCurrentDirectory call failed. Could not get " + "current working directory\n. Exiting.\n"); } dwFileLength = wcslen( szCommonFileW ); diff --git a/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.cpp b/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.cpp index 293b2c167356e..88482f394491c 100644 --- a/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.cpp @@ -10,7 +10,7 @@ ** This process (the parent process) reads the file created by the child and ** compares the value the child wrote to the file. (a const char *) ** -** Dependencies: GetTempPath +** Dependencies: GetCurrentDirectory ** MultiByteToWideChar ** wcslen ** strlen @@ -68,12 +68,12 @@ PALTEST(threading_CreateProcessW_test1_paltest_createprocessw_test1, "threading/ szAbsPathNameW=&absPathBuf[0]; - dwDirLength = GetTempPath(_MAX_PATH, szDirNameW); + dwDirLength = GetCurrentDirectory(_MAX_PATH, szDirNameW); if (0 == dwDirLength) { - Fail ("GetTempPath call failed. Could not get " - "temp directory\n. Exiting.\n"); + Fail ("GetCurrentDirectory call failed. Could not get " + "current working directory\n. Exiting.\n"); } int mbwcResult = MultiByteToWideChar(CP_ACP, 0, argv[0], -1, szAbsPathNameW, sizeof(absPathBuf)); diff --git a/src/coreclr/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.cpp new file mode 100644 index 0000000000000..7e559ac4cbf51 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.cpp @@ -0,0 +1,374 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: CriticalSectionFunctions/test3/test3.c +** +** Purpose: Create two threads to exercise TryEnterCriticalSection +** and EnterCriticalSection. TryEnterCriticalSection acquires +** and holds a CRITICAL_SECTION object. Another call to +** TryEnterCriticalSection is made from a different thread, at +** this time, to establish a call to TryEnterCriticalSection +** will return immediately and to establish +** TryEnterCriticalSection returns the proper value when it +** attempts to lock a CRITICAL_SECTION that is already owned +** by another thread. The CRITICAL_SECTION object is then +** released and held by a call to EnterCriticalSection. A new +** thread is invoked and attempts to acquire the held +** CRITICAL_SECTION with a call to TryEnterCriticalSection. +** TryEnterCriticalSection returns immediately and returns +** with the value that states the CRITICAL_SECTION object is +** held by another thread. This establishes +** TryEnterCriticalSection behaves the same way with +** CriticalSections locked by TryEnterCriticalSection and +** EnterCriticalSection. +** +** +**===================================================================*/ +#include + +#define NUM_THREADS 2 + +HANDLE hThread_CriticalSectionFunctions_test3[NUM_THREADS]; +HANDLE hEvent_CriticalSectionFunctions_test3[NUM_THREADS]; +BOOL bRet_CriticalSectionFunctions_test3 = FAIL; + +DWORD PALAPI Thread_CriticalSectionFunctions_test3(LPVOID lpParam) +{ + DWORD dwRet; + + if (0 == TryEnterCriticalSection(&CriticalSection)) + { + dwRet = WaitForMultipleObjects(NUM_THREADS, hEvent_CriticalSectionFunctions_test3, TRUE, 10000); + if ((WAIT_OBJECT_0 > dwRet) || + ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet)) + { +#if 0 + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up.\nGetLastError returned '%d'.\n", + hThread_CriticalSectionFunctions_test3[1], GetLastError()); + } +#endif + Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call" + "returned an unexpected value, '%d'.\nGetLastError returned " + "%d.\n", NUM_THREADS, hEvent_CriticalSectionFunctions_test3, TRUE, 10000, dwRet, + GetLastError()); + } + else + { + bRet_CriticalSectionFunctions_test3 = PASS; + } + } + else + { + /* signal thread 0 */ + if (0 == SetEvent(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + LeaveCriticalSection(&CriticalSection); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up\nGetLastError returned '%d'.\n", + hThread_CriticalSectionFunctions_test3[0], GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up\nGetLastError returned '%d'.\n", + hEvent_CriticalSectionFunctions_test3[0], GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up\nGetLastError returned '%d'.\n", + hEvent_CriticalSectionFunctions_test3[1], GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + + /* wait to be signaled */ + dwRet = WaitForSingleObject(hEvent_CriticalSectionFunctions_test3[1], 10000); + if (WAIT_OBJECT_0 != dwRet) + { + Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have " + "returned\nWAIT_OBJECT_0 ('%d'), instead it returned " + "('%d').\nGetLastError returned '%d'.\n", + hEvent_CriticalSectionFunctions_test3[0], 10000, WAIT_OBJECT_0, dwRet, GetLastError()); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up.\nGetLastError returned '%d'.\n", + hThread_CriticalSectionFunctions_test3[0], GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up.\nGetLastError returned '%d'.\n", + hEvent_CriticalSectionFunctions_test3[0], GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " + "during clean up.\nGetLastError returned '%d.'\n", + hEvent_CriticalSectionFunctions_test3[1], GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + LeaveCriticalSection(&CriticalSection); + } + return FAIL; +} + +PALTEST(threading_CriticalSectionFunctions_test3_paltest_criticalsectionfunctions_test3, "threading/CriticalSectionFunctions/test3/paltest_criticalsectionfunctions_test3") +{ + HANDLE hThread_CriticalSectionFunctions_test3[NUM_THREADS]; + DWORD dwThreadId[NUM_THREADS]; + DWORD dwRet; + + if ((PAL_Initialize(argc,argv)) != 0) + { + return(bRet_CriticalSectionFunctions_test3); + } + + /* thread 0 event */ + hEvent_CriticalSectionFunctions_test3[0] = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (hEvent_CriticalSectionFunctions_test3[0] == NULL) + { + Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError " + "returned %d.\n", GetLastError()); + } + + /* thread 1 event */ + hEvent_CriticalSectionFunctions_test3[1] = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (hEvent_CriticalSectionFunctions_test3[1] == NULL) + { + Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError " + "returned %d.\n", GetLastError()); + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0]); + } + Fail(""); + } + + InitializeCriticalSection ( &CriticalSection ); + + hThread_CriticalSectionFunctions_test3[0] = CreateThread(NULL, + 0, + &Thread_CriticalSectionFunctions_test3, + (LPVOID) NULL, + 0, + &dwThreadId[0]); + + if (hThread_CriticalSectionFunctions_test3[0] == NULL) + { + Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError " + "returned %d.\n", GetLastError()); + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + + + /* wait for thread 0 to be signaled */ + dwRet = WaitForSingleObject(hEvent_CriticalSectionFunctions_test3[0], 10000); + if (WAIT_OBJECT_0 != dwRet) + { + Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have " + "returned\nWAIT_OBJECT_0 ('%d'), instead it returned " + "('%d').\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], 10000, + WAIT_OBJECT_0, dwRet, GetLastError()); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + Fail(""); + } + + /* + * Attempting to enter CRITICAL_SECTION object owned by the + * created thread and locked with TryEnterCriticalSection + */ + if (0 == TryEnterCriticalSection(&CriticalSection)) + { + /* signal thread 1 */ + if (0 == SetEvent(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n" + "GetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + goto done; + } + } + else + { + Trace("PALSUITE_ERROR: TryEnterCriticalSection was able to grab a" + " CRITICAL_SECTION object\nwhich was already owned.\n"); + LeaveCriticalSection(&CriticalSection); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + /* + * Enter the CRITICAL_SECTION and launch another thread to attempt + * to access the CRITICAL_SECTION with a call to TryEnterCriticalSection. + */ + EnterCriticalSection(&CriticalSection); + + hThread_CriticalSectionFunctions_test3[1] = CreateThread(NULL, + 0, + &Thread_CriticalSectionFunctions_test3, + (LPVOID) NULL, + 0, + &dwThreadId[1]); + + if (hThread_CriticalSectionFunctions_test3[1] == NULL) + { + Trace("PALSUITE ERROR: CreateThread call #1 failed. GetLastError " + "returned %d.\n", GetLastError()); + LeaveCriticalSection(&CriticalSection); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + + dwRet = WaitForMultipleObjects(NUM_THREADS, hThread_CriticalSectionFunctions_test3, TRUE, 10000); + if ((WAIT_OBJECT_0 > dwRet) || + ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet)) + { + Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call " + "returned an unexpected value, '%d'.\nGetLastError returned " + "%d.\n", NUM_THREADS, hThread_CriticalSectionFunctions_test3, TRUE, 10000, dwRet, + GetLastError()); + LeaveCriticalSection(&CriticalSection); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[1], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + Fail(""); + } + + LeaveCriticalSection(&CriticalSection); + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[1], + GetLastError()); + } +done: + if (0 == CloseHandle(hThread_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hThread_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[0])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[0], + GetLastError()); + } + if (0 == CloseHandle(hEvent_CriticalSectionFunctions_test3[1])) + { + Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " + "clean up.\nGetLastError returned '%d'.\n", hEvent_CriticalSectionFunctions_test3[1], + GetLastError()); + } + DeleteCriticalSection(&CriticalSection); + + PAL_TerminateEx(bRet_CriticalSectionFunctions_test3); + + return (bRet_CriticalSectionFunctions_test3); +} + diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.cpp index b6bb5c1c68197..2efe1c66fb57a 100644 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.cpp @@ -83,8 +83,21 @@ PALTEST(threading_DuplicateHandle_test11_paltest_duplicatehandle_test11, "thread rgchAbsPathName = &absPathBuf[0]; dwFileLength = strlen( rgchChildFile ); - strcpy(rgchDirName, ".\\"); - dwDirLength = strlen(rgchDirName); + dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName ); + if( dwDirLength == 0 ) + { + dwError = GetLastError(); + if( ReleaseMutex( hMutex ) == 0 ) + { + Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() ); + } + if( CloseHandle( hMutex ) == 0 ) + { + Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); + } + Fail( "GetCurrentDirectory call failed with error code %d\n", + dwError ); + } dwSize = mkAbsoluteFilename( rgchDirName, dwDirLength, diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.cpp new file mode 100644 index 0000000000000..2033c2aa9be55 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.cpp @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test5.c (DuplicateHandle) +** +** Purpose: Tests the PAL implementation of the DuplicateHandle function, +** with CreatePipe. This test will create a pipe and write to it, +** the duplicate the read handle and read what was written. +** +** Depends: WriteFile +** ReadFile +** memcmp +** CloseHandle +** +** +**===================================================================*/ + +#include + +#define cTestString "one fish, two fish, read fish, blue fish." + +PALTEST(threading_DuplicateHandle_test5_paltest_duplicatehandle_test5, "threading/DuplicateHandle/test5/paltest_duplicatehandle_test5") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + HANDLE hDupPipe = NULL; + BOOL bRetVal = FALSE; + DWORD dwBytesWritten; + DWORD dwBytesRead; + char buffer[256]; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, /* read handle*/ + &hWritePipe, /* write handle */ + &lpPipeAttributes,/* security attributes*/ + 0); /* pipe size*/ + if (bRetVal == FALSE) + { + Fail("ERROR:%u:Unable to create pipe\n", GetLastError()); + } + + /*Write to the write pipe handle*/ + bRetVal = WriteFile(hWritePipe, /* handle to write pipe*/ + cTestString, /* buffer to write*/ + strlen(cTestString),/* number of bytes to write*/ + &dwBytesWritten, /* number of bytes written*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Trace("ERROR:%u:unable to write to write pipe handle " + "hWritePipe=0x%lx\n", GetLastError(), hWritePipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + Fail(""); + } + + /*Duplicate the pipe handle*/ + if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/ + hReadPipe, /* handle to duplicate*/ + GetCurrentProcess(), /* target process handle*/ + &hDupPipe, /* duplicate handle*/ + GENERIC_READ|GENERIC_WRITE,/* requested access*/ + FALSE, /* handle inheritance*/ + DUPLICATE_SAME_ACCESS))) /* optional actions*/ + { + Trace("ERROR:%u:Fail to create the duplicate handle" + " to hReadPipe=0x%lx", + GetLastError(), + hReadPipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + Fail(""); + } + + /*Read from the duplicated handle, 256 bytes, more bytes + than actually written. This will allow us to use the + value that ReadFile returns for comparison.*/ + bRetVal = ReadFile(hDupPipe, /* handle to read pipe*/ + buffer, /* buffer to write to*/ + 256, /* number of bytes to read*/ + &dwBytesRead, /* number of bytes read*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Trace("ERROR:%u:unable read from the duplicated pipe " + "hDupPipe=0x%lx\n", + GetLastError(), + hDupPipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Compare what was read with what was written.*/ + if ((memcmp(cTestString, buffer, dwBytesRead)) != 0) + { + Trace("ERROR:%u: read \"%s\" expected \"%s\" \n", + GetLastError(), + buffer, + cTestString); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Compare values returned from WriteFile and ReadFile.*/ + if (dwBytesWritten != dwBytesRead) + { + Trace("ERROR:%u: WriteFile wrote \"%s\", but ReadFile read \"%s\"," + " these should be the same\n", + GetLastError(), + buffer, + cTestString); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Cleanup.*/ + CloseHandle(hWritePipe); + CloseHandle(hReadPipe); + CloseHandle(hDupPipe); + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.cpp new file mode 100644 index 0000000000000..1a28b83455465 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.cpp @@ -0,0 +1,145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*===================================================================== +** +** Source: test6.c (DuplicateHandle) +** +** Purpose: Tests the PAL implementation of the DuplicateHandle function, +** with CreatePipe. This test will create a pipe, then duplicate +** the write handle, write to the handle, and use the read to +** verify. +** +** Depends: WriteFile +** ReadFile +** memcmp +** CloseHandle +** +** +**===================================================================*/ + +#include + +#define cTestString "one fish, two fish, read fish, blue fish." + +PALTEST(threading_DuplicateHandle_test6_paltest_duplicatehandle_test6, "threading/DuplicateHandle/test6/paltest_duplicatehandle_test6") +{ + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + HANDLE hDupPipe = NULL; + BOOL bRetVal = FALSE; + DWORD dwBytesWritten; + DWORD dwBytesRead; + char buffer[256]; + + SECURITY_ATTRIBUTES lpPipeAttributes; + + /*Initialize the PAL*/ + if ((PAL_Initialize(argc, argv)) != 0) + { + return (FAIL); + } + + /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/ + lpPipeAttributes.nLength = sizeof(lpPipeAttributes); + lpPipeAttributes.lpSecurityDescriptor = NULL; + lpPipeAttributes.bInheritHandle = TRUE; + + /*Create a Pipe*/ + bRetVal = CreatePipe(&hReadPipe, /* read handle*/ + &hWritePipe, /* write handle */ + &lpPipeAttributes,/* security attributes*/ + 0); /* pipe size*/ + if (bRetVal == FALSE) + { + Fail("ERROR: %ld :Unable to create pipe\n", GetLastError()); + } + + /*Duplicate the pipe handle*/ + if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/ + hWritePipe, /* handle to duplicate*/ + GetCurrentProcess(), /* target process handle*/ + &hDupPipe, /* duplicate handle*/ + GENERIC_READ|GENERIC_WRITE,/* requested access*/ + FALSE, /* handle inheritance*/ + DUPLICATE_SAME_ACCESS))) /* optional actions*/ + { + Trace("ERROR: %ld :Fail to create the duplicate handle" + " to hWritePipe=0x%lx", + GetLastError(), + hWritePipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + Fail(""); + } + + /*Write to the duplicate write pipe handle*/ + bRetVal = WriteFile(hDupPipe, /* handle to write pipe*/ + cTestString, /* buffer to write*/ + strlen(cTestString),/* number of bytes to write*/ + &dwBytesWritten, /* number of bytes written*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Trace("ERROR: %ld :unable to write to duplicate write pipe handle " + "hDupPipe=0x%lx\n", + GetLastError(), + hDupPipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Read from the read handle, 256 bytes, more bytes + then actually written. This will give allow us to use + the value that ReadFile returns for comparison.*/ + bRetVal = ReadFile(hReadPipe, /* handle to read pipe*/ + buffer, /* buffer to write to*/ + 256, /* number of bytes to read*/ + &dwBytesRead, /* number of bytes read*/ + NULL); /* overlapped buffer*/ + if (bRetVal == FALSE) + { + Trace("ERROR: %ld : unable read hReadPipe=0x%lx\n", + GetLastError(), hReadPipe); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Compare what was read with what was written.*/ + if ((memcmp(cTestString, buffer, dwBytesRead)) != 0) + { + Trace("ERROR: read \"%s\" expected \"%s\" \n", + buffer, + cTestString); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Compare values returned from WriteFile and ReadFile.*/ + if (dwBytesWritten != dwBytesRead) + { + Trace("ERROR: WriteFile wrote \"%s\", but ReadFile read \"%s\"," + " these should be the same\n", + buffer, + cTestString); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + Fail(""); + } + + /*Cleanup.*/ + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + CloseHandle(hDupPipe); + + + PAL_Terminate(); + return (PASS); +} diff --git a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/ExitThread/test2/test2.cpp index 8a6537e9833a2..4b9418d859edd 100644 --- a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test2/test2.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/ExitThread/test2/test2.cpp @@ -59,8 +59,13 @@ PALTEST(threading_ExitThread_test2_paltest_exitthread_test2, "threading/ExitThre rgchAbsPathName = &absPathBuf[0]; dwFileLength = strlen( rgchChildFile ); - strcpy(rgchDirName, ".\\"); - dwDirLength = strlen(rgchDirName); + dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName ); + if( dwDirLength == 0 ) + { + dwError = GetLastError(); + Fail( "GetCurrentDirectory call failed with error code %d\n", + dwError ); + } dwSize = mkAbsoluteFilename( rgchDirName, dwDirLength, diff --git a/src/coreclr/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.cpp index b0ab729f1e025..cfce4169bf5c8 100644 --- a/src/coreclr/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.cpp @@ -56,8 +56,13 @@ PALTEST(threading_GetExitCodeProcess_test1_paltest_getexitcodeprocess_test1, "th rgchAbsPathName = &absPathBuf[0]; dwFileLength = strlen( rgchChildFile ); - strcpy(rgchDirName, ".\\"); - dwDirLength = strlen(rgchDirName); + dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName ); + if( dwDirLength == 0 ) + { + dwError = GetLastError(); + Fail( "GetCurrentDirectory call failed with error code %d\n", + dwError ); + } dwSize = mkAbsoluteFilename( rgchDirName, dwDirLength, diff --git a/src/coreclr/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.cpp new file mode 100644 index 0000000000000..255fab77642ce --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.cpp @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================ +** +** Source: +** +** Source : test1.c +** +** Purpose: Test for GetThreadTimes() function +** +** +**=========================================================*/ + +#include + +PALTEST(threading_GetThreadTimes_test1_paltest_getthreadtimes_test1, "threading/GetThreadTimes/test1/paltest_getthreadtimes_test1") +{ + int ret = FAIL; + + //Test is failing unreliably, so for now we always return pass. + if (TRUE){ + ret = PASS; + goto EXIT; + } + { + FILETIME kernelTime1, userTime1, kernelTime2, userTime2; + /* Delta = .01 sec */ + LONG64 Actual, Expected, Delta = 850000000; + Actual = 0; + Expected = 0; + const ULONG64 MSEC_TO_NSEC = 1000000; + + /* + * Initialize the PAL and return FAILURE if this fails + */ + + if(0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + HANDLE cThread = GetCurrentThread(); + + int i; + /* Take 2000 tiny measurements */ + for (i = 0; i < 2000; i++){ + ULONG64 Time1, Time2; + + Sleep(1); + + /* Grab a FirstCount, then loop for a bit to make the clock increase */ + if (!GetThreadTimes(cThread, NULL, NULL, &kernelTime1, &userTime1)) + { + Fail("ERROR: GetThreadTimes returned failure.\n"); + } + LONG64 x, Init; + /* Init is in milliseconds, so we will convert later */ + Init = (ULONG64)GetTickCount(); + /* Spin for < 1 Quantum so we don't get interrupted */ + x = Init + 3; + volatile int counter; + do { + for (counter = 0; counter < 100000; counter++) + { + // spin to consume CPU time + } + + } while (x > GetTickCount()); + Expected += (GetTickCount() - Init) * MSEC_TO_NSEC; + /* Get a second count */ + if (!GetThreadTimes(cThread, NULL, NULL, &kernelTime2, &userTime2)) + { + Fail("ERROR: GetThreadTimes returned failure.\n"); + } + + Time1 = ((ULONG64)kernelTime1.dwHighDateTime << 32); + Time1 += (ULONG64)kernelTime1.dwLowDateTime; + Time1 += ((ULONG64)userTime1.dwHighDateTime << 32); + Time1 += (ULONG64)userTime1.dwLowDateTime; + + Time2 = ((ULONG64)kernelTime2.dwHighDateTime << 32); + Time2 += (ULONG64)kernelTime2.dwLowDateTime; + Time2 += ((ULONG64)userTime2.dwHighDateTime << 32); + Time2 += (ULONG64)userTime2.dwLowDateTime; + + Actual += (Time2 - Time1) * 100; + } + + if(llabs(Expected - Actual) > Delta) + { + Fail("ERROR: The measured time (%llu millisecs) was not within Delta %llu " + "of the expected time (%llu millisecs).\n", + (Actual / MSEC_TO_NSEC), (Delta / MSEC_TO_NSEC), (Expected / MSEC_TO_NSEC)); + } + //printf("%llu, %llu\n", Expected, Actual); + PAL_Terminate(); + ret = PASS; + } +EXIT: + return ret; +} diff --git a/src/coreclr/pal/tests/palsuite/threading/OpenProcess/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/OpenProcess/test1/test1.cpp index 38cd61014a01c..6a4b3cb978945 100644 --- a/src/coreclr/pal/tests/palsuite/threading/OpenProcess/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/OpenProcess/test1/test1.cpp @@ -73,8 +73,21 @@ PALTEST(threading_OpenProcess_test1_paltest_openprocess_test1, "threading/OpenPr rgchAbsPathName = &absPathBuf[0]; dwFileLength = strlen( rgchChildFile ); - strcpy(rgchDirName, ".\\"); - dwDirLength = strlen(rgchDirName); + dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName ); + if( dwDirLength == 0 ) + { + dwError = GetLastError(); + if( ReleaseMutex( hMutex ) == 0 ) + { + Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() ); + } + if( CloseHandle( hMutex ) == 0 ) + { + Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); + } + Fail( "GetCurrentDirectory call failed with error code %d\n", + dwError ); + } dwSize = mkAbsoluteFilename( rgchDirName, dwDirLength, diff --git a/src/coreclr/tools/superpmi/mcs/verbmerge.cpp b/src/coreclr/tools/superpmi/mcs/verbmerge.cpp index 82af9cd63e272..da9cf7bef19f0 100644 --- a/src/coreclr/tools/superpmi/mcs/verbmerge.cpp +++ b/src/coreclr/tools/superpmi/mcs/verbmerge.cpp @@ -5,7 +5,6 @@ #include "verbmerge.h" #include "simpletimer.h" #include "logging.h" -#include // Do reads/writes in large 256MB chunks. #define BUFFER_SIZE 0x10000000 @@ -571,8 +570,8 @@ int verbMerge::DoWork(const char* nameOfOutputFile, const char* pattern, bool re if (result != 0) { // There was a failure. Delete the output file, to avoid leaving some half-created file. - int st = remove(nameOfOutputFile); - if (st != 0) + BOOL ok = DeleteFileW(nameOfOutputFileAsWchar); + if (!ok) { LogError("Failed to delete file after MCS /merge failed. GetLastError()=%u", GetLastError()); } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp b/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp index 653b73d861084..1a1ef7019435c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp @@ -9,7 +9,6 @@ #include "logging.h" #include "errorhandling.h" #include -#include // // NOTE: Since the logging system is at the core of the error handling infrastructure, any errors @@ -84,10 +83,10 @@ void Logger::CloseLogFile() // Avoid polluting the file system with empty log files if (GetFileSize(s_logFile, nullptr) == 0 && s_logFilePath != nullptr) { - // We can call this before closing the handle because remove just marks the file + // We can call this before closing the handle because DeleteFile just marks the file // for deletion, i.e. it does not actually get deleted until its last handle is closed. - if (remove(s_logFilePath) == -1) - fprintf(stderr, "WARNING: [Logger::CloseLogFile] remove failed. GetLastError()=%u\n", + if (!DeleteFileA(s_logFilePath)) + fprintf(stderr, "WARNING: [Logger::CloseLogFile] DeleteFile failed. GetLastError()=%u\n", GetLastError()); } diff --git a/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp b/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp index c3dc26501f1dc..228fea9393412 100644 --- a/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp +++ b/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp @@ -794,22 +794,22 @@ int doParallelSuperPMI(CommandLine::Options& o) PerWorkerData& wd = perWorkerData[i]; if (wd.failingMCListPath != nullptr) { - remove(wd.failingMCListPath); + DeleteFile(wd.failingMCListPath); } if (wd.diffsInfoPath != nullptr) { - remove(wd.diffsInfoPath); + DeleteFile(wd.diffsInfoPath); } if (wd.baseMetricsSummaryPath != nullptr) { - remove(wd.baseMetricsSummaryPath); + DeleteFile(wd.baseMetricsSummaryPath); } if (wd.diffMetricsSummaryPath != nullptr) { - remove(wd.diffMetricsSummaryPath); + DeleteFile(wd.diffMetricsSummaryPath); } - remove(wd.stdOutputPath); - remove(wd.stdErrorPath); + DeleteFile(wd.stdOutputPath); + DeleteFile(wd.stdErrorPath); } } diff --git a/src/coreclr/utilcode/fstream.cpp b/src/coreclr/utilcode/fstream.cpp index 8282118692319..835e24f624950 100644 --- a/src/coreclr/utilcode/fstream.cpp +++ b/src/coreclr/utilcode/fstream.cpp @@ -176,7 +176,48 @@ HRESULT CFileStream::Write(void const *pv, ULONG cb, ULONG *pcbWritten) HRESULT CFileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { +#if 1 // SetFilePointerEx not supported on Win9x return E_NOTIMPL; +#else + HRESULT hr = S_OK; + DWORD dwFileOrigin; + BOOL bRet; + + _ASSERTE(_hFile != INVALID_HANDLE_VALUE); + if (_hFile == INVALID_HANDLE_VALUE) { + hr = E_UNEXPECTED; + goto Exit; + } + + switch (dwOrigin) { + case STREAM_SEEK_SET: + dwFileOrigin = FILE_BEGIN; + break; + + case STREAM_SEEK_CUR: + dwFileOrigin = FILE_CURRENT; + break; + + case STREAM_SEEK_END: + dwFileOrigin = FILE_END; + break; + + default: + hr = E_UNEXPECTED; + goto Exit; + } + + bRet = SetFilePointerEx(_hFile, dlibMove, (LARGE_INTEGER *)plibNewPosition, + dwFileOrigin); + if (!bRet) { + hr = HRESULT_FROM_WIN32(::GetLastError()); + goto Exit; + } + + +Exit: + return hr; +#endif } HRESULT CFileStream::SetSize(ULARGE_INTEGER libNewSize) diff --git a/src/coreclr/utilcode/longfilepathwrappers.cpp b/src/coreclr/utilcode/longfilepathwrappers.cpp index 41635c7084f99..3c11ccedca63d 100644 --- a/src/coreclr/utilcode/longfilepathwrappers.cpp +++ b/src/coreclr/utilcode/longfilepathwrappers.cpp @@ -223,6 +223,48 @@ GetFileAttributesExWrapper( return ret; } +BOOL +DeleteFileWrapper( + _In_ LPCWSTR lpFileName + ) +{ + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + HRESULT hr = S_OK; + BOOL ret = FALSE; + DWORD lastError = 0; + + EX_TRY + { + LongPathString path(LongPathString::Literal, lpFileName); + + if (SUCCEEDED(LongFile::NormalizePath(path))) + { + ret = DeleteFileW( + path.GetUnicode() + ); + } + + lastError = GetLastError(); + } + EX_CATCH_HRESULT(hr); + + if (hr != S_OK ) + { + SetLastError(hr); + } + else if(ret == FALSE) + { + SetLastError(lastError); + } + + return ret; +} + DWORD SearchPathWrapper( _In_opt_ LPCWSTR lpPath, @@ -415,6 +457,47 @@ DWORD WINAPI GetTempPathWrapper( return ret; } +DWORD WINAPI GetCurrentDirectoryWrapper( + SString& lpBuffer + ) +{ + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + HRESULT hr = S_OK; + DWORD ret = 0; + DWORD lastError = 0; + + EX_TRY + { + //Change the behaviour in Redstone to retry + COUNT_T size = MAX_LONGPATH; + + ret = GetCurrentDirectoryW( + size, + lpBuffer.OpenUnicodeBuffer(size - 1) + ); + + lastError = GetLastError(); + lpBuffer.CloseBuffer(ret); + } + EX_CATCH_HRESULT(hr); + + if (hr != S_OK) + { + SetLastError(hr); + } + else if (ret == 0) + { + SetLastError(lastError); + } + + return ret; +} + DWORD WINAPI GetEnvironmentVariableWrapper( _In_opt_ LPCTSTR lpName, _Out_opt_ SString& lpBuffer diff --git a/src/coreclr/vm/synch.cpp b/src/coreclr/vm/synch.cpp index c691a1575e625..7152d00ee0cc2 100644 --- a/src/coreclr/vm/synch.cpp +++ b/src/coreclr/vm/synch.cpp @@ -467,3 +467,578 @@ DWORD CLREventBase::WaitEx(DWORD dwMilliseconds, WaitMode mode, PendingSync *syn } } } + +void CLRSemaphore::Create (DWORD dwInitial, DWORD dwMax) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + PRECONDITION(m_handle == INVALID_HANDLE_VALUE); + } + CONTRACTL_END; + + { + HANDLE h = WszCreateSemaphore(NULL,dwInitial,dwMax,NULL); + if (h == NULL) { + ThrowOutOfMemory(); + } + m_handle = h; + } +} + + +void CLRSemaphore::Close() +{ + LIMITED_METHOD_CONTRACT; + + if (m_handle != INVALID_HANDLE_VALUE) { + CloseHandle(m_handle); + m_handle = INVALID_HANDLE_VALUE; + } +} + +BOOL CLRSemaphore::Release(LONG lReleaseCount, LONG *lpPreviousCount) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(m_handle != INVALID_HANDLE_VALUE); + } + CONTRACTL_END; + + { + return ::ReleaseSemaphore(m_handle, lReleaseCount, lpPreviousCount); + } +} + + +DWORD CLRSemaphore::Wait(DWORD dwMilliseconds, BOOL alertable) +{ + CONTRACTL + { + if (GetThreadNULLOk() && alertable) + { + THROWS; // Thread::DoAppropriateWait can throw + } + else + { + NOTHROW; + } + + if (GetThreadNULLOk()) + { + if (alertable) + GC_TRIGGERS; + else + GC_NOTRIGGER; + } + else + { + DISABLED(GC_TRIGGERS); + } + + PRECONDITION(m_handle != INVALID_HANDLE_VALUE); // Invalid to have invalid handle + } + CONTRACTL_END; + + + Thread *pThread = GetThreadNULLOk(); + _ASSERTE (pThread || !g_fEEStarted || dbgOnly_IsSpecialEEThread()); + + { + // TODO wwl: if alertable is FALSE, do we support a host to break a deadlock? + // Currently we can not call through DoAppropriateWait because of CannotThrowComplusException. + // We should re-consider this after our code is exception safe. + if (pThread && alertable) { + return pThread->DoAppropriateWait(1, &m_handle, FALSE, dwMilliseconds, + alertable?WaitMode_Alertable:WaitMode_None, + NULL); + } + else { + DWORD result = WAIT_FAILED; + EX_TRY + { + result = WaitForSingleObjectEx(m_handle,dwMilliseconds,alertable); + } + EX_CATCH + { + result = WAIT_FAILED; + } + EX_END_CATCH(SwallowAllExceptions); + return result; + } + } +} + +void CLRLifoSemaphore::Create(INT32 initialSignalCount, INT32 maximumSignalCount) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + _ASSERTE(maximumSignalCount > 0); + _ASSERTE(initialSignalCount <= maximumSignalCount); + _ASSERTE(m_handle == nullptr); + +#ifdef TARGET_UNIX + HANDLE h = WszCreateSemaphore(nullptr, 0, maximumSignalCount, nullptr); +#else // !TARGET_UNIX + HANDLE h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, maximumSignalCount); +#endif // TARGET_UNIX + if (h == nullptr) + { + ThrowOutOfMemory(); + } + + m_handle = h; + m_counts.signalCount = initialSignalCount; + INDEBUG(m_maximumSignalCount = maximumSignalCount); +} + +void CLRLifoSemaphore::Close() +{ + LIMITED_METHOD_CONTRACT; + + if (m_handle == nullptr) + { + return; + } + + CloseHandle(m_handle); + m_handle = nullptr; +} + +bool CLRLifoSemaphore::WaitForSignal(DWORD timeoutMs) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + _ASSERTE(timeoutMs != 0); + _ASSERTE(m_handle != nullptr); + _ASSERTE(m_counts.VolatileLoadWithoutBarrier().waiterCount != (UINT16)0); + + while (true) + { + // Wait for a signal + BOOL waitSuccessful; + { +#ifdef TARGET_UNIX + // Do a prioritized wait to get LIFO waiter release order + DWORD waitResult = PAL_WaitForSingleObjectPrioritized(m_handle, timeoutMs); + _ASSERTE(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT); + waitSuccessful = waitResult == WAIT_OBJECT_0; +#else // !TARGET_UNIX + // I/O completion ports release waiters in LIFO order, see + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.85).aspx + DWORD numberOfBytes; + ULONG_PTR completionKey; + LPOVERLAPPED overlapped; + waitSuccessful = GetQueuedCompletionStatus(m_handle, &numberOfBytes, &completionKey, &overlapped, timeoutMs); + _ASSERTE(waitSuccessful || GetLastError() == WAIT_TIMEOUT); + _ASSERTE(overlapped == nullptr); +#endif // TARGET_UNIX + } + + if (!waitSuccessful) + { + // Unregister the waiter. The wait subsystem used above guarantees that a thread that wakes due to a timeout does + // not observe a signal to the object being waited upon. + Counts toSubtract; + ++toSubtract.waiterCount; + Counts countsBeforeUpdate = m_counts.ExchangeAdd(-toSubtract); + _ASSERTE(countsBeforeUpdate.waiterCount != (UINT16)0); + return false; + } + + // Unregister the waiter if this thread will not be waiting anymore, and try to acquire the semaphore + Counts counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + _ASSERTE(counts.waiterCount != (UINT16)0); + Counts newCounts = counts; + if (counts.signalCount != 0) + { + --newCounts.signalCount; + --newCounts.waiterCount; + } + + // This waiter has woken up and this needs to be reflected in the count of waiters signaled to wake + if (counts.countOfWaitersSignaledToWake != (UINT8)0) + { + --newCounts.countOfWaitersSignaledToWake; + } + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + if (counts.signalCount != 0) + { + return true; + } + break; + } + + counts = countsBeforeUpdate; + } + } +} + +bool CLRLifoSemaphore::Wait(DWORD timeoutMs) +{ + WRAPPER_NO_CONTRACT; + + _ASSERTE(m_handle != nullptr); + + // Acquire the semaphore or register as a waiter + Counts counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + _ASSERTE(counts.signalCount <= m_maximumSignalCount); + Counts newCounts = counts; + if (counts.signalCount != 0) + { + --newCounts.signalCount; + } + else if (timeoutMs != 0) + { + ++newCounts.waiterCount; + _ASSERTE(newCounts.waiterCount != (UINT16)0); // overflow check, this many waiters is currently not supported + } + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + return counts.signalCount != 0 || (timeoutMs != 0 && WaitForSignal(timeoutMs)); + } + + counts = countsBeforeUpdate; + } +} + +bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorCount) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + _ASSERTE(m_handle != nullptr); + + if (timeoutMs == 0 || spinCount == 0) + { + return Wait(timeoutMs); + } + + // Try to acquire the semaphore or register as a spinner + Counts counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + Counts newCounts = counts; + if (counts.signalCount != 0) + { + --newCounts.signalCount; + } + else + { + ++newCounts.spinnerCount; + if (newCounts.spinnerCount == (UINT8)0) + { + // Maximum number of spinners reached, register as a waiter instead + --newCounts.spinnerCount; + ++newCounts.waiterCount; + _ASSERTE(newCounts.waiterCount != (UINT16)0); // overflow check, this many waiters is currently not supported + } + } + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + if (counts.signalCount != 0) + { + return true; + } + if (newCounts.waiterCount != counts.waiterCount) + { + return WaitForSignal(timeoutMs); + } + break; + } + + counts = countsBeforeUpdate; + } + +#ifdef TARGET_ARM64 + // For now, the spinning changes are disabled on ARM64. The spin loop below replicates how UnfairSemaphore used to spin. + // Once more tuning is done on ARM64, it should be possible to come up with a spinning scheme that works well everywhere. + int spinCountPerProcessor = spinCount; + for (UINT32 i = 1; ; ++i) + { + // Wait + ClrSleepEx(0, false); + + // Try to acquire the semaphore and unregister as a spinner + counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + _ASSERTE(counts.spinnerCount != (UINT8)0); + if (counts.signalCount == 0) + { + break; + } + + Counts newCounts = counts; + --newCounts.signalCount; + --newCounts.spinnerCount; + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + return true; + } + + counts = countsBeforeUpdate; + } + + // Determine whether to spin further + double spinnersPerProcessor = (double)counts.spinnerCount / processorCount; + UINT32 spinLimit = (UINT32)(spinCountPerProcessor / spinnersPerProcessor + 0.5); + if (i >= spinLimit) + { + break; + } + } +#else // !TARGET_ARM64 + const UINT32 Sleep0Threshold = 10; + YieldProcessorNormalizationInfo normalizationInfo; +#ifdef TARGET_UNIX + // The PAL's wait subsystem is quite slow, spin more to compensate for the more expensive wait + spinCount *= 2; +#endif // TARGET_UNIX + for (UINT32 i = 0; i < spinCount; ++i) + { + // Wait + // + // (i - Sleep0Threshold) % 2 != 0: The purpose of this check is to interleave Thread.Yield/Sleep(0) with + // Thread.SpinWait. Otherwise, the following issues occur: + // - When there are no threads to switch to, Yield and Sleep(0) become no-op and it turns the spin loop into a + // busy-spin that may quickly reach the max spin count and cause the thread to enter a wait state. Completing the + // spin loop too early can cause excessive context switcing from the wait. + // - If there are multiple threads doing Yield and Sleep(0) (typically from the same spin loop due to contention), + // they may switch between one another, delaying work that can make progress. + if (i < Sleep0Threshold || (i - Sleep0Threshold) % 2 != 0) + { + YieldProcessorWithBackOffNormalized(normalizationInfo, i); + } + else + { + // Not doing SwitchToThread(), it does not seem to have any benefit over Sleep(0) + ClrSleepEx(0, false); + } + + // Try to acquire the semaphore and unregister as a spinner + counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + _ASSERTE(counts.spinnerCount != (UINT8)0); + if (counts.signalCount == 0) + { + break; + } + + Counts newCounts = counts; + --newCounts.signalCount; + --newCounts.spinnerCount; + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + return true; + } + + counts = countsBeforeUpdate; + } + } +#endif // TARGET_ARM64 + + // Unregister as a spinner, and acquire the semaphore or register as a waiter + counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + _ASSERTE(counts.spinnerCount != (UINT8)0); + Counts newCounts = counts; + --newCounts.spinnerCount; + if (counts.signalCount != 0) + { + --newCounts.signalCount; + } + else + { + ++newCounts.waiterCount; + _ASSERTE(newCounts.waiterCount != (UINT16)0); // overflow check, this many waiters is currently not supported + } + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + return counts.signalCount != 0 || WaitForSignal(timeoutMs); + } + + counts = countsBeforeUpdate; + } +} + +void CLRLifoSemaphore::Release(INT32 releaseCount) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + _ASSERTE(releaseCount > 0); + _ASSERTE((UINT32)releaseCount <= m_maximumSignalCount); + _ASSERTE(m_handle != INVALID_HANDLE_VALUE); + + INT32 countOfWaitersToWake; + Counts counts = m_counts.VolatileLoadWithoutBarrier(); + while (true) + { + Counts newCounts = counts; + + // Increase the signal count. The addition doesn't overflow because of the limit on the max signal count in Create. + newCounts.signalCount += releaseCount; + _ASSERTE(newCounts.signalCount > counts.signalCount); + + // Determine how many waiters to wake, taking into account how many spinners and waiters there are and how many waiters + // have previously been signaled to wake but have not yet woken + countOfWaitersToWake = + (INT32)min(newCounts.signalCount, (UINT32)newCounts.waiterCount + newCounts.spinnerCount) - + newCounts.spinnerCount - + newCounts.countOfWaitersSignaledToWake; + if (countOfWaitersToWake > 0) + { + // Ideally, limiting to a maximum of releaseCount would not be necessary and could be an assert instead, but since + // WaitForSignal() does not have enough information to tell whether a woken thread was signaled, and due to the cap + // below, it's possible for countOfWaitersSignaledToWake to be less than the number of threads that have actually + // been signaled to wake. + if (countOfWaitersToWake > releaseCount) + { + countOfWaitersToWake = releaseCount; + } + + // Cap countOfWaitersSignaledToWake to its max value. It's ok to ignore some woken threads in this count, it just + // means some more threads will be woken next time. Typically, it won't reach the max anyway. + newCounts.countOfWaitersSignaledToWake += (UINT8)min(countOfWaitersToWake, (INT32)UINT8_MAX); + if (newCounts.countOfWaitersSignaledToWake <= counts.countOfWaitersSignaledToWake) + { + newCounts.countOfWaitersSignaledToWake = UINT8_MAX; + } + } + + Counts countsBeforeUpdate = m_counts.CompareExchange(newCounts, counts); + if (countsBeforeUpdate == counts) + { + _ASSERTE((UINT32)releaseCount <= m_maximumSignalCount - counts.signalCount); + if (countOfWaitersToWake <= 0) + { + return; + } + break; + } + + counts = countsBeforeUpdate; + } + + // Wake waiters +#ifdef TARGET_UNIX + BOOL released = ReleaseSemaphore(m_handle, countOfWaitersToWake, nullptr); + _ASSERTE(released); +#else // !TARGET_UNIX + while (--countOfWaitersToWake >= 0) + { + while (!PostQueuedCompletionStatus(m_handle, 0, 0, nullptr)) + { + // Probably out of memory. It's not valid to stop and throw here, so try again after a delay. + ClrSleepEx(1, false); + } + } +#endif // TARGET_UNIX +} + +void CLRMutex::Create(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + PRECONDITION(m_handle == INVALID_HANDLE_VALUE && m_handle != NULL); + } + CONTRACTL_END; + + m_handle = WszCreateMutex(lpMutexAttributes,bInitialOwner,lpName); + if (m_handle == NULL) + { + ThrowOutOfMemory(); + } +} + +void CLRMutex::Close() +{ + LIMITED_METHOD_CONTRACT; + + if (m_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(m_handle); + m_handle = INVALID_HANDLE_VALUE; + } +} + +BOOL CLRMutex::Release() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(m_handle != INVALID_HANDLE_VALUE && m_handle != NULL); + } + CONTRACTL_END; + + BOOL fRet = ReleaseMutex(m_handle); + if (fRet) + { + EE_LOCK_RELEASED(this); + } + return fRet; +} + +DWORD CLRMutex::Wait(DWORD dwMilliseconds, BOOL bAlertable) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + CAN_TAKE_LOCK; + PRECONDITION(m_handle != INVALID_HANDLE_VALUE && m_handle != NULL); + } + CONTRACTL_END; + + DWORD fRet = WaitForSingleObjectEx(m_handle, dwMilliseconds, bAlertable); + + if (fRet == WAIT_OBJECT_0) + { + EE_LOCK_TAKEN(this); + } + + return fRet; +} diff --git a/src/coreclr/vm/synch.h b/src/coreclr/vm/synch.h index 72e19f1c33b60..5a7cffacb2bb7 100644 --- a/src/coreclr/vm/synch.h +++ b/src/coreclr/vm/synch.h @@ -18,6 +18,7 @@ enum WaitMode struct PendingSync; +class CRWLock; class CLREventBase { @@ -143,5 +144,175 @@ class CLREventStatic : public CLREventBase { }; + +class CLRSemaphore { +public: + CLRSemaphore() + : m_handle(INVALID_HANDLE_VALUE) + { + LIMITED_METHOD_CONTRACT; + } + + ~CLRSemaphore() + { + WRAPPER_NO_CONTRACT; + Close (); + } + + void Create(DWORD dwInitial, DWORD dwMax); + void Close(); + + BOOL IsValid() const + { + LIMITED_METHOD_CONTRACT; + return m_handle != INVALID_HANDLE_VALUE; + } + + DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable); + BOOL Release(LONG lReleaseCount, LONG* lpPreviousCount); + +private: + HANDLE m_handle; +}; + +class CLRLifoSemaphore +{ +private: + struct Counts + { + union + { + struct + { + UINT32 signalCount; + UINT16 waiterCount; + UINT8 spinnerCount; + UINT8 countOfWaitersSignaledToWake; + }; + UINT64 data; + }; + + Counts(UINT64 data = 0) : data(data) + { + LIMITED_METHOD_CONTRACT; + } + + operator UINT64() const + { + LIMITED_METHOD_CONTRACT; + return data; + } + + Counts operator -() const + { + LIMITED_METHOD_CONTRACT; + return -(INT64)data; + } + + Counts &operator =(UINT64 data) + { + LIMITED_METHOD_CONTRACT; + + this->data = data; + return *this; + } + + Counts VolatileLoadWithoutBarrier() const + { + LIMITED_METHOD_CONTRACT; + return ::VolatileLoadWithoutBarrier(&data); + } + + Counts CompareExchange(Counts toCounts, Counts fromCounts) + { + LIMITED_METHOD_CONTRACT; + return (UINT64)InterlockedCompareExchange64((LONG64 *)&data, (LONG64)toCounts, (LONG64)fromCounts); + } + + Counts ExchangeAdd(Counts toAdd) + { + LIMITED_METHOD_CONTRACT; + return (UINT64)InterlockedExchangeAdd64((LONG64 *)&data, (LONG64)toAdd); + } + }; + +public: + CLRLifoSemaphore() : m_handle(nullptr) + { + LIMITED_METHOD_CONTRACT; + } + + ~CLRLifoSemaphore() + { + WRAPPER_NO_CONTRACT; + Close(); + } + +public: + void Create(INT32 initialSignalCount, INT32 maximumSignalCount); + void Close(); + +public: + BOOL IsValid() const + { + LIMITED_METHOD_CONTRACT; + return m_handle != nullptr; + } + +private: + bool WaitForSignal(DWORD timeoutMs); +public: + bool Wait(DWORD timeoutMs); + bool Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorCount); + void Release(INT32 releaseCount); + +private: + BYTE __padding1[MAX_CACHE_LINE_SIZE]; // padding to ensure that m_counts gets its own cache line + + // Take care to use 'm_counts.VolatileLoadWithoutBarrier()` when loading this value into a local variable that will be + // reused. See AwareLock::m_lockState for details. + Counts m_counts; + + BYTE __padding2[MAX_CACHE_LINE_SIZE]; // padding to ensure that m_counts gets its own cache line + +#if defined(DEBUG) + UINT32 m_maximumSignalCount; +#endif // _DEBUG && !TARGET_UNIX + + // When TARGET_UNIX is defined, this is a handle to an instance of the PAL's LIFO semaphore. When TARGET_UNIX is not + // defined, this is a handle to an I/O completion port. + HANDLE m_handle; +}; + +class CLRMutex { +public: + CLRMutex() + : m_handle(INVALID_HANDLE_VALUE) + { + LIMITED_METHOD_CONTRACT; + } + + ~CLRMutex() + { + WRAPPER_NO_CONTRACT; + Close (); + } + + void Create(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName); + void Close(); + + BOOL IsValid() const + { + LIMITED_METHOD_CONTRACT; + return m_handle != INVALID_HANDLE_VALUE; + } + + DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable); + BOOL Release(); + +private: + HANDLE m_handle; +}; + BOOL CLREventWaitWithTry(CLREventBase *pEvent, DWORD timeout, BOOL fAlertable, DWORD *pStatus); #endif