reactos/dll/win32/kernel32/file/move.c

797 lines
23 KiB
C
Raw Normal View History

/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/kernel32/file/file.c
* PURPOSE: Directory functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
* Gerhard W. Gruber (sparhawk_at_gmx.at)
* Dmitry Philippov (shedon@mail.ru)
* UPDATE HISTORY:
* Created 01/11/98
* DP (29/07/2006)
* Fix some bugs in the add_boot_rename_entry function
*/
/* INCLUDES *****************************************************************/
2003-01-15 Casper S. Hornstrup <chorns@users.sourceforge.net> * lib/kernel32/k32.h: New file. * lib/kernel32/makefile (TARGET_CFLAGS): Add -I./. (TARGET_PCH): Set to k32.h. * lib/kernel32/except/except.c: Use <k32.h>. * lib/kernel32/file/backup.c: Ditto. * lib/kernel32/file/cnotify.c: Ditto. * lib/kernel32/file/copy.c: Ditto. * lib/kernel32/file/create.c: Ditto. * lib/kernel32/file/curdir.c: Ditto. * lib/kernel32/file/delete.c: Ditto. * lib/kernel32/file/deviceio.c: Ditto. * lib/kernel32/file/dir.c: Ditto. * lib/kernel32/file/dosdev.c: Ditto. * lib/kernel32/file/file.c: Ditto. * lib/kernel32/file/find.c: Ditto. * lib/kernel32/file/iocompl.c: Ditto. * lib/kernel32/file/lfile.c: Ditto. * lib/kernel32/file/lock.c: Ditto. * lib/kernel32/file/mailslot.c: Ditto. * lib/kernel32/file/move.c: Ditto. * lib/kernel32/file/npipe.c: Ditto. * lib/kernel32/file/pipe.c: Ditto. * lib/kernel32/file/rw.c: Ditto. * lib/kernel32/file/tape.c: Ditto. * lib/kernel32/file/volume.c: Ditto. * lib/kernel32/mem/global.c: Ditto. * lib/kernel32/mem/heap.c: Ditto. * lib/kernel32/mem/isbad.c: Ditto. * lib/kernel32/mem/local.c: Ditto. * lib/kernel32/mem/procmem.c: Ditto. * lib/kernel32/mem/section.c: Ditto. * lib/kernel32/mem/virtual.c: Ditto. * lib/kernel32/misc/atom.c: Ditto. * lib/kernel32/misc/comm.c: Ditto. * lib/kernel32/misc/console.c: Ditto. * lib/kernel32/misc/debug.c: Ditto. * lib/kernel32/misc/dllmain.c: Ditto. * lib/kernel32/misc/env.c: Ditto. * lib/kernel32/misc/error.c: Ditto. * lib/kernel32/misc/handle.c: Ditto. * lib/kernel32/misc/ldr.c: Ditto. * lib/kernel32/misc/profile.c: Ditto. * lib/kernel32/misc/res.c: Ditto. * lib/kernel32/misc/stubs.c: Ditto. * lib/kernel32/misc/sysinfo.c: Ditto. * lib/kernel32/misc/time.c: Ditto. * lib/kernel32/process/cmdline.c: Ditto. * lib/kernel32/process/create.c: Ditto. * lib/kernel32/process/proc.c: Ditto. * lib/kernel32/process/session.c: Ditto. * lib/kernel32/string/lstring.c: Ditto. * lib/kernel32/synch/critical.c: Ditto. * lib/kernel32/synch/event.c: Ditto. * lib/kernel32/synch/intrlck.c: Ditto. * lib/kernel32/synch/mutex.c: Ditto. * lib/kernel32/synch/sem.c: Ditto. * lib/kernel32/synch/timer.c: Ditto. * lib/kernel32/synch/wait.c: Ditto. * lib/kernel32/thread/fiber.c: Ditto. * lib/kernel32/thread/thread.c: Ditto. * lib/kernel32/thread/tls.c: Ditto. svn path=/trunk/; revision=4009
2003-01-15 21:24:36 +00:00
#include <k32.h>
#include <malloc.h>
[KERNEL32]: While working on the CMAKE branch, Amine and myself discovered a rather serious issue in kernel32 (and perhaps other libraries as well). Unlike rbuild, CMake does not allow you to export non-existant DLL functions (try it: add "poopyhead" in kernel32's exports under RBuild, and will it export "poopyhead", God knowing what that will actually link to). As an additional feature on top of the "allow non-existing functions to be exported" "feature", because rbuild generates and links STDCALL function names without the proper decoration (vs. enforcing decoration at linking, but only removing it at export-time), this allows the definition (as an export) of a STDCALL function that is completely different from the actual function itself. For example, the 5-parameter Foo function is normally Foo@20, while the 3-parameter Foo function woudl be Foo@12. Linking one against the other would fail (say, 2 parameters were added to Foo in a newer version). However, under RBUILD, both of these would appear as "Foo", and the linker/compiler would happilly connect the caller of Foo@3 (that has pushed 3 parameters) to the receiving side of Foo@5 (that is about to pop 5 parameters). Even -if- decorations WERE to be applied, Foo@12 would STILL succeed, because of the first feature, which would enable the export of Foo@12 even though no such function exist. In a further, bizare, twist of fate, the behavior of this RBUILD "feature", when the target function is not found, is to link the exported DLL TO ITSELF. Therefore, one can see how, previously to this patch, kernel32.dll would import a dozen functions from itself (all the non-existing functions). To really seal the deal, the behavior of exported functions used by kernel32, but that are actually forwarded to another DLL deserves a special mention. GetLastError, for example, merely forwards to RtlGetLastWin32Error, so it is normal behavior to use a #define in the C code so that all internal calls to the function are routed correctly. This did not happen, so instead, kernel32 tried importing/linking/exporting GetLastError, but this symbol is not found in the binary, because it is only a forwarder. This caused kernel32 to import from itself (the behavior when an exported symbol is not found). When importing from itself, the loader would now find the _forwarded_ for GetLastError, and correctly link with ntdll. What should be a one-liner of assembly (inline TEB access) thus became a triple-call indirection (GetLastError@0->StubLastError@0->__impGetLastError@0->__impRtlGetLastWin32Error->RtlGetLastWin32Error. While analyzing these issues, we also realized a strange macro SetLastErrorByStatus that manually tried to perform what there already exists a function for: RtlSetLastNtStatusFromWin32Error. And, in an exciting coda, we also realized that our Server 2003 Kernel32 exports more than a dozen Windows 95 APIs, through an auto-stub generation mechanism within winebuild, that gets linked as an object behind the scenes. [KERNEL32]: Removed all Win95 exports, cleaned up exports. [KERNEL32]: Fixed up set/get error macros by making them inline and/or calling the correct ntdll function. [KERNEL32]: Removed bizare calls to Wine-internal/specific APIs from our core Win32 DLL. [KERNEL32]: Wrote stubs for all functions which should be exported, and set the correct number of parameters for them. [KERNEL32]: Kernel32 is smaller, loads faster, does not export Windows 95 functions, does not export non-existing functions, and does not import from itself anymore. Note: This is one of the many failings of RBUILD the CMAKE system has helped us discover. I believe these issues are serious enough to warrant an immediate sync with trunk, but rest assured, there are many more completely broken, infinitely-regressing things that we discovered while switching to CMAKE. svn path=/trunk/; revision=48475
2010-08-07 05:02:58 +00:00
#define NDEBUG
#include <debug.h>
DEBUG_CHANNEL(kernel32file);
/* GLOBALS *****************************************************************/
/* FUNCTIONS ****************************************************************/
static BOOL
RemoveReadOnlyAttributeW(IN LPCWSTR lpFileName)
{
DWORD Attributes;
Attributes = GetFileAttributesW(lpFileName);
if (Attributes != INVALID_FILE_ATTRIBUTES)
{
return SetFileAttributesW(lpFileName,Attributes -
(Attributes & ~FILE_ATTRIBUTE_READONLY));
}
return FALSE;
}
/***********************************************************************
* add_boot_rename_entry
*
* Adds an entry to the registry that is loaded when windows boots and
* checks if there are some files to be removed or renamed/moved.
* <fn1> has to be valid and <fn2> may be NULL. If both pointers are
* non-NULL then the file is moved, otherwise it is deleted. The
* entry of the registrykey is always appended with two zero
* terminated strings. If <fn2> is NULL then the second entry is
* simply a single 0-byte. Otherwise the second filename goes
* there. The entries are prepended with \??\ before the path and the
* second filename gets also a '!' as the first character if
* MOVEFILE_REPLACE_EXISTING is set. After the final string another
* 0-byte follows to indicate the end of the strings.
* i.e.:
* \??\D:\test\file1[0]
* !\??\D:\test\file1_renamed[0]
* \??\D:\Test|delete[0]
* [0] <- file is to be deleted, second string empty
* \??\D:\test\file2[0]
* !\??\D:\test\file2_renamed[0]
* [0] <- indicates end of strings
*
* or:
* \??\D:\test\file1[0]
* !\??\D:\test\file1_renamed[0]
* \??\D:\Test|delete[0]
* [0] <- file is to be deleted, second string empty
* [0] <- indicates end of strings
*
*/
static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
{
static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
'F','i','l','e','R','e','n','a','m','e',
'O','p','e','r','a','t','i','o','n','s',0};
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING nameW, source_name, dest_name;
KEY_VALUE_PARTIAL_INFORMATION *info;
BOOL rc = FALSE;
HANDLE Reboot = NULL;
DWORD len1, len2;
DWORD DestLen = 0;
DWORD DataSize = 0;
BYTE *Buffer = NULL;
WCHAR *p;
NTSTATUS Status;
TRACE("add_boot_rename_entry( %S, %S, %d ) \n", source, dest, flags);
if(dest)
DestLen = wcslen(dest);
if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
{
SetLastError( ERROR_PATH_NOT_FOUND );
return FALSE;
}
dest_name.Buffer = NULL;
if (DestLen && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
{
RtlFreeHeap( RtlGetProcessHeap(), 0, source_name.Buffer );
SetLastError( ERROR_PATH_NOT_FOUND );
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&Reboot,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (Status == STATUS_ACCESS_DENIED)
{
Status = NtCreateKey(
&Reboot,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
NULL);
}
if (!NT_SUCCESS(Status))
{
WARN("NtCreateKey() failed (Status 0x%lx)\n", Status);
if (source_name.Buffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
if (dest_name.Buffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
return FALSE;
}
len1 = source_name.Length + sizeof(WCHAR);
if (DestLen)
{
len2 = dest_name.Length + sizeof(WCHAR);
if (flags & MOVEFILE_REPLACE_EXISTING)
len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
}
else
{
len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
}
RtlInitUnicodeString( &nameW, ValueName );
/* First we check if the key exists and if so how many bytes it already contains. */
Status = NtQueryValueKey(
Reboot,
&nameW,
KeyValuePartialInformation,
NULL,
0,
&DataSize );
if ((Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_BUFFER_TOO_SMALL))
{
if (!(Buffer = HeapAlloc(GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR))))
goto Quit;
Status = NtQueryValueKey(Reboot, &nameW, KeyValuePartialInformation,
Buffer, DataSize, &DataSize);
if(!NT_SUCCESS(Status))
goto Quit;
info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
if (info->Type != REG_MULTI_SZ) goto Quit;
if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
}
else
{
DataSize = info_size;
if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
goto Quit;
}
memcpy( Buffer + DataSize, source_name.Buffer, len1 );
DataSize += len1;
p = (WCHAR *)(Buffer + DataSize);
if (DestLen)
{
if (flags & MOVEFILE_REPLACE_EXISTING)
*p++ = '!';
memcpy( p, dest_name.Buffer, len2 );
DataSize += len2;
}
else
{
*p = 0;
DataSize += sizeof(WCHAR);
}
/* add final null */
p = (WCHAR *)(Buffer + DataSize);
*p = 0;
DataSize += sizeof(WCHAR);
rc = NT_SUCCESS(NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size));
Quit:
RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
if (dest_name.Buffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
NtClose(Reboot);
if(Buffer)
HeapFree(GetProcessHeap(), 0, Buffer);
return(rc);
}
2003-07-10 Casper S. Hornstrup <chorns@users.sourceforge.net> * lib/kernel32/debug/break.c: Add @implemented and @unimplemented to APIs. * lib/kernel32/debug/debugger.c: Ditto. * lib/kernel32/debug/output.c: Ditto. * lib/kernel32/except/except.c: Ditto. * lib/kernel32/file/backup.c: Ditto. * lib/kernel32/file/cnotify.c: Ditto. * lib/kernel32/file/copy.c: Ditto. * lib/kernel32/file/create.c: Ditto. * lib/kernel32/file/curdir.c: Ditto. * lib/kernel32/file/delete.c: Ditto. * lib/kernel32/file/deviceio.c: Ditto. * lib/kernel32/file/dir.c: Ditto. * lib/kernel32/file/dosdev.c: Ditto. * lib/kernel32/file/file.c: Ditto. * lib/kernel32/file/find.c: Ditto. * lib/kernel32/file/iocompl.c: Ditto. * lib/kernel32/file/lfile.c: Ditto. * lib/kernel32/file/lock.c: Ditto. * lib/kernel32/file/mailslot.c: Ditto. * lib/kernel32/file/move.c: Ditto. * lib/kernel32/file/npipe.c: Ditto. * lib/kernel32/file/pipe.c: Ditto. * lib/kernel32/file/rw.c: Ditto. * lib/kernel32/file/tape.c: Ditto. * lib/kernel32/file/volume.c: Ditto. * lib/kernel32/mem/global.c: Ditto. * lib/kernel32/mem/heap.c: Ditto. * lib/kernel32/mem/isbad.c: Ditto. * lib/kernel32/mem/local.c: Ditto. * lib/kernel32/mem/procmem.c: Ditto. * lib/kernel32/mem/section.c: Ditto. * lib/kernel32/mem/virtual.c: Ditto. * lib/kernel32/misc/atom.c: Ditto. * lib/kernel32/misc/comm.c: Ditto. * lib/kernel32/misc/computername.c: Ditto. * lib/kernel32/misc/console.c: Ditto. * lib/kernel32/misc/env.c: Ditto. * lib/kernel32/misc/error.c: Ditto. * lib/kernel32/misc/errormsg.c: Ditto. * lib/kernel32/misc/handle.c: Ditto. * lib/kernel32/misc/ldr.c: Ditto. * lib/kernel32/misc/mbchars.c: Ditto. * lib/kernel32/misc/muldiv.c: Ditto. * lib/kernel32/misc/perfcnt.c: Ditto. * lib/kernel32/misc/profile.c: Ditto. * lib/kernel32/misc/res.c: Ditto. * lib/kernel32/misc/stubs.c: Ditto. * lib/kernel32/misc/sysinfo.c: Ditto. * lib/kernel32/misc/time.c: Ditto. * lib/kernel32/misc/toolhelp.c: Ditto. * lib/kernel32/process/cmdline.c: Ditto. * lib/kernel32/process/create.c: Ditto. * lib/kernel32/process/proc.c: Ditto. * lib/kernel32/process/session.c: Ditto. * lib/kernel32/string/lstring.c: Ditto. * lib/kernel32/synch/critical.c: Ditto. * lib/kernel32/synch/event.c: Ditto. * lib/kernel32/synch/intrlck.c: Ditto. * lib/kernel32/synch/mutex.c: Ditto. * lib/kernel32/synch/sem.c: Ditto. * lib/kernel32/synch/timer.c: Ditto. * lib/kernel32/synch/wait.c: Ditto. * lib/kernel32/thread/fiber.c: Ditto. * lib/kernel32/thread/fls.c: Ditto. * lib/kernel32/thread/thread.c: Ditto. * lib/kernel32/thread/tls.c: Ditto. svn path=/trunk/; revision=5045
2003-07-10 18:50:51 +00:00
/*
* @implemented
*/
BOOL
WINAPI
MoveFileWithProgressW (
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
LPPROGRESS_ROUTINE lpProgressRoutine,
LPVOID lpData,
DWORD dwFlags
)
{
HANDLE hFile = NULL, hNewFile = NULL;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PFILE_RENAME_INFORMATION FileRename;
NTSTATUS errCode;
BOOL Result;
UNICODE_STRING DstPathU;
BOOL folder = FALSE;
TRACE("MoveFileWithProgressW()\n");
if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)
return add_boot_rename_entry( lpExistingFileName, lpNewFileName, dwFlags );
// if (dwFlags & MOVEFILE_WRITE_THROUGH)
// FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");
if (!lpNewFileName)
return DeleteFileW(lpExistingFileName);
/* validate & translate the filename */
if (!RtlDosPathNameToNtPathName_U (lpNewFileName,
&DstPathU,
NULL,
NULL))
{
WARN("Invalid destination path\n");
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&DstPathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
errCode = NtOpenFile( &hNewFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0) );
if (NT_SUCCESS(errCode)) /* Destination exists */
{
NtClose(hNewFile);
if (!(dwFlags & MOVEFILE_REPLACE_EXISTING))
{
SetLastError(ERROR_ALREADY_EXISTS);
return FALSE;
}
else if (GetFileAttributesW(lpNewFileName) & FILE_ATTRIBUTE_DIRECTORY)
{
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
}
hFile = CreateFileW (lpExistingFileName,
GENERIC_ALL,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_FLAG_WRITE_THROUGH : 0),
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
FileRename = RtlAllocateHeap(
RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length);
if( !FileRename ) {
CloseHandle(hFile);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
if( dwFlags & MOVEFILE_REPLACE_EXISTING ) {
FileRename->ReplaceIfExists = TRUE;
}
else {
FileRename->ReplaceIfExists = FALSE;
}
memcpy(FileRename->FileName, DstPathU.Buffer, DstPathU.Length);
RtlFreeHeap (RtlGetProcessHeap (),
0,
DstPathU.Buffer);
FileRename->FileNameLength = DstPathU.Length;
errCode = NtSetInformationFile (hFile,
&IoStatusBlock,
FileRename,
sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length,
FileRenameInformation);
CloseHandle(hFile);
RtlFreeHeap(RtlGetProcessHeap(), 0, FileRename);
if (GetFileAttributesW(lpExistingFileName) & FILE_ATTRIBUTE_DIRECTORY)
{
folder = TRUE;
}
/*
* FIXME:
* Fail now move the folder
* Before we fail at CreateFileW
*/
if (NT_SUCCESS(errCode))
{
Result = TRUE;
}
else
{
if (folder==FALSE)
{
Result = CopyFileExW (lpExistingFileName,
lpNewFileName,
lpProgressRoutine,
lpData,
NULL,
(dwFlags & MOVEFILE_REPLACE_EXISTING) ? 0 : COPY_FILE_FAIL_IF_EXISTS);
if (Result)
{
/* Cleanup the source file */
Result = DeleteFileW (lpExistingFileName);
}
}
else
{
/* move folder code start */
WIN32_FIND_DATAW findBuffer;
LPWSTR lpExistingFileName2 = NULL;
LPWSTR lpNewFileName2 = NULL;
LPWSTR lpDeleteFile = NULL;
INT size;
INT size2;
BOOL loop = TRUE;
BOOL Result = FALSE;
INT max_size = MAX_PATH;
/* Build the string */
size = wcslen(lpExistingFileName);
if (size+6> max_size)
max_size = size + 6;
lpDeleteFile = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
if (lpDeleteFile == NULL)
return FALSE;
lpNewFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
if (lpNewFileName2 == NULL)
{
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
lpExistingFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
if (lpExistingFileName2 == NULL)
{
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
wcscpy( (WCHAR *)lpExistingFileName2,lpExistingFileName);
wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\\*.*\0");
/* Get the file name */
memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
if (hFile == NULL)
loop=FALSE;
if (findBuffer.cFileName[0] == L'\0')
loop=FALSE;
/* FIXME
* remove readonly flag from source folder and do not set the readonly flag to dest folder
*/
RemoveReadOnlyAttributeW(lpExistingFileName);
RemoveReadOnlyAttributeW(lpNewFileName);
//CreateDirectoryExW(lpExistingFileName,lpNewFileName,NULL);
CreateDirectoryW(lpNewFileName, NULL);
/* search the files/folders and move them */
while (loop==TRUE)
{
Result = TRUE;
if ((!wcscmp(findBuffer.cFileName,L"..")) || (!wcscmp(findBuffer.cFileName,L".")))
{
loop = FindNextFileW(hFile, &findBuffer);
if (!loop)
{
size = wcslen(lpExistingFileName2)-4;
FindClose(hFile);
wcscpy( &lpExistingFileName2[size],L"\0");
if (wcsncmp(lpExistingFileName,lpExistingFileName2,size))
{
DWORD Attributes;
FindClose(hFile);
/* delete folder */
TRACE("MoveFileWithProgressW : Delete folder : %S\n",lpDeleteFile);
/* remove system folder flag other wise we can not delete the folder */
Attributes = GetFileAttributesW(lpExistingFileName2);
if (Attributes != INVALID_FILE_ATTRIBUTES)
{
SetFileAttributesW(lpExistingFileName2,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
}
RemoveReadOnlyAttributeW(lpExistingFileName2);
Result = RemoveDirectoryW(lpExistingFileName2);
if (Result == FALSE)
break;
loop=TRUE;
size = wcslen(lpExistingFileName);
if (size+6>max_size)
{
if (lpNewFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
if (lpExistingFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
if (lpDeleteFile != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
wcscpy( lpExistingFileName2,lpExistingFileName);
wcscpy( &lpExistingFileName2[size],L"\\*.*\0");
/* Get the file name */
memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
}
}
continue;
}
if (findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
/* Build the new src string */
size = wcslen(findBuffer.cFileName);
size2= wcslen(lpExistingFileName2);
if (size2+size+6>max_size)
{
FindClose(hFile);
if (lpNewFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
if (lpExistingFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
if (lpDeleteFile != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
wcscpy( &lpExistingFileName2[size2-3],findBuffer.cFileName);
wcscpy( &lpExistingFileName2[size2+size-3],L"\0");
/* Continue */
wcscpy( lpDeleteFile,lpExistingFileName2);
wcscpy( &lpExistingFileName2[size2+size-3],L"\\*.*\0");
/* Build the new dst string */
size = wcslen(lpExistingFileName2) + wcslen(lpNewFileName);
size2 = wcslen(lpExistingFileName);
if (size>max_size)
{
FindClose(hFile);
if (lpNewFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
if (lpExistingFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
if (lpDeleteFile != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
wcscpy( lpNewFileName2,lpNewFileName);
size = wcslen(lpNewFileName);
wcscpy( &lpNewFileName2[size], &lpExistingFileName2[size2]);
size = wcslen(lpNewFileName2);
wcscpy( &lpNewFileName2[size-4],L"\0");
/* Create Folder */
/* FIXME
* remove readonly flag from source folder and do not set the readonly flag to dest folder
*/
RemoveReadOnlyAttributeW(lpDeleteFile);
RemoveReadOnlyAttributeW(lpNewFileName2);
CreateDirectoryW(lpNewFileName2,NULL);
//CreateDirectoryExW(lpDeleteFile, lpNewFileName2,NULL);
/* set new search path from src string */
FindClose(hFile);
memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
}
else
{
/* Build the new string */
size = wcslen(findBuffer.cFileName);
size2= wcslen(lpExistingFileName2);
wcscpy( lpDeleteFile,lpExistingFileName2);
wcscpy( &lpDeleteFile[size2-3],findBuffer.cFileName);
/* Build dest string */
size = wcslen(lpDeleteFile) + wcslen(lpNewFileName);
size2 = wcslen(lpExistingFileName);
if (size>max_size)
{
FindClose(hFile);
if (lpNewFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
if (lpExistingFileName2 != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
if (lpDeleteFile != NULL)
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
return FALSE;
}
wcscpy( lpNewFileName2,lpNewFileName);
size = wcslen(lpNewFileName);
wcscpy(&lpNewFileName2[size],&lpDeleteFile[size2]);
/* overrite existsen file, if the file got the flag have readonly
* we need reomve that flag
*/
/* copy file */
TRACE("MoveFileWithProgressW : Copy file : %S to %S\n",lpDeleteFile, lpNewFileName2);
RemoveReadOnlyAttributeW(lpDeleteFile);
RemoveReadOnlyAttributeW(lpNewFileName2);
Result = CopyFileExW (lpDeleteFile,
lpNewFileName2,
lpProgressRoutine,
lpData,
NULL,
0);
if (Result == FALSE)
break;
/* delete file */
TRACE("MoveFileWithProgressW : remove readonly flag from file : %S\n",lpNewFileName2);
Result = RemoveReadOnlyAttributeW(lpDeleteFile);
if (Result == FALSE)
break;
TRACE("MoveFileWithProgressW : Delete file : %S\n",lpDeleteFile);
Result = DeleteFileW(lpDeleteFile);
if (Result == FALSE)
break;
}
loop = FindNextFileW(hFile, &findBuffer);
}
/* Remove last folder */
if ((loop == FALSE) && (Result != FALSE))
{
DWORD Attributes;
Attributes = GetFileAttributesW(lpDeleteFile);
if (Attributes != INVALID_FILE_ATTRIBUTES)
{
SetFileAttributesW(lpDeleteFile,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
}
Result = RemoveDirectoryW(lpExistingFileName);
}
/* Cleanup */
FindClose(hFile);
if (lpNewFileName2 != NULL)
{
HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
lpNewFileName2 = NULL;
}
if (lpExistingFileName2 != NULL)
{
HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
lpExistingFileName2 = NULL;
}
if (lpDeleteFile != NULL)
{
HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
lpDeleteFile = NULL;
}
return Result;
// end move folder code
}
}
return Result;
}
/*
* @implemented
*/
BOOL
WINAPI
MoveFileWithProgressA (
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName,
LPPROGRESS_ROUTINE lpProgressRoutine,
LPVOID lpData,
DWORD dwFlags
)
{
PWCHAR ExistingFileNameW;
PWCHAR NewFileNameW;
BOOL ret;
if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, FALSE)))
return FALSE;
if (!(NewFileNameW= FilenameA2W(lpNewFileName, TRUE)))
return FALSE;
ret = MoveFileWithProgressW (ExistingFileNameW ,
NewFileNameW,
lpProgressRoutine,
lpData,
dwFlags);
RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW);
return ret;
}
/*
* @implemented
*/
BOOL
WINAPI
MoveFileW (
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName
)
{
return MoveFileExW (lpExistingFileName,
lpNewFileName,
MOVEFILE_COPY_ALLOWED);
}
/*
* @implemented
*/
BOOL
WINAPI
MoveFileExW (
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
DWORD dwFlags
)
{
return MoveFileWithProgressW (lpExistingFileName,
lpNewFileName,
NULL,
NULL,
dwFlags);
}
/*
* @implemented
*/
BOOL
WINAPI
MoveFileA (
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName
)
{
return MoveFileExA (lpExistingFileName,
lpNewFileName,
MOVEFILE_COPY_ALLOWED);
}
/*
* @implemented
*/
BOOL
WINAPI
MoveFileExA (
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName,
DWORD dwFlags
)
{
return MoveFileWithProgressA (lpExistingFileName,
lpNewFileName,
NULL,
NULL,
dwFlags);
}
/* EOF */