Remove the unneeded $Id$ blabla from the source code. (Part 8/8) Done !!
[reactos.git] / reactos / dll / win32 / kernel32 / client / file / move.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/file.c
5 * PURPOSE: Directory functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Gerhard W. Gruber (sparhawk_at_gmx.at)
8 * Dmitry Philippov (shedon@mail.ru)
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 * DP (29/07/2006)
12 * Fix some bugs in the add_boot_rename_entry function
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 #include <k32.h>
18 #include <malloc.h>
19 #define NDEBUG
20 #include <debug.h>
21 DEBUG_CHANNEL(kernel32file);
22
23 /* GLOBALS *****************************************************************/
24
25 /* FUNCTIONS ****************************************************************/
26 static BOOL
27 RemoveReadOnlyAttributeW(IN LPCWSTR lpFileName)
28 {
29 DWORD Attributes;
30 Attributes = GetFileAttributesW(lpFileName);
31 if (Attributes != INVALID_FILE_ATTRIBUTES)
32 {
33 return SetFileAttributesW(lpFileName,Attributes -
34 (Attributes & ~FILE_ATTRIBUTE_READONLY));
35 }
36
37 return FALSE;
38 }
39
40
41 /***********************************************************************
42 * add_boot_rename_entry
43 *
44 * Adds an entry to the registry that is loaded when windows boots and
45 * checks if there are some files to be removed or renamed/moved.
46 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
47 * non-NULL then the file is moved, otherwise it is deleted. The
48 * entry of the registrykey is always appended with two zero
49 * terminated strings. If <fn2> is NULL then the second entry is
50 * simply a single 0-byte. Otherwise the second filename goes
51 * there. The entries are prepended with \??\ before the path and the
52 * second filename gets also a '!' as the first character if
53 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
54 * 0-byte follows to indicate the end of the strings.
55 * i.e.:
56 * \??\D:\test\file1[0]
57 * !\??\D:\test\file1_renamed[0]
58 * \??\D:\Test|delete[0]
59 * [0] <- file is to be deleted, second string empty
60 * \??\D:\test\file2[0]
61 * !\??\D:\test\file2_renamed[0]
62 * [0] <- indicates end of strings
63 *
64 * or:
65 * \??\D:\test\file1[0]
66 * !\??\D:\test\file1_renamed[0]
67 * \??\D:\Test|delete[0]
68 * [0] <- file is to be deleted, second string empty
69 * [0] <- indicates end of strings
70 *
71 */
72 static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
73 {
74 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
75 'F','i','l','e','R','e','n','a','m','e',
76 'O','p','e','r','a','t','i','o','n','s',0};
77
78 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
79
80 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
81
82 OBJECT_ATTRIBUTES ObjectAttributes;
83 UNICODE_STRING nameW, source_name, dest_name;
84 KEY_VALUE_PARTIAL_INFORMATION *info;
85 BOOL rc = FALSE;
86 HANDLE Reboot = NULL;
87 DWORD len1, len2;
88 DWORD DestLen = 0;
89 DWORD DataSize = 0;
90 BYTE *Buffer = NULL;
91 WCHAR *p;
92 NTSTATUS Status;
93
94 TRACE("add_boot_rename_entry( %S, %S, %d ) \n", source, dest, flags);
95
96 if(dest)
97 DestLen = wcslen(dest);
98
99 if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
100 {
101 SetLastError( ERROR_PATH_NOT_FOUND );
102 return FALSE;
103 }
104 dest_name.Buffer = NULL;
105 if (DestLen && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
106 {
107 RtlFreeHeap( RtlGetProcessHeap(), 0, source_name.Buffer );
108 SetLastError( ERROR_PATH_NOT_FOUND );
109 return FALSE;
110 }
111
112 InitializeObjectAttributes(&ObjectAttributes,
113 &KeyName,
114 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
115 NULL,
116 NULL);
117
118 Status = NtCreateKey(&Reboot,
119 KEY_QUERY_VALUE | KEY_SET_VALUE,
120 &ObjectAttributes,
121 0,
122 NULL,
123 REG_OPTION_NON_VOLATILE,
124 NULL);
125
126 if (Status == STATUS_ACCESS_DENIED)
127 {
128 Status = NtCreateKey(
129 &Reboot,
130 KEY_QUERY_VALUE | KEY_SET_VALUE,
131 &ObjectAttributes,
132 0,
133 NULL,
134 REG_OPTION_BACKUP_RESTORE,
135 NULL);
136 }
137
138 if (!NT_SUCCESS(Status))
139 {
140 WARN("NtCreateKey() failed (Status 0x%lx)\n", Status);
141 if (source_name.Buffer)
142 RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
143 if (dest_name.Buffer)
144 RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
145 return FALSE;
146 }
147
148 len1 = source_name.Length + sizeof(WCHAR);
149 if (DestLen)
150 {
151 len2 = dest_name.Length + sizeof(WCHAR);
152 if (flags & MOVEFILE_REPLACE_EXISTING)
153 len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
154 }
155 else
156 {
157 len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
158 }
159
160 RtlInitUnicodeString( &nameW, ValueName );
161
162 /* First we check if the key exists and if so how many bytes it already contains. */
163 Status = NtQueryValueKey(
164 Reboot,
165 &nameW,
166 KeyValuePartialInformation,
167 NULL,
168 0,
169 &DataSize );
170 if ((Status == STATUS_BUFFER_OVERFLOW) ||
171 (Status == STATUS_BUFFER_TOO_SMALL))
172 {
173 if (!(Buffer = HeapAlloc(GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR))))
174 goto Quit;
175 Status = NtQueryValueKey(Reboot, &nameW, KeyValuePartialInformation,
176 Buffer, DataSize, &DataSize);
177 if(!NT_SUCCESS(Status))
178 goto Quit;
179 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
180 if (info->Type != REG_MULTI_SZ) goto Quit;
181 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
182 }
183 else
184 {
185 DataSize = info_size;
186 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
187 goto Quit;
188 }
189
190 memcpy( Buffer + DataSize, source_name.Buffer, len1 );
191 DataSize += len1;
192 p = (WCHAR *)(Buffer + DataSize);
193 if (DestLen)
194 {
195 if (flags & MOVEFILE_REPLACE_EXISTING)
196 *p++ = '!';
197 memcpy( p, dest_name.Buffer, len2 );
198 DataSize += len2;
199 }
200 else
201 {
202 *p = 0;
203 DataSize += sizeof(WCHAR);
204 }
205
206 /* add final null */
207 p = (WCHAR *)(Buffer + DataSize);
208 *p = 0;
209 DataSize += sizeof(WCHAR);
210
211 rc = NT_SUCCESS(NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size));
212
213 Quit:
214 RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
215 if (dest_name.Buffer)
216 RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
217 NtClose(Reboot);
218 if(Buffer)
219 HeapFree(GetProcessHeap(), 0, Buffer);
220 return(rc);
221 }
222
223
224 /*
225 * @implemented
226 */
227 BOOL
228 WINAPI
229 MoveFileWithProgressW (
230 LPCWSTR lpExistingFileName,
231 LPCWSTR lpNewFileName,
232 LPPROGRESS_ROUTINE lpProgressRoutine,
233 LPVOID lpData,
234 DWORD dwFlags
235 )
236 {
237 HANDLE hFile = NULL, hNewFile = NULL;
238 IO_STATUS_BLOCK IoStatusBlock;
239 OBJECT_ATTRIBUTES ObjectAttributes;
240 PFILE_RENAME_INFORMATION FileRename;
241 NTSTATUS errCode;
242 BOOL Result;
243 UNICODE_STRING DstPathU;
244 BOOL folder = FALSE;
245
246 TRACE("MoveFileWithProgressW()\n");
247
248 if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)
249 return add_boot_rename_entry( lpExistingFileName, lpNewFileName, dwFlags );
250
251 // if (dwFlags & MOVEFILE_WRITE_THROUGH)
252 // FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");
253
254 if (!lpNewFileName)
255 return DeleteFileW(lpExistingFileName);
256
257 /* validate & translate the filename */
258 if (!RtlDosPathNameToNtPathName_U (lpNewFileName,
259 &DstPathU,
260 NULL,
261 NULL))
262 {
263 WARN("Invalid destination path\n");
264 SetLastError(ERROR_PATH_NOT_FOUND);
265 return FALSE;
266 }
267
268 InitializeObjectAttributes(&ObjectAttributes,
269 &DstPathU,
270 OBJ_CASE_INSENSITIVE,
271 NULL,
272 NULL);
273
274 errCode = NtOpenFile( &hNewFile,
275 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
276 &ObjectAttributes,
277 &IoStatusBlock,
278 0,
279 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
280 ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0) );
281
282 if (NT_SUCCESS(errCode)) /* Destination exists */
283 {
284 NtClose(hNewFile);
285
286 if (!(dwFlags & MOVEFILE_REPLACE_EXISTING))
287 {
288 SetLastError(ERROR_ALREADY_EXISTS);
289 return FALSE;
290 }
291 else if (GetFileAttributesW(lpNewFileName) & FILE_ATTRIBUTE_DIRECTORY)
292 {
293 SetLastError(ERROR_ACCESS_DENIED);
294 return FALSE;
295 }
296 }
297
298 hFile = CreateFileW (lpExistingFileName,
299 GENERIC_ALL,
300 FILE_SHARE_WRITE|FILE_SHARE_READ,
301 NULL,
302 OPEN_EXISTING,
303 FILE_FLAG_BACKUP_SEMANTICS |
304 ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_FLAG_WRITE_THROUGH : 0),
305 NULL);
306
307 if (hFile == INVALID_HANDLE_VALUE)
308 {
309 return FALSE;
310 }
311
312 FileRename = RtlAllocateHeap(
313 RtlGetProcessHeap(),
314 HEAP_ZERO_MEMORY,
315 sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length);
316 if( !FileRename ) {
317 CloseHandle(hFile);
318 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
319 return FALSE;
320 }
321 if( dwFlags & MOVEFILE_REPLACE_EXISTING ) {
322 FileRename->ReplaceIfExists = TRUE;
323 }
324 else {
325 FileRename->ReplaceIfExists = FALSE;
326 }
327
328
329 memcpy(FileRename->FileName, DstPathU.Buffer, DstPathU.Length);
330 RtlFreeHeap (RtlGetProcessHeap (),
331 0,
332 DstPathU.Buffer);
333
334 FileRename->FileNameLength = DstPathU.Length;
335 errCode = NtSetInformationFile (hFile,
336 &IoStatusBlock,
337 FileRename,
338 sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length,
339 FileRenameInformation);
340 CloseHandle(hFile);
341 RtlFreeHeap(RtlGetProcessHeap(), 0, FileRename);
342
343 if (GetFileAttributesW(lpExistingFileName) & FILE_ATTRIBUTE_DIRECTORY)
344 {
345 folder = TRUE;
346 }
347
348
349 /*
350 * FIXME:
351 * Fail now move the folder
352 * Before we fail at CreateFileW
353 */
354
355
356 if (NT_SUCCESS(errCode))
357 {
358 Result = TRUE;
359 }
360 else
361 {
362 if (folder==FALSE)
363 {
364 Result = CopyFileExW (lpExistingFileName,
365 lpNewFileName,
366 lpProgressRoutine,
367 lpData,
368 NULL,
369 (dwFlags & MOVEFILE_REPLACE_EXISTING) ? 0 : COPY_FILE_FAIL_IF_EXISTS);
370 if (Result)
371 {
372 /* Cleanup the source file */
373 Result = DeleteFileW (lpExistingFileName);
374 }
375 }
376 else
377 {
378 /* move folder code start */
379 WIN32_FIND_DATAW findBuffer;
380 LPWSTR lpExistingFileName2 = NULL;
381 LPWSTR lpNewFileName2 = NULL;
382 LPWSTR lpDeleteFile = NULL;
383 INT size;
384 INT size2;
385 BOOL loop = TRUE;
386 BOOL Result = FALSE;
387 INT max_size = MAX_PATH;
388
389
390 /* Build the string */
391 size = wcslen(lpExistingFileName);
392 if (size+6> max_size)
393 max_size = size + 6;
394
395 lpDeleteFile = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
396 if (lpDeleteFile == NULL)
397 return FALSE;
398
399 lpNewFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
400 if (lpNewFileName2 == NULL)
401 {
402 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
403 return FALSE;
404 }
405
406 lpExistingFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
407 if (lpExistingFileName2 == NULL)
408 {
409 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
410 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
411 return FALSE;
412 }
413
414 wcscpy( (WCHAR *)lpExistingFileName2,lpExistingFileName);
415 wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\\*.*\0");
416
417 /* Get the file name */
418 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
419 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
420 if (hFile == INVALID_HANDLE_VALUE)
421 loop=FALSE;
422
423 if (findBuffer.cFileName[0] == L'\0')
424 loop=FALSE;
425
426
427 /* FIXME
428 * remove readonly flag from source folder and do not set the readonly flag to dest folder
429 */
430 RemoveReadOnlyAttributeW(lpExistingFileName);
431 RemoveReadOnlyAttributeW(lpNewFileName);
432 //CreateDirectoryExW(lpExistingFileName,lpNewFileName,NULL);
433 CreateDirectoryW(lpNewFileName, NULL);
434
435 /* search the files/folders and move them */
436 while (loop==TRUE)
437 {
438 Result = TRUE;
439
440 if ((!wcscmp(findBuffer.cFileName,L"..")) || (!wcscmp(findBuffer.cFileName,L".")))
441 {
442 loop = FindNextFileW(hFile, &findBuffer);
443
444 if (!loop)
445 {
446 size = wcslen(lpExistingFileName2)-4;
447 FindClose(hFile);
448 hFile = INVALID_HANDLE_VALUE;
449
450 wcscpy( &lpExistingFileName2[size],L"\0");
451
452 if (wcsncmp(lpExistingFileName,lpExistingFileName2,size))
453 {
454 DWORD Attributes;
455
456 /* delete folder */
457 TRACE("MoveFileWithProgressW : Delete folder : %S\n",lpDeleteFile);
458
459 /* remove system folder flag other wise we can not delete the folder */
460 Attributes = GetFileAttributesW(lpExistingFileName2);
461 if (Attributes != INVALID_FILE_ATTRIBUTES)
462 {
463 SetFileAttributesW(lpExistingFileName2,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
464 }
465
466 RemoveReadOnlyAttributeW(lpExistingFileName2);
467
468 Result = RemoveDirectoryW(lpExistingFileName2);
469 if (Result == FALSE)
470 break;
471
472 loop=TRUE;
473 size = wcslen(lpExistingFileName);
474
475 if (size+6>max_size)
476 {
477 if (lpNewFileName2 != NULL)
478 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
479
480 if (lpExistingFileName2 != NULL)
481 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
482
483 if (lpDeleteFile != NULL)
484 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
485
486 return FALSE;
487 }
488
489 wcscpy( lpExistingFileName2,lpExistingFileName);
490 wcscpy( &lpExistingFileName2[size],L"\\*.*\0");
491
492 /* Get the file name */
493 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
494 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
495 }
496 }
497 continue;
498 }
499
500 if (findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
501 {
502
503 /* Build the new src string */
504 size = wcslen(findBuffer.cFileName);
505 size2= wcslen(lpExistingFileName2);
506
507 if (size2+size+6>max_size)
508 {
509 FindClose(hFile);
510
511 if (lpNewFileName2 != NULL)
512 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
513
514 if (lpExistingFileName2 != NULL)
515 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
516
517 if (lpDeleteFile != NULL)
518 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
519
520 return FALSE;
521 }
522
523 wcscpy( &lpExistingFileName2[size2-3],findBuffer.cFileName);
524 wcscpy( &lpExistingFileName2[size2+size-3],L"\0");
525
526
527 /* Continue */
528 wcscpy( lpDeleteFile,lpExistingFileName2);
529 wcscpy( &lpExistingFileName2[size2+size-3],L"\\*.*\0");
530
531
532 /* Build the new dst string */
533 size = wcslen(lpExistingFileName2) + wcslen(lpNewFileName);
534 size2 = wcslen(lpExistingFileName);
535
536 if (size>max_size)
537 {
538 FindClose(hFile);
539
540 if (lpNewFileName2 != NULL)
541 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
542
543 if (lpExistingFileName2 != NULL)
544 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
545
546 if (lpDeleteFile != NULL)
547 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
548
549 return FALSE;
550 }
551
552 wcscpy( lpNewFileName2,lpNewFileName);
553 size = wcslen(lpNewFileName);
554 wcscpy( &lpNewFileName2[size], &lpExistingFileName2[size2]);
555 size = wcslen(lpNewFileName2);
556 wcscpy( &lpNewFileName2[size-4],L"\0");
557
558 /* Create Folder */
559
560 /* FIXME
561 * remove readonly flag from source folder and do not set the readonly flag to dest folder
562 */
563 RemoveReadOnlyAttributeW(lpDeleteFile);
564 RemoveReadOnlyAttributeW(lpNewFileName2);
565
566 CreateDirectoryW(lpNewFileName2,NULL);
567 //CreateDirectoryExW(lpDeleteFile, lpNewFileName2,NULL);
568
569
570 /* set new search path from src string */
571 FindClose(hFile);
572 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
573 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
574 }
575 else
576 {
577
578 /* Build the new string */
579 size = wcslen(findBuffer.cFileName);
580 size2= wcslen(lpExistingFileName2);
581 wcscpy( lpDeleteFile,lpExistingFileName2);
582 wcscpy( &lpDeleteFile[size2-3],findBuffer.cFileName);
583
584 /* Build dest string */
585 size = wcslen(lpDeleteFile) + wcslen(lpNewFileName);
586 size2 = wcslen(lpExistingFileName);
587
588 if (size>max_size)
589 {
590 FindClose(hFile);
591
592 if (lpNewFileName2 != NULL)
593 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
594
595 if (lpExistingFileName2 != NULL)
596 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
597
598 if (lpDeleteFile != NULL)
599 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
600
601 return FALSE;
602 }
603
604 wcscpy( lpNewFileName2,lpNewFileName);
605 size = wcslen(lpNewFileName);
606 wcscpy(&lpNewFileName2[size],&lpDeleteFile[size2]);
607
608
609 /* overrite existsen file, if the file got the flag have readonly
610 * we need reomve that flag
611 */
612
613 /* copy file */
614
615 TRACE("MoveFileWithProgressW : Copy file : %S to %S\n",lpDeleteFile, lpNewFileName2);
616 RemoveReadOnlyAttributeW(lpDeleteFile);
617 RemoveReadOnlyAttributeW(lpNewFileName2);
618
619 Result = CopyFileExW (lpDeleteFile,
620 lpNewFileName2,
621 lpProgressRoutine,
622 lpData,
623 NULL,
624 0);
625
626 if (Result == FALSE)
627 break;
628
629 /* delete file */
630 TRACE("MoveFileWithProgressW : remove readonly flag from file : %S\n",lpNewFileName2);
631 Result = RemoveReadOnlyAttributeW(lpDeleteFile);
632 if (Result == FALSE)
633 break;
634
635 TRACE("MoveFileWithProgressW : Delete file : %S\n",lpDeleteFile);
636 Result = DeleteFileW(lpDeleteFile);
637 if (Result == FALSE)
638 break;
639
640 }
641 loop = FindNextFileW(hFile, &findBuffer);
642 }
643
644
645 /* Remove last folder */
646 if ((loop == FALSE) && (Result != FALSE))
647 {
648 DWORD Attributes;
649
650 Attributes = GetFileAttributesW(lpDeleteFile);
651 if (Attributes != INVALID_FILE_ATTRIBUTES)
652 {
653 SetFileAttributesW(lpDeleteFile,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
654 }
655
656 Result = RemoveDirectoryW(lpExistingFileName);
657 }
658
659 /* Cleanup */
660 FindClose(hFile);
661
662 if (lpNewFileName2 != NULL)
663 {
664 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
665 lpNewFileName2 = NULL;
666 }
667
668 if (lpExistingFileName2 != NULL)
669 {
670 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
671 lpExistingFileName2 = NULL;
672 }
673
674 if (lpDeleteFile != NULL)
675 {
676 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
677 lpDeleteFile = NULL;
678 }
679
680 return Result;
681
682 // end move folder code
683 }
684 }
685
686
687 return Result;
688 }
689
690
691 /*
692 * @implemented
693 */
694 BOOL
695 WINAPI
696 MoveFileWithProgressA (
697 LPCSTR lpExistingFileName,
698 LPCSTR lpNewFileName,
699 LPPROGRESS_ROUTINE lpProgressRoutine,
700 LPVOID lpData,
701 DWORD dwFlags
702 )
703 {
704 PWCHAR ExistingFileNameW;
705 PWCHAR NewFileNameW;
706 BOOL ret;
707
708 if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, FALSE)))
709 return FALSE;
710
711 if (!(NewFileNameW= FilenameA2W(lpNewFileName, TRUE)))
712 return FALSE;
713
714 ret = MoveFileWithProgressW (ExistingFileNameW ,
715 NewFileNameW,
716 lpProgressRoutine,
717 lpData,
718 dwFlags);
719
720 RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW);
721
722 return ret;
723 }
724
725
726 /*
727 * @implemented
728 */
729 BOOL
730 WINAPI
731 MoveFileW (
732 LPCWSTR lpExistingFileName,
733 LPCWSTR lpNewFileName
734 )
735 {
736 return MoveFileExW (lpExistingFileName,
737 lpNewFileName,
738 MOVEFILE_COPY_ALLOWED);
739 }
740
741
742 /*
743 * @implemented
744 */
745 BOOL
746 WINAPI
747 MoveFileExW (
748 LPCWSTR lpExistingFileName,
749 LPCWSTR lpNewFileName,
750 DWORD dwFlags
751 )
752 {
753 return MoveFileWithProgressW (lpExistingFileName,
754 lpNewFileName,
755 NULL,
756 NULL,
757 dwFlags);
758 }
759
760
761 /*
762 * @implemented
763 */
764 BOOL
765 WINAPI
766 MoveFileA (
767 LPCSTR lpExistingFileName,
768 LPCSTR lpNewFileName
769 )
770 {
771 return MoveFileExA (lpExistingFileName,
772 lpNewFileName,
773 MOVEFILE_COPY_ALLOWED);
774 }
775
776
777 /*
778 * @implemented
779 */
780 BOOL
781 WINAPI
782 MoveFileExA (
783 LPCSTR lpExistingFileName,
784 LPCSTR lpNewFileName,
785 DWORD dwFlags
786 )
787 {
788 return MoveFileWithProgressA (lpExistingFileName,
789 lpNewFileName,
790 NULL,
791 NULL,
792 dwFlags);
793 }
794
795 /*
796 * @implemented
797 */
798 BOOL
799 WINAPI
800 ReplaceFileA(
801 LPCSTR lpReplacedFileName,
802 LPCSTR lpReplacementFileName,
803 LPCSTR lpBackupFileName,
804 DWORD dwReplaceFlags,
805 LPVOID lpExclude,
806 LPVOID lpReserved
807 )
808 {
809 WCHAR *replacedW, *replacementW, *backupW = NULL;
810 BOOL ret;
811
812 /* This function only makes sense when the first two parameters are defined */
813 if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
814 {
815 SetLastError(ERROR_INVALID_PARAMETER);
816 return FALSE;
817 }
818
819 if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
820 {
821 HeapFree(GetProcessHeap(), 0, replacedW);
822 SetLastError(ERROR_INVALID_PARAMETER);
823 return FALSE;
824 }
825
826 /* The backup parameter, however, is optional */
827 if (lpBackupFileName)
828 {
829 if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
830 {
831 HeapFree(GetProcessHeap(), 0, replacedW);
832 HeapFree(GetProcessHeap(), 0, replacementW);
833 SetLastError(ERROR_INVALID_PARAMETER);
834 return FALSE;
835 }
836 }
837
838 ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
839 HeapFree(GetProcessHeap(), 0, replacedW);
840 HeapFree(GetProcessHeap(), 0, replacementW);
841 HeapFree(GetProcessHeap(), 0, backupW);
842
843 return ret;
844 }
845
846 /*
847 * @unimplemented
848 */
849 BOOL
850 WINAPI
851 ReplaceFileW(
852 LPCWSTR lpReplacedFileName,
853 LPCWSTR lpReplacementFileName,
854 LPCWSTR lpBackupFileName,
855 DWORD dwReplaceFlags,
856 LPVOID lpExclude,
857 LPVOID lpReserved
858 )
859 {
860 HANDLE hReplaced = NULL, hReplacement = NULL;
861 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
862 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
863 DWORD Error = ERROR_SUCCESS;
864 NTSTATUS Status;
865 BOOL Ret = FALSE;
866 IO_STATUS_BLOCK IoStatusBlock;
867 OBJECT_ATTRIBUTES ObjectAttributes;
868 PVOID Buffer = NULL ;
869
870 if (dwReplaceFlags)
871 FIXME("Ignoring flags %x\n", dwReplaceFlags);
872
873 /* First two arguments are mandatory */
874 if (!lpReplacedFileName || !lpReplacementFileName)
875 {
876 SetLastError(ERROR_INVALID_PARAMETER);
877 return FALSE;
878 }
879
880 /* Back it up */
881 if(lpBackupFileName)
882 {
883 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
884 {
885 Error = GetLastError();
886 goto Cleanup ;
887 }
888 }
889
890 /* Open the "replaced" file for reading and writing */
891 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
892 {
893 Error = ERROR_PATH_NOT_FOUND;
894 goto Cleanup;
895 }
896
897 InitializeObjectAttributes(&ObjectAttributes,
898 &NtReplacedName,
899 OBJ_CASE_INSENSITIVE,
900 NULL,
901 NULL);
902
903 Status = NtOpenFile(&hReplaced,
904 GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE | WRITE_DAC,
905 &ObjectAttributes,
906 &IoStatusBlock,
907 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
908 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
909
910 if (!NT_SUCCESS(Status))
911 {
912 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
913 Error = ERROR_FILE_NOT_FOUND;
914 else
915 Error = ERROR_UNABLE_TO_REMOVE_REPLACED;
916 goto Cleanup;
917 }
918
919 /* Blank it */
920 SetEndOfFile(hReplaced) ;
921
922 /*
923 * Open the replacement file for reading, writing, and deleting
924 * (deleting is needed when finished)
925 */
926 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
927 {
928 Error = ERROR_PATH_NOT_FOUND;
929 goto Cleanup;
930 }
931
932 InitializeObjectAttributes(&ObjectAttributes,
933 &NtReplacementName,
934 OBJ_CASE_INSENSITIVE,
935 NULL,
936 NULL);
937
938 Status = NtOpenFile(&hReplacement,
939 GENERIC_READ | DELETE | SYNCHRONIZE,
940 &ObjectAttributes,
941 &IoStatusBlock,
942 0,
943 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
944
945 if (!NT_SUCCESS(Status))
946 {
947 Error = RtlNtStatusToDosError(Status);
948 goto Cleanup;
949 }
950
951 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
952 if (!Buffer)
953 {
954 Error = ERROR_NOT_ENOUGH_MEMORY;
955 goto Cleanup ;
956 }
957 while (Status != STATUS_END_OF_FILE)
958 {
959 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
960 if (NT_SUCCESS(Status))
961 {
962 Status = NtWriteFile(hReplaced, NULL, NULL, NULL, &IoStatusBlock, Buffer,
963 IoStatusBlock.Information, NULL, NULL) ;
964 if (!NT_SUCCESS(Status))
965 {
966 Error = RtlNtStatusToDosError(Status);
967 goto Cleanup;
968 }
969 }
970 else if (Status != STATUS_END_OF_FILE)
971 {
972 Error = RtlNtStatusToDosError(Status);
973 goto Cleanup;
974 }
975 }
976
977 Ret = TRUE;
978
979 /* Perform resource cleanup */
980 Cleanup:
981 if (hReplaced) NtClose(hReplaced);
982 if (hReplacement) NtClose(hReplacement);
983 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
984
985 if (NtReplacementName.Buffer)
986 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
987 if (NtReplacedName.Buffer)
988 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
989
990 /* If there was an error, set the error code */
991 if(!Ret)
992 {
993 TRACE("ReplaceFileW failed (error=%d)\n", Error);
994 SetLastError(Error);
995 }
996 return Ret;
997 }
998
999 /*
1000 * @unimplemented
1001 */
1002 BOOL
1003 WINAPI
1004 PrivMoveFileIdentityW(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3)
1005 {
1006 STUB;
1007 return FALSE;
1008 }
1009
1010 /* EOF */