From 621e96bfdb55182dbaf89a1500971ebcf547c0b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20D=C3=B6singer?= Date: Mon, 17 Jul 2017 14:23:50 +0200 Subject: [PATCH] msvcp140: Implement _Stat and _Lstat. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Dösinger Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- dlls/msvcp140/msvcp140.spec | 4 +- dlls/msvcp140/tests/msvcp140.c | 149 +++++++++++++++++++++++++++++++++++++++++ dlls/msvcp90/ios.c | 59 +++++++++++++++- 3 files changed, 207 insertions(+), 5 deletions(-) diff --git a/dlls/msvcp140/msvcp140.spec b/dlls/msvcp140/msvcp140.spec index 22871bca92e..afada991d3b 100644 --- a/dlls/msvcp140/msvcp140.spec +++ b/dlls/msvcp140/msvcp140.spec @@ -3669,7 +3669,7 @@ @ stub _Last_write_time @ stub _Link @ cdecl _Lock_shared_ptr_spin_lock() -@ stub _Lstat +@ cdecl _Lstat(wstr ptr) @ cdecl _Make_dir(wstr) tr2_sys__Make_dir_wchar @ cdecl _Mbrtowc(ptr ptr long ptr ptr) _Mbrtowc @ stub _Mtx_clear_owner @@ -3699,7 +3699,7 @@ @ stub _Set_last_write_time @ stub _Sinh @ extern _Snan _Snan -@ stub _Stat +@ cdecl _Stat(wstr ptr) @ stub _Statvfs @ cdecl _Stod(ptr ptr long) _Stod @ cdecl _Stodx(ptr ptr long ptr) _Stodx diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index 7ab1ba5cc65..dd2255dc803 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -135,6 +135,19 @@ typedef struct { void *arg; } _Threadpool_chore; +enum file_type { + file_not_found = -1, + none_file, + regular_file, + directory_file, + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + status_unknown +}; + static unsigned int (__cdecl *p__Thrd_id)(void); static task_continuation_context* (__thiscall *p_task_continuation_context_ctor)(task_continuation_context*); static void (__thiscall *p__ContextCallback__Assign)(_ContextCallback*, void*); @@ -155,14 +168,20 @@ static void (__cdecl *p__Release_chore)(_Threadpool_chore*); static MSVCP_bool (__cdecl *p_Current_get)(WCHAR *); static MSVCP_bool (__cdecl *p_Current_set)(WCHAR const *); static ULONGLONG (__cdecl *p_File_size)(WCHAR const *); +static enum file_type (__cdecl *p_Lstat)(WCHAR const *, int *); +static enum file_type (__cdecl *p_Stat)(WCHAR const *, int *); static int (__cdecl *p_To_byte)(const WCHAR *src, char *dst); static int (__cdecl *p_To_wide)(const char *src, WCHAR *dst); +static BOOLEAN (WINAPI *pCreateSymbolicLinkW)(const WCHAR *, const WCHAR *, DWORD); + static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) static BOOL init(void) { + HANDLE hdll; + msvcp = LoadLibraryA("msvcp140.dll"); if(!msvcp) { @@ -222,9 +241,14 @@ static BOOL init(void) SET(p_Current_get, "_Current_get"); SET(p_Current_set, "_Current_set"); SET(p_File_size, "_File_size"); + SET(p_Lstat, "_Lstat"); + SET(p_Stat, "_Stat"); SET(p_To_byte, "_To_byte"); SET(p_To_wide, "_To_wide"); + hdll = GetModuleHandleA("kernel32.dll"); + pCreateSymbolicLinkW = (void*)GetProcAddress(hdll, "CreateSymbolicLinkW"); + init_thiscall_thunk(); return TRUE; } @@ -691,6 +715,130 @@ static void test_Current_set(void) wine_dbgstr_w(origin_path), wine_dbgstr_w(current_path)); } +static void test_Stat(void) +{ + int i, perms, ret; + HANDLE file; + enum file_type val; + WCHAR test_dirW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0}; + WCHAR test_f1W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0}; + WCHAR test_f2W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0}; + WCHAR pipeW[] = {'\\','\\','.','\\','P','i','P','e','\\','t','e','s','t','s','_','p','i','p','e','.','c', 0}; + WCHAR test_neW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0}; + WCHAR test_invW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','?','?','i','n','v','a','l','i','d','_','n','a','m','e','>','>',0}; + WCHAR test_f1_linkW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','f','1','_','l','i','n','k',0}; + WCHAR test_dir_linkW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','d','i','r','_','l','i','n','k',0}; + WCHAR sys_path[MAX_PATH], origin_path[MAX_PATH], temp_path[MAX_PATH]; + struct { + WCHAR const *path; + enum file_type ret; + int perms; + int is_todo; + } tests[] = { + { NULL, file_not_found, 0xdeadbeef, FALSE }, + { test_dirW, directory_file, 0777, FALSE }, + { test_f1W, regular_file, 0777, FALSE }, + { test_f2W, regular_file, 0555, FALSE }, + { test_neW, file_not_found, 0xdeadbeef, FALSE }, + { test_invW, file_not_found, 0xdeadbeef, FALSE }, + { test_f1_linkW, regular_file, 0777, TRUE }, + { test_dir_linkW, directory_file, 0777, TRUE }, + }; + + memset(origin_path, 0, sizeof(origin_path)); + memset(origin_path, 0, sizeof(temp_path)); + GetCurrentDirectoryW(MAX_PATH, origin_path); + GetTempPathW(MAX_PATH, temp_path); + ok(SetCurrentDirectoryW(temp_path), "SetCurrentDirectoryW to temp_path failed\n"); + + CreateDirectoryW(test_dirW, NULL); + + file = CreateFileW(test_f1W, 0, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); + ok(CloseHandle(file), "CloseHandle\n"); + + file = CreateFileW(test_f2W, 0, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); + ok(CloseHandle(file), "CloseHandle\n"); + SetFileAttributesW(test_f2W, FILE_ATTRIBUTE_READONLY); + + SetLastError(0xdeadbeef); + ret = pCreateSymbolicLinkW && pCreateSymbolicLinkW(test_f1_linkW, test_f1W, 0); + if(!ret && (!pCreateSymbolicLinkW || GetLastError()==ERROR_PRIVILEGE_NOT_HELD||GetLastError()==ERROR_INVALID_FUNCTION)) { + tests[6].ret = tests[7].ret = file_not_found; + tests[6].perms = tests[7].perms = 0xdeadbeef; + win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n"); + }else { + ok(ret, "CreateSymbolicLinkW failed\n"); + ok(pCreateSymbolicLinkW(test_dir_linkW, test_dirW, 1), "CreateSymbolicLinkW failed\n"); + } + + file = CreateNamedPipeW(pipeW, + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + perms = 0xdeadbeef; + val = p_Stat(pipeW, &perms); + todo_wine ok(regular_file == val, "_Stat(): expect: regular, got %d\n", val); + todo_wine ok(0777 == perms, "_Stat(): perms expect: 0777, got 0%o\n", perms); + perms = 0xdeadbeef; + val = p_Lstat(pipeW, &perms); + ok(status_unknown == val, "_Lstat(): expect: unknown, got %d\n", val); + ok(0xdeadbeef == perms, "_Lstat(): perms expect: 0xdeadbeef, got %x\n", perms); + ok(CloseHandle(file), "CloseHandle\n"); + file = CreateNamedPipeW(pipeW, + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + perms = 0xdeadbeef; + val = p_Lstat(pipeW, &perms); + todo_wine ok(regular_file == val, "_Lstat(): expect: regular, got %d\n", val); + todo_wine ok(0777 == perms, "_Lstat(): perms expect: 0777, got 0%o\n", perms); + ok(CloseHandle(file), "CloseHandle\n"); + + for(i=0; i= 110 @@ -15645,6 +15661,37 @@ enum file_type __cdecl tr2_sys__Stat_wchar(WCHAR const* path, int* err_code) return (attr & FILE_ATTRIBUTE_DIRECTORY)?directory_file:regular_file; } +/* _Stat, msvcp140 version */ +enum file_type __cdecl _Stat(WCHAR const* path, int* permissions) +{ + DWORD attr; + TRACE("(%s %p)\n", debugstr_w(path), permissions); + if(!path) { + return file_not_found; + } + + attr=GetFileAttributesW(path); + if(attr == INVALID_FILE_ATTRIBUTES) { + enum file_type ret; + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_BAD_NETPATH: + case ERROR_INVALID_NAME: + case ERROR_BAD_PATHNAME: + case ERROR_PATH_NOT_FOUND: + ret = file_not_found; + break; + default: + ret = status_unknown; + } + return ret; + } + + if (permissions) + *permissions = (attr & FILE_ATTRIBUTE_READONLY) ? 0555 : 0777; + return (attr & FILE_ATTRIBUTE_DIRECTORY) ? directory_file : regular_file; +} + /* ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z */ /* ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z */ enum file_type __cdecl tr2_sys__Lstat_wchar(WCHAR const* path, int* err_code) @@ -15652,6 +15699,12 @@ enum file_type __cdecl tr2_sys__Lstat_wchar(WCHAR const* path, int* err_code) return tr2_sys__Stat_wchar(path, err_code); } +/* _Lstat, msvcp140 version */ +enum file_type __cdecl _Lstat(WCHAR const* path, int* permissions) +{ + return _Stat(path, permissions); +} + /* ??1_Winit@std@@QAE@XZ */ /* ??1_Winit@std@@QAE@XZ */ DEFINE_THISCALL_WRAPPER(_Winit_dtor, 4) -- 2.11.4.GIT