Commit 686e46b4 authored by Andriy Palamarchuk's avatar Andriy Palamarchuk Committed by Alexandre Julliard

SHFileOperationA: improved, implemented FO_MOVE action, added more

conformance tests.
parent cb1f1454
......@@ -2,6 +2,7 @@
* SHFileOperation
*
* Copyright 2000 Juergen Schmied
* Copyright 2002 Andriy Palamarchuk
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -163,6 +164,28 @@ BOOL WINAPI Win32DeleteFile(LPSTR fName)
return TRUE;
}
/**************************************************************************
* SHELL_FileNamesMatch()
*
* Accepts two \0 delimited lists of the file names. Checks whether number of
* files in the both lists is the same.
*/
BOOL SHELL_FileNamesMatch(LPCSTR pszFiles1, LPCSTR pszFiles2)
{
while ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
(pszFiles2[strlen(pszFiles2) + 1] != '\0'))
{
pszFiles1 += strlen(pszFiles1) + 1;
pszFiles2 += strlen(pszFiles2) + 1;
}
return
((pszFiles1[strlen(pszFiles1) + 1] == '\0') &&
(pszFiles2[strlen(pszFiles2) + 1] == '\0')) ||
((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
(pszFiles2[strlen(pszFiles2) + 1] != '\0'));
}
/*************************************************************************
* SHFileOperationA [SHELL32.@]
*
......@@ -188,7 +211,9 @@ DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
lpFileOp->fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
lpFileOp->fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
switch(lpFileOp->wFunc) {
case FO_COPY: {
case FO_COPY:
case FO_MOVE:
{
/* establish when pTo is interpreted as the name of the destination file
* or the directory where the Fromfile should be copied to.
* This depends on:
......@@ -207,16 +232,40 @@ DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
*/
int multifrom = pFrom[strlen(pFrom) + 1] != '\0';
int destisdir = PathIsDirectoryA( pTo );
int copytodir = 0;
TRACE("File Copy:\n");
int todir = 0;
if (lpFileOp->wFunc == FO_COPY)
TRACE("File Copy:\n");
else
TRACE("File Move:\n");
if( destisdir ) {
if ( !((lpFileOp->fFlags & FOF_MULTIDESTFILES) && !multifrom))
copytodir = 1;
todir = 1;
} else {
if ( !(lpFileOp->fFlags & FOF_MULTIDESTFILES) && multifrom)
copytodir = 1;
todir = 1;
}
if ((pTo[strlen(pTo) + 1] != '\0') &&
!(lpFileOp->fFlags & FOF_MULTIDESTFILES))
{
WARN("Attempt to use multiple file names as a destination "
"without specifying FOF_MULTIDESTFILES\n");
return 1;
}
if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
!SHELL_FileNamesMatch(pTo, pFrom))
{
WARN("Attempt to use multiple file names as a destination "
"with mismatching number of files in the source and "
"destination lists\n");
return 1;
}
if ( copytodir ) {
if ( todir ) {
char szTempFrom[MAX_PATH];
char *fromfile;
int lenPTo;
if ( ! destisdir) {
......@@ -225,17 +274,71 @@ DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
}
lenPTo = strlen(pTo);
while(1) {
HANDLE hFind;
WIN32_FIND_DATAA wfd;
if(!pFrom[0]) break;
fromfile = PathFindFileNameA( pFrom);
pTempTo = HeapAlloc(GetProcessHeap(), 0, lenPTo + strlen(fromfile) + 2);
if (pTempTo) {
strcpy(pTempTo,pTo);
if(lenPTo && pTo[lenPTo] != '\\')
strcat(pTempTo,"\\");
strcat(pTempTo,fromfile);
TRACE(" From='%s' To='%s'\n", pFrom, pTempTo);
CopyFileA(pFrom, pTempTo, FALSE);
HeapFree(GetProcessHeap(), 0, pTempTo);
TRACE(" From Pattern='%s'\n", pFrom);
if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
{
do
{
if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
{
strcpy(szTempFrom, pFrom);
pTempTo = HeapAlloc(GetProcessHeap(), 0,
lenPTo + strlen(wfd.cFileName) + 5);
if (pTempTo) {
strcpy(pTempTo,pTo);
PathAddBackslashA(pTempTo);
strcat(pTempTo,wfd.cFileName);
fromfile = PathFindFileNameA(szTempFrom);
fromfile[0] = '\0';
PathAddBackslashA(szTempFrom);
strcat(szTempFrom, wfd.cFileName);
TRACE(" From='%s' To='%s'\n", szTempFrom, pTempTo);
if(lpFileOp->wFunc == FO_COPY)
{
if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
{
/* copy recursively */
if(!(lpFileOp->fFlags & FOF_FILESONLY))
{
SHFILEOPSTRUCTA shfo;
SHCreateDirectory(NULL,pTempTo);
PathAddBackslashA(szTempFrom);
strcat(szTempFrom, "*.*");
szTempFrom[strlen(szTempFrom) + 1] = '\0';
pTempTo[strlen(pTempTo) + 1] = '\0';
memcpy(&shfo, lpFileOp, sizeof(shfo));
shfo.pFrom = szTempFrom;
shfo.pTo = pTempTo;
SHFileOperationA(&shfo);
szTempFrom[strlen(szTempFrom) - 4] = '\0';
}
}
else
CopyFileA(szTempFrom, pTempTo, FALSE);
}
else
{
/* move file/directory */
MoveFileA(szTempFrom, pTempTo);
}
HeapFree(GetProcessHeap(), 0, pTempTo);
}
}
} while(FindNextFileA(hFind, &wfd));
FindClose(hFind);
}
else
{
/* can't find file with specified name */
break;
}
pFrom += strlen(pFrom) + 1;
}
......@@ -254,7 +357,10 @@ DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
SHCreateDirectory(NULL,pTempTo);
HeapFree(GetProcessHeap(), 0, pTempTo);
}
CopyFileA(pFrom, pTo, FALSE);
if (lpFileOp->wFunc == FO_COPY)
CopyFileA(pFrom, pTo, FALSE);
else
MoveFileA(pFrom, pTo);
pFrom += strlen(pFrom) + 1;
pTo += strlen(pTo) + 1;
......
......@@ -30,9 +30,11 @@ void createTestFile(CHAR *name)
{
HANDLE file;
DWORD written;
CHAR msg[MAX_PATH];
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, (HANDLE)NULL);
ok(file != INVALID_HANDLE_VALUE, "Failure to open file");
sprintf(msg, "Failure to open file %s", name);
ok(file != INVALID_HANDLE_VALUE, msg);
WriteFile(file, name, strlen(name), &written, NULL);
WriteFile(file, "\n", strlen("\n"), &written, NULL);
CloseHandle(file);
......@@ -51,6 +53,7 @@ void init_shfo_tests(void)
createTestFile(".\\test2.txt");
createTestFile(".\\test3.txt");
CreateDirectoryA(".\\test4.txt", NULL);
CreateDirectoryA(".\\testdir2", NULL);
}
/* cleans after tests */
......@@ -63,12 +66,19 @@ void clean_after_shfo_tests(void)
DeleteFileA(".\\test4.txt\\test2.txt");
DeleteFileA(".\\test4.txt\\test3.txt");
RemoveDirectoryA(".\\test4.txt");
DeleteFileA(".\\testdir2\\test1.txt");
DeleteFileA(".\\testdir2\\test2.txt");
DeleteFileA(".\\testdir2\\test3.txt");
DeleteFileA(".\\testdir2\\test4.txt\\test1.txt");
RemoveDirectoryA(".\\testdir2\\test4.txt");
RemoveDirectoryA(".\\testdir2");
}
/**
/*
puts into the specified buffer file names with current directory.
files - string with file names, separated by null characters. Ends on a double
null characters */
null characters
*/
void set_curr_dir_path(CHAR *buf, CHAR* files)
{
buf[0] = 0;
......@@ -110,7 +120,7 @@ void test_delete(void)
ok(!SHFileOperationA(&shfo), "Directory exists, but is not removed");
ok(file_exists(".\\test4.txt"), "Directory should not be removed");
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT;
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
ok(!SHFileOperationA(&shfo), "Directory removed");
ok(!file_exists(".\\test4.txt"), "Directory should be removed");
......@@ -135,7 +145,7 @@ void test_delete(void)
/* tests the FO_RENAME action */
void test_rename()
{
SHFILEOPSTRUCTA shfo;
SHFILEOPSTRUCTA shfo, shfo2;
CHAR from[MAX_PATH];
CHAR to[MAX_PATH];
......@@ -163,6 +173,14 @@ void test_rename()
ok(SHFileOperationA(&shfo), "Can't rename many files");
ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified ");
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
shfo2.fFlags |= FOF_MULTIDESTFILES;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(SHFileOperationA(&shfo2), "Can't rename many files");
ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified ");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
ok(!SHFileOperationA(&shfo), "Rename file");
......@@ -182,6 +200,176 @@ void test_rename()
ok(!SHFileOperationA(&shfo), "Rename dir back");
}
/* tests the FO_COPY action */
void test_copy(void)
{
SHFILEOPSTRUCTA shfo, shfo2;
CHAR from[MAX_PATH];
CHAR to[MAX_PATH];
FILEOP_FLAGS tmp_flags;
shfo.hwnd = (HANDLE)NULL;
shfo.wFunc = FO_COPY;
shfo.pFrom = from;
shfo.pTo = to;
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
shfo.hNameMappings = NULL;
shfo.lpszProgressTitle = NULL;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(SHFileOperationA(&shfo), "Can't copy many files");
ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
"specified as a target");
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
shfo2.fFlags |= FOF_MULTIDESTFILES;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(!SHFileOperationA(&shfo2), "Can't copy many files");
ok(file_exists(".\\test6.txt"), "The file is copied - many files are "
"specified as a target");
DeleteFileA(".\\test6.txt");
DeleteFileA(".\\test7.txt");
RemoveDirectoryA(".\\test8.txt");
/* number of sources do not correspond to number of targets */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
ok(SHFileOperationA(&shfo2), "Can't copy many files");
ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
"specified as a target");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are copied recursively");
ok(file_exists(".\\test4.txt\\test1.txt"), "The file is copied");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet");
ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet");
ok(!SHFileOperationA(&shfo), "Files and directories are copied to directory ");
ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied");
ok(file_exists(".\\testdir2\\test4.txt"), "The directory is copied");
ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied");
clean_after_shfo_tests();
init_shfo_tests();
shfo.fFlags |= FOF_FILESONLY;
ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet");
ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet");
ok(!SHFileOperationA(&shfo), "Files are copied to other directory ");
ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied");
ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is copied");
clean_after_shfo_tests();
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet");
ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet");
ok(!SHFileOperationA(&shfo), "Files are copied to other directory ");
ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied");
ok(file_exists(".\\testdir2\\test2.txt"), "The file is copied");
clean_after_shfo_tests();
init_shfo_tests();
tmp_flags = shfo.fFlags;
set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet");
ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet");
ok(!SHFileOperationA(&shfo), "Files are copied to other directory ");
ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied");
ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied");
shfo.fFlags = tmp_flags;
}
/* tests the FO_MOVE action */
void test_move(void)
{
SHFILEOPSTRUCTA shfo, shfo2;
CHAR from[MAX_PATH];
CHAR to[MAX_PATH];
shfo.hwnd = (HANDLE)NULL;
shfo.wFunc = FO_MOVE;
shfo.pFrom = from;
shfo.pTo = to;
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
shfo.hNameMappings = NULL;
shfo.lpszProgressTitle = NULL;
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are moved recursively");
ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not moved yet");
ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not moved yet");
ok(!SHFileOperationA(&shfo), "Files and directories are moved to directory ");
ok(file_exists(".\\testdir2\\test2.txt"), "The file is moved");
ok(file_exists(".\\testdir2\\test4.txt"), "The directory is moved");
ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved");
clean_after_shfo_tests();
init_shfo_tests();
memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
shfo2.fFlags |= FOF_MULTIDESTFILES;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(!SHFileOperationA(&shfo2), "Move many files");
ok(file_exists(".\\test6.txt"), "The file is moved - many files are "
"specified as a target");
DeleteFileA(".\\test6.txt");
DeleteFileA(".\\test7.txt");
RemoveDirectoryA(".\\test8.txt");
init_shfo_tests();
/* number of sources do not correspond to number of targets */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
ok(SHFileOperationA(&shfo2), "Can't move many files");
ok(!file_exists(".\\test6.txt"), "The file is not moved - many files are "
"specified as a target");
init_shfo_tests();
set_curr_dir_path(from, "test3.txt\0");
set_curr_dir_path(to, "test4.txt\\test1.txt\0");
ok(!SHFileOperationA(&shfo), "File is moved moving to other directory");
ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved");
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
ok(SHFileOperationA(&shfo), "Can not move many files");
ok(file_exists(".\\test1.txt"), "The file is not moved. Many files are specified ");
ok(file_exists(".\\test4.txt"), "The directory not is moved. Many files are specified ");
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
ok(!SHFileOperationA(&shfo), "Move file");
ok(!file_exists(".\\test1.txt"), "The file is moved");
ok(file_exists(".\\test6.txt"), "The file is moved ");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test1.txt\0");
ok(!SHFileOperationA(&shfo), "Move file back");
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test6.txt\0");
ok(!SHFileOperationA(&shfo), "Move dir");
ok(!file_exists(".\\test4.txt"), "The dir is moved");
ok(file_exists(".\\test6.txt"), "The dir is moved ");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test4.txt\0");
ok(!SHFileOperationA(&shfo), "Move dir back");
}
START_TEST(shlfileop)
{
clean_after_shfo_tests();
......@@ -193,4 +381,12 @@ START_TEST(shlfileop)
init_shfo_tests();
test_rename();
clean_after_shfo_tests();
init_shfo_tests();
test_copy();
clean_after_shfo_tests();
init_shfo_tests();
test_move();
clean_after_shfo_tests();
}
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