From: YongHao Hu Subject: [PATCH 2/2] msvcp110: Add tr2_sys__Stat and tr2_sys__Lstat implementation and test.(try 2) Message-Id: <55B91504.7090005@gmail.com> Date: Thu, 30 Jul 2015 02:01:40 +0800 try2: detect CreateSymbolicLink, reparse point failure and skip some tests.(thanks Piotr) --- dlls/msvcp110/msvcp110.spec | 8 +- dlls/msvcp120/msvcp120.spec | 8 +- dlls/msvcp120/tests/msvcp120.c | 142 ++++++++++++++++++++++++++++++++++++ dlls/msvcp120_app/msvcp120_app.spec | 8 +- dlls/msvcp90/ios.c | 47 ++++++++++++ 5 files changed, 201 insertions(+), 12 deletions(-) diff --git a/dlls/msvcp110/msvcp110.spec b/dlls/msvcp110/msvcp110.spec index a8692ec..c5d438a 100644 --- a/dlls/msvcp110/msvcp110.spec +++ b/dlls/msvcp110/msvcp110.spec @@ -1605,8 +1605,8 @@ @ cdecl -arch=win32 ?_Lockit_dtor@_Lockit@std@@CAXPAV12@@Z(ptr) _Lockit__Lockit_dtor @ cdecl -arch=win64 ?_Lockit_dtor@_Lockit@std@@CAXPEAV12@@Z(ptr) _Lockit__Lockit_dtor @ cdecl ?_Lockit_dtor@_Lockit@std@@SAXH@Z(long) _Lockit_free -@ stub -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z -@ stub -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z +@ cdecl -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z(str ptr) tr2_sys__Lstat +@ cdecl -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z(str ptr) tr2_sys__Lstat @ stub -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z @ stub -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z @ stub -arch=win32 ?_MP_Add@std@@YAXQA_K_K@Z @@ -1757,8 +1757,8 @@ @ stub -arch=win64 ?_Src@?3??_Getffld@?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@AEBAHPEADAEAV?$istreambuf_iterator@GU?$char_traits@G@std@@@3@1AEAVios_base@3@PEAH@Z@4QBDB @ stub -arch=win32 ?_Src@?3??_Getffld@?$num_get@_WV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@ABAHPADAAV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@3@1AAVios_base@3@PAH@Z@4QBDB @ stub -arch=win64 ?_Src@?3??_Getffld@?$num_get@_WV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@AEBAHPEADAEAV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@3@1AEAVios_base@3@PEAH@Z@4QBDB -@ stub -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z -@ stub -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z +@ cdecl -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z(str ptr) tr2_sys__Stat +@ cdecl -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z(str ptr) tr2_sys__Stat @ stub -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z @ stub -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z @ cdecl -arch=win32 ?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PBD@Z(str) tr2_sys__Statvfs diff --git a/dlls/msvcp120/msvcp120.spec b/dlls/msvcp120/msvcp120.spec index b251ca3..e9a7217 100644 --- a/dlls/msvcp120/msvcp120.spec +++ b/dlls/msvcp120/msvcp120.spec @@ -1566,8 +1566,8 @@ @ cdecl -arch=win32 ?_Lockit_dtor@_Lockit@std@@CAXPAV12@@Z(ptr) _Lockit__Lockit_dtor @ cdecl -arch=win64 ?_Lockit_dtor@_Lockit@std@@CAXPEAV12@@Z(ptr) _Lockit__Lockit_dtor @ cdecl ?_Lockit_dtor@_Lockit@std@@SAXH@Z(long) _Lockit_free -@ stub -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z -@ stub -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z +@ cdecl -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z(str ptr) tr2_sys__Lstat +@ cdecl -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z(str ptr) tr2_sys__Lstat @ stub -arch=win32 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z @ stub -arch=win64 ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z @ stub -arch=win32 ?_MP_Add@std@@YAXQA_K_K@Z @@ -1718,8 +1718,8 @@ @ stub -arch=win64 ?_Src@?3??_Getffld@?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@AEBAHPEADAEAV?$istreambuf_iterator@GU?$char_traits@G@std@@@3@1AEAVios_base@3@PEAH@Z@4QBDB @ stub -arch=win32 ?_Src@?3??_Getffld@?$num_get@_WV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@ABAHPADAAV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@3@1AAVios_base@3@PAH@Z@4QBDB @ stub -arch=win64 ?_Src@?3??_Getffld@?$num_get@_WV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@AEBAHPEADAEAV?$istreambuf_iterator@_WU?$char_traits@_W@std@@@3@1AEAVios_base@3@PEAH@Z@4QBDB -@ stub -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z -@ stub -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z +@ cdecl -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z(str ptr) tr2_sys__Stat +@ cdecl -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z(str ptr) tr2_sys__Stat @ stub -arch=win32 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PB_WAAH@Z @ stub -arch=win64 ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEB_WAEAH@Z @ cdecl -arch=win32 ?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PBD@Z(str) tr2_sys__Statvfs diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c index bc7c69b..4340791 100644 --- a/dlls/msvcp120/tests/msvcp120.c +++ b/dlls/msvcp120/tests/msvcp120.c @@ -21,6 +21,7 @@ #include "wine/test.h" #include "winbase.h" +#include "ntifs.h" typedef int MSVCRT_long; typedef unsigned char MSVCP_bool; @@ -44,6 +45,12 @@ struct space_info { ULONGLONG available; }; +enum file_type { + status_unknown, file_not_found, regular_file, directory_file, + symlink_file, block_file, character_file, fifo_file, socket_file, + type_unknown +}; + static inline const char* debugstr_longlong(ULONGLONG ll) { static char string[17]; @@ -75,6 +82,8 @@ static MSVCP_bool (__cdecl *p_tr2_sys__Remove_dir)(char const*); static int (__cdecl *p_tr2_sys__Copy_file)(char const*, char const*, MSVCP_bool); static int (__cdecl *p_tr2_sys__Rename)(char const*, char const*); static struct space_info (__cdecl *p_tr2_sys__Statvfs)(char const*); +static enum file_type (__cdecl *p_tr2_sys__Stat)(char const*, int *); +static enum file_type (__cdecl *p_tr2_sys__Lstat)(char const*, int *); static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) @@ -121,6 +130,10 @@ static BOOL init(void) "?_Rename@sys@tr2@std@@YAHPEBD0@Z"); SET(p_tr2_sys__Statvfs, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PEBD@Z"); + SET(p_tr2_sys__Stat, + "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z"); + SET(p_tr2_sys__Lstat, + "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z"); } else { SET(p_tr2_sys__File_size, "?_File_size@sys@tr2@std@@YA_KPBD@Z"); @@ -140,6 +153,10 @@ static BOOL init(void) "?_Rename@sys@tr2@std@@YAHPBD0@Z"); SET(p_tr2_sys__Statvfs, "?_Statvfs@sys@tr2@std@@YA?AUspace_info@123@PBD@Z"); + SET(p_tr2_sys__Stat, + "?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z"); + SET(p_tr2_sys__Lstat, + "?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z"); } msvcr = GetModuleHandleA("msvcr120.dll"); @@ -707,6 +724,130 @@ static void test_tr2_sys__Statvfs(void) 0, debugstr_longlong(info.free)); } +static void test_tr2_sys__Stat(void) +{ + int i, err_code, len, ret, device_io_control_ret; + HANDLE file; + enum file_type val; + DWORD rec; + BYTE buf[sizeof(REPARSE_MOUNTPOINT_DATA_BUFFER) + MAX_PATH * sizeof(WCHAR)]; + REPARSE_MOUNTPOINT_DATA_BUFFER* ReparseBuffer; + struct { + char const *path; + enum file_type ret; + int err_code; + int is_todo; + } tests[] = { + { NULL, status_unknown, ERROR_INVALID_PARAMETER, FALSE }, + { "tr2_test_dir", directory_file, ERROR_SUCCESS, FALSE }, + { "tr2_test_dir\\f1", regular_file, ERROR_SUCCESS, FALSE }, + { "tr2_test_dir\\not_exist_file ", file_not_found, ERROR_SUCCESS, FALSE }, + { "tr2_test_dir\\??invalid_name>>", file_not_found, ERROR_SUCCESS, FALSE }, + { "tr2_test_dir\\f1_link" , regular_file, ERROR_SUCCESS, TRUE }, + { "tr2_test_dir\\dir_link", directory_file, ERROR_SUCCESS, TRUE }, + { "tr2_test_dir\\test_junction_dir", directory_file, ERROR_SUCCESS, FALSE }, + { "tr2_test_dir\\test_junction_file", regular_file, ERROR_SUCCESS, FALSE } + }; + + CreateDirectoryA("tr2_test_dir", NULL); + file = CreateFileA("tr2_test_dir/f1", 0, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); + ok(CloseHandle(file), "CloseHandle\n"); + SetLastError(0xdeadbeef); + ret = CreateSymbolicLinkA("tr2_test_dir/f1_link", "tr2_test_dir/f1", 0); + if(!ret && (GetLastError()==ERROR_PRIVILEGE_NOT_HELD||GetLastError()==ERROR_INVALID_FUNCTION)) { + tests[5].ret = tests[6].ret = file_not_found; + win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n"); + }else { + ok(ret, "CreateSymbolicLinkA failed\n"); + ok(CreateSymbolicLinkA("tr2_test_dir/dir_link", "tr2_test_dir", 1), "CreateSymbolicLinkA failed\n"); + } + + CreateDirectoryA("tr2_test_dir/test_junction_dir", NULL); + file = CreateFileA("tr2_test_dir/test_junction_dir", GENERIC_ALL, 0, NULL, OPEN_ALWAYS, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT , NULL); + ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); + memset(buf, 0, sizeof(buf)); + ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER*)buf; + ReparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + len = 10; + ReparseBuffer->ReparseTargetMaximumLength = (len--) * sizeof(WCHAR); + ReparseBuffer->ReparseTargetLength = len * sizeof(WCHAR); + ReparseBuffer->ReparseDataLength = ReparseBuffer->ReparseTargetLength + 12; + SetLastError(0xdeadbeef); + device_io_control_ret = DeviceIoControl(file, FSCTL_SET_REPARSE_POINT, ReparseBuffer, + ReparseBuffer->ReparseDataLength+REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &rec, NULL); + todo_wine ok(device_io_control_ret || GetLastError()==ERROR_INVALID_FUNCTION, + "expect success or ERROR_INVALID_FUNCTION, got %u\n", GetLastError()); + CloseHandle(file); + file = CreateFileA("tr2_test_dir/test_junction_file", GENERIC_ALL, 0, NULL, OPEN_ALWAYS, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT , NULL); + ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n"); + ReparseBuffer->ReparseTag = IO_REPARSE_TAG_SIS; + SetLastError(0xdeadbeef); + device_io_control_ret = DeviceIoControl(file, FSCTL_SET_REPARSE_POINT, ReparseBuffer, + ReparseBuffer->ReparseDataLength+REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &rec, NULL); + todo_wine ok(device_io_control_ret || GetLastError()==ERROR_INVALID_FUNCTION, + "expect success or ERROR_INVALID_FUNCTION, got %u\n", GetLastError()); + CloseHandle(file); + + file = CreateNamedPipeA("\\\\.\\PiPe\\tests_pipe.c", + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + err_code = 0xdeadbeef; + val = p_tr2_sys__Stat("\\\\.\\PiPe\\tests_pipe.c", &err_code); + todo_wine ok(regular_file == val, "tr2_sys__Stat(): expect: regular_file, got %d\n", val); + todo_wine ok(ERROR_SUCCESS == err_code, "tr2_sys__Stat(): err_code expect: ERROR_SUCCESS, got %d\n", err_code); + err_code = 0xdeadbeef; + val = p_tr2_sys__Lstat("\\\\.\\PiPe\\tests_pipe.c", &err_code); + ok(status_unknown == val, "tr2_sys__Lstat(): expect: status_unknown, got %d\n", val); + todo_wine ok(ERROR_PIPE_BUSY == err_code, "tr2_sys__Lstat(): err_code expect: ERROR_PIPE_BUSY, got %d\n", err_code); + ok(CloseHandle(file), "CloseHandle\n"); + file = CreateNamedPipeA("\\\\.\\PiPe\\tests_pipe.c", + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + err_code = 0xdeadbeef; + val = p_tr2_sys__Lstat("\\\\.\\PiPe\\tests_pipe.c", &err_code); + todo_wine ok(regular_file == val, "tr2_sys__Lstat(): expect: regular_file, got %d\n", val); + todo_wine ok(ERROR_SUCCESS == err_code, "tr2_sys__Lstat(): err_code expect: ERROR_SUCCESS, got %d\n", err_code); + ok(CloseHandle(file), "CloseHandle\n"); + + for(i=0; i= 100 #define VBTABLE_ALIGN 8 #else @@ -14333,6 +14339,47 @@ struct space_info __cdecl tr2_sys__Statvfs(const char* path) return info; } +/* ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z */ +/* ?_Stat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z */ +enum file_type tr2_sys__Stat(char const* path, int* err_code) +{ + DWORD attr; + TRACE("(%s %p)\n", debugstr_a(path), err_code); + if(!path) { + *err_code = ERROR_INVALID_PARAMETER; + return status_unknown; + } + + attr=GetFileAttributesA(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; + *err_code = ERROR_SUCCESS; + break; + default: + ret = status_unknown; + *err_code = GetLastError(); + } + return ret; + } + + *err_code = ERROR_SUCCESS; + return (attr & FILE_ATTRIBUTE_DIRECTORY)?directory_file:regular_file; +} + +/* ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PBDAAH@Z */ +/* ?_Lstat@sys@tr2@std@@YA?AW4file_type@123@PEBDAEAH@Z */ +enum file_type tr2_sys__Lstat(char const* path, int* err_code) +{ + return tr2_sys__Stat(path, err_code); +} + /* ??0strstream@std@@QAE@PADHH@Z */ /* ??0strstream@std@@QEAA@PEAD_JH@Z */ #if STREAMSIZE_BITS == 64