 
            -- v2: scrrun: Implement MoveFolder().
 
            From: Robert Wilhelm robert.wilhelm@gmx.net
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52128 --- dlls/scrrun/Makefile.in | 2 +- dlls/scrrun/filesystem.c | 83 ++++++++++++++++++++- dlls/scrrun/tests/filesystem.c | 130 +++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 5 deletions(-)
diff --git a/dlls/scrrun/Makefile.in b/dlls/scrrun/Makefile.in index 94395f52797..39147d837f2 100644 --- a/dlls/scrrun/Makefile.in +++ b/dlls/scrrun/Makefile.in @@ -1,6 +1,6 @@ MODULE = scrrun.dll IMPORTLIB = scrrun -IMPORTS = uuid oleaut32 version advapi32 +IMPORTS = uuid oleaut32 version advapi32 kernelbase
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index d174125ea91..ae6c583fd06 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -25,6 +25,7 @@
#include "windef.h" #include "winbase.h" +#include "pathcch.h" #include "ole2.h" #include "olectl.h" #include "dispex.h" @@ -3811,12 +3812,86 @@ static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR source, BSTR de return MoveFileW(source, destination) ? S_OK : create_error(GetLastError()); }
-static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source, - BSTR Destination) +static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface, BSTR src, BSTR dst) { - FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination)); + BOOL wildcard = FALSE, separator = FALSE, success = FALSE; + int src_len, dst_len, name_len; + WIN32_FIND_DATAW find_data; + HANDLE find; + BOOL ret;
- return E_NOTIMPL; + TRACE("%p %s %s\n", iface, debugstr_w(src), debugstr_w(dst)); + + if (!src || !src[0] || !dst || !dst[0]) + return E_INVALIDARG; + + src_len = SysStringLen(src); + if (src[src_len - 1] == '\' || src[src_len - 1] == '/') + return CTL_E_ILLEGALFUNCTIONCALL; + + if (wcspbrk(src, L"*?><")) + wildcard = TRUE; + + dst_len = SysStringLen(dst); + if (dst[dst_len - 1] == '\' || dst[dst_len - 1] == '/') + separator = TRUE; + + if (!wildcard && !separator) + { + /* Ensure that we open a directory by appending a slash. */ + WCHAR *src_copy = malloc((src_len + 2) * sizeof(WCHAR)); + + memcpy(src_copy, src, src_len * sizeof(WCHAR)); + wcscpy(src_copy + src_len, L"\"); + + ret = MoveFileW(src_copy, dst); + free(src_copy); + if (ret) + return S_OK; + if (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_FILE_NOT_FOUND) + return CTL_E_PATHNOTFOUND; + return create_error(GetLastError()); + } + + /* Back up to the slash if there is one. */ + while (src_len > 0 && src[src_len] != '/' && src[src_len] != '\') + --src_len; + + if ((find = FindFirstFileW(src, &find_data)) == INVALID_HANDLE_VALUE) + return create_error(GetLastError()); + + do + { + WCHAR *src_folder, *dst_folder; + + if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + name_len = wcslen(find_data.cFileName); + src_folder = malloc((src_len + name_len + 1) * sizeof(WCHAR)); + + if (src_len) + memcpy(src_folder, src, src_len * sizeof(WCHAR)); + memcpy(src_folder + src_len, find_data.cFileName, (name_len + 1) * sizeof(WCHAR)); + + PathAllocCombine(dst, find_data.cFileName, + PATHCCH_ALLOW_LONG_PATHS | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &dst_folder); + + ret = MoveFileW(src_folder, dst_folder); + free(src_folder); + LocalFree(dst_folder); + if (!ret) + { + FindClose(find); + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return CTL_E_PATHNOTFOUND; + return create_error(GetLastError()); + } + success = TRUE; + } while (FindNextFileW(find, &find_data)); + + FindClose(find); + return success ? S_OK : CTL_E_PATHNOTFOUND; }
static inline HRESULT copy_file(const WCHAR *source, DWORD source_len, diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index ea0d0925a42..5edf11824e0 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -2709,6 +2709,135 @@ static void test_MoveFile(void) SysFreeString(str); }
+static void test_MoveFolder(void) +{ + WCHAR temp_path[MAX_PATH], cwd[MAX_PATH]; + BSTR src, dst, empty; + HANDLE file; + HRESULT hr; + BOOL ret; + + GetCurrentDirectoryW(MAX_PATH, cwd); + GetTempPathW(MAX_PATH, temp_path); + SetCurrentDirectoryW(temp_path); + src = SysAllocString(L"winetest_src"); + dst = SysAllocString(L"winetest_dst"); + + ret = CreateDirectoryW(L"winetest_src", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_PATHNOTFOUND, "Got hr %#lx.\n", hr); + ret = CreateDirectoryW(L"winetest_src", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_FILEALREADYEXISTS, "Got hr %#lx.\n", hr); + ret = RemoveDirectoryW(L"winetest_dst"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_src"); + ok(ret, "Got error %lu.\n", GetLastError()); + + empty = SysAllocString(L""); + hr = IFileSystem3_MoveFolder(fs3, src, NULL); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = IFileSystem3_MoveFolder(fs3, NULL, dst); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = IFileSystem3_MoveFolder(fs3, src, empty); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = IFileSystem3_MoveFolder(fs3, empty, dst); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + SysFreeString(empty); + + file = CreateFileW(L"winetest_src", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "Got error %lu.\n", GetLastError()); + CloseHandle(file); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_PATHNOTFOUND, "Got hr %#lx.\n", hr); + ret = DeleteFileW(L"winetest_src"); + ok(ret, "Got error %lu.\n", GetLastError()); + + dst = SysAllocString(L"winetest_dst\"); + + ret = CreateDirectoryW(L"winetest_src", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_PATHNOTFOUND, "Got hr %#lx.\n", hr); + ret = CreateDirectoryW(L"winetest_dst", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = RemoveDirectoryW(L"winetest_dst\winetest_src"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_dst"); + ok(ret, "Got error %lu.\n", GetLastError()); + + src = SysAllocString(L"winetest_src\"); + dst = SysAllocString(L"winetest_dst"); + + ret = CreateDirectoryW(L"winetest_src", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "Got hr %#lx.\n", hr); + src = SysAllocString(L"winetest_src\"); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "Got hr %#lx.\n", hr); + + ret = RemoveDirectoryW(L"winetest_src"); + ok(ret, "Got error %lu.\n", GetLastError()); + + ret = CreateDirectoryW(L"winetest_src1", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = CreateDirectoryW(L"winetest_src2", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + file = CreateFileW(L"winetest_src3", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "Got error %lu.\n", GetLastError()); + CloseHandle(file); + + src = SysAllocString(L"winetest_src*"); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_PATHNOTFOUND, "Got hr %#lx.\n", hr); + ret = CreateDirectoryW(L"winetest_dst", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_PATHNOTFOUND, "Got hr %#lx.\n", hr); + ret = RemoveDirectoryW(L"winetest_dst/winetest_src1"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_dst/winetest_src2"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_dst"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = DeleteFileW(L"winetest_src3"); + ok(ret, "Got error %lu.\n", GetLastError()); + + /* Fail to copy one file. */ + ret = CreateDirectoryW(L"winetest_src1", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = CreateDirectoryW(L"winetest_src2", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = CreateDirectoryW(L"winetest_src3", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = CreateDirectoryW(L"winetest_dst", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = CreateDirectoryW(L"winetest_dst\winetest_src2", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + hr = IFileSystem3_MoveFolder(fs3, src, dst); + ok(hr == CTL_E_FILEALREADYEXISTS, "Got hr %#lx.\n", hr); + ret = RemoveDirectoryW(L"winetest_dst/winetest_src1"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_dst/winetest_src2"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_dst"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_src2"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"winetest_src3"); + ok(ret, "Got error %lu.\n", GetLastError()); +} + static void test_DoOpenPipeStream(void) { static const char testdata[] = "test"; @@ -2843,6 +2972,7 @@ START_TEST(filesystem) test_GetExtensionName(); test_GetSpecialFolder(); test_MoveFile(); + test_MoveFolder(); test_DoOpenPipeStream();
IFileSystem3_Release(fs3);

