[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / file / file.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 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <k32.h>
16 #define NDEBUG
17 #include <debug.h>
18 DEBUG_CHANNEL(kernel32file);
19
20 /* GLOBALS ******************************************************************/
21
22 BOOL bIsFileApiAnsi = TRUE; // set the file api to ansi or oem
23
24 /* FUNCTIONS ****************************************************************/
25
26
27
28 PWCHAR
29 FilenameA2W(LPCSTR NameA, BOOL alloc)
30 {
31 ANSI_STRING str;
32 UNICODE_STRING strW;
33 PUNICODE_STRING pstrW;
34 NTSTATUS Status;
35
36 //ASSERT(NtCurrentTeb()->StaticUnicodeString.Buffer == NtCurrentTeb()->StaticUnicodeBuffer);
37 ASSERT(NtCurrentTeb()->StaticUnicodeString.MaximumLength == sizeof(NtCurrentTeb()->StaticUnicodeBuffer));
38
39 RtlInitAnsiString(&str, NameA);
40 pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
41
42 if (bIsFileApiAnsi)
43 Status= RtlAnsiStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc );
44 else
45 Status= RtlOemStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc );
46
47 if (NT_SUCCESS(Status))
48 return pstrW->Buffer;
49
50 if (Status== STATUS_BUFFER_OVERFLOW)
51 SetLastError( ERROR_FILENAME_EXCED_RANGE );
52 else
53 SetLastErrorByStatus(Status);
54
55 return NULL;
56 }
57
58
59 /*
60 No copy/conversion is done if the dest. buffer is too small.
61
62 Returns:
63 Success: number of TCHARS copied into dest. buffer NOT including nullterm
64 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm
65 */
66 DWORD
67 FilenameU2A_FitOrFail(
68 LPSTR DestA,
69 INT destLen, /* buffer size in TCHARS incl. nullchar */
70 PUNICODE_STRING SourceU
71 )
72 {
73 DWORD ret;
74
75 /* destLen should never exceed MAX_PATH */
76 if (destLen > MAX_PATH) destLen = MAX_PATH;
77
78 ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
79 /* ret incl. nullchar */
80
81 if (DestA && (INT)ret <= destLen)
82 {
83 ANSI_STRING str;
84
85 str.Buffer = DestA;
86 str.MaximumLength = (USHORT)destLen;
87
88
89 if (bIsFileApiAnsi)
90 RtlUnicodeStringToAnsiString(&str, SourceU, FALSE );
91 else
92 RtlUnicodeStringToOemString(&str, SourceU, FALSE );
93
94 ret = str.Length; /* SUCCESS: length without terminating 0 */
95 }
96
97 return ret;
98 }
99
100
101 /*
102 No copy/conversion is done if the dest. buffer is too small.
103
104 Returns:
105 Success: number of TCHARS copied into dest. buffer NOT including nullterm
106 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm
107 */
108 DWORD
109 FilenameW2A_FitOrFail(
110 LPSTR DestA,
111 INT destLen, /* buffer size in TCHARS incl. nullchar */
112 LPCWSTR SourceW,
113 INT sourceLen /* buffer size in TCHARS incl. nullchar */
114 )
115 {
116 UNICODE_STRING strW;
117
118 if (sourceLen < 0) sourceLen = wcslen(SourceW) + 1;
119
120 strW.Buffer = (PWCHAR)SourceW;
121 strW.MaximumLength = sourceLen * sizeof(WCHAR);
122 strW.Length = strW.MaximumLength - sizeof(WCHAR);
123
124 return FilenameU2A_FitOrFail(DestA, destLen, &strW);
125 }
126
127
128 /*
129 Return: num. TCHARS copied into dest including nullterm
130 */
131 DWORD
132 FilenameA2W_N(
133 LPWSTR dest,
134 INT destlen, /* buffer size in TCHARS incl. nullchar */
135 LPCSTR src,
136 INT srclen /* buffer size in TCHARS incl. nullchar */
137 )
138 {
139 DWORD ret;
140
141 if (srclen < 0) srclen = strlen( src ) + 1;
142
143 if (bIsFileApiAnsi)
144 RtlMultiByteToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen );
145 else
146 RtlOemToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen );
147
148 if (ret) dest[(ret/sizeof(WCHAR))-1]=0;
149
150 return ret/sizeof(WCHAR);
151 }
152
153 /*
154 Return: num. TCHARS copied into dest including nullterm
155 */
156 DWORD
157 FilenameW2A_N(
158 LPSTR dest,
159 INT destlen, /* buffer size in TCHARS incl. nullchar */
160 LPCWSTR src,
161 INT srclen /* buffer size in TCHARS incl. nullchar */
162 )
163 {
164 DWORD ret;
165
166 if (srclen < 0) srclen = wcslen( src ) + 1;
167
168 if (bIsFileApiAnsi)
169 RtlUnicodeToMultiByteN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR));
170 else
171 RtlUnicodeToOemN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR) );
172
173 if (ret) dest[ret-1]=0;
174
175 return ret;
176 }
177
178
179 /*
180 * @implemented
181 */
182 VOID
183 WINAPI
184 SetFileApisToOEM(VOID)
185 {
186 /* Set the correct Base Api */
187 Basep8BitStringToUnicodeString = (PRTL_CONVERT_STRING)RtlOemStringToUnicodeString;
188
189 /* FIXME: Old, deprecated way */
190 bIsFileApiAnsi = FALSE;
191 }
192
193
194 /*
195 * @implemented
196 */
197 VOID
198 WINAPI
199 SetFileApisToANSI(VOID)
200 {
201 /* Set the correct Base Api */
202 Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
203
204 /* FIXME: Old, deprecated way */
205 bIsFileApiAnsi = TRUE;
206 }
207
208
209 /*
210 * @implemented
211 */
212 BOOL WINAPI
213 AreFileApisANSI(VOID)
214 {
215 return bIsFileApiAnsi;
216 }
217
218
219 /*
220 * @implemented
221 */
222 HFILE WINAPI
223 OpenFile(LPCSTR lpFileName,
224 LPOFSTRUCT lpReOpenBuff,
225 UINT uStyle)
226 {
227 OBJECT_ATTRIBUTES ObjectAttributes;
228 IO_STATUS_BLOCK IoStatusBlock;
229 UNICODE_STRING FileNameString;
230 UNICODE_STRING FileNameU;
231 ANSI_STRING FileName;
232 WCHAR PathNameW[MAX_PATH];
233 HANDLE FileHandle = NULL;
234 NTSTATUS errCode;
235 PWCHAR FilePart;
236 ULONG Len;
237
238 TRACE("OpenFile('%s', lpReOpenBuff %x, uStyle %x)\n", lpFileName, lpReOpenBuff, uStyle);
239
240 if (lpReOpenBuff == NULL)
241 {
242 return HFILE_ERROR;
243 }
244
245 lpReOpenBuff->nErrCode = 0;
246
247 if (uStyle & OF_REOPEN) lpFileName = lpReOpenBuff->szPathName;
248
249 if (!lpFileName)
250 {
251 return HFILE_ERROR;
252 }
253
254 if (!GetFullPathNameA(lpFileName,
255 sizeof(lpReOpenBuff->szPathName),
256 lpReOpenBuff->szPathName,
257 NULL))
258 {
259 lpReOpenBuff->nErrCode = GetLastError();
260 return HFILE_ERROR;
261 }
262
263 if (uStyle & OF_PARSE)
264 {
265 lpReOpenBuff->fFixedDisk = (GetDriveTypeA(lpReOpenBuff->szPathName) != DRIVE_REMOVABLE);
266 TRACE("(%s): OF_PARSE, res = '%s'\n", lpFileName, lpReOpenBuff->szPathName);
267 return 0;
268 }
269
270 if ((uStyle & OF_EXIST) && !(uStyle & OF_CREATE))
271 {
272 DWORD dwAttributes = GetFileAttributesA(lpReOpenBuff->szPathName);
273
274 switch (dwAttributes)
275 {
276 case 0xFFFFFFFF: /* File does not exist */
277 SetLastError(ERROR_FILE_NOT_FOUND);
278 lpReOpenBuff->nErrCode = (WORD) ERROR_FILE_NOT_FOUND;
279 return -1;
280
281 case FILE_ATTRIBUTE_DIRECTORY:
282 SetLastError(ERROR_ACCESS_DENIED);
283 lpReOpenBuff->nErrCode = (WORD) ERROR_ACCESS_DENIED;
284 return -1;
285
286 default:
287 lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
288 return 1;
289 }
290 }
291 lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
292 if ((uStyle & OF_CREATE) == OF_CREATE)
293 {
294 DWORD Sharing;
295 switch (uStyle & 0x70)
296 {
297 case OF_SHARE_EXCLUSIVE: Sharing = 0; break;
298 case OF_SHARE_DENY_WRITE: Sharing = FILE_SHARE_READ; break;
299 case OF_SHARE_DENY_READ: Sharing = FILE_SHARE_WRITE; break;
300 case OF_SHARE_DENY_NONE:
301 case OF_SHARE_COMPAT:
302 default:
303 Sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
304 }
305 return (HFILE) CreateFileA (lpFileName,
306 GENERIC_READ | GENERIC_WRITE,
307 Sharing,
308 NULL,
309 CREATE_ALWAYS,
310 FILE_ATTRIBUTE_NORMAL,
311 0);
312 }
313
314 RtlInitAnsiString (&FileName, (LPSTR)lpFileName);
315
316 /* convert ansi (or oem) string to unicode */
317 if (bIsFileApiAnsi)
318 RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE);
319 else
320 RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE);
321
322 Len = SearchPathW (NULL,
323 FileNameU.Buffer,
324 NULL,
325 OFS_MAXPATHNAME,
326 PathNameW,
327 &FilePart);
328
329 RtlFreeUnicodeString(&FileNameU);
330
331 if (Len == 0 || Len > OFS_MAXPATHNAME)
332 {
333 lpReOpenBuff->nErrCode = GetLastError();
334 return (HFILE)INVALID_HANDLE_VALUE;
335 }
336
337 if (uStyle & OF_DELETE)
338 {
339 if (!DeleteFileW(PathNameW))
340 {
341 lpReOpenBuff->nErrCode = GetLastError();
342 return HFILE_ERROR;
343 }
344 TRACE("(%s): OF_DELETE return = OK\n", lpFileName);
345 return TRUE;
346 }
347
348 FileName.Buffer = lpReOpenBuff->szPathName;
349 FileName.Length = 0;
350 FileName.MaximumLength = OFS_MAXPATHNAME;
351
352 RtlInitUnicodeString(&FileNameU, PathNameW);
353
354 /* convert unicode string to ansi (or oem) */
355 if (bIsFileApiAnsi)
356 RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE);
357 else
358 RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE);
359
360 if (!RtlDosPathNameToNtPathName_U (PathNameW,
361 &FileNameString,
362 NULL,
363 NULL))
364 {
365 return (HFILE)INVALID_HANDLE_VALUE;
366 }
367
368 // FILE_SHARE_READ
369 // FILE_NO_INTERMEDIATE_BUFFERING
370
371 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
372 ObjectAttributes.RootDirectory = NULL;
373 ObjectAttributes.ObjectName = &FileNameString;
374 ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
375 ObjectAttributes.SecurityDescriptor = NULL;
376 ObjectAttributes.SecurityQualityOfService = NULL;
377
378 errCode = NtOpenFile (&FileHandle,
379 GENERIC_READ|SYNCHRONIZE,
380 &ObjectAttributes,
381 &IoStatusBlock,
382 FILE_SHARE_READ,
383 FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
384
385 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer);
386
387 lpReOpenBuff->nErrCode = RtlNtStatusToDosError(errCode);
388
389 if (!NT_SUCCESS(errCode))
390 {
391 SetLastErrorByStatus (errCode);
392 return (HFILE)INVALID_HANDLE_VALUE;
393 }
394
395 if (uStyle & OF_EXIST)
396 {
397 NtClose(FileHandle);
398 return (HFILE)1;
399 }
400
401 return (HFILE)FileHandle;
402 }
403
404
405 /*
406 * @implemented
407 */
408 BOOL WINAPI
409 FlushFileBuffers(IN HANDLE hFile)
410 {
411 NTSTATUS Status;
412 IO_STATUS_BLOCK IoStatusBlock;
413
414 hFile = TranslateStdHandle(hFile);
415
416 if (IsConsoleHandle(hFile))
417 {
418 return FlushConsoleInputBuffer(hFile);
419 }
420
421 Status = NtFlushBuffersFile(hFile,
422 &IoStatusBlock);
423 if (!NT_SUCCESS(Status))
424 {
425 BaseSetLastNTError(Status);
426 return FALSE;
427 }
428 return TRUE;
429 }
430
431
432 /*
433 * @implemented
434 */
435 DWORD WINAPI
436 SetFilePointer(HANDLE hFile,
437 LONG lDistanceToMove,
438 PLONG lpDistanceToMoveHigh,
439 DWORD dwMoveMethod)
440 {
441 FILE_POSITION_INFORMATION FilePosition;
442 FILE_STANDARD_INFORMATION FileStandard;
443 NTSTATUS errCode;
444 IO_STATUS_BLOCK IoStatusBlock;
445 LARGE_INTEGER Distance;
446
447 TRACE("SetFilePointer(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
448 hFile,lDistanceToMove,dwMoveMethod);
449
450 if(IsConsoleHandle(hFile))
451 {
452 SetLastError(ERROR_INVALID_HANDLE);
453 return INVALID_SET_FILE_POINTER;
454 }
455
456 if (lpDistanceToMoveHigh)
457 {
458 Distance.u.HighPart = *lpDistanceToMoveHigh;
459 Distance.u.LowPart = lDistanceToMove;
460 }
461 else
462 {
463 Distance.QuadPart = lDistanceToMove;
464 }
465
466 switch(dwMoveMethod)
467 {
468 case FILE_CURRENT:
469 errCode = NtQueryInformationFile(hFile,
470 &IoStatusBlock,
471 &FilePosition,
472 sizeof(FILE_POSITION_INFORMATION),
473 FilePositionInformation);
474 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
475 if (!NT_SUCCESS(errCode))
476 {
477 if (lpDistanceToMoveHigh != NULL)
478 *lpDistanceToMoveHigh = -1;
479 SetLastErrorByStatus(errCode);
480 return INVALID_SET_FILE_POINTER;
481 }
482 break;
483 case FILE_END:
484 errCode = NtQueryInformationFile(hFile,
485 &IoStatusBlock,
486 &FileStandard,
487 sizeof(FILE_STANDARD_INFORMATION),
488 FileStandardInformation);
489 FilePosition.CurrentByteOffset.QuadPart =
490 FileStandard.EndOfFile.QuadPart + Distance.QuadPart;
491 if (!NT_SUCCESS(errCode))
492 {
493 if (lpDistanceToMoveHigh != NULL)
494 *lpDistanceToMoveHigh = -1;
495 SetLastErrorByStatus(errCode);
496 return INVALID_SET_FILE_POINTER;
497 }
498 break;
499 case FILE_BEGIN:
500 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
501 break;
502 default:
503 SetLastError(ERROR_INVALID_PARAMETER);
504 return INVALID_SET_FILE_POINTER;
505 }
506
507 if(FilePosition.CurrentByteOffset.QuadPart < 0)
508 {
509 SetLastError(ERROR_NEGATIVE_SEEK);
510 return INVALID_SET_FILE_POINTER;
511 }
512
513 if (lpDistanceToMoveHigh == NULL && FilePosition.CurrentByteOffset.HighPart != 0)
514 {
515 /* If we're moving the pointer outside of the 32 bit boundaries but
516 the application only passed a 32 bit value we need to bail out! */
517 SetLastError(ERROR_INVALID_PARAMETER);
518 return INVALID_SET_FILE_POINTER;
519 }
520
521 errCode = NtSetInformationFile(hFile,
522 &IoStatusBlock,
523 &FilePosition,
524 sizeof(FILE_POSITION_INFORMATION),
525 FilePositionInformation);
526 if (!NT_SUCCESS(errCode))
527 {
528 if (lpDistanceToMoveHigh != NULL)
529 *lpDistanceToMoveHigh = -1;
530
531 SetLastErrorByStatus(errCode);
532 return INVALID_SET_FILE_POINTER;
533 }
534
535 if (lpDistanceToMoveHigh != NULL)
536 {
537 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
538 }
539
540 if (FilePosition.CurrentByteOffset.u.LowPart == MAXDWORD)
541 {
542 /* The value of -1 is valid here, especially when the new
543 file position is greater than 4 GB. Since NtSetInformationFile
544 succeeded we never set an error code and we explicitly need
545 to clear a previously set error code in this case, which
546 an application will check if INVALID_SET_FILE_POINTER is returned! */
547 SetLastError(ERROR_SUCCESS);
548 }
549
550 return FilePosition.CurrentByteOffset.u.LowPart;
551 }
552
553
554 /*
555 * @implemented
556 */
557 BOOL
558 WINAPI
559 SetFilePointerEx(HANDLE hFile,
560 LARGE_INTEGER liDistanceToMove,
561 PLARGE_INTEGER lpNewFilePointer,
562 DWORD dwMoveMethod)
563 {
564 FILE_POSITION_INFORMATION FilePosition;
565 FILE_STANDARD_INFORMATION FileStandard;
566 NTSTATUS errCode;
567 IO_STATUS_BLOCK IoStatusBlock;
568
569 if(IsConsoleHandle(hFile))
570 {
571 SetLastError(ERROR_INVALID_HANDLE);
572 return FALSE;
573 }
574
575 switch(dwMoveMethod)
576 {
577 case FILE_CURRENT:
578 NtQueryInformationFile(hFile,
579 &IoStatusBlock,
580 &FilePosition,
581 sizeof(FILE_POSITION_INFORMATION),
582 FilePositionInformation);
583 FilePosition.CurrentByteOffset.QuadPart += liDistanceToMove.QuadPart;
584 break;
585 case FILE_END:
586 NtQueryInformationFile(hFile,
587 &IoStatusBlock,
588 &FileStandard,
589 sizeof(FILE_STANDARD_INFORMATION),
590 FileStandardInformation);
591 FilePosition.CurrentByteOffset.QuadPart =
592 FileStandard.EndOfFile.QuadPart + liDistanceToMove.QuadPart;
593 break;
594 case FILE_BEGIN:
595 FilePosition.CurrentByteOffset.QuadPart = liDistanceToMove.QuadPart;
596 break;
597 default:
598 SetLastError(ERROR_INVALID_PARAMETER);
599 return FALSE;
600 }
601
602 if(FilePosition.CurrentByteOffset.QuadPart < 0)
603 {
604 SetLastError(ERROR_NEGATIVE_SEEK);
605 return FALSE;
606 }
607
608 errCode = NtSetInformationFile(hFile,
609 &IoStatusBlock,
610 &FilePosition,
611 sizeof(FILE_POSITION_INFORMATION),
612 FilePositionInformation);
613 if (!NT_SUCCESS(errCode))
614 {
615 SetLastErrorByStatus(errCode);
616 return FALSE;
617 }
618
619 if (lpNewFilePointer)
620 {
621 *lpNewFilePointer = FilePosition.CurrentByteOffset;
622 }
623 return TRUE;
624 }
625
626
627 /*
628 * @implemented
629 */
630 DWORD WINAPI
631 GetFileType(HANDLE hFile)
632 {
633 FILE_FS_DEVICE_INFORMATION DeviceInfo;
634 IO_STATUS_BLOCK StatusBlock;
635 NTSTATUS Status;
636
637 /* Get real handle */
638 hFile = TranslateStdHandle(hFile);
639
640 /* Check for console handle */
641 if (IsConsoleHandle(hFile))
642 {
643 if (VerifyConsoleIoHandle(hFile))
644 return FILE_TYPE_CHAR;
645 }
646
647 Status = NtQueryVolumeInformationFile(hFile,
648 &StatusBlock,
649 &DeviceInfo,
650 sizeof(FILE_FS_DEVICE_INFORMATION),
651 FileFsDeviceInformation);
652 if (!NT_SUCCESS(Status))
653 {
654 SetLastErrorByStatus(Status);
655 return FILE_TYPE_UNKNOWN;
656 }
657
658 switch (DeviceInfo.DeviceType)
659 {
660 case FILE_DEVICE_CD_ROM:
661 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
662 case FILE_DEVICE_CONTROLLER:
663 case FILE_DEVICE_DATALINK:
664 case FILE_DEVICE_DFS:
665 case FILE_DEVICE_DISK:
666 case FILE_DEVICE_DISK_FILE_SYSTEM:
667 case FILE_DEVICE_VIRTUAL_DISK:
668 return FILE_TYPE_DISK;
669
670 case FILE_DEVICE_KEYBOARD:
671 case FILE_DEVICE_MOUSE:
672 case FILE_DEVICE_NULL:
673 case FILE_DEVICE_PARALLEL_PORT:
674 case FILE_DEVICE_PRINTER:
675 case FILE_DEVICE_SERIAL_PORT:
676 case FILE_DEVICE_SCREEN:
677 case FILE_DEVICE_SOUND:
678 case FILE_DEVICE_MODEM:
679 return FILE_TYPE_CHAR;
680
681 case FILE_DEVICE_NAMED_PIPE:
682 return FILE_TYPE_PIPE;
683 }
684
685 return FILE_TYPE_UNKNOWN;
686 }
687
688
689 /*
690 * @implemented
691 */
692 DWORD WINAPI
693 GetFileSize(HANDLE hFile,
694 LPDWORD lpFileSizeHigh)
695 {
696 NTSTATUS errCode;
697 FILE_STANDARD_INFORMATION FileStandard;
698 IO_STATUS_BLOCK IoStatusBlock;
699
700 errCode = NtQueryInformationFile(hFile,
701 &IoStatusBlock,
702 &FileStandard,
703 sizeof(FILE_STANDARD_INFORMATION),
704 FileStandardInformation);
705 if (!NT_SUCCESS(errCode))
706 {
707 SetLastErrorByStatus(errCode);
708 if ( lpFileSizeHigh == NULL )
709 {
710 return -1;
711 }
712 else
713 {
714 return 0;
715 }
716 }
717 if ( lpFileSizeHigh != NULL )
718 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
719
720 return FileStandard.EndOfFile.u.LowPart;
721 }
722
723
724 /*
725 * @implemented
726 */
727 BOOL
728 WINAPI
729 GetFileSizeEx(
730 HANDLE hFile,
731 PLARGE_INTEGER lpFileSize
732 )
733 {
734 NTSTATUS errCode;
735 FILE_STANDARD_INFORMATION FileStandard;
736 IO_STATUS_BLOCK IoStatusBlock;
737
738 errCode = NtQueryInformationFile(hFile,
739 &IoStatusBlock,
740 &FileStandard,
741 sizeof(FILE_STANDARD_INFORMATION),
742 FileStandardInformation);
743 if (!NT_SUCCESS(errCode))
744 {
745 SetLastErrorByStatus(errCode);
746 return FALSE;
747 }
748 if (lpFileSize)
749 *lpFileSize = FileStandard.EndOfFile;
750
751 return TRUE;
752 }
753
754
755 /*
756 * @implemented
757 */
758 DWORD WINAPI
759 GetCompressedFileSizeA(LPCSTR lpFileName,
760 LPDWORD lpFileSizeHigh)
761 {
762 PWCHAR FileNameW;
763
764 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
765 return INVALID_FILE_SIZE;
766
767 return GetCompressedFileSizeW(FileNameW, lpFileSizeHigh);
768 }
769
770
771 /*
772 * @implemented
773 */
774 DWORD WINAPI
775 GetCompressedFileSizeW(LPCWSTR lpFileName,
776 LPDWORD lpFileSizeHigh)
777 {
778 FILE_COMPRESSION_INFORMATION FileCompression;
779 NTSTATUS errCode;
780 IO_STATUS_BLOCK IoStatusBlock;
781 HANDLE hFile;
782
783 hFile = CreateFileW(lpFileName,
784 GENERIC_READ,
785 FILE_SHARE_READ,
786 NULL,
787 OPEN_EXISTING,
788 FILE_ATTRIBUTE_NORMAL,
789 NULL);
790
791 if (hFile == INVALID_HANDLE_VALUE)
792 return INVALID_FILE_SIZE;
793
794 errCode = NtQueryInformationFile(hFile,
795 &IoStatusBlock,
796 &FileCompression,
797 sizeof(FILE_COMPRESSION_INFORMATION),
798 FileCompressionInformation);
799
800 CloseHandle(hFile);
801
802 if (!NT_SUCCESS(errCode))
803 {
804 SetLastErrorByStatus(errCode);
805 return INVALID_FILE_SIZE;
806 }
807
808 if(lpFileSizeHigh)
809 *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart;
810
811 SetLastError(NO_ERROR);
812 return FileCompression.CompressedFileSize.u.LowPart;
813 }
814
815
816 /*
817 * @implemented
818 */
819 BOOL WINAPI
820 GetFileInformationByHandle(HANDLE hFile,
821 LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
822 {
823 struct
824 {
825 FILE_FS_VOLUME_INFORMATION FileFsVolume;
826 WCHAR Name[255];
827 }
828 FileFsVolume;
829
830 FILE_BASIC_INFORMATION FileBasic;
831 FILE_INTERNAL_INFORMATION FileInternal;
832 FILE_STANDARD_INFORMATION FileStandard;
833 NTSTATUS errCode;
834 IO_STATUS_BLOCK IoStatusBlock;
835
836 if(IsConsoleHandle(hFile))
837 {
838 SetLastError(ERROR_INVALID_HANDLE);
839 return FALSE;
840 }
841
842 errCode = NtQueryInformationFile(hFile,
843 &IoStatusBlock,
844 &FileBasic,
845 sizeof(FILE_BASIC_INFORMATION),
846 FileBasicInformation);
847 if (!NT_SUCCESS(errCode))
848 {
849 SetLastErrorByStatus(errCode);
850 return FALSE;
851 }
852
853 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
854
855 lpFileInformation->ftCreationTime.dwHighDateTime = FileBasic.CreationTime.u.HighPart;
856 lpFileInformation->ftCreationTime.dwLowDateTime = FileBasic.CreationTime.u.LowPart;
857
858 lpFileInformation->ftLastAccessTime.dwHighDateTime = FileBasic.LastAccessTime.u.HighPart;
859 lpFileInformation->ftLastAccessTime.dwLowDateTime = FileBasic.LastAccessTime.u.LowPart;
860
861 lpFileInformation->ftLastWriteTime.dwHighDateTime = FileBasic.LastWriteTime.u.HighPart;
862 lpFileInformation->ftLastWriteTime.dwLowDateTime = FileBasic.LastWriteTime.u.LowPart;
863
864 errCode = NtQueryInformationFile(hFile,
865 &IoStatusBlock,
866 &FileInternal,
867 sizeof(FILE_INTERNAL_INFORMATION),
868 FileInternalInformation);
869 if (!NT_SUCCESS(errCode))
870 {
871 SetLastErrorByStatus(errCode);
872 return FALSE;
873 }
874
875 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
876 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
877
878 errCode = NtQueryVolumeInformationFile(hFile,
879 &IoStatusBlock,
880 &FileFsVolume,
881 sizeof(FileFsVolume),
882 FileFsVolumeInformation);
883 if (!NT_SUCCESS(errCode))
884 {
885 SetLastErrorByStatus(errCode);
886 return FALSE;
887 }
888
889 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
890
891 errCode = NtQueryInformationFile(hFile,
892 &IoStatusBlock,
893 &FileStandard,
894 sizeof(FILE_STANDARD_INFORMATION),
895 FileStandardInformation);
896 if (!NT_SUCCESS(errCode))
897 {
898 SetLastErrorByStatus(errCode);
899 return FALSE;
900 }
901
902 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
903 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
904 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
905
906 return TRUE;
907 }
908
909
910 /*
911 * @implemented
912 */
913 BOOL WINAPI
914 GetFileAttributesExW(LPCWSTR lpFileName,
915 GET_FILEEX_INFO_LEVELS fInfoLevelId,
916 LPVOID lpFileInformation)
917 {
918 FILE_NETWORK_OPEN_INFORMATION FileInformation;
919 OBJECT_ATTRIBUTES ObjectAttributes;
920 UNICODE_STRING FileName;
921 NTSTATUS Status;
922 WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData;
923
924 TRACE("GetFileAttributesExW(%S) called\n", lpFileName);
925
926
927 if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL)
928 {
929 SetLastError(ERROR_INVALID_PARAMETER);
930 return FALSE;
931 }
932
933 /* Validate and translate the filename */
934 if (!RtlDosPathNameToNtPathName_U (lpFileName,
935 &FileName,
936 NULL,
937 NULL))
938 {
939 WARN ("Invalid path '%S'\n", lpFileName);
940 SetLastError (ERROR_BAD_PATHNAME);
941 return FALSE;
942 }
943
944 /* build the object attributes */
945 InitializeObjectAttributes (&ObjectAttributes,
946 &FileName,
947 OBJ_CASE_INSENSITIVE,
948 NULL,
949 NULL);
950
951 /* Get file attributes */
952 Status = NtQueryFullAttributesFile(&ObjectAttributes,
953 &FileInformation);
954
955 RtlFreeUnicodeString (&FileName);
956 if (!NT_SUCCESS (Status))
957 {
958 WARN ("NtQueryFullAttributesFile() failed (Status %lx)\n", Status);
959 SetLastErrorByStatus (Status);
960 return FALSE;
961 }
962
963 FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation;
964 FileAttributeData->dwFileAttributes = FileInformation.FileAttributes;
965 FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart;
966 FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart;
967 FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart;
968 FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart;
969 FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart;
970 FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart;
971 FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart;
972 FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart;
973
974 return TRUE;
975 }
976
977 /*
978 * @implemented
979 */
980 BOOL WINAPI
981 GetFileAttributesExA(LPCSTR lpFileName,
982 GET_FILEEX_INFO_LEVELS fInfoLevelId,
983 LPVOID lpFileInformation)
984 {
985 PWCHAR FileNameW;
986
987 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
988 return FALSE;
989
990 return GetFileAttributesExW(FileNameW, fInfoLevelId, lpFileInformation);
991 }
992
993
994 /*
995 * @implemented
996 */
997 DWORD WINAPI
998 GetFileAttributesA(LPCSTR lpFileName)
999 {
1000 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
1001 PWSTR FileNameW;
1002 BOOL ret;
1003
1004 if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE)))
1005 return INVALID_FILE_ATTRIBUTES;
1006
1007 ret = GetFileAttributesExW(FileNameW, GetFileExInfoStandard, &FileAttributeData);
1008
1009 return ret ? FileAttributeData.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
1010 }
1011
1012
1013 /*
1014 * @implemented
1015 */
1016 DWORD WINAPI
1017 GetFileAttributesW(LPCWSTR lpFileName)
1018 {
1019 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
1020 BOOL Result;
1021
1022 TRACE ("GetFileAttributeW(%S) called\n", lpFileName);
1023
1024 Result = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &FileAttributeData);
1025
1026 return Result ? FileAttributeData.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
1027 }
1028
1029
1030 /*
1031 * @implemented
1032 */
1033 BOOL WINAPI
1034 GetFileAttributesByHandle(IN HANDLE hFile,
1035 OUT LPDWORD dwFileAttributes,
1036 IN DWORD dwFlags)
1037 {
1038 FILE_BASIC_INFORMATION FileBasic;
1039 IO_STATUS_BLOCK IoStatusBlock;
1040 NTSTATUS Status;
1041
1042 UNREFERENCED_PARAMETER(dwFlags);
1043
1044 if (IsConsoleHandle(hFile))
1045 {
1046 SetLastError(ERROR_INVALID_HANDLE);
1047 return FALSE;
1048 }
1049
1050 Status = NtQueryInformationFile(hFile,
1051 &IoStatusBlock,
1052 &FileBasic,
1053 sizeof(FileBasic),
1054 FileBasicInformation);
1055 if (NT_SUCCESS(Status))
1056 {
1057 *dwFileAttributes = FileBasic.FileAttributes;
1058 return TRUE;
1059 }
1060
1061 SetLastErrorByStatus(Status);
1062 return FALSE;
1063 }
1064
1065
1066 /*
1067 * @implemented
1068 */
1069 BOOL WINAPI
1070 SetFileAttributesByHandle(IN HANDLE hFile,
1071 IN DWORD dwFileAttributes,
1072 IN DWORD dwFlags)
1073 {
1074 FILE_BASIC_INFORMATION FileBasic;
1075 IO_STATUS_BLOCK IoStatusBlock;
1076 NTSTATUS Status;
1077
1078 UNREFERENCED_PARAMETER(dwFlags);
1079
1080 if (IsConsoleHandle(hFile))
1081 {
1082 SetLastError(ERROR_INVALID_HANDLE);
1083 return FALSE;
1084 }
1085
1086 Status = NtQueryInformationFile(hFile,
1087 &IoStatusBlock,
1088 &FileBasic,
1089 sizeof(FileBasic),
1090 FileBasicInformation);
1091 if (NT_SUCCESS(Status))
1092 {
1093 FileBasic.FileAttributes = dwFileAttributes;
1094
1095 Status = NtSetInformationFile(hFile,
1096 &IoStatusBlock,
1097 &FileBasic,
1098 sizeof(FileBasic),
1099 FileBasicInformation);
1100 }
1101
1102 if (!NT_SUCCESS(Status))
1103 {
1104 SetLastErrorByStatus(Status);
1105 return FALSE;
1106 }
1107
1108 return TRUE;
1109 }
1110
1111
1112 /*
1113 * @implemented
1114 */
1115 BOOL WINAPI
1116 SetFileAttributesA(
1117 LPCSTR lpFileName,
1118 DWORD dwFileAttributes)
1119 {
1120 PWCHAR FileNameW;
1121
1122 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
1123 return FALSE;
1124
1125 return SetFileAttributesW(FileNameW, dwFileAttributes);
1126 }
1127
1128
1129 /*
1130 * @implemented
1131 */
1132 BOOL WINAPI
1133 SetFileAttributesW(LPCWSTR lpFileName,
1134 DWORD dwFileAttributes)
1135 {
1136 FILE_BASIC_INFORMATION FileInformation;
1137 OBJECT_ATTRIBUTES ObjectAttributes;
1138 IO_STATUS_BLOCK IoStatusBlock;
1139 UNICODE_STRING FileName;
1140 HANDLE FileHandle;
1141 NTSTATUS Status;
1142
1143 TRACE ("SetFileAttributeW(%S, 0x%lx) called\n", lpFileName, dwFileAttributes);
1144
1145 /* Validate and translate the filename */
1146 if (!RtlDosPathNameToNtPathName_U (lpFileName,
1147 &FileName,
1148 NULL,
1149 NULL))
1150 {
1151 WARN ("Invalid path\n");
1152 SetLastError (ERROR_BAD_PATHNAME);
1153 return FALSE;
1154 }
1155 TRACE ("FileName: \'%wZ\'\n", &FileName);
1156
1157 /* build the object attributes */
1158 InitializeObjectAttributes (&ObjectAttributes,
1159 &FileName,
1160 OBJ_CASE_INSENSITIVE,
1161 NULL,
1162 NULL);
1163
1164 /* Open the file */
1165 Status = NtOpenFile (&FileHandle,
1166 SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
1167 &ObjectAttributes,
1168 &IoStatusBlock,
1169 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1170 FILE_SYNCHRONOUS_IO_NONALERT);
1171 RtlFreeUnicodeString (&FileName);
1172 if (!NT_SUCCESS (Status))
1173 {
1174 WARN ("NtOpenFile() failed (Status %lx)\n", Status);
1175 SetLastErrorByStatus (Status);
1176 return FALSE;
1177 }
1178
1179 Status = NtQueryInformationFile(FileHandle,
1180 &IoStatusBlock,
1181 &FileInformation,
1182 sizeof(FILE_BASIC_INFORMATION),
1183 FileBasicInformation);
1184 if (!NT_SUCCESS(Status))
1185 {
1186 WARN ("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", Status);
1187 NtClose (FileHandle);
1188 SetLastErrorByStatus (Status);
1189 return FALSE;
1190 }
1191
1192 FileInformation.FileAttributes = dwFileAttributes;
1193 Status = NtSetInformationFile(FileHandle,
1194 &IoStatusBlock,
1195 &FileInformation,
1196 sizeof(FILE_BASIC_INFORMATION),
1197 FileBasicInformation);
1198 NtClose (FileHandle);
1199 if (!NT_SUCCESS(Status))
1200 {
1201 WARN ("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", Status);
1202 SetLastErrorByStatus (Status);
1203 return FALSE;
1204 }
1205
1206 return TRUE;
1207 }
1208
1209
1210
1211
1212 /***********************************************************************
1213 * GetTempFileNameA (KERNEL32.@)
1214 */
1215 UINT WINAPI
1216 GetTempFileNameA(IN LPCSTR lpPathName,
1217 IN LPCSTR lpPrefixString,
1218 IN UINT uUnique,
1219 OUT LPSTR lpTempFileName)
1220 {
1221 UINT ID;
1222 NTSTATUS Status;
1223 LPWSTR lpTempFileNameW;
1224 PUNICODE_STRING lpPathNameW;
1225 ANSI_STRING TempFileNameStringA;
1226 UNICODE_STRING lpPrefixStringW, TempFileNameStringW;
1227
1228 /* Convert strings */
1229 lpPathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
1230 if (!lpPathNameW)
1231 {
1232 return 0;
1233 }
1234
1235 if (!Basep8BitStringToDynamicUnicodeString(&lpPrefixStringW, lpPrefixString))
1236 {
1237 return 0;
1238 }
1239
1240 lpTempFileNameW = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
1241 if (!lpTempFileNameW)
1242 {
1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1244 RtlFreeUnicodeString(&lpPrefixStringW);
1245 return 0;
1246 }
1247
1248 /* Call Unicode */
1249 ID = GetTempFileNameW(lpPathNameW->Buffer, lpPrefixStringW.Buffer, uUnique, lpTempFileNameW);
1250 if (ID)
1251 {
1252 RtlInitUnicodeString(&TempFileNameStringW, lpTempFileNameW);
1253 TempFileNameStringA.Buffer = lpTempFileName;
1254 TempFileNameStringA.MaximumLength = MAX_PATH;
1255
1256 Status = BasepUnicodeStringTo8BitString(&TempFileNameStringA, &TempFileNameStringW, FALSE);
1257 if (!NT_SUCCESS(Status))
1258 {
1259 BaseSetLastNTError(Status);
1260 ID = 0;
1261 }
1262 }
1263
1264 /* Cleanup */
1265 RtlFreeUnicodeString(&lpPrefixStringW);
1266 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTempFileNameW);
1267 return ID;
1268 }
1269
1270 /***********************************************************************
1271 * GetTempFileNameW (KERNEL32.@)
1272 */
1273 UINT WINAPI
1274 GetTempFileNameW(IN LPCWSTR lpPathName,
1275 IN LPCWSTR lpPrefixString,
1276 IN UINT uUnique,
1277 OUT LPWSTR lpTempFileName)
1278 {
1279 CHAR * Let;
1280 HANDLE TempFile;
1281 UINT ID, Num = 0;
1282 CHAR IDString[5];
1283 WCHAR * TempFileName;
1284 CSR_API_MESSAGE ApiMessage;
1285 DWORD FileAttributes, LastError;
1286 UNICODE_STRING PathNameString, PrefixString;
1287 static const WCHAR Ext[] = { L'.', 't', 'm', 'p', UNICODE_NULL };
1288
1289 RtlInitUnicodeString(&PathNameString, lpPathName);
1290 if (PathNameString.Length == 0 || PathNameString.Buffer[(PathNameString.Length / sizeof(WCHAR)) - 1] != L'\\')
1291 {
1292 PathNameString.Length += sizeof(WCHAR);
1293 }
1294
1295 /* lpTempFileName must be able to contain: PathName, Prefix (3), number(4), .tmp(4) & \0(1)
1296 * See: http://msdn.microsoft.com/en-us/library/aa364991%28v=vs.85%29.aspx
1297 */
1298 if (PathNameString.Length > (MAX_PATH - 3 - 4 - 4 - 1) * sizeof(WCHAR))
1299 {
1300 SetLastError(ERROR_BUFFER_OVERFLOW);
1301 return 0;
1302 }
1303
1304 /* If PathName and TempFileName aren't the same buffer, move PathName to TempFileName */
1305 if (lpPathName != lpTempFileName)
1306 {
1307 memmove(lpTempFileName, PathNameString.Buffer, PathNameString.Length);
1308 }
1309
1310 /* PathName MUST BE a path. Check it */
1311 lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
1312 FileAttributes = GetFileAttributesW(lpTempFileName);
1313 if (FileAttributes == INVALID_FILE_ATTRIBUTES)
1314 {
1315 /* Append a '\' if necessary */
1316 lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
1317 lpTempFileName[PathNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
1318 FileAttributes = GetFileAttributesW(lpTempFileName);
1319 if (FileAttributes == INVALID_FILE_ATTRIBUTES)
1320 {
1321 SetLastError(ERROR_DIRECTORY);
1322 return 0;
1323 }
1324 }
1325 if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1326 {
1327 SetLastError(ERROR_DIRECTORY);
1328 return 0;
1329 }
1330
1331 /* Make sure not to mix path & prefix */
1332 lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
1333 RtlInitUnicodeString(&PrefixString, lpPrefixString);
1334 if (PrefixString.Length > 3 * sizeof(WCHAR))
1335 {
1336 PrefixString.Length = 3 * sizeof(WCHAR);
1337 }
1338
1339 /* Append prefix to path */
1340 TempFileName = lpTempFileName + PathNameString.Length / sizeof(WCHAR);
1341 memmove(TempFileName, PrefixString.Buffer, PrefixString.Length);
1342 TempFileName += PrefixString.Length / sizeof(WCHAR);
1343
1344 /* Then, generate filename */
1345 do
1346 {
1347 /* If user didn't gave any ID, ask Csrss to give one */
1348 if (!uUnique)
1349 {
1350 CsrClientCallServer(&ApiMessage, NULL, MAKE_CSR_API(GET_TEMP_FILE, CSR_NATIVE), sizeof(CSR_API_MESSAGE));
1351 if (ApiMessage.Data.GetTempFile.UniqueID == 0)
1352 {
1353 Num++;
1354 continue;
1355 }
1356
1357 ID = ApiMessage.Data.GetTempFile.UniqueID;
1358 }
1359 else
1360 {
1361 ID = uUnique;
1362 }
1363
1364 /* Convert that ID to wchar */
1365 RtlIntegerToChar(ID, 0x10, sizeof(IDString), IDString);
1366 Let = IDString;
1367 do
1368 {
1369 *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
1370 } while (*Let != 0);
1371
1372 /* Append extension & UNICODE_NULL */
1373 memmove(TempFileName, Ext, sizeof(Ext) + sizeof(WCHAR));
1374
1375 /* If user provided its ID, just return */
1376 if (uUnique)
1377 {
1378 return uUnique;
1379 }
1380
1381 /* Then, try to create file */
1382 if (!RtlIsDosDeviceName_U(lpTempFileName))
1383 {
1384 TempFile = CreateFileW(lpTempFileName,
1385 GENERIC_READ,
1386 0,
1387 NULL,
1388 CREATE_NEW,
1389 FILE_ATTRIBUTE_NORMAL,
1390 0);
1391 if (TempFile != INVALID_HANDLE_VALUE)
1392 {
1393 NtClose(TempFile);
1394 DPRINT("Temp file: %S\n", lpTempFileName);
1395 return ID;
1396 }
1397
1398 LastError = GetLastError();
1399 /* There is no need to recover from those errors, they would hit next step */
1400 if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
1401 LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
1402 LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
1403 LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
1404 LastError == ERROR_DISK_CORRUPT ||
1405 (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
1406 {
1407 break;
1408 }
1409 }
1410 Num++;
1411 } while (Num & 0xFFFF);
1412
1413 return 0;
1414 }
1415
1416
1417
1418
1419
1420 /*
1421 * @implemented
1422 */
1423 BOOL WINAPI
1424 GetFileTime(HANDLE hFile,
1425 LPFILETIME lpCreationTime,
1426 LPFILETIME lpLastAccessTime,
1427 LPFILETIME lpLastWriteTime)
1428 {
1429 IO_STATUS_BLOCK IoStatusBlock;
1430 FILE_BASIC_INFORMATION FileBasic;
1431 NTSTATUS Status;
1432
1433 if(IsConsoleHandle(hFile))
1434 {
1435 SetLastError(ERROR_INVALID_HANDLE);
1436 return FALSE;
1437 }
1438
1439 Status = NtQueryInformationFile(hFile,
1440 &IoStatusBlock,
1441 &FileBasic,
1442 sizeof(FILE_BASIC_INFORMATION),
1443 FileBasicInformation);
1444 if (!NT_SUCCESS(Status))
1445 {
1446 SetLastErrorByStatus(Status);
1447 return FALSE;
1448 }
1449
1450 if (lpCreationTime)
1451 memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
1452 if (lpLastAccessTime)
1453 memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
1454 if (lpLastWriteTime)
1455 memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
1456
1457 return TRUE;
1458 }
1459
1460
1461 /*
1462 * @implemented
1463 */
1464 BOOL WINAPI
1465 SetFileTime(HANDLE hFile,
1466 CONST FILETIME *lpCreationTime,
1467 CONST FILETIME *lpLastAccessTime,
1468 CONST FILETIME *lpLastWriteTime)
1469 {
1470 FILE_BASIC_INFORMATION FileBasic;
1471 IO_STATUS_BLOCK IoStatusBlock;
1472 NTSTATUS Status;
1473
1474 if(IsConsoleHandle(hFile))
1475 {
1476 SetLastError(ERROR_INVALID_HANDLE);
1477 return FALSE;
1478 }
1479
1480 Status = NtQueryInformationFile(hFile,
1481 &IoStatusBlock,
1482 &FileBasic,
1483 sizeof(FILE_BASIC_INFORMATION),
1484 FileBasicInformation);
1485 if (!NT_SUCCESS(Status))
1486 {
1487 SetLastErrorByStatus(Status);
1488 return FALSE;
1489 }
1490
1491 if (lpCreationTime)
1492 memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
1493 if (lpLastAccessTime)
1494 memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
1495 if (lpLastWriteTime)
1496 memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
1497
1498 // should i initialize changetime ???
1499
1500 Status = NtSetInformationFile(hFile,
1501 &IoStatusBlock,
1502 &FileBasic,
1503 sizeof(FILE_BASIC_INFORMATION),
1504 FileBasicInformation);
1505 if (!NT_SUCCESS(Status))
1506 {
1507 SetLastErrorByStatus(Status);
1508 return FALSE;
1509 }
1510
1511 return TRUE;
1512 }
1513
1514
1515 /*
1516 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1517 *
1518 * @implemented
1519 */
1520 BOOL WINAPI
1521 SetEndOfFile(HANDLE hFile)
1522 {
1523 IO_STATUS_BLOCK IoStatusBlock;
1524 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1525 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1526 FILE_POSITION_INFORMATION FilePosInfo;
1527 NTSTATUS Status;
1528
1529 if(IsConsoleHandle(hFile))
1530 {
1531 SetLastError(ERROR_INVALID_HANDLE);
1532 return FALSE;
1533 }
1534
1535 //get current position
1536 Status = NtQueryInformationFile(
1537 hFile,
1538 &IoStatusBlock,
1539 &FilePosInfo,
1540 sizeof(FILE_POSITION_INFORMATION),
1541 FilePositionInformation
1542 );
1543
1544 if (!NT_SUCCESS(Status)){
1545 SetLastErrorByStatus(Status);
1546 return FALSE;
1547 }
1548
1549 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1550
1551 /*
1552 NOTE:
1553 This call is not supposed to free up any space after the eof marker
1554 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1555 But...most file systems dispatch both FileEndOfFileInformation
1556 and FileAllocationInformation as they were the same command.
1557
1558 */
1559 Status = NtSetInformationFile(
1560 hFile,
1561 &IoStatusBlock, //out
1562 &EndOfFileInfo,
1563 sizeof(FILE_END_OF_FILE_INFORMATION),
1564 FileEndOfFileInformation
1565 );
1566
1567 if (!NT_SUCCESS(Status)){
1568 SetLastErrorByStatus(Status);
1569 return FALSE;
1570 }
1571
1572 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1573
1574
1575 Status = NtSetInformationFile(
1576 hFile,
1577 &IoStatusBlock, //out
1578 &FileAllocationInfo,
1579 sizeof(FILE_ALLOCATION_INFORMATION),
1580 FileAllocationInformation
1581 );
1582
1583 if (!NT_SUCCESS(Status)){
1584 SetLastErrorByStatus(Status);
1585 return FALSE;
1586 }
1587
1588 return TRUE;
1589
1590 }
1591
1592
1593 /*
1594 * @implemented
1595 */
1596 BOOL
1597 WINAPI
1598 SetFileValidData(
1599 HANDLE hFile,
1600 LONGLONG ValidDataLength
1601 )
1602 {
1603 IO_STATUS_BLOCK IoStatusBlock;
1604 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1605 NTSTATUS Status;
1606
1607 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1608
1609 Status = NtSetInformationFile(
1610 hFile,
1611 &IoStatusBlock, //out
1612 &ValidDataLengthInformation,
1613 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1614 FileValidDataLengthInformation
1615 );
1616
1617 if (!NT_SUCCESS(Status)){
1618 SetLastErrorByStatus(Status);
1619 return FALSE;
1620 }
1621
1622 return TRUE;
1623 }
1624
1625
1626
1627 /*
1628 * @implemented
1629 */
1630 BOOL
1631 WINAPI
1632 SetFileShortNameW(
1633 HANDLE hFile,
1634 LPCWSTR lpShortName)
1635 {
1636 NTSTATUS Status;
1637 ULONG NeededSize;
1638 UNICODE_STRING ShortName;
1639 IO_STATUS_BLOCK IoStatusBlock;
1640 PFILE_NAME_INFORMATION FileNameInfo;
1641
1642 if(IsConsoleHandle(hFile))
1643 {
1644 SetLastError(ERROR_INVALID_HANDLE);
1645 return FALSE;
1646 }
1647
1648 if(!lpShortName)
1649 {
1650 SetLastError(ERROR_INVALID_PARAMETER);
1651 return FALSE;
1652 }
1653
1654 RtlInitUnicodeString(&ShortName, lpShortName);
1655
1656 NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
1657 if(!(FileNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
1658 {
1659 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1660 return FALSE;
1661 }
1662
1663 FileNameInfo->FileNameLength = ShortName.Length;
1664 RtlCopyMemory(FileNameInfo->FileName, ShortName.Buffer, ShortName.Length);
1665
1666 Status = NtSetInformationFile(hFile,
1667 &IoStatusBlock, //out
1668 FileNameInfo,
1669 NeededSize,
1670 FileShortNameInformation);
1671
1672 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInfo);
1673 if(!NT_SUCCESS(Status))
1674 {
1675 SetLastErrorByStatus(Status);
1676 return FALSE;
1677 }
1678
1679 return TRUE;
1680 }
1681
1682
1683 /*
1684 * @implemented
1685 */
1686 BOOL
1687 WINAPI
1688 SetFileShortNameA(
1689 HANDLE hFile,
1690 LPCSTR lpShortName
1691 )
1692 {
1693 PWCHAR ShortNameW;
1694
1695 if(IsConsoleHandle(hFile))
1696 {
1697 SetLastError(ERROR_INVALID_HANDLE);
1698 return FALSE;
1699 }
1700
1701 if(!lpShortName)
1702 {
1703 SetLastError(ERROR_INVALID_PARAMETER);
1704 return FALSE;
1705 }
1706
1707 if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
1708 return FALSE;
1709
1710 return SetFileShortNameW(hFile, ShortNameW);
1711 }
1712
1713
1714 /*
1715 * @implemented
1716 */
1717 BOOL
1718 WINAPI
1719 CheckNameLegalDOS8Dot3W(
1720 LPCWSTR lpName,
1721 LPSTR lpOemName OPTIONAL,
1722 DWORD OemNameSize OPTIONAL,
1723 PBOOL pbNameContainsSpaces OPTIONAL,
1724 PBOOL pbNameLegal
1725 )
1726 {
1727 UNICODE_STRING Name;
1728 ANSI_STRING AnsiName;
1729
1730 if(lpName == NULL ||
1731 (lpOemName == NULL && OemNameSize != 0) ||
1732 pbNameLegal == NULL)
1733 {
1734 SetLastError(ERROR_INVALID_PARAMETER);
1735 return FALSE;
1736 }
1737
1738 if(lpOemName != NULL)
1739 {
1740 AnsiName.Buffer = lpOemName;
1741 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1742 AnsiName.Length = 0;
1743 }
1744
1745 RtlInitUnicodeString(&Name, lpName);
1746
1747 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1748 (lpOemName ? &AnsiName : NULL),
1749 (BOOLEAN*)pbNameContainsSpaces);
1750
1751 return TRUE;
1752 }
1753
1754
1755 /*
1756 * @implemented
1757 */
1758 BOOL
1759 WINAPI
1760 CheckNameLegalDOS8Dot3A(
1761 LPCSTR lpName,
1762 LPSTR lpOemName OPTIONAL,
1763 DWORD OemNameSize OPTIONAL,
1764 PBOOL pbNameContainsSpaces OPTIONAL,
1765 PBOOL pbNameLegal
1766 )
1767 {
1768 UNICODE_STRING Name;
1769 ANSI_STRING AnsiName, AnsiInputName;
1770 NTSTATUS Status;
1771
1772 if(lpName == NULL ||
1773 (lpOemName == NULL && OemNameSize != 0) ||
1774 pbNameLegal == NULL)
1775 {
1776 SetLastError(ERROR_INVALID_PARAMETER);
1777 return FALSE;
1778 }
1779
1780 if(lpOemName != NULL)
1781 {
1782 AnsiName.Buffer = lpOemName;
1783 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1784 AnsiName.Length = 0;
1785 }
1786
1787 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
1788 if(bIsFileApiAnsi)
1789 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1790 else
1791 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1792
1793 if(!NT_SUCCESS(Status))
1794 {
1795 SetLastErrorByStatus(Status);
1796 return FALSE;
1797 }
1798
1799 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1800 (lpOemName ? &AnsiName : NULL),
1801 (BOOLEAN*)pbNameContainsSpaces);
1802
1803 RtlFreeUnicodeString(&Name);
1804
1805 return TRUE;
1806 }
1807
1808
1809 /*
1810 * @implemented
1811 */
1812 DWORD
1813 WINAPI
1814 GetFinalPathNameByHandleA(IN HANDLE hFile,
1815 OUT LPSTR lpszFilePath,
1816 IN DWORD cchFilePath,
1817 IN DWORD dwFlags)
1818 {
1819 WCHAR FilePathW[MAX_PATH];
1820 UNICODE_STRING FilePathU;
1821 DWORD PrevLastError;
1822 DWORD Ret = 0;
1823
1824 if (cchFilePath != 0 &&
1825 cchFilePath > sizeof(FilePathW) / sizeof(FilePathW[0]))
1826 {
1827 FilePathU.Length = 0;
1828 FilePathU.MaximumLength = (USHORT)cchFilePath * sizeof(WCHAR);
1829 FilePathU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1830 0,
1831 FilePathU.MaximumLength);
1832 if (FilePathU.Buffer == NULL)
1833 {
1834 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1835 return 0;
1836 }
1837 }
1838 else
1839 {
1840 FilePathU.Length = 0;
1841 FilePathU.MaximumLength = sizeof(FilePathW);
1842 FilePathU.Buffer = FilePathW;
1843 }
1844
1845 /* save the last error code */
1846 PrevLastError = GetLastError();
1847 SetLastError(ERROR_SUCCESS);
1848
1849 /* call the unicode version that does all the work */
1850 Ret = GetFinalPathNameByHandleW(hFile,
1851 FilePathU.Buffer,
1852 cchFilePath,
1853 dwFlags);
1854
1855 if (GetLastError() == ERROR_SUCCESS)
1856 {
1857 /* no error, restore the last error code and convert the string */
1858 SetLastError(PrevLastError);
1859
1860 Ret = FilenameU2A_FitOrFail(lpszFilePath,
1861 cchFilePath,
1862 &FilePathU);
1863 }
1864
1865 /* free allocated memory if necessary */
1866 if (FilePathU.Buffer != FilePathW)
1867 {
1868 RtlFreeHeap(RtlGetProcessHeap(),
1869 0,
1870 FilePathU.Buffer);
1871 }
1872
1873 return Ret;
1874 }
1875
1876
1877 /*
1878 * @unimplemented
1879 */
1880 DWORD
1881 WINAPI
1882 GetFinalPathNameByHandleW(IN HANDLE hFile,
1883 OUT LPWSTR lpszFilePath,
1884 IN DWORD cchFilePath,
1885 IN DWORD dwFlags)
1886 {
1887 if (dwFlags & ~(VOLUME_NAME_DOS | VOLUME_NAME_GUID | VOLUME_NAME_NT |
1888 VOLUME_NAME_NONE | FILE_NAME_NORMALIZED | FILE_NAME_OPENED))
1889 {
1890 SetLastError(ERROR_INVALID_PARAMETER);
1891 return 0;
1892 }
1893
1894 UNIMPLEMENTED;
1895 return 0;
1896 }
1897
1898
1899 /*
1900 * @unimplemented
1901 */
1902 BOOL
1903 WINAPI
1904 SetFileBandwidthReservation(IN HANDLE hFile,
1905 IN DWORD nPeriodMilliseconds,
1906 IN DWORD nBytesPerPeriod,
1907 IN BOOL bDiscardable,
1908 OUT LPDWORD lpTransferSize,
1909 OUT LPDWORD lpNumOutstandingRequests)
1910 {
1911 UNIMPLEMENTED;
1912 return FALSE;
1913 }
1914
1915
1916 /*
1917 * @unimplemented
1918 */
1919 BOOL
1920 WINAPI
1921 GetFileBandwidthReservation(IN HANDLE hFile,
1922 OUT LPDWORD lpPeriodMilliseconds,
1923 OUT LPDWORD lpBytesPerPeriod,
1924 OUT LPBOOL pDiscardable,
1925 OUT LPDWORD lpTransferSize,
1926 OUT LPDWORD lpNumOutstandingRequests)
1927 {
1928 UNIMPLEMENTED;
1929 return FALSE;
1930 }
1931
1932
1933 /*
1934 * @unimplemented
1935 */
1936 BOOL
1937 WINAPI
1938 SetFileCompletionNotificationModes(IN HANDLE FileHandle,
1939 IN UCHAR Flags)
1940 {
1941 if (Flags & ~(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE))
1942 {
1943 SetLastError(ERROR_INVALID_PARAMETER);
1944 return FALSE;
1945 }
1946
1947 UNIMPLEMENTED;
1948 return FALSE;
1949 }
1950
1951
1952 /*
1953 * @unimplemented
1954 */
1955 HANDLE
1956 WINAPI
1957 OpenFileById(IN HANDLE hFile,
1958 IN LPFILE_ID_DESCRIPTOR lpFileID,
1959 IN DWORD dwDesiredAccess,
1960 IN DWORD dwShareMode,
1961 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
1962 IN DWORD dwFlags)
1963 {
1964 UNIMPLEMENTED;
1965 return INVALID_HANDLE_VALUE;
1966 }
1967
1968 /*
1969 * @implemented
1970 */
1971 BOOL
1972 WINAPI
1973 ReplaceFileA(
1974 LPCSTR lpReplacedFileName,
1975 LPCSTR lpReplacementFileName,
1976 LPCSTR lpBackupFileName,
1977 DWORD dwReplaceFlags,
1978 LPVOID lpExclude,
1979 LPVOID lpReserved
1980 )
1981 {
1982 WCHAR *replacedW, *replacementW, *backupW = NULL;
1983 BOOL ret;
1984
1985 /* This function only makes sense when the first two parameters are defined */
1986 if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
1987 {
1988 SetLastError(ERROR_INVALID_PARAMETER);
1989 return FALSE;
1990 }
1991
1992 if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
1993 {
1994 HeapFree(GetProcessHeap(), 0, replacedW);
1995 SetLastError(ERROR_INVALID_PARAMETER);
1996 return FALSE;
1997 }
1998
1999 /* The backup parameter, however, is optional */
2000 if (lpBackupFileName)
2001 {
2002 if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
2003 {
2004 HeapFree(GetProcessHeap(), 0, replacedW);
2005 HeapFree(GetProcessHeap(), 0, replacementW);
2006 SetLastError(ERROR_INVALID_PARAMETER);
2007 return FALSE;
2008 }
2009 }
2010
2011 ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
2012 HeapFree(GetProcessHeap(), 0, replacedW);
2013 HeapFree(GetProcessHeap(), 0, replacementW);
2014 HeapFree(GetProcessHeap(), 0, backupW);
2015
2016 return ret;
2017 }
2018
2019 /*
2020 * @unimplemented
2021 */
2022 BOOL
2023 WINAPI
2024 ReplaceFileW(
2025 LPCWSTR lpReplacedFileName,
2026 LPCWSTR lpReplacementFileName,
2027 LPCWSTR lpBackupFileName,
2028 DWORD dwReplaceFlags,
2029 LPVOID lpExclude,
2030 LPVOID lpReserved
2031 )
2032 {
2033 HANDLE hReplaced = NULL, hReplacement = NULL;
2034 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
2035 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
2036 DWORD Error = ERROR_SUCCESS;
2037 NTSTATUS Status;
2038 BOOL Ret = FALSE;
2039 IO_STATUS_BLOCK IoStatusBlock;
2040 OBJECT_ATTRIBUTES ObjectAttributes;
2041 PVOID Buffer = NULL ;
2042
2043 if (dwReplaceFlags)
2044 FIXME("Ignoring flags %x\n", dwReplaceFlags);
2045
2046 /* First two arguments are mandatory */
2047 if (!lpReplacedFileName || !lpReplacementFileName)
2048 {
2049 SetLastError(ERROR_INVALID_PARAMETER);
2050 return FALSE;
2051 }
2052
2053 /* Back it up */
2054 if(lpBackupFileName)
2055 {
2056 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
2057 {
2058 Error = GetLastError();
2059 goto Cleanup ;
2060 }
2061 }
2062
2063 /* Open the "replaced" file for reading and writing */
2064 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
2065 {
2066 Error = ERROR_PATH_NOT_FOUND;
2067 goto Cleanup;
2068 }
2069
2070 InitializeObjectAttributes(&ObjectAttributes,
2071 &NtReplacedName,
2072 OBJ_CASE_INSENSITIVE,
2073 NULL,
2074 NULL);
2075
2076 Status = NtOpenFile(&hReplaced,
2077 GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE | WRITE_DAC,
2078 &ObjectAttributes,
2079 &IoStatusBlock,
2080 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2081 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
2082
2083 if (!NT_SUCCESS(Status))
2084 {
2085 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2086 Error = ERROR_FILE_NOT_FOUND;
2087 else
2088 Error = ERROR_UNABLE_TO_REMOVE_REPLACED;
2089 goto Cleanup;
2090 }
2091
2092 /* Blank it */
2093 SetEndOfFile(hReplaced) ;
2094
2095 /*
2096 * Open the replacement file for reading, writing, and deleting
2097 * (deleting is needed when finished)
2098 */
2099 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
2100 {
2101 Error = ERROR_PATH_NOT_FOUND;
2102 goto Cleanup;
2103 }
2104
2105 InitializeObjectAttributes(&ObjectAttributes,
2106 &NtReplacementName,
2107 OBJ_CASE_INSENSITIVE,
2108 NULL,
2109 NULL);
2110
2111 Status = NtOpenFile(&hReplacement,
2112 GENERIC_READ | DELETE | SYNCHRONIZE,
2113 &ObjectAttributes,
2114 &IoStatusBlock,
2115 0,
2116 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
2117
2118 if (!NT_SUCCESS(Status))
2119 {
2120 Error = RtlNtStatusToDosError(Status);
2121 goto Cleanup;
2122 }
2123
2124 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
2125 if (!Buffer)
2126 {
2127 Error = ERROR_NOT_ENOUGH_MEMORY;
2128 goto Cleanup ;
2129 }
2130 while (Status != STATUS_END_OF_FILE)
2131 {
2132 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
2133 if (NT_SUCCESS(Status))
2134 {
2135 Status = NtWriteFile(hReplaced, NULL, NULL, NULL, &IoStatusBlock, Buffer,
2136 IoStatusBlock.Information, NULL, NULL) ;
2137 if (!NT_SUCCESS(Status))
2138 {
2139 Error = RtlNtStatusToDosError(Status);
2140 goto Cleanup;
2141 }
2142 }
2143 else if (Status != STATUS_END_OF_FILE)
2144 {
2145 Error = RtlNtStatusToDosError(Status);
2146 goto Cleanup;
2147 }
2148 }
2149
2150 Ret = TRUE;
2151
2152 /* Perform resource cleanup */
2153 Cleanup:
2154 if (hReplaced) NtClose(hReplaced);
2155 if (hReplacement) NtClose(hReplacement);
2156 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2157
2158 if (NtReplacementName.Buffer)
2159 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
2160 if (NtReplacedName.Buffer)
2161 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
2162
2163 /* If there was an error, set the error code */
2164 if(!Ret)
2165 {
2166 TRACE("ReplaceFileW failed (error=%d)\n", Error);
2167 SetLastError(Error);
2168 }
2169 return Ret;
2170 }
2171
2172 /* EOF */