375493c4d75ec54561352b5a58dd007da7584554
[reactos.git] / reactos / lib / kernel32 / file / move.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/file.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Gerhard W. Gruber (sparhawk_at_gmx.at)
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <k32.h>
16 #include <malloc.h>
17
18 #define NDEBUG
19 #include "../include/debug.h"
20
21 /* GLOBALS *****************************************************************/
22
23 /* FUNCTIONS ****************************************************************/
24
25 static BOOL
26 AdjustFileAttributes (
27 LPCWSTR ExistingFileName,
28 LPCWSTR NewFileName
29 )
30 {
31 IO_STATUS_BLOCK IoStatusBlock;
32 FILE_BASIC_INFORMATION ExistingInfo,
33 NewInfo;
34 HANDLE hFile;
35 DWORD Attributes;
36 NTSTATUS errCode;
37 BOOL Result = FALSE;
38
39 hFile = CreateFileW (ExistingFileName,
40 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
41 FILE_SHARE_READ,
42 NULL,
43 OPEN_EXISTING,
44 FILE_ATTRIBUTE_NORMAL,
45 NULL);
46 if (INVALID_HANDLE_VALUE != hFile)
47 {
48 errCode = NtQueryInformationFile (hFile,
49 &IoStatusBlock,
50 &ExistingInfo,
51 sizeof(FILE_BASIC_INFORMATION),
52 FileBasicInformation);
53 if (NT_SUCCESS (errCode))
54 {
55 if (0 != (ExistingInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
56 {
57 Attributes = ExistingInfo.FileAttributes;
58 ExistingInfo.FileAttributes &= ~ FILE_ATTRIBUTE_READONLY;
59 if (0 == (ExistingInfo.FileAttributes &
60 (FILE_ATTRIBUTE_HIDDEN |
61 FILE_ATTRIBUTE_SYSTEM |
62 FILE_ATTRIBUTE_ARCHIVE)))
63 {
64 ExistingInfo.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
65 }
66 errCode = NtSetInformationFile (hFile,
67 &IoStatusBlock,
68 &ExistingInfo,
69 sizeof(FILE_BASIC_INFORMATION),
70 FileBasicInformation);
71 if (!NT_SUCCESS(errCode))
72 {
73 DPRINT("Removing READONLY attribute from source failed with status 0x%08x\n", errCode);
74 }
75 ExistingInfo.FileAttributes = Attributes;
76 }
77 CloseHandle(hFile);
78
79 if (NT_SUCCESS(errCode))
80 {
81 hFile = CreateFileW (NewFileName,
82 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
83 FILE_SHARE_READ,
84 NULL,
85 OPEN_EXISTING,
86 FILE_ATTRIBUTE_NORMAL,
87 NULL);
88 if (INVALID_HANDLE_VALUE != hFile)
89 {
90 errCode = NtQueryInformationFile(hFile,
91 &IoStatusBlock,
92 &NewInfo,
93 sizeof(FILE_BASIC_INFORMATION),
94 FileBasicInformation);
95 if (NT_SUCCESS(errCode))
96 {
97 NewInfo.FileAttributes = (NewInfo.FileAttributes &
98 ~ (FILE_ATTRIBUTE_HIDDEN |
99 FILE_ATTRIBUTE_SYSTEM |
100 FILE_ATTRIBUTE_READONLY |
101 FILE_ATTRIBUTE_NORMAL)) |
102 (ExistingInfo.FileAttributes &
103 (FILE_ATTRIBUTE_HIDDEN |
104 FILE_ATTRIBUTE_SYSTEM |
105 FILE_ATTRIBUTE_READONLY |
106 FILE_ATTRIBUTE_NORMAL)) |
107 FILE_ATTRIBUTE_ARCHIVE;
108 NewInfo.CreationTime = ExistingInfo.CreationTime;
109 NewInfo.LastAccessTime = ExistingInfo.LastAccessTime;
110 NewInfo.LastWriteTime = ExistingInfo.LastWriteTime;
111 errCode = NtSetInformationFile (hFile,
112 &IoStatusBlock,
113 &NewInfo,
114 sizeof(FILE_BASIC_INFORMATION),
115 FileBasicInformation);
116 if (NT_SUCCESS(errCode))
117 {
118 Result = TRUE;
119 }
120 else
121 {
122 DPRINT("Setting attributes on dest file failed with status 0x%08x\n", errCode);
123 }
124 }
125 else
126 {
127 DPRINT("Obtaining attributes from dest file failed with status 0x%08x\n", errCode);
128 }
129 CloseHandle(hFile);
130 }
131 else
132 {
133 DPRINT("Opening dest file to set attributes failed with code %d\n", GetLastError());
134 }
135 }
136 }
137 else
138 {
139 DPRINT("Obtaining attributes from source file failed with status 0x%08x\n", errCode);
140 CloseHandle(hFile);
141 }
142 }
143 else
144 {
145 DPRINT("Opening source file to obtain attributes failed with code %d\n", GetLastError());
146 }
147
148 return Result;
149 }
150
151 /***********************************************************************
152 * add_boot_rename_entry
153 *
154 * Adds an entry to the registry that is loaded when windows boots and
155 * checks if there are some files to be removed or renamed/moved.
156 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
157 * non-NULL then the file is moved, otherwise it is deleted. The
158 * entry of the registrykey is always appended with two zero
159 * terminated strings. If <fn2> is NULL then the second entry is
160 * simply a single 0-byte. Otherwise the second filename goes
161 * there. The entries are prepended with \??\ before the path and the
162 * second filename gets also a '!' as the first character if
163 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
164 * 0-byte follows to indicate the end of the strings.
165 * i.e.:
166 * \??\D:\test\file1[0]
167 * !\??\D:\test\file1_renamed[0]
168 * \??\D:\Test|delete[0]
169 * [0] <- file is to be deleted, second string empty
170 * \??\D:\test\file2[0]
171 * !\??\D:\test\file2_renamed[0]
172 * [0] <- indicates end of strings
173 *
174 * or:
175 * \??\D:\test\file1[0]
176 * !\??\D:\test\file1_renamed[0]
177 * \??\D:\Test|delete[0]
178 * [0] <- file is to be deleted, second string empty
179 * [0] <- indicates end of strings
180 *
181 */
182 static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
183 {
184 static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
185 'F','i','l','e','R','e','n','a','m','e',
186 'O','p','e','r','a','t','i','o','n','s',0};
187 static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
188 'S','y','s','t','e','m','\\',
189 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
190 'C','o','n','t','r','o','l','\\',
191 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
192 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
193
194 OBJECT_ATTRIBUTES attr;
195 UNICODE_STRING nameW, source_name, dest_name;
196 KEY_VALUE_PARTIAL_INFORMATION *info;
197 BOOL rc = FALSE;
198 HANDLE Reboot = 0;
199 DWORD len1, len2;
200 DWORD DataSize = 0;
201 BYTE *Buffer = NULL;
202 WCHAR *p;
203
204 DPRINT("Add support to smss for keys created by MOVEFILE_DELAY_UNTIL_REBOOT\n");
205
206 if (!RtlDosPathNameToNtPathName_U( (LPWSTR)source, &source_name, NULL, NULL ))
207 {
208 SetLastError( ERROR_PATH_NOT_FOUND );
209 return FALSE;
210 }
211 dest_name.Buffer = NULL;
212 if (dest && !RtlDosPathNameToNtPathName_U( (LPWSTR)dest, &dest_name, NULL, NULL ))
213 {
214 RtlFreeUnicodeString( &source_name );
215 SetLastError( ERROR_PATH_NOT_FOUND );
216 return FALSE;
217 }
218
219 attr.Length = sizeof(attr);
220 attr.RootDirectory = 0;
221 attr.ObjectName = &nameW;
222 attr.Attributes = 0;
223 attr.SecurityDescriptor = NULL;
224 attr.SecurityQualityOfService = NULL;
225 RtlInitUnicodeString( &nameW, SessionW );
226
227 if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
228 {
229 DPRINT1("Error creating key for reboot managment [%s]\n",
230 "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
231 RtlFreeUnicodeString( &source_name );
232 RtlFreeUnicodeString( &dest_name );
233 return FALSE;
234 }
235
236 len1 = source_name.Length + sizeof(WCHAR);
237 if (dest)
238 {
239 len2 = dest_name.Length + sizeof(WCHAR);
240 if (flags & MOVEFILE_REPLACE_EXISTING)
241 len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
242 }
243 else len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
244
245 RtlInitUnicodeString( &nameW, ValueName );
246
247 /* First we check if the key exists and if so how many bytes it already contains. */
248 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
249 NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
250 {
251 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
252 goto Quit;
253 if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
254 Buffer, DataSize, &DataSize )) goto Quit;
255 info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
256 if (info->Type != REG_MULTI_SZ) goto Quit;
257 if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
258 }
259 else
260 {
261 DataSize = info_size;
262 if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
263 goto Quit;
264 }
265
266 memcpy( Buffer + DataSize, source_name.Buffer, len1 );
267 DataSize += len1;
268 p = (WCHAR *)(Buffer + DataSize);
269 if (dest)
270 {
271 if (flags & MOVEFILE_REPLACE_EXISTING)
272 *p++ = '!';
273 memcpy( p, dest_name.Buffer, len2 );
274 DataSize += len2;
275 }
276 else
277 {
278 *p = 0;
279 DataSize += sizeof(WCHAR);
280 }
281
282 /* add final null */
283 p = (WCHAR *)(Buffer + DataSize);
284 *p = 0;
285 DataSize += sizeof(WCHAR);
286
287 rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
288
289 Quit:
290 RtlFreeUnicodeString( &source_name );
291 RtlFreeUnicodeString( &dest_name );
292 if (Reboot) NtClose(Reboot);
293 HeapFree( GetProcessHeap(), 0, Buffer );
294 return(rc);
295 }
296
297
298 /*
299 * @implemented
300 */
301 BOOL
302 STDCALL
303 MoveFileWithProgressW (
304 LPCWSTR lpExistingFileName,
305 LPCWSTR lpNewFileName,
306 LPPROGRESS_ROUTINE lpProgressRoutine,
307 LPVOID lpData,
308 DWORD dwFlags
309 )
310 {
311 HANDLE hFile = NULL;
312 IO_STATUS_BLOCK IoStatusBlock;
313 PFILE_RENAME_INFORMATION FileRename;
314 NTSTATUS errCode;
315 BOOL Result;
316 UNICODE_STRING DstPathU;
317 BOOL folder = FALSE;
318
319 DPRINT("MoveFileWithProgressW()\n");
320
321 if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)
322 return add_boot_rename_entry( lpExistingFileName, lpNewFileName, dwFlags );
323
324 hFile = CreateFileW (lpExistingFileName,
325 GENERIC_ALL,
326 FILE_SHARE_WRITE|FILE_SHARE_READ,
327 NULL,
328 OPEN_EXISTING,
329 FILE_FLAG_BACKUP_SEMANTICS,
330 NULL);
331
332 if (hFile == INVALID_HANDLE_VALUE)
333 {
334 return FALSE;
335 }
336
337
338 /* validate & translate the filename */
339 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewFileName,
340 &DstPathU,
341 NULL,
342 NULL))
343 {
344 DPRINT("Invalid destination path\n");
345 CloseHandle(hFile);
346 SetLastError(ERROR_PATH_NOT_FOUND);
347 return FALSE;
348 }
349
350 FileRename = alloca(sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length);
351 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == MOVEFILE_REPLACE_EXISTING)
352 FileRename->ReplaceIfExists = TRUE;
353 else
354 FileRename->ReplaceIfExists = FALSE;
355
356 memcpy(FileRename->FileName, DstPathU.Buffer, DstPathU.Length);
357 RtlFreeHeap (RtlGetProcessHeap (),
358 0,
359 DstPathU.Buffer);
360 /*
361 * FIXME:
362 * Is the length the count of characters or the length of the buffer?
363 */
364 FileRename->FileNameLength = DstPathU.Length / sizeof(WCHAR);
365 errCode = NtSetInformationFile (hFile,
366 &IoStatusBlock,
367 FileRename,
368 sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length,
369 FileRenameInformation);
370 CloseHandle(hFile);
371
372 if (GetFileAttributesW(lpExistingFileName) & FILE_ATTRIBUTE_DIRECTORY)
373 {
374 folder = TRUE;
375 }
376
377
378 /*
379 * FIXME:
380 * Fail now move the folder
381 * Before we fail at CreateFileW
382 */
383
384
385 if (NT_SUCCESS(errCode))
386 {
387 Result = TRUE;
388 }
389 else
390 {
391 if (folder==FALSE)
392 {
393 Result = CopyFileExW (lpExistingFileName,
394 lpNewFileName,
395 lpProgressRoutine,
396 lpData,
397 NULL,
398 FileRename->ReplaceIfExists ? 0 : COPY_FILE_FAIL_IF_EXISTS);
399 if (Result)
400 {
401 /* Cleanup the source file */
402 AdjustFileAttributes(lpExistingFileName, lpNewFileName);
403 Result = DeleteFileW (lpExistingFileName);
404 }
405 }
406 else
407 {
408 /* move folder code start */
409 WIN32_FIND_DATAW findBuffer;
410 LPCWSTR lpExistingFileName2 = NULL;
411 LPCWSTR lpNewFileName2 = NULL;
412 LPCWSTR lpDeleteFile = NULL;
413 INT size;
414 INT size2;
415 BOOL loop = TRUE;
416 BOOL Result = FALSE;
417
418 /* Build the string */
419 size = wcslen(lpExistingFileName);
420
421 lpDeleteFile = (LPCWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PATH * sizeof(WCHAR));
422 if (lpDeleteFile == NULL)
423 goto FreeMemAndExit;
424
425 lpNewFileName2 = (LPCWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PATH * sizeof(WCHAR));
426 if (lpNewFileName2 == NULL)
427 goto FreeMemAndExit;
428
429 lpExistingFileName2 = (LPCWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PATH * sizeof(WCHAR));
430 if (lpExistingFileName2 == NULL)
431 goto FreeMemAndExit;
432
433 if ((size+6)*sizeof(WCHAR)>MAX_PATH)
434 {
435 HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(VOID *) lpExistingFileName2,(size+6)*sizeof(WCHAR));
436 if (lpExistingFileName2 == NULL)
437 goto FreeMemAndExit;
438 }
439
440 wcscpy( (WCHAR *)lpExistingFileName2,lpExistingFileName);
441 wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\\*.*\0");
442
443 /* Get the file name */
444 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
445 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
446 if (hFile == NULL)
447 loop=FALSE;
448
449 if (findBuffer.cFileName[0] == L'\0')
450 loop=FALSE;
451
452 DPRINT("MoveFileWithProgressW : lpExistingFileName1 = %S\n",lpExistingFileName);
453 DPRINT("MoveFileWithProgressW : lpExistingFileName2 = %S\n",lpExistingFileName2);
454 DPRINT("MoveFileWithProgressW : lpNewFileName = %S\n",lpNewFileName);
455
456 DPRINT("MoveFileWithProgressW : loop = %d %d %d\n",TRUE, FALSE, loop);
457
458
459 CreateDirectoryW(lpNewFileName,NULL);
460
461
462 /* search the file */
463 while (loop==TRUE)
464 {
465 Result = TRUE;
466
467 if ((!wcscmp(findBuffer.cFileName,L"..")) || (!wcscmp(findBuffer.cFileName,L".")))
468 {
469 loop = FindNextFileW(hFile, &findBuffer);
470
471 if (!loop)
472 {
473 size = wcslen(lpExistingFileName2)-4;
474 FindClose(hFile);
475 wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\0");
476
477 if (wcsncmp(lpExistingFileName,lpExistingFileName2,size))
478 {
479 FindClose(hFile);
480
481 /* delete folder */
482
483 size = GetFullPathNameW(lpExistingFileName2, MAX_PATH,(LPWSTR) lpDeleteFile, NULL);
484 if (size>MAX_PATH)
485 {
486 lpDeleteFile = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
487 (VOID *) lpDeleteFile,size);
488
489 if (lpDeleteFile == NULL)
490 {
491 Result = FALSE;
492 goto FreeMemAndExit;
493 }
494
495 GetFullPathNameW(lpExistingFileName2, size,(LPWSTR) lpDeleteFile, NULL);
496 }
497
498 DPRINT("MoveFileWithProgressW : folder : %s\n",lpDeleteFile);
499
500 Result = RemoveDirectoryW(lpDeleteFile);
501 if (Result == FALSE)
502 break;
503
504 loop=TRUE;
505 size = wcslen(lpExistingFileName);
506
507 if ((size+6)*sizeof(WCHAR)>MAX_PATH)
508 {
509 lpExistingFileName2 = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
510 (VOID *)lpExistingFileName2,(size+6)*sizeof(WCHAR));
511
512 if (lpExistingFileName2 == NULL)
513 {
514 Result = FALSE;
515 goto FreeMemAndExit;
516 }
517 }
518
519 wcscpy( (WCHAR *)lpExistingFileName2,lpExistingFileName);
520 wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\\*.*\0");
521
522 /* Get the file name */
523 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
524 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
525 }
526 }
527 continue;
528 }
529
530 if (findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
531 {
532 DPRINT("MoveFileWithProgressW : 1: %S %S\n",lpExistingFileName2,findBuffer.cFileName);
533
534 /* Build the new string */
535 size = wcslen(findBuffer.cFileName);
536 size2= wcslen(lpExistingFileName2);
537
538 if ((size2+size+6)*sizeof(WCHAR)>MAX_PATH)
539 {
540 lpExistingFileName2 = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
541 (VOID *)lpExistingFileName2, (size2+size+6)*sizeof(WCHAR));
542
543 if (lpExistingFileName2 == NULL)
544 {
545 Result = FALSE;
546 goto FreeMemAndExit;
547 }
548 }
549
550 wcscpy( (WCHAR *)&lpExistingFileName2[size2-3],findBuffer.cFileName);
551 wcscpy( (WCHAR *)&lpExistingFileName2[size2+size-3],L"\\*.*\0");
552
553
554 /* Build the new dst string */
555 size = wcslen(lpExistingFileName2) + wcslen(lpNewFileName);
556 size2 = wcslen(lpExistingFileName);
557
558 if (size>MAX_PATH)
559 {
560 lpNewFileName2 = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
561 (VOID *) lpNewFileName2, size*sizeof(WCHAR));
562
563 if (lpNewFileName2 == NULL)
564 {
565 Result = FALSE;
566 goto FreeMemAndExit;
567 }
568 }
569
570 wcscpy((WCHAR *) lpNewFileName2,lpNewFileName);
571 size = wcslen(lpNewFileName);
572 wcscpy((WCHAR *)&lpNewFileName2[size], (WCHAR *)&lpExistingFileName2[size2]);
573 size = wcslen(lpNewFileName2);
574 wcscpy( (WCHAR *)&lpNewFileName2[size-4],L"\0");
575
576 /* build dest path */
577 /* remove this code when it will be out into kernel32.dll ? */
578
579 size = GetFullPathNameW(lpNewFileName2, MAX_PATH,(LPWSTR) lpDeleteFile, NULL);
580 if (MAX_PATH>size2)
581 {
582 lpDeleteFile = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
583 (VOID *) lpDeleteFile,size) ;
584
585 if (lpDeleteFile == NULL)
586 {
587 Result = FALSE;
588 goto FreeMemAndExit;
589 }
590
591 GetFullPathNameW(lpNewFileName2, size,(LPWSTR) lpDeleteFile, NULL);
592 }
593
594 /* Create Folder */
595
596 DPRINT("MoveFileWithProgressW : CreateDirectoryW lpNewFileName2 : %S\n",lpNewFileName2);
597 DPRINT("MoveFileWithProgressW : CreateDirectoryW : %S\n",lpDeleteFile);
598
599 CreateDirectoryW(lpDeleteFile,NULL);
600
601 DPRINT("MoveFileWithProgressW : 1x: %S : %S \n",lpExistingFileName2, lpNewFileName2);
602
603 FindClose(hFile);
604 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
605 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
606 }
607 else
608 {
609
610 /* Build the new string */
611 size = wcslen(findBuffer.cFileName);
612 size2= wcslen(lpExistingFileName2);
613 wcscpy( (WCHAR *)lpDeleteFile,lpExistingFileName2);
614 wcscpy( (WCHAR *)&lpDeleteFile[size2-3],findBuffer.cFileName);
615
616 /* Build dest string */
617 size = wcslen(lpDeleteFile) + wcslen(lpNewFileName);
618 size2 = wcslen(lpExistingFileName);
619
620 if (size*sizeof(WCHAR)>MAX_PATH)
621 {
622 lpNewFileName2 = (LPCWSTR) HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
623 (VOID *) lpNewFileName2, size*sizeof(WCHAR));
624
625 if (lpNewFileName2 == NULL)
626 {
627 Result = FALSE;
628 goto FreeMemAndExit;
629 }
630 }
631
632 wcscpy((WCHAR *) lpNewFileName2,lpNewFileName);
633 size = wcslen(lpNewFileName);
634 wcscpy((WCHAR *)&lpNewFileName2[size], (WCHAR *)&lpDeleteFile[size2]);
635
636 /* copy file */
637 Result = CopyFileW(lpDeleteFile,lpNewFileName2, FALSE);
638
639 /* delete file */
640 DPRINT("MoveFileWithProgressW : Delete file : %S : %S\n",lpDeleteFile, lpNewFileName2);
641
642
643 Result = DeleteFileW(lpDeleteFile);
644 if (Result == FALSE)
645 {
646 DPRINT("MoveFileWithProgressW : Fails\n");
647 break;
648 }
649 }
650 DPRINT("MoveFileWithProgressW : 2 : %S : %S \n",lpExistingFileName2,findBuffer.cFileName);
651 loop = FindNextFileW(hFile, &findBuffer);
652 }
653
654 FindClose(hFile);
655 memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
656 hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
657 if (hFile == NULL)
658 loop=TRUE;
659
660 if (findBuffer.cFileName[0] == L'\0')
661 loop=TRUE;
662
663 if (loop == FALSE)
664 {
665 FindClose(hFile);
666 Result = RemoveDirectoryW(lpExistingFileName);
667 DPRINT("MoveFileWithProgressW RemoveDirectoryW :%S",lpExistingFileName);
668 }
669
670 FreeMemAndExit:
671 DPRINT("MoveFileWithProgressW : result : r=%d, T=%d, F=%d",Result,TRUE,FALSE);
672
673 if (lpNewFileName2 != NULL)
674 {
675 HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
676 lpNewFileName2 = NULL;
677 }
678
679 if (lpExistingFileName2 != NULL)
680 {
681 HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
682 lpExistingFileName2 = NULL;
683 }
684
685 if (lpDeleteFile != NULL)
686 {
687 HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
688 lpDeleteFile = NULL;
689 }
690
691 return Result;
692 // end move folder code
693 }
694 }
695
696 #if 1
697 /* FIXME file rename not yet implemented in all FSDs so it will always
698 * fail, even when the move is to the same device
699 */
700 //else if (STATUS_NOT_IMPLEMENTED == errCode)
701 {
702
703 UNICODE_STRING SrcPathU;
704
705 SrcPathU.Buffer = alloca(sizeof(WCHAR) * MAX_PATH);
706 SrcPathU.MaximumLength = MAX_PATH * sizeof(WCHAR);
707 SrcPathU.Length = GetFullPathNameW(lpExistingFileName, MAX_PATH, SrcPathU.Buffer, NULL);
708 if (SrcPathU.Length >= MAX_PATH)
709 {
710 SetLastError(ERROR_FILENAME_EXCED_RANGE);
711 return FALSE;
712 }
713 SrcPathU.Length *= sizeof(WCHAR);
714
715 DstPathU.Buffer = alloca(sizeof(WCHAR) * MAX_PATH);
716 DstPathU.MaximumLength = MAX_PATH * sizeof(WCHAR);
717 DstPathU.Length = GetFullPathNameW(lpNewFileName, MAX_PATH, DstPathU.Buffer, NULL);
718 if (DstPathU.Length >= MAX_PATH)
719 {
720 SetLastError(ERROR_FILENAME_EXCED_RANGE);
721 return FALSE;
722 }
723 DstPathU.Length *= sizeof(WCHAR);
724
725 if (0 == RtlCompareUnicodeString(&SrcPathU, &DstPathU, TRUE))
726 {
727 /* Source and destination file are the same, nothing to do */
728 return TRUE;
729 }
730
731 Result = CopyFileExW (lpExistingFileName,
732 lpNewFileName,
733 lpProgressRoutine,
734 lpData,
735 NULL,
736 FileRename->ReplaceIfExists ? 0 : COPY_FILE_FAIL_IF_EXISTS);
737 if (Result)
738 {
739 /* Cleanup the source file */
740 AdjustFileAttributes(lpExistingFileName, lpNewFileName);
741 Result = DeleteFileW (lpExistingFileName);
742 }
743 }
744 #endif
745
746 return Result;
747 }
748
749
750 /*
751 * @implemented
752 */
753 BOOL
754 STDCALL
755 MoveFileWithProgressA (
756 LPCSTR lpExistingFileName,
757 LPCSTR lpNewFileName,
758 LPPROGRESS_ROUTINE lpProgressRoutine,
759 LPVOID lpData,
760 DWORD dwFlags
761 )
762 {
763 PWCHAR ExistingFileNameW;
764 PWCHAR NewFileNameW;
765 BOOL ret;
766
767 if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, FALSE)))
768 return FALSE;
769
770 if (!(NewFileNameW= FilenameA2W(lpNewFileName, TRUE)))
771 return FALSE;
772
773 ret = MoveFileWithProgressW (ExistingFileNameW ,
774 NewFileNameW,
775 lpProgressRoutine,
776 lpData,
777 dwFlags);
778
779 RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW);
780
781 return ret;
782 }
783
784
785 /*
786 * @implemented
787 */
788 BOOL
789 STDCALL
790 MoveFileW (
791 LPCWSTR lpExistingFileName,
792 LPCWSTR lpNewFileName
793 )
794 {
795 return MoveFileExW (lpExistingFileName,
796 lpNewFileName,
797 MOVEFILE_COPY_ALLOWED);
798 }
799
800
801 /*
802 * @implemented
803 */
804 BOOL
805 STDCALL
806 MoveFileExW (
807 LPCWSTR lpExistingFileName,
808 LPCWSTR lpNewFileName,
809 DWORD dwFlags
810 )
811 {
812 return MoveFileWithProgressW (lpExistingFileName,
813 lpNewFileName,
814 NULL,
815 NULL,
816 dwFlags);
817 }
818
819
820 /*
821 * @implemented
822 */
823 BOOL
824 STDCALL
825 MoveFileA (
826 LPCSTR lpExistingFileName,
827 LPCSTR lpNewFileName
828 )
829 {
830 return MoveFileExA (lpExistingFileName,
831 lpNewFileName,
832 MOVEFILE_COPY_ALLOWED);
833 }
834
835
836 /*
837 * @implemented
838 */
839 BOOL
840 STDCALL
841 MoveFileExA (
842 LPCSTR lpExistingFileName,
843 LPCSTR lpNewFileName,
844 DWORD dwFlags
845 )
846 {
847 return MoveFileWithProgressA (lpExistingFileName,
848 lpNewFileName,
849 NULL,
850 NULL,
851 dwFlags);
852 }
853
854 /* EOF */