Commit 72f96552 authored by Erich E. Hoover's avatar Erich E. Hoover Committed by Vitaly Lipatov

kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse points.

parent 488c3e26
......@@ -352,8 +352,16 @@ WCHAR * CDECL wine_get_dos_file_name( LPCSTR str )
*/
BOOLEAN WINAPI CreateSymbolicLinkA(LPCSTR link, LPCSTR target, DWORD flags)
{
FIXME("(%s %s %ld): stub\n", debugstr_a(link), debugstr_a(target), flags);
return TRUE;
WCHAR *linkW, *targetW;
BOOL ret;
if (!(linkW = FILE_name_AtoW( link, FALSE ))) return FALSE;
if (!(targetW = FILE_name_AtoW( target, TRUE ))) return FALSE;
ret = CreateSymbolicLinkW( linkW, targetW, flags );
HeapFree( GetProcessHeap(), 0, targetW );
return ret;
}
/*************************************************************************
......
......@@ -83,6 +83,9 @@ static NTSTATUS (WINAPI *pLdrGetDllPath)(LPCWSTR,ULONG,LPWSTR*,LPWSTR*);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3W)(const WCHAR *, char *, DWORD, BOOL *, BOOL *);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3A)(const char *, char *, DWORD, BOOL *, BOOL *);
/* Present in Vista+ */
static BOOL (WINAPI *pCreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD);
/* a structure to deal with wine todos somewhat cleanly */
typedef struct {
DWORD shortlen;
......@@ -2106,6 +2109,7 @@ static void init_pointers(void)
MAKEFUNC(SetDefaultDllDirectories);
MAKEFUNC(CheckNameLegalDOS8Dot3W);
MAKEFUNC(CheckNameLegalDOS8Dot3A);
MAKEFUNC(CreateSymbolicLinkW);
mod = GetModuleHandleA("ntdll.dll");
MAKEFUNC(LdrGetDllPath);
MAKEFUNC(RtlGetExePath);
......@@ -2692,6 +2696,95 @@ static void test_LdrGetDllPath(void)
SetEnvironmentVariableW( pathW, old_path );
}
static void test_CreateSymbolicLink(void)
{
static const WCHAR target_fileW[] = {'t','a','r','g','e','t','_','f','i','l','e',0};
static const WCHAR target_dirW[] = {'t','a','r','g','e','t','_','d','i','r',0};
static const WCHAR linkW[] = {'l','i','n','k',0};
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
static const WCHAR dotW[] = {'.',0};
WCHAR path[MAX_PATH], old_path[MAX_PATH], tmp[MAX_PATH];
DWORD dwLen, dwFlags;
TOKEN_PRIVILEGES tp;
HANDLE token;
LUID luid;
BOOL bret;
HANDLE h;
if (!pCreateSymbolicLinkW)
{
win_skip( "CreateSymbolicLink isn't available\n" );
return;
}
/* Create a temporary folder for the symlink tests */
GetTempFileNameW( dotW, fooW, 0, path );
DeleteFileW( path );
if (!CreateDirectoryW( path, NULL ))
{
win_skip("Unable to create a temporary reparse point directory.\n");
return;
}
GetCurrentDirectoryW( sizeof(old_path)/sizeof(WCHAR), old_path );
SetCurrentDirectoryW( path );
/* Check that the volume this folder is located on supports reparse points */
GetFullPathNameW( path, sizeof(tmp)/sizeof(WCHAR), tmp, NULL );
volW[0] = tmp[0];
GetVolumeInformationW( volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0 );
if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
{
skip("File system does not support reparse points.\n");
goto cleanup;
}
/* Establish permissions for symlink creation */
bret = OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &token );
ok(bret, "OpenProcessToken failed: %u\n", GetLastError());
bret = LookupPrivilegeValueA( NULL, "SeCreateSymbolicLinkPrivilege", &luid );
todo_wine ok(bret || broken(!bret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE) /* winxp */,
"LookupPrivilegeValue failed: %u\n", GetLastError());
if (bret)
{
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bret = AdjustTokenPrivileges( token, FALSE, &tp, 0, NULL, NULL );
ok(bret, "AdjustTokenPrivileges failed: %u\n", GetLastError());
}
if ((!bret && GetLastError() != ERROR_NO_SUCH_PRIVILEGE) || GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
win_skip("Insufficient permissions to perform symlink tests.\n");
goto cleanup;
}
/* Create a destination folder and file for symlinks to target */
bret = CreateDirectoryW( target_dirW, NULL );
ok(bret, "Failed to create symlink target directory.\n");
h = CreateFileW( target_fileW, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
ok(h != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n");
CloseHandle( h );
/* Create a directory symbolic link */
bret = CreateSymbolicLinkW( linkW, target_dirW, SYMBOLIC_LINK_FLAG_DIRECTORY );
ok(bret, "Failed to create directory symbolic link! (0x%x)\n", GetLastError());
bret = RemoveDirectoryW( linkW );
ok(bret, "Failed to remove directory symbolic link! (0x%x)\n", GetLastError());
/* Create a file symbolic link */
bret = CreateSymbolicLinkW( linkW, target_fileW, 0x0 );
ok(bret, "Failed to create file symbolic link! (0x%x)\n", GetLastError());
bret = DeleteFileW( linkW );
ok(bret, "Failed to remove file symbolic link! (0x%x)\n", GetLastError());
cleanup:
DeleteFileW( target_fileW );
RemoveDirectoryW( target_dirW );
SetCurrentDirectoryW( old_path );
RemoveDirectoryW( path );
}
START_TEST(path)
{
CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
......@@ -2721,4 +2814,5 @@ START_TEST(path)
test_RtlGetSearchPath();
test_RtlGetExePath();
test_LdrGetDllPath();
test_CreateSymbolicLink();
}
......@@ -38,6 +38,7 @@
#include "shlwapi.h"
#include "ddk/ntddk.h"
#include "ddk/ntddser.h"
#include "ntifs.h"
#include "kernelbase.h"
#include "wine/exception.h"
......@@ -946,10 +947,108 @@ done:
/*************************************************************************
* CreateSymbolicLinkW (kernelbase.@)
*/
BOOLEAN WINAPI /* DECLSPEC_HOTPATCH */ CreateSymbolicLinkW( LPCWSTR link, LPCWSTR target, DWORD flags )
BOOLEAN WINAPI DECLSPEC_HOTPATCH CreateSymbolicLinkW( const WCHAR *link, const WCHAR *target, DWORD flags )
{
FIXME( "(%s %s %ld): stub\n", debugstr_w(link), debugstr_w(target), flags );
return TRUE;
static INT struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]);
static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
INT buffer_size, data_size, string_len, prefix_len;
WCHAR *subst_dest, *print_dest, *string;
REPARSE_DATA_BUFFER *buffer;
LPWSTR target_path = NULL;
BOOL is_relative, is_dir;
int target_path_len = 0;
UNICODE_STRING nt_name;
BOOLEAN bret = FALSE;
NTSTATUS status;
HANDLE hlink;
DWORD dwret;
TRACE( "(%s %s %#lx)\n", debugstr_w(link), debugstr_w(target), flags );
is_relative = (RtlDetermineDosPathNameType_U( target ) == RELATIVE_PATH);
is_dir = (flags & SYMBOLIC_LINK_FLAG_DIRECTORY);
if (is_dir && !CreateDirectoryW( link, NULL ))
return FALSE;
hlink = CreateFileW( link, GENERIC_READ | GENERIC_WRITE, 0, 0,
is_dir ? OPEN_EXISTING : CREATE_NEW,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0 );
if (hlink == INVALID_HANDLE_VALUE)
goto cleanup;
if (is_relative)
{
UNICODE_STRING nt_path;
int len;
status = RtlDosPathNameToNtPathName_U_WithStatus( link, &nt_path, NULL, NULL );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
goto cleanup;
}
/* obtain the path of the link */
for (; nt_path.Length > 0; nt_path.Length -= sizeof(WCHAR))
{
WCHAR c = nt_path.Buffer[nt_path.Length/sizeof(WCHAR)];
if (c == '/' || c == '\\')
{
nt_path.Length += sizeof(WCHAR);
break;
}
}
/* append the target to the link path */
target_path_len = nt_path.Length / sizeof(WCHAR);
len = target_path_len + (lstrlenW( target ) + 1);
target_path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR) );
lstrcpynW( target_path, nt_path.Buffer, target_path_len+1 );
target_path[target_path_len+1] = 0;
lstrcatW( target_path, target );
RtlFreeUnicodeString( &nt_path );
}
else
target_path = (LPWSTR)target;
status = RtlDosPathNameToNtPathName_U_WithStatus( target_path, &nt_name, NULL, NULL );
if (status != STATUS_SUCCESS)
{
SetLastError( RtlNtStatusToDosError(status) );
goto cleanup;
}
if (is_relative && _wcsnicmp( target_path, nt_name.Buffer, target_path_len ) != 0)
{
SetLastError( RtlNtStatusToDosError(status) );
goto cleanup;
}
prefix_len = is_relative ? 0 : strlen("\\??\\");
string = &nt_name.Buffer[target_path_len];
string_len = lstrlenW( &string[prefix_len] );
data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
buffer_size = struct_size + data_size;
buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size );
buffer->ReparseTag = IO_REPARSE_TAG_SYMLINK;
buffer->ReparseDataLength = struct_size - header_size + data_size;
buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.Flags = is_relative ? SYMLINK_FLAG_RELATIVE : 0;
subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
lstrcpyW( subst_dest, string );
lstrcpyW( print_dest, &string[prefix_len] );
RtlFreeUnicodeString( &nt_name );
bret = DeviceIoControl( hlink, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_size, NULL, 0,
&dwret, 0 );
HeapFree( GetProcessHeap(), 0, buffer );
cleanup:
CloseHandle( hlink );
if (!bret)
{
if (is_dir)
RemoveDirectoryW( link );
else
DeleteFileW( link );
}
if (is_relative) HeapFree( GetProcessHeap(), 0, target_path );
return bret;
}
......
......@@ -1613,15 +1613,14 @@ static void test_tr2_sys__Stat(void)
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 },
{ NULL, status_unknown, ERROR_INVALID_PARAMETER },
{ "tr2_test_dir", directory_file, ERROR_SUCCESS },
{ "tr2_test_dir\\f1", regular_file, ERROR_SUCCESS },
{ "tr2_test_dir\\not_exist_file ", file_not_found, ERROR_SUCCESS },
{ "tr2_test_dir\\??invalid_name>>", file_not_found, ERROR_SUCCESS },
{ "tr2_test_dir\\f1_link" , regular_file, ERROR_SUCCESS },
{ "tr2_test_dir\\dir_link", directory_file, ERROR_SUCCESS },
};
CreateDirectoryA("tr2_test_dir", NULL);
......@@ -1664,16 +1663,14 @@ static void test_tr2_sys__Stat(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
err_code = 0xdeadbeef;
val = p_tr2_sys__Stat(tests[i].path, &err_code);
todo_wine_if(tests[i].is_todo)
ok(tests[i].ret == val, "tr2_sys__Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].ret == val, "tr2_sys__Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].err_code == err_code, "tr2_sys__Stat(): test %d err_code expect: %d, got %d\n",
i+1, tests[i].err_code, err_code);
/* test tr2_sys__Lstat */
err_code = 0xdeadbeef;
val = p_tr2_sys__Lstat(tests[i].path, &err_code);
todo_wine_if(tests[i].is_todo)
ok(tests[i].ret == val, "tr2_sys__Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].ret == val, "tr2_sys__Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].err_code == err_code, "tr2_sys__Lstat(): test %d err_code expect: %d, got %d\n",
i+1, tests[i].err_code, err_code);
}
......@@ -1688,8 +1685,8 @@ static void test_tr2_sys__Stat(void)
ok(ERROR_SUCCESS == err_code, "tr2_sys__Lstat_wchar(): err_code expect ERROR_SUCCESS, got %d\n", err_code);
if(ret) {
todo_wine ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
todo_wine ok(RemoveDirectoryA("tr2_test_dir/dir_link"), "expect tr2_test_dir/dir_link to exist\n");
ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
ok(RemoveDirectoryA("tr2_test_dir/dir_link"), "expect tr2_test_dir/dir_link to exist\n");
}
ok(DeleteFileA("tr2_test_dir/f1"), "expect tr2_test_dir/f1 to exist\n");
ok(RemoveDirectoryA("tr2_test_dir"), "expect tr2_test_dir to exist\n");
......@@ -1918,16 +1915,15 @@ static void test_tr2_sys__Symlink(void)
char const *existing_path;
char const *new_path;
int last_error;
MSVCP_bool is_todo;
} tests[] = {
{ "f1", "f1_link", ERROR_SUCCESS, FALSE },
{ "f1", "tr2_test_dir\\f1_link", ERROR_SUCCESS, FALSE },
{ "tr2_test_dir\\f1_link", "tr2_test_dir\\f1_link_link", ERROR_SUCCESS, FALSE },
{ "tr2_test_dir", "dir_link", ERROR_SUCCESS, FALSE },
{ NULL, "NULL_link", ERROR_INVALID_PARAMETER, FALSE },
{ "f1", NULL, ERROR_INVALID_PARAMETER, FALSE },
{ "not_exist", "not_exist_link", ERROR_SUCCESS, FALSE },
{ "f1", "not_exist_dir\\f1_link", ERROR_PATH_NOT_FOUND, TRUE }
{ "f1", "f1_link", ERROR_SUCCESS },
{ "f1", "tr2_test_dir\\f1_link", ERROR_SUCCESS },
{ "tr2_test_dir\\f1_link", "tr2_test_dir\\f1_link_link", ERROR_SUCCESS },
{ "tr2_test_dir", "dir_link", ERROR_SUCCESS },
{ NULL, "NULL_link", ERROR_INVALID_PARAMETER },
{ "f1", NULL, ERROR_INVALID_PARAMETER },
{ "not_exist", "not_exist_link", ERROR_SUCCESS },
{ "f1", "not_exist_dir\\f1_link", ERROR_PATH_NOT_FOUND }
};
ret = p_tr2_sys__Make_dir("tr2_test_dir");
......@@ -1952,18 +1948,17 @@ static void test_tr2_sys__Symlink(void)
}
ok(errno == 0xdeadbeef, "tr2_sys__Symlink(): test %d errno expect 0xdeadbeef, got %d\n", i+1, errno);
todo_wine_if(tests[i].is_todo)
ok(ret == tests[i].last_error, "tr2_sys__Symlink(): test %d expect: %d, got %d\n", i+1, tests[i].last_error, ret);
ok(ret == tests[i].last_error, "tr2_sys__Symlink(): test %d expect: %d, got %d\n", i+1, tests[i].last_error, ret);
if(ret == ERROR_SUCCESS)
ok(p_tr2_sys__File_size(tests[i].new_path) == 0, "tr2_sys__Symlink(): expect 0, got %s\n", wine_dbgstr_longlong(p_tr2_sys__File_size(tests[i].new_path)));
}
ok(DeleteFileA("f1"), "expect f1 to exist\n");
todo_wine ok(DeleteFileA("f1_link"), "expect f1_link to exist\n");
todo_wine ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
todo_wine ok(DeleteFileA("tr2_test_dir/f1_link_link"), "expect tr2_test_dir/f1_link_link to exist\n");
todo_wine ok(DeleteFileA("not_exist_link"), "expect not_exist_link to exist\n");
todo_wine ok(DeleteFileA("dir_link"), "expect dir_link to exist\n");
ok(DeleteFileA("f1_link"), "expect f1_link to exist\n");
ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
ok(DeleteFileA("tr2_test_dir/f1_link_link"), "expect tr2_test_dir/f1_link_link to exist\n");
ok(DeleteFileA("not_exist_link"), "expect not_exist_link to exist\n");
ok(DeleteFileA("dir_link"), "expect dir_link to exist\n");
ret = p_tr2_sys__Remove_dir("tr2_test_dir");
ok(ret == 1, "tr2_sys__Remove_dir(): expect 1 got %d\n", ret);
}
......@@ -1977,15 +1972,14 @@ static void test_tr2_sys__Unlink(void)
struct {
char const *path;
int last_error;
MSVCP_bool is_todo;
} tests[] = {
{ "tr2_test_dir\\f1_symlink", ERROR_SUCCESS, TRUE },
{ "tr2_test_dir\\f1_link", ERROR_SUCCESS, FALSE },
{ "tr2_test_dir\\f1", ERROR_SUCCESS, FALSE },
{ "tr2_test_dir", ERROR_ACCESS_DENIED, FALSE },
{ "not_exist", ERROR_FILE_NOT_FOUND, FALSE },
{ "not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND, FALSE },
{ NULL, ERROR_PATH_NOT_FOUND, FALSE }
{ "tr2_test_dir\\f1_symlink", ERROR_SUCCESS },
{ "tr2_test_dir\\f1_link", ERROR_SUCCESS },
{ "tr2_test_dir\\f1", ERROR_SUCCESS },
{ "tr2_test_dir", ERROR_ACCESS_DENIED },
{ "not_exist", ERROR_FILE_NOT_FOUND },
{ "not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND },
{ NULL, ERROR_PATH_NOT_FOUND }
};
GetCurrentDirectoryA(MAX_PATH, current_path);
......@@ -2014,9 +2008,8 @@ static void test_tr2_sys__Unlink(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = 0xdeadbeef;
ret = p_tr2_sys__Unlink(tests[i].path);
todo_wine_if(tests[i].is_todo)
ok(ret == tests[i].last_error, "tr2_sys__Unlink(): test %d expect: %d, got %d\n",
i+1, tests[i].last_error, ret);
ok(ret == tests[i].last_error, "tr2_sys__Unlink(): test %d expect: %d, got %d\n",
i+1, tests[i].last_error, ret);
ok(errno == 0xdeadbeef, "tr2_sys__Unlink(): test %d errno expect: 0xdeadbeef, got %d\n", i+1, ret);
}
......
......@@ -857,16 +857,15 @@ static void test_Stat(void)
WCHAR const *path;
enum file_type ret;
int perms;
int is_todo;
} tests[] = {
{ NULL, file_not_found, 0xdeadbeef, FALSE },
{ L"wine_test_dir", directory_file, 0777, FALSE },
{ L"wine_test_dir/f1", regular_file, 0777, FALSE },
{ L"wine_test_dir/f2", regular_file, 0555, FALSE },
{ L"wine_test_dir/ne", file_not_found, 0xdeadbeef, FALSE },
{ L"wine_test_dir\\??invalid_name>>", file_not_found, 0xdeadbeef, FALSE },
{ L"wine_test_dir\\f1_link", regular_file, 0777, TRUE },
{ L"wine_test_dir\\dir_link", directory_file, 0777, TRUE },
{ NULL, file_not_found, 0xdeadbeef },
{ L"wine_test_dir", directory_file, 0777 },
{ L"wine_test_dir/f1", regular_file, 0777 },
{ L"wine_test_dir/f2", regular_file, 0555 },
{ L"wine_test_dir/ne", file_not_found, 0xdeadbeef },
{ L"wine_test_dir\\??invalid_name>>", file_not_found, 0xdeadbeef },
{ L"wine_test_dir\\f1_link", regular_file, 0777 },
{ L"wine_test_dir\\dir_link", directory_file, 0777 },
};
GetCurrentDirectoryW(MAX_PATH, origin_path);
......@@ -924,26 +923,20 @@ static void test_Stat(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
perms = 0xdeadbeef;
val = p_Stat(tests[i].path, &perms);
todo_wine_if(tests[i].is_todo) {
ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].perms == perms, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
i+1, tests[i].perms, perms);
}
ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].perms == perms, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
i+1, tests[i].perms, perms);
val = p_Stat(tests[i].path, NULL);
todo_wine_if(tests[i].is_todo)
ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
/* test _Lstat */
perms = 0xdeadbeef;
val = p_Lstat(tests[i].path, &perms);
todo_wine_if(tests[i].is_todo) {
ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].perms == perms, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
i+1, tests[i].perms, perms);
}
ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].perms == perms, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
i+1, tests[i].perms, perms);
val = p_Lstat(tests[i].path, NULL);
todo_wine_if(tests[i].is_todo)
ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
}
GetSystemDirectoryW(sys_path, MAX_PATH);
......@@ -955,9 +948,9 @@ static void test_Stat(void)
ok(perms == expected_perms, "_Stat(): perms expect: 0%o, got 0%o\n", expected_perms, perms);
if(ret) {
todo_wine ok(DeleteFileW(L"wine_test_dir\\f1_link"),
ok(DeleteFileW(L"wine_test_dir\\f1_link"),
"expect wine_test_dir/f1_link to exist\n");
todo_wine ok(RemoveDirectoryW(L"wine_test_dir\\dir_link"),
ok(RemoveDirectoryW(L"wine_test_dir\\dir_link"),
"expect wine_test_dir/dir_link to exist\n");
}
ok(DeleteFileW(L"wine_test_dir/f1"), "expect wine_test_dir/f1 to exist\n");
......@@ -1076,15 +1069,14 @@ static void test_Unlink(void)
struct {
WCHAR const *path;
int last_error;
MSVCP_bool is_todo;
} tests[] = {
{ L"wine_test_dir\\f1_symlink", ERROR_SUCCESS, TRUE },
{ L"wine_test_dir\\f1_link", ERROR_SUCCESS, FALSE },
{ L"wine_test_dir\\f1", ERROR_SUCCESS, FALSE },
{ L"wine_test_dir", ERROR_ACCESS_DENIED, FALSE },
{ L"not_exist", ERROR_FILE_NOT_FOUND, FALSE },
{ L"not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND, FALSE },
{ NULL, ERROR_PATH_NOT_FOUND, FALSE }
{ L"wine_test_dir\\f1_symlink", ERROR_SUCCESS },
{ L"wine_test_dir\\f1_link", ERROR_SUCCESS },
{ L"wine_test_dir\\f1", ERROR_SUCCESS },
{ L"wine_test_dir", ERROR_ACCESS_DENIED },
{ L"not_exist", ERROR_FILE_NOT_FOUND },
{ L"not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND },
{ NULL, ERROR_PATH_NOT_FOUND }
};
GetCurrentDirectoryW(MAX_PATH, current_path);
......@@ -1113,9 +1105,8 @@ static void test_Unlink(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = 0xdeadbeef;
ret = p_Unlink(tests[i].path);
todo_wine_if(tests[i].is_todo)
ok(ret == tests[i].last_error, "_Unlink(): test %d expect: %d, got %d\n",
i+1, tests[i].last_error, ret);
ok(ret == tests[i].last_error, "_Unlink(): test %d expect: %d, got %d\n",
i+1, tests[i].last_error, ret);
ok(errno == 0xdeadbeef, "_Unlink(): test %d errno expect: 0xdeadbeef, got %d\n", i+1, ret);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment